@brillout/json-serializer 0.5.4 → 0.5.6
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.
- package/dist/cjs/replacerWithPath.d.ts +3 -0
- package/dist/cjs/replacerWithPath.js +24 -0
- package/dist/cjs/stringify.js +27 -15
- package/dist/cjs/types.d.ts +1 -1
- package/dist/cjs/utils/isObject.d.ts +1 -1
- package/dist/esm/replacerWithPath.d.ts +3 -0
- package/dist/esm/replacerWithPath.js +21 -0
- package/dist/esm/stringify.js +26 -14
- package/dist/esm/types.d.ts +1 -1
- package/dist/esm/utils/isObject.d.ts +1 -1
- package/package.json +15 -6
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.replacerWithPath = void 0;
|
|
4
|
+
function replacerWithPath(replacer, canBeFirstKey) {
|
|
5
|
+
const paths = new WeakMap();
|
|
6
|
+
return function (key, value) {
|
|
7
|
+
const prefix = paths.get(this);
|
|
8
|
+
const path = (prefix !== null && prefix !== void 0 ? prefix : '') + (key ? getKeyName(key, this, !prefix && canBeFirstKey) : '');
|
|
9
|
+
if (isIterable(value))
|
|
10
|
+
paths.set(value, path);
|
|
11
|
+
return replacer.call(this, key, value, path);
|
|
12
|
+
};
|
|
13
|
+
}
|
|
14
|
+
exports.replacerWithPath = replacerWithPath;
|
|
15
|
+
function isIterable(value) {
|
|
16
|
+
return value === Object(value);
|
|
17
|
+
}
|
|
18
|
+
function getKeyName(key, obj, isFirstKey) {
|
|
19
|
+
if (Array.isArray(obj))
|
|
20
|
+
return `[${key}]`;
|
|
21
|
+
if (/^[a-z0-9\$_]+$/i.test(key))
|
|
22
|
+
return !isFirstKey ? `.${key}` : key;
|
|
23
|
+
return `[${JSON.stringify(key)}]`;
|
|
24
|
+
}
|
package/dist/cjs/stringify.js
CHANGED
|
@@ -5,26 +5,23 @@ const types_1 = require("./types");
|
|
|
5
5
|
const isReactElement_1 = require("./utils/isReactElement");
|
|
6
6
|
const isCallable_1 = require("./utils/isCallable");
|
|
7
7
|
const isObject_1 = require("./utils/isObject");
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const replacerWithPath_1 = require("./replacerWithPath");
|
|
9
|
+
function stringify(value, { forbidReactElements, space, valueName, sortObjectKeys } = {}) {
|
|
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:
|
|
13
13
|
// - Cyclic references
|
|
14
14
|
// - Functions
|
|
15
15
|
// - React elements
|
|
16
|
-
const serializer = (val) => JSON.stringify(val, replacer, space);
|
|
16
|
+
const serializer = (val) => JSON.stringify(val, (0, replacerWithPath_1.replacerWithPath)(replacer, !valueName), space);
|
|
17
17
|
return serializer(value);
|
|
18
|
-
function replacer(key, value) {
|
|
19
|
-
if (key !== '') {
|
|
20
|
-
path.push(key);
|
|
21
|
-
}
|
|
18
|
+
function replacer(key, value, path) {
|
|
22
19
|
if (forbidReactElements && (0, isReactElement_1.isReactElement)(value)) {
|
|
23
|
-
throw
|
|
20
|
+
throw genErr(genErrMsg('React element', path, valueName));
|
|
24
21
|
}
|
|
25
22
|
if ((0, isCallable_1.isCallable)(value)) {
|
|
26
23
|
const functionName = value.name;
|
|
27
|
-
throw
|
|
24
|
+
throw genErr(genErrMsg('function', path, valueName, path.length === 0 ? functionName : undefined));
|
|
28
25
|
}
|
|
29
26
|
const valueOriginal = this[key];
|
|
30
27
|
for (const { is, serialize } of types_1.types.slice().reverse()) {
|
|
@@ -44,11 +41,26 @@ function stringify(value, { forbidReactElements, space, valueName = 'value', sor
|
|
|
44
41
|
}
|
|
45
42
|
return value;
|
|
46
43
|
}
|
|
47
|
-
function genErrMsg(valueType, valName) {
|
|
48
|
-
const name = valName ? ' `' + valName + '`' : '';
|
|
49
|
-
const location = path.length === 0 ? '' : ` ${name ? 'at ' : ''}\`${valueName}[${path.map((p) => `'${p}'`).join('][')}]\``;
|
|
50
|
-
const fallback = name === '' && location === '' ? ` ${valueName}` : '';
|
|
51
|
-
return `@brillout/json-serializer (https://github.com/brillout/json-serializer) cannot serialize${name}${location}${fallback} because it's a ${valueType}.`;
|
|
52
|
-
}
|
|
53
44
|
}
|
|
54
45
|
exports.stringify = stringify;
|
|
46
|
+
function genErr(errMsg) {
|
|
47
|
+
const err = new Error(`[@brillout/json-serializer](https://github.com/brillout/json-serializer) ${errMsg}.`);
|
|
48
|
+
err.messageCore = errMsg;
|
|
49
|
+
return err;
|
|
50
|
+
}
|
|
51
|
+
function genErrMsg(valueType, path, rootValueName, problematicValueName) {
|
|
52
|
+
let subject;
|
|
53
|
+
if (!path) {
|
|
54
|
+
subject = rootValueName || problematicValueName || 'value';
|
|
55
|
+
}
|
|
56
|
+
else {
|
|
57
|
+
if (problematicValueName) {
|
|
58
|
+
subject = problematicValueName + ' at ';
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
subject = '';
|
|
62
|
+
}
|
|
63
|
+
subject = subject + (rootValueName || '') + path;
|
|
64
|
+
}
|
|
65
|
+
return `cannot serialize ${subject} because it's a ${valueType}`;
|
|
66
|
+
}
|
package/dist/cjs/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { types };
|
|
2
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
|
-
|
|
3
|
+
type Type<T, IntermediateType> = {
|
|
4
4
|
is: (val: unknown) => asserts val is T;
|
|
5
5
|
match: (str: string) => boolean;
|
|
6
6
|
serialize: (val: T, serializer: (val: IntermediateType) => string) => string;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { replacerWithPath };
|
|
2
|
+
function replacerWithPath(replacer, canBeFirstKey) {
|
|
3
|
+
const paths = new WeakMap();
|
|
4
|
+
return function (key, value) {
|
|
5
|
+
const prefix = paths.get(this);
|
|
6
|
+
const path = (prefix ?? '') + (key ? getKeyName(key, this, !prefix && canBeFirstKey) : '');
|
|
7
|
+
if (isIterable(value))
|
|
8
|
+
paths.set(value, path);
|
|
9
|
+
return replacer.call(this, key, value, path);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function isIterable(value) {
|
|
13
|
+
return value === Object(value);
|
|
14
|
+
}
|
|
15
|
+
function getKeyName(key, obj, isFirstKey) {
|
|
16
|
+
if (Array.isArray(obj))
|
|
17
|
+
return `[${key}]`;
|
|
18
|
+
if (/^[a-z0-9\$_]+$/i.test(key))
|
|
19
|
+
return !isFirstKey ? `.${key}` : key;
|
|
20
|
+
return `[${JSON.stringify(key)}]`;
|
|
21
|
+
}
|
package/dist/esm/stringify.js
CHANGED
|
@@ -3,26 +3,23 @@ import { types } from './types';
|
|
|
3
3
|
import { isReactElement } from './utils/isReactElement';
|
|
4
4
|
import { isCallable } from './utils/isCallable';
|
|
5
5
|
import { isObject } from './utils/isObject';
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
import { replacerWithPath } from './replacerWithPath';
|
|
7
|
+
function stringify(value, { forbidReactElements, space, valueName, sortObjectKeys } = {}) {
|
|
8
8
|
// The only error `JSON.stringify()` can throw is `TypeError "cyclic object value"`.
|
|
9
9
|
// - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify#exceptions
|
|
10
10
|
// - This means we have total of 3 possible errors while serializing:
|
|
11
11
|
// - Cyclic references
|
|
12
12
|
// - Functions
|
|
13
13
|
// - React elements
|
|
14
|
-
const serializer = (val) => JSON.stringify(val, replacer, space);
|
|
14
|
+
const serializer = (val) => JSON.stringify(val, replacerWithPath(replacer, !valueName), space);
|
|
15
15
|
return serializer(value);
|
|
16
|
-
function replacer(key, value) {
|
|
17
|
-
if (key !== '') {
|
|
18
|
-
path.push(key);
|
|
19
|
-
}
|
|
16
|
+
function replacer(key, value, path) {
|
|
20
17
|
if (forbidReactElements && isReactElement(value)) {
|
|
21
|
-
throw
|
|
18
|
+
throw genErr(genErrMsg('React element', path, valueName));
|
|
22
19
|
}
|
|
23
20
|
if (isCallable(value)) {
|
|
24
21
|
const functionName = value.name;
|
|
25
|
-
throw
|
|
22
|
+
throw genErr(genErrMsg('function', path, valueName, path.length === 0 ? functionName : undefined));
|
|
26
23
|
}
|
|
27
24
|
const valueOriginal = this[key];
|
|
28
25
|
for (const { is, serialize } of types.slice().reverse()) {
|
|
@@ -42,10 +39,25 @@ function stringify(value, { forbidReactElements, space, valueName = 'value', sor
|
|
|
42
39
|
}
|
|
43
40
|
return value;
|
|
44
41
|
}
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
}
|
|
43
|
+
function genErr(errMsg) {
|
|
44
|
+
const err = new Error(`[@brillout/json-serializer](https://github.com/brillout/json-serializer) ${errMsg}.`);
|
|
45
|
+
err.messageCore = errMsg;
|
|
46
|
+
return err;
|
|
47
|
+
}
|
|
48
|
+
function genErrMsg(valueType, path, rootValueName, problematicValueName) {
|
|
49
|
+
let subject;
|
|
50
|
+
if (!path) {
|
|
51
|
+
subject = rootValueName || problematicValueName || 'value';
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
if (problematicValueName) {
|
|
55
|
+
subject = problematicValueName + ' at ';
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
subject = '';
|
|
59
|
+
}
|
|
60
|
+
subject = subject + (rootValueName || '') + path;
|
|
50
61
|
}
|
|
62
|
+
return `cannot serialize ${subject} because it's a ${valueType}`;
|
|
51
63
|
}
|
package/dist/esm/types.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { types };
|
|
2
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
|
-
|
|
3
|
+
type Type<T, IntermediateType> = {
|
|
4
4
|
is: (val: unknown) => asserts val is T;
|
|
5
5
|
match: (str: string) => boolean;
|
|
6
6
|
serialize: (val: T, serializer: (val: IntermediateType) => string) => string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brillout/json-serializer",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.6",
|
|
4
|
+
"dependencies": {},
|
|
4
5
|
"description": "Same as JSON but with added support for `Date`, `undefined`, `Map`, `Set`, and more.",
|
|
5
6
|
"main": "./index.mjs",
|
|
6
7
|
"exports": {
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
"scripts": {
|
|
20
21
|
"dev": "pnpm run tsc:watch:cjs",
|
|
21
22
|
"build": "pnpm run clean && pnpm run tsc:esm && pnpm run tsc:cjs",
|
|
22
|
-
"test": "
|
|
23
|
+
"test": "vitest",
|
|
23
24
|
"docs": "mdocs",
|
|
24
25
|
"tsc:esm": "tsc",
|
|
25
26
|
"tsc:cjs": "tsc --project ./tsconfig.cjs.json",
|
|
@@ -32,11 +33,19 @@
|
|
|
32
33
|
"devDependencies": {
|
|
33
34
|
"@brillout/mdocs": "^0.1.30",
|
|
34
35
|
"@brillout/release-me": "^0.0.5",
|
|
35
|
-
"@types/node": "
|
|
36
|
+
"@types/node": "^20.5.6",
|
|
37
|
+
"@types/react": "^18.2.21",
|
|
36
38
|
"lodash.isequal": "^4.5.0",
|
|
37
39
|
"react": "^17.0.2",
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
+
"typescript": "^5.2.2",
|
|
41
|
+
"vitest": "^0.34.3"
|
|
42
|
+
},
|
|
43
|
+
"packageManager": "pnpm@8.6.12",
|
|
44
|
+
"// Use @vitest/snapshot PR https://github.com/vitest-dev/vitest/pull/3961": "",
|
|
45
|
+
"pnpm": {
|
|
46
|
+
"overrides": {
|
|
47
|
+
"vitest>@vitest/snapshot": "npm:@brillout/vitest-snapshot@0.35.0-prerelease"
|
|
48
|
+
}
|
|
40
49
|
},
|
|
41
50
|
"files": [
|
|
42
51
|
"dist/",
|
|
@@ -45,7 +54,7 @@
|
|
|
45
54
|
"*.js"
|
|
46
55
|
],
|
|
47
56
|
"repository": "github:brillout/json-serializer",
|
|
48
|
-
"
|
|
57
|
+
"license": "MIT",
|
|
49
58
|
"publishConfig": {
|
|
50
59
|
"access": "public"
|
|
51
60
|
}
|