Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 0 additions & 19 deletions .eslintrc.cjs

This file was deleted.

2 changes: 1 addition & 1 deletion .husky/pre-commit
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"

yarn tsdx lint
yarn lint
26 changes: 0 additions & 26 deletions commonjs.js

This file was deleted.

57 changes: 57 additions & 0 deletions eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import eslintPluginEsX from 'eslint-plugin-es-x';
import eslintConfigPrettier from 'eslint-config-prettier';
import eslintPluginPrettier from 'eslint-plugin-prettier';

export default tseslint.config(
eslint.configs.recommended,
...tseslint.configs.recommended,
eslintConfigPrettier,
{
plugins: {
'es-x': eslintPluginEsX,
prettier: eslintPluginPrettier,
},
rules: {
// Prettier integration
'prettier/prettier': 'error',

// Selective ES5 compatibility rules for browser features
// Note: Map, Set, Symbol are core to this library's functionality, so not restricted
'es-x/no-for-of-loops': 'error',
'es-x/no-generators': 'error',
'es-x/no-array-prototype-find': 'error',
'es-x/no-object-values': 'error',
'es-x/no-object-entries': 'error',
'es-x/no-object-setprototypeof': 'error',

// Allow Object.assign (commonly polyfilled and already in exception)
'es-x/no-object-assign': 'off',

// Code quality rules - similar to tsdx
'@typescript-eslint/no-unused-vars': [
'error',
{ argsIgnorePattern: '^_' },
],
'@typescript-eslint/no-explicit-any': 'off', // Allow any - this is a serialization library
'@typescript-eslint/no-non-null-assertion': 'off', // Allow non-null assertions
'@typescript-eslint/ban-ts-comment': 'off', // Allow @ts-ignore in tests
'@typescript-eslint/no-empty-object-type': 'off', // Allow empty object types
'@typescript-eslint/no-wrapper-object-types': 'off', // Allow Symbol type
'no-prototype-builtins': 'off', // Allow hasOwnProperty usage
'no-extra-boolean-cast': 'off', // Allow double negation
'no-object-constructor': 'error', // Replaces deprecated no-new-object

// Maintain some restrictions for code quality
'no-restricted-syntax': [
'error',
{
selector: 'ForInStatement',
message:
'for..in loops iterate over the entire prototype chain, which is virtually never what you want. Use Object.{keys,values,entries}, and iterate over the resulting array.',
},
],
},
}
);
46 changes: 28 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,31 @@
"version": "2.2.2",
"license": "MIT",
"type": "module",
"typings": "dist/index.d.ts",
"main": "./dist/index.js",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
"import": "./dist/index.js",
"require": "./dist-cjs/index.cjs"
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"files": [
"dist",
"dist-cjs"
"dist"
],
"engines": {
"node": ">=16"
},
"scripts": {
"build": "yarn run build:esm && yarn run build:cjs",
"build:esm": "tsc -p tsconfig.json",
"build:cjs": "tsc -p tsconfig.cjs.json && node commonjs.js",
"build": "tsup",
"test": "vitest run",
"lint": "tsdx lint",
"lint": "eslint src --ext .ts",
"prepack": "yarn build",
"prepare": "husky install",
"publish-please": "publish-please",
Expand All @@ -35,7 +41,8 @@
"printWidth": 80,
"semi": true,
"singleQuote": true,
"trailingComma": "es5"
"trailingComma": "es5",
"arrowParens": "avoid"
},
"name": "superjson",
"author": {
Expand Down Expand Up @@ -63,21 +70,24 @@
"@types/debug": "^4.1.5",
"@types/mongodb": "^3.6.12",
"@types/node": "^18.7.18",
"@typescript-eslint/eslint-plugin": "^8.41.0",
"@typescript-eslint/parser": "^8.41.0",
"benchmark": "^2.1.4",
"decimal.js": "^10.3.1",
"eslint-plugin-es5": "^1.5.0",
"eslint": "^9.34.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-es-x": "^9.1.0",
"eslint-plugin-prettier": "^5.5.4",
"husky": "^6.0.0",
"mongodb": "^3.6.6",
"prettier": "^3.6.2",
"publish-please": "^5.5.2",
"tsdx": "^0.14.1",
"typescript": "^4.2.4",
"tsup": "^8.5.0",
"typescript": "^5.0.0",
"typescript-eslint": "^8.41.0",
"vitest": "^0.34.6"
},
"dependencies": {
"copy-anything": "^4"
},
"resolutions": {
"**/@typescript-eslint/eslint-plugin": "^4.11.1",
"**/@typescript-eslint/parser": "^4.11.1"
}
}
55 changes: 31 additions & 24 deletions src/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/* eslint-disable es5/no-for-of */
/* eslint-disable es5/no-es6-methods */
/* eslint-disable es-x/no-for-of-loops */
/* eslint-disable es-x/no-object-values */
/* eslint-disable es-x/no-object-entries */

import * as fs from 'fs';

Expand Down Expand Up @@ -324,25 +325,26 @@ describe('stringify & parse', () => {
},
},

'works for Maps with two keys that serialize to the same string but have a different reference': {
input: new Map([
[/a/g, 'foo'],
[/a/g, 'bar'],
]),
output: [
['/a/g', 'foo'],
['/a/g', 'bar'],
],
outputAnnotations: {
values: [
'map',
{
'0.0': ['regexp'],
'1.0': ['regexp'],
},
'works for Maps with two keys that serialize to the same string but have a different reference':
{
input: new Map([
[/a/g, 'foo'],
[/a/g, 'bar'],
]),
output: [
['/a/g', 'foo'],
['/a/g', 'bar'],
],
outputAnnotations: {
values: [
'map',
{
'0.0': ['regexp'],
'1.0': ['regexp'],
},
],
},
},
},

"works for Maps with a key that's referentially equal to another field": {
input: () => {
Expand Down Expand Up @@ -590,7 +592,10 @@ describe('stringify & parse', () => {
'works with custom allowedProps': {
input: () => {
class User {
constructor(public username: string, public password: string) {}
constructor(
public username: string,
public password: string
) {}
}
SuperJSON.registerClass(User, { allowProps: ['username'] });
return new User('bongocat', 'supersecurepassword');
Expand Down Expand Up @@ -911,7 +916,7 @@ describe('stringify & parse', () => {
class CustomError extends Error {
constructor(public readonly customProperty: number) {
super("I'm a custom error");
// eslint-disable-next-line es5/no-es6-static-methods
// eslint-disable-next-line es-x/no-object-setprototypeof
Object.setPrototypeOf(this, CustomError.prototype);
}
}
Expand Down Expand Up @@ -1009,8 +1014,8 @@ test('regression https://github.com/blitz-js/babel-plugin-superjson-next/issues/
test('performance regression', () => {
const data: any[] = [];
for (let i = 0; i < 100; i++) {
let nested1 = [];
let nested2 = [];
const nested1 = [];
const nested2 = [];
for (let j = 0; j < 10; j++) {
nested1[j] = {
createdAt: new Date(),
Expand Down Expand Up @@ -1275,7 +1280,9 @@ test('doesnt iterate to keys that dont exist', () => {
test('deserialize in place', () => {
const serialized = SuperJSON.serialize({ a: new Date() });
const deserializedCopy = SuperJSON.deserialize(serialized);
const deserializedInPlace = SuperJSON.deserialize(serialized, { inPlace: true });
const deserializedInPlace = SuperJSON.deserialize(serialized, {
inPlace: true,
});
expect(deserializedInPlace).toBe(serialized.json);
expect(deserializedCopy).not.toBe(serialized.json);
expect(deserializedCopy).toEqual(deserializedInPlace);
Expand Down
7 changes: 5 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,10 +60,13 @@ export default class SuperJSON {
return res;
}

deserialize<T = unknown>(payload: SuperJSONResult, options?: { inPlace?: boolean }): T {
deserialize<T = unknown>(
payload: SuperJSONResult,
options?: { inPlace?: boolean }
): T {
const { json, meta } = payload;

let result: T = options?.inPlace ? json : copy(json) as any;
let result: T = options?.inPlace ? json : (copy(json) as any);

if (meta?.values) {
result = applyValueAnnotations(result, meta.values, meta.v ?? 0, this);
Expand Down
4 changes: 2 additions & 2 deletions src/is.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ test('Basic true tests', () => {
expect(isTypedArray(new Uint8Array())).toBe(true);
expect(isURL(new URL('https://example.com'))).toBe(true);
expect(isPlainObject({})).toBe(true);
// eslint-disable-next-line no-new-object
// eslint-disable-next-line no-object-constructor
expect(isPlainObject(new Object())).toBe(true);
});

Expand Down Expand Up @@ -78,7 +78,7 @@ test('Primitive tests', () => {
expect(isPrimitive([])).toBe(false);
expect(isPrimitive([])).toBe(false);
expect(isPrimitive({})).toBe(false);
// eslint-disable-next-line no-new-object
// eslint-disable-next-line no-object-constructor
expect(isPrimitive(new Object())).toBe(false);
expect(isPrimitive(new Date())).toBe(false);
expect(isPrimitive(() => {})).toBe(false);
Expand Down
12 changes: 6 additions & 6 deletions src/pathstringifier.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ describe('parsePath', () => {
expect(parsePath(input, false)).toEqual(expectedOutput);
});

it.each([
'test\\a.b',
'foo.bar.baz\\',
])('parsePath(%p) is rejected', (input) => {
expect(() => parsePath(input, false)).toThrowError();
});
it.each(['test\\a.b', 'foo.bar.baz\\'])(
'parsePath(%p) is rejected',
input => {
expect(() => parsePath(input, false)).toThrowError();
}
);
});

describe('escapeKey', () => {
Expand Down
7 changes: 2 additions & 5 deletions src/pathstringifier.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,14 @@ export const escapeKey = (key: string) =>
key.replace(/\\/g, '\\\\').replace(/\./g, '\\.');

export const stringifyPath = (path: Path): StringifiedPath =>
path
.map(String)
.map(escapeKey)
.join('.');
path.map(String).map(escapeKey).join('.');

export const parsePath = (string: StringifiedPath, legacyPaths: boolean) => {
const result: string[] = [];

let segment = '';
for (let i = 0; i < string.length; i++) {
let char = string.charAt(i);
const char = string.charAt(i);

if (!legacyPaths && char === '\\') {
const escaped = string.charAt(i + 1);
Expand Down
5 changes: 2 additions & 3 deletions src/plainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,8 @@ export function generateReferentialEqualityAnnotations(
if (representativePath.length === 0) {
rootEqualityPaths = identicalPaths.map(stringifyPath);
} else {
result[stringifyPath(representativePath)] = identicalPaths.map(
stringifyPath
);
result[stringifyPath(representativePath)] =
identicalPaths.map(stringifyPath);
}
});

Expand Down
Loading