@brillout/json-serializer 0.5.8 → 0.5.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,2 +1,4 @@
1
1
  export { parse };
2
+ export { parseTransform };
2
3
  declare function parse(str: string): unknown;
4
+ declare function parseTransform(value: unknown): unknown;
package/dist/cjs/parse.js CHANGED
@@ -1,25 +1,29 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parse = void 0;
3
+ exports.parseTransform = exports.parse = void 0;
4
4
  const types_1 = require("./types");
5
5
  function parse(str) {
6
6
  // We don't use the reviver option in `JSON.parse(str, reviver)` because it doesn't support `undefined` values
7
7
  const value = JSON.parse(str);
8
- return modifier(value);
8
+ return parseTransform(value);
9
9
  }
10
10
  exports.parse = parse;
11
- function modifier(value) {
11
+ function parseTransform(value) {
12
12
  if (typeof value === 'string') {
13
13
  return reviver(value);
14
14
  }
15
- if (typeof value === 'object' && value !== null) {
15
+ if (
16
+ // Also matches arrays
17
+ typeof value === 'object' &&
18
+ value !== null) {
16
19
  Object.entries(value).forEach(([key, val]) => {
17
20
  ;
18
- value[key] = modifier(val);
21
+ value[key] = parseTransform(val);
19
22
  });
20
23
  }
21
24
  return value;
22
25
  }
26
+ exports.parseTransform = parseTransform;
23
27
  function reviver(value) {
24
28
  for (const { match, deserialize } of types_1.types) {
25
29
  if (match(value)) {
@@ -1,10 +1,14 @@
1
1
  export { stringify };
2
2
  export { isJsonSerializerError };
3
- declare function stringify(value: unknown, { forbidReactElements, space, valueName, sortObjectKeys }?: {
3
+ import { type Iterable } from './utils/replacerWithPath';
4
+ declare function stringify(value: unknown, { forbidReactElements, space, valueName, sortObjectKeys, replacer: replacerUserProvided, }?: {
4
5
  forbidReactElements?: boolean;
5
6
  space?: number;
6
7
  valueName?: string;
7
8
  sortObjectKeys?: boolean;
9
+ replacer?: (this: Iterable, key: string, value: unknown, path: string) => void | {
10
+ replacement: unknown;
11
+ };
8
12
  }): string;
9
13
  type JsonSerializerError = Error & {
10
14
  messageCore: string;
@@ -6,7 +6,7 @@ const isReactElement_1 = require("./utils/isReactElement");
6
6
  const isCallable_1 = require("./utils/isCallable");
7
7
  const isObject_1 = require("./utils/isObject");
8
8
  const replacerWithPath_1 = require("./utils/replacerWithPath");
9
- function stringify(value, { forbidReactElements, space, valueName, sortObjectKeys } = {}) {
9
+ function stringify(value, { forbidReactElements, space, valueName, sortObjectKeys, replacer: replacerUserProvided, } = {}) {
10
10
  // The only error `JSON.stringify()` can throw is `TypeError "cyclic object value"`.
11
11
  // - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#exceptions
12
12
  // - This means we have total of 3 possible errors while serializing:
@@ -16,6 +16,11 @@ function stringify(value, { forbidReactElements, space, valueName, sortObjectKey
16
16
  const serializer = (val) => JSON.stringify(val, (0, replacerWithPath_1.replacerWithPath)(replacer, !valueName), space);
17
17
  return serializer(value);
18
18
  function replacer(key, value, path) {
19
+ {
20
+ const ret = replacerUserProvided === null || replacerUserProvided === void 0 ? void 0 : replacerUserProvided.call(this, key, value, path);
21
+ if (ret)
22
+ return ret.replacement;
23
+ }
19
24
  if (forbidReactElements && (0, isReactElement_1.isReactElement)(value)) {
20
25
  throw genErr(genErrMsg('React element', path, valueName));
21
26
  }
@@ -48,7 +53,7 @@ function genErr(errMsg) {
48
53
  const err = new Error(`[@brillout/json-serializer](https://github.com/brillout/json-serializer) ${errMsg}.`);
49
54
  Object.assign(err, {
50
55
  messageCore: errMsg,
51
- [stamp]: true
56
+ [stamp]: true,
52
57
  });
53
58
  return err;
54
59
  }
@@ -1,8 +1,8 @@
1
1
  export { types };
2
- declare const types: readonly [Type<undefined, unknown>, Type<number, unknown>, Type<number, unknown>, Type<number, unknown>, Type<Date, any>, Type<BigInt, any>, Type<RegExp, any>, Type<Map<any, any>, any[]>, Type<Set<unknown>, unknown[]>, Type<string, any>];
3
- type Type<T, IntermediateType> = {
4
- is: (val: unknown) => asserts val is T;
2
+ declare const types: readonly Type<any, any>[];
3
+ type Type<ValueType, IntermediateType> = {
4
+ is: (val: unknown) => asserts val is ValueType;
5
5
  match: (str: string) => boolean;
6
- serialize: (val: T, serializer: (val: IntermediateType) => string) => string;
7
- deserialize: (str: string, deserializer: (str: string) => IntermediateType) => T;
6
+ serialize: (val: ValueType, serializer: (val: IntermediateType) => string) => string;
7
+ deserialize: (str: string, deserializer: (str: string) => IntermediateType) => ValueType;
8
8
  };
package/dist/cjs/types.js CHANGED
@@ -6,31 +6,31 @@ const types = [
6
6
  is: (val) => val === undefined,
7
7
  match: (str) => str === '!undefined',
8
8
  serialize: () => '!undefined',
9
- deserialize: () => undefined
9
+ deserialize: () => undefined,
10
10
  }),
11
11
  ts({
12
12
  is: (val) => val === Infinity,
13
13
  match: (str) => str === '!Infinity',
14
14
  serialize: () => '!Infinity',
15
- deserialize: () => Infinity
15
+ deserialize: () => Infinity,
16
16
  }),
17
17
  ts({
18
18
  is: (val) => val === -Infinity,
19
19
  match: (str) => str === '!-Infinity',
20
20
  serialize: () => '!-Infinity',
21
- deserialize: () => -Infinity
21
+ deserialize: () => -Infinity,
22
22
  }),
23
23
  ts({
24
24
  is: (val) => typeof val === 'number' && isNaN(val),
25
25
  match: (str) => str === '!NaN',
26
26
  serialize: () => '!NaN',
27
- deserialize: () => NaN
27
+ deserialize: () => NaN,
28
28
  }),
29
29
  ts({
30
30
  is: (val) => val instanceof Date,
31
31
  match: (str) => str.startsWith('!Date:'),
32
32
  serialize: (val) => '!Date:' + val.toISOString(),
33
- deserialize: (str) => new Date(str.slice('!Date:'.length))
33
+ deserialize: (str) => new Date(str.slice('!Date:'.length)),
34
34
  }),
35
35
  ts({
36
36
  is: (val) => typeof val === 'bigint',
@@ -41,7 +41,7 @@ const types = [
41
41
  throw new Error('Your JavaScript environement does not support BigInt. Consider adding a polyfill.');
42
42
  }
43
43
  return BigInt(str.slice('!BigInt:'.length));
44
- }
44
+ },
45
45
  }),
46
46
  ts({
47
47
  is: (val) => val instanceof RegExp,
@@ -54,27 +54,27 @@ const types = [
54
54
  const pattern = args[1];
55
55
  const flags = args[2];
56
56
  return new RegExp(pattern, flags);
57
- }
57
+ },
58
58
  }),
59
59
  ts({
60
60
  is: (val) => val instanceof Map,
61
61
  match: (str) => str.startsWith('!Map:'),
62
62
  serialize: (val, serializer) => '!Map:' + serializer(Array.from(val.entries())),
63
- deserialize: (str, deserializer) => new Map(deserializer(str.slice('!Map:'.length)))
63
+ deserialize: (str, deserializer) => new Map(deserializer(str.slice('!Map:'.length))),
64
64
  }),
65
65
  ts({
66
66
  is: (val) => val instanceof Set,
67
67
  match: (str) => str.startsWith('!Set:'),
68
68
  serialize: (val, serializer) => '!Set:' + serializer(Array.from(val.values())),
69
- deserialize: (str, deserializer) => new Set(deserializer(str.slice('!Set:'.length)))
69
+ deserialize: (str, deserializer) => new Set(deserializer(str.slice('!Set:'.length))),
70
70
  }),
71
71
  // Avoid collisions with the special strings defined above
72
72
  ts({
73
73
  is: (val) => typeof val === 'string' && val.startsWith('!'),
74
74
  match: (str) => str.startsWith('!'),
75
75
  serialize: (val) => '!' + val,
76
- deserialize: (str) => str.slice(1)
77
- })
76
+ deserialize: (str) => str.slice(1),
77
+ }),
78
78
  ];
79
79
  exports.types = types;
80
80
  // Type check
@@ -1,3 +1,5 @@
1
1
  export { replacerWithPath };
2
+ export type { Iterable };
2
3
  type Iterable = Record<string, unknown>;
3
- declare function replacerWithPath(replacer: (this: Iterable, key: string, value: unknown, path: string) => unknown, canBeFirstKey: boolean): (this: Iterable, key: string, value: unknown) => unknown;
4
+ type Replacer = (this: Iterable, key: string, value: unknown, path: string) => unknown;
5
+ declare function replacerWithPath(replacer: Replacer, canBeFirstKey: boolean): (this: Iterable, key: string, value: unknown) => unknown;
@@ -1,2 +1,4 @@
1
1
  export { parse };
2
+ export { parseTransform };
2
3
  declare function parse(str: string): unknown;
4
+ declare function parseTransform(value: unknown): unknown;
package/dist/esm/parse.js CHANGED
@@ -1,18 +1,22 @@
1
1
  export { parse };
2
+ export { parseTransform };
2
3
  import { types } from './types';
3
4
  function parse(str) {
4
5
  // We don't use the reviver option in `JSON.parse(str, reviver)` because it doesn't support `undefined` values
5
6
  const value = JSON.parse(str);
6
- return modifier(value);
7
+ return parseTransform(value);
7
8
  }
8
- function modifier(value) {
9
+ function parseTransform(value) {
9
10
  if (typeof value === 'string') {
10
11
  return reviver(value);
11
12
  }
12
- if (typeof value === 'object' && value !== null) {
13
+ if (
14
+ // Also matches arrays
15
+ typeof value === 'object' &&
16
+ value !== null) {
13
17
  Object.entries(value).forEach(([key, val]) => {
14
18
  ;
15
- value[key] = modifier(val);
19
+ value[key] = parseTransform(val);
16
20
  });
17
21
  }
18
22
  return value;
@@ -1,10 +1,14 @@
1
1
  export { stringify };
2
2
  export { isJsonSerializerError };
3
- declare function stringify(value: unknown, { forbidReactElements, space, valueName, sortObjectKeys }?: {
3
+ import { type Iterable } from './utils/replacerWithPath';
4
+ declare function stringify(value: unknown, { forbidReactElements, space, valueName, sortObjectKeys, replacer: replacerUserProvided, }?: {
4
5
  forbidReactElements?: boolean;
5
6
  space?: number;
6
7
  valueName?: string;
7
8
  sortObjectKeys?: boolean;
9
+ replacer?: (this: Iterable, key: string, value: unknown, path: string) => void | {
10
+ replacement: unknown;
11
+ };
8
12
  }): string;
9
13
  type JsonSerializerError = Error & {
10
14
  messageCore: string;
@@ -5,7 +5,7 @@ import { isReactElement } from './utils/isReactElement';
5
5
  import { isCallable } from './utils/isCallable';
6
6
  import { isObject } from './utils/isObject';
7
7
  import { replacerWithPath } from './utils/replacerWithPath';
8
- function stringify(value, { forbidReactElements, space, valueName, sortObjectKeys } = {}) {
8
+ function stringify(value, { forbidReactElements, space, valueName, sortObjectKeys, replacer: replacerUserProvided, } = {}) {
9
9
  // The only error `JSON.stringify()` can throw is `TypeError "cyclic object value"`.
10
10
  // - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#exceptions
11
11
  // - This means we have total of 3 possible errors while serializing:
@@ -15,6 +15,11 @@ function stringify(value, { forbidReactElements, space, valueName, sortObjectKey
15
15
  const serializer = (val) => JSON.stringify(val, replacerWithPath(replacer, !valueName), space);
16
16
  return serializer(value);
17
17
  function replacer(key, value, path) {
18
+ {
19
+ const ret = replacerUserProvided?.call(this, key, value, path);
20
+ if (ret)
21
+ return ret.replacement;
22
+ }
18
23
  if (forbidReactElements && isReactElement(value)) {
19
24
  throw genErr(genErrMsg('React element', path, valueName));
20
25
  }
@@ -46,7 +51,7 @@ function genErr(errMsg) {
46
51
  const err = new Error(`[@brillout/json-serializer](https://github.com/brillout/json-serializer) ${errMsg}.`);
47
52
  Object.assign(err, {
48
53
  messageCore: errMsg,
49
- [stamp]: true
54
+ [stamp]: true,
50
55
  });
51
56
  return err;
52
57
  }
@@ -1,8 +1,8 @@
1
1
  export { types };
2
- declare const types: readonly [Type<undefined, unknown>, Type<number, unknown>, Type<number, unknown>, Type<number, unknown>, Type<Date, any>, Type<BigInt, any>, Type<RegExp, any>, Type<Map<any, any>, any[]>, Type<Set<unknown>, unknown[]>, Type<string, any>];
3
- type Type<T, IntermediateType> = {
4
- is: (val: unknown) => asserts val is T;
2
+ declare const types: readonly Type<any, any>[];
3
+ type Type<ValueType, IntermediateType> = {
4
+ is: (val: unknown) => asserts val is ValueType;
5
5
  match: (str: string) => boolean;
6
- serialize: (val: T, serializer: (val: IntermediateType) => string) => string;
7
- deserialize: (str: string, deserializer: (str: string) => IntermediateType) => T;
6
+ serialize: (val: ValueType, serializer: (val: IntermediateType) => string) => string;
7
+ deserialize: (str: string, deserializer: (str: string) => IntermediateType) => ValueType;
8
8
  };
package/dist/esm/types.js CHANGED
@@ -4,31 +4,31 @@ const types = [
4
4
  is: (val) => val === undefined,
5
5
  match: (str) => str === '!undefined',
6
6
  serialize: () => '!undefined',
7
- deserialize: () => undefined
7
+ deserialize: () => undefined,
8
8
  }),
9
9
  ts({
10
10
  is: (val) => val === Infinity,
11
11
  match: (str) => str === '!Infinity',
12
12
  serialize: () => '!Infinity',
13
- deserialize: () => Infinity
13
+ deserialize: () => Infinity,
14
14
  }),
15
15
  ts({
16
16
  is: (val) => val === -Infinity,
17
17
  match: (str) => str === '!-Infinity',
18
18
  serialize: () => '!-Infinity',
19
- deserialize: () => -Infinity
19
+ deserialize: () => -Infinity,
20
20
  }),
21
21
  ts({
22
22
  is: (val) => typeof val === 'number' && isNaN(val),
23
23
  match: (str) => str === '!NaN',
24
24
  serialize: () => '!NaN',
25
- deserialize: () => NaN
25
+ deserialize: () => NaN,
26
26
  }),
27
27
  ts({
28
28
  is: (val) => val instanceof Date,
29
29
  match: (str) => str.startsWith('!Date:'),
30
30
  serialize: (val) => '!Date:' + val.toISOString(),
31
- deserialize: (str) => new Date(str.slice('!Date:'.length))
31
+ deserialize: (str) => new Date(str.slice('!Date:'.length)),
32
32
  }),
33
33
  ts({
34
34
  is: (val) => typeof val === 'bigint',
@@ -39,7 +39,7 @@ const types = [
39
39
  throw new Error('Your JavaScript environement does not support BigInt. Consider adding a polyfill.');
40
40
  }
41
41
  return BigInt(str.slice('!BigInt:'.length));
42
- }
42
+ },
43
43
  }),
44
44
  ts({
45
45
  is: (val) => val instanceof RegExp,
@@ -52,27 +52,27 @@ const types = [
52
52
  const pattern = args[1];
53
53
  const flags = args[2];
54
54
  return new RegExp(pattern, flags);
55
- }
55
+ },
56
56
  }),
57
57
  ts({
58
58
  is: (val) => val instanceof Map,
59
59
  match: (str) => str.startsWith('!Map:'),
60
60
  serialize: (val, serializer) => '!Map:' + serializer(Array.from(val.entries())),
61
- deserialize: (str, deserializer) => new Map(deserializer(str.slice('!Map:'.length)))
61
+ deserialize: (str, deserializer) => new Map(deserializer(str.slice('!Map:'.length))),
62
62
  }),
63
63
  ts({
64
64
  is: (val) => val instanceof Set,
65
65
  match: (str) => str.startsWith('!Set:'),
66
66
  serialize: (val, serializer) => '!Set:' + serializer(Array.from(val.values())),
67
- deserialize: (str, deserializer) => new Set(deserializer(str.slice('!Set:'.length)))
67
+ deserialize: (str, deserializer) => new Set(deserializer(str.slice('!Set:'.length))),
68
68
  }),
69
69
  // Avoid collisions with the special strings defined above
70
70
  ts({
71
71
  is: (val) => typeof val === 'string' && val.startsWith('!'),
72
72
  match: (str) => str.startsWith('!'),
73
73
  serialize: (val) => '!' + val,
74
- deserialize: (str) => str.slice(1)
75
- })
74
+ deserialize: (str) => str.slice(1),
75
+ }),
76
76
  ];
77
77
  // Type check
78
78
  function ts(t) {
@@ -1,3 +1,5 @@
1
1
  export { replacerWithPath };
2
+ export type { Iterable };
2
3
  type Iterable = Record<string, unknown>;
3
- declare function replacerWithPath(replacer: (this: Iterable, key: string, value: unknown, path: string) => unknown, canBeFirstKey: boolean): (this: Iterable, key: string, value: unknown) => unknown;
4
+ type Replacer = (this: Iterable, key: string, value: unknown, path: string) => unknown;
5
+ declare function replacerWithPath(replacer: Replacer, canBeFirstKey: boolean): (this: Iterable, key: string, value: unknown) => unknown;
package/index.mjs CHANGED
@@ -4,4 +4,6 @@
4
4
  // @brillout/json-s doesn't appear to be written in CJS, but also doesn't appear to be a valid ES module (i.e. it doesn't have "type": "module" or an .mjs extension for the entry point). Please contact the package author to fix.
5
5
  // ```
6
6
  // - Reproduction: https://github.com/brillout/sveltekit-telefunc-repro
7
- throw new Error("Module `@brillout/json-serializer` doesn't exist anymore: load `@brillout/json-serializer/parse` and `@brillout/json-serializer/stringify` instead.")
7
+ throw new Error(
8
+ "Module `@brillout/json-serializer` doesn't exist anymore: load `@brillout/json-serializer/parse` and `@brillout/json-serializer/stringify` instead.",
9
+ )
package/package.json CHANGED
@@ -1,7 +1,6 @@
1
1
  {
2
2
  "name": "@brillout/json-serializer",
3
- "version": "0.5.8",
4
- "dependencies": {},
3
+ "version": "0.5.10",
5
4
  "description": "Same as JSON but with added support for `Date`, `undefined`, `Map`, `Set`, and more.",
6
5
  "main": "./index.mjs",
7
6
  "exports": {
@@ -18,24 +17,38 @@
18
17
  }
19
18
  },
20
19
  "scripts": {
20
+ "========= Dev": "",
21
21
  "dev": "pnpm run tsc:watch:cjs",
22
- "build": "pnpm run clean && pnpm run tsc:esm && pnpm run tsc:cjs",
23
- "test": "vitest",
24
- "docs": "mdocs",
22
+ "========= Build": "",
23
+ "build": "rm -rf dist/ && pnpm run tsc:esm && pnpm run tsc:cjs",
25
24
  "tsc:esm": "tsc",
26
25
  "tsc:cjs": "tsc --project ./tsconfig.cjs.json",
27
26
  "tsc:watch:esm": "tsc --incremental --watch",
28
27
  "tsc:watch:cjs": "tsc --incremental --watch --project ./tsconfig.cjs.json",
29
- "clean": "rm -rf dist/",
30
- "reset": "git clean -Xdf && pnpm install && pnpm build",
28
+ "========= Test": "",
29
+ "test": "vitest",
30
+ "========= Build readme.md": "",
31
+ "docs": "mdocs",
32
+ "========= Clean": "",
33
+ "// Remove all generated files": "",
34
+ "clean": "git clean -Xdf",
35
+ "reset": "pnpm run clean && pnpm install && pnpm run build",
36
+ "========= Formatting": "",
37
+ "format": "pnpm run format:biome",
38
+ "format:prettier": "git ls-files | egrep '\\.(json|js|jsx|css|ts|tsx|vue|mjs|cjs)$' | grep --invert-match package.json | xargs pnpm exec prettier --write",
39
+ "format:biome": "biome format --write .",
40
+ "format:check": "biome format . || echo Fix formatting by running: $ pnpm -w run format",
41
+ "========= Release": "",
31
42
  "release": "release-me patch"
32
43
  },
33
44
  "devDependencies": {
45
+ "@biomejs/biome": "^1.7.2",
34
46
  "@brillout/mdocs": "^0.1.30",
35
- "@brillout/release-me": "^0.0.5",
47
+ "@brillout/release-me": "^0.3.7",
36
48
  "@types/node": "^20.5.6",
37
49
  "@types/react": "^18.2.21",
38
50
  "lodash.isequal": "^4.5.0",
51
+ "prettier": "^3.2.5",
39
52
  "react": "^17.0.2",
40
53
  "typescript": "^5.2.2",
41
54
  "vitest": "^0.34.3"
package/parse.js CHANGED
@@ -3,6 +3,9 @@
3
3
  // - Expo/Metro
4
4
  // - ESLint
5
5
  // prettier-ignore
6
+ // biome-ignore format:
6
7
  'use strict';
7
8
  // prettier-ignore
9
+ // biome-ignore format:
8
10
  exports.parse = require('./dist/cjs/parse.js').parse;
11
+ exports.parseTransform = require('./dist/cjs/parse.js').parseTransform;
package/stringify.js CHANGED
@@ -3,6 +3,8 @@
3
3
  // - Expo/Metro
4
4
  // - ESLint
5
5
  // prettier-ignore
6
+ // biome-ignore format:
6
7
  'use strict';
7
8
  // prettier-ignore
9
+ // biome-ignore format:
8
10
  exports.stringify = require('./dist/cjs/stringify.js').stringify;