ox 0.12.1 → 0.12.2
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/CHANGELOG.md +6 -0
- package/_cjs/core/Json.js +26 -0
- package/_cjs/core/Json.js.map +1 -1
- package/_cjs/version.js +1 -1
- package/_esm/core/Json.js +52 -0
- package/_esm/core/Json.js.map +1 -1
- package/_esm/version.js +1 -1
- package/_types/core/Json.d.ts +31 -0
- package/_types/core/Json.d.ts.map +1 -1
- package/_types/version.d.ts +1 -1
- package/core/Json.ts +57 -0
- package/package.json +1 -1
- package/version.ts +1 -1
package/CHANGELOG.md
CHANGED
package/_cjs/core/Json.js
CHANGED
|
@@ -1,8 +1,34 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.canonicalize = canonicalize;
|
|
3
4
|
exports.parse = parse;
|
|
4
5
|
exports.stringify = stringify;
|
|
5
6
|
const bigIntSuffix = '#__bigint';
|
|
7
|
+
function canonicalize(value) {
|
|
8
|
+
if (value === null || typeof value === 'boolean' || typeof value === 'string')
|
|
9
|
+
return JSON.stringify(value);
|
|
10
|
+
if (typeof value === 'number') {
|
|
11
|
+
if (!Number.isFinite(value))
|
|
12
|
+
throw new TypeError('Cannot canonicalize non-finite number');
|
|
13
|
+
return Object.is(value, -0) ? '0' : JSON.stringify(value);
|
|
14
|
+
}
|
|
15
|
+
if (typeof value === 'bigint')
|
|
16
|
+
throw new TypeError('Cannot canonicalize bigint');
|
|
17
|
+
if (Array.isArray(value))
|
|
18
|
+
return `[${value.map((item) => canonicalize(item)).join(',')}]`;
|
|
19
|
+
if (typeof value === 'object') {
|
|
20
|
+
const entries = Object.keys(value)
|
|
21
|
+
.sort()
|
|
22
|
+
.reduce((acc, key) => {
|
|
23
|
+
const v = value[key];
|
|
24
|
+
if (v !== undefined)
|
|
25
|
+
acc.push(`${JSON.stringify(key)}:${canonicalize(v)}`);
|
|
26
|
+
return acc;
|
|
27
|
+
}, []);
|
|
28
|
+
return `{${entries.join(',')}}`;
|
|
29
|
+
}
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
6
32
|
function parse(string, reviver) {
|
|
7
33
|
return JSON.parse(string, (key, value_) => {
|
|
8
34
|
const value = value_;
|
package/_cjs/core/Json.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Json.js","sourceRoot":"","sources":["../../core/Json.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"Json.js","sourceRoot":"","sources":["../../core/Json.ts"],"names":[],"mappings":";;AA+BA,oCAwBC;AAwBD,sBAUC;AAyBD,8BAcC;AA9HD,MAAM,YAAY,GAAG,WAAW,CAAA;AA6BhC,SAAgB,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,SAAS,IAAI,OAAO,KAAK,KAAK,QAAQ;QAC3E,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC9B,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC;YACzB,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAA;QAC9D,OAAO,MAAM,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAA;IAC3D,CAAC;IACD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAC3B,MAAM,IAAI,SAAS,CAAC,4BAA4B,CAAC,CAAA;IACnD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACtB,OAAO,IAAI,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAA;IACjE,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAgC,CAAC;aAC1D,IAAI,EAAE;aACN,MAAM,CAAW,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YAC7B,MAAM,CAAC,GAAI,KAAiC,CAAC,GAAG,CAAC,CAAA;YACjD,IAAI,CAAC,KAAK,SAAS;gBACjB,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,YAAY,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;YACvD,OAAO,GAAG,CAAA;QACZ,CAAC,EAAE,EAAE,CAAC,CAAA;QACR,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAA;IACjC,CAAC;IACD,OAAO,SAAkB,CAAA;AAC3B,CAAC;AAwBD,SAAgB,KAAK,CACnB,MAAc,EACd,OAAmE;IAEnE,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,MAAM,CAAA;QACpB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC;YAC3D,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAA;QACrD,OAAO,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IACpE,CAAC,CAAC,CAAA;AACJ,CAAC;AAyBD,SAAgB,SAAS,CACvB,KAAU,EACV,QAA2E,EAC3E,KAAmC;IAEnC,OAAO,IAAI,CAAC,SAAS,CACnB,KAAK,EACL,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACb,IAAI,OAAO,QAAQ,KAAK,UAAU;YAAE,OAAO,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC/D,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,CAAA;QACrE,OAAO,KAAK,CAAA;IACd,CAAC,EACD,KAAK,CACN,CAAA;AACH,CAAC"}
|
package/_cjs/version.js
CHANGED
package/_esm/core/Json.js
CHANGED
|
@@ -1,4 +1,56 @@
|
|
|
1
1
|
const bigIntSuffix = '#__bigint';
|
|
2
|
+
/**
|
|
3
|
+
* Serializes a value to a canonical JSON string as defined by
|
|
4
|
+
* [RFC 8785 (JSON Canonicalization Scheme)](https://www.rfc-editor.org/rfc/rfc8785).
|
|
5
|
+
*
|
|
6
|
+
* - Object keys are sorted recursively by UTF-16 code unit comparison.
|
|
7
|
+
* - Primitives are serialized per ECMAScript rules (no trailing zeros on numbers, etc.).
|
|
8
|
+
* - No whitespace is inserted.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts twoslash
|
|
12
|
+
* import { Json } from 'ox'
|
|
13
|
+
*
|
|
14
|
+
* const json = Json.canonicalize({ b: 2, a: 1 })
|
|
15
|
+
* // @log: '{"a":1,"b":2}'
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts twoslash
|
|
20
|
+
* import { Json } from 'ox'
|
|
21
|
+
*
|
|
22
|
+
* const json = Json.canonicalize({ z: [3, { y: 1, x: 2 }], a: 'hello' })
|
|
23
|
+
* // @log: '{"a":"hello","z":[3,{"x":2,"y":1}]}'
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @param value - The value to canonicalize.
|
|
27
|
+
* @returns The canonical JSON string.
|
|
28
|
+
*/
|
|
29
|
+
export function canonicalize(value) {
|
|
30
|
+
if (value === null || typeof value === 'boolean' || typeof value === 'string')
|
|
31
|
+
return JSON.stringify(value);
|
|
32
|
+
if (typeof value === 'number') {
|
|
33
|
+
if (!Number.isFinite(value))
|
|
34
|
+
throw new TypeError('Cannot canonicalize non-finite number');
|
|
35
|
+
return Object.is(value, -0) ? '0' : JSON.stringify(value);
|
|
36
|
+
}
|
|
37
|
+
if (typeof value === 'bigint')
|
|
38
|
+
throw new TypeError('Cannot canonicalize bigint');
|
|
39
|
+
if (Array.isArray(value))
|
|
40
|
+
return `[${value.map((item) => canonicalize(item)).join(',')}]`;
|
|
41
|
+
if (typeof value === 'object') {
|
|
42
|
+
const entries = Object.keys(value)
|
|
43
|
+
.sort()
|
|
44
|
+
.reduce((acc, key) => {
|
|
45
|
+
const v = value[key];
|
|
46
|
+
if (v !== undefined)
|
|
47
|
+
acc.push(`${JSON.stringify(key)}:${canonicalize(v)}`);
|
|
48
|
+
return acc;
|
|
49
|
+
}, []);
|
|
50
|
+
return `{${entries.join(',')}}`;
|
|
51
|
+
}
|
|
52
|
+
return undefined;
|
|
53
|
+
}
|
|
2
54
|
/**
|
|
3
55
|
* Parses a JSON string, with support for `bigint`.
|
|
4
56
|
*
|
package/_esm/core/Json.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Json.js","sourceRoot":"","sources":["../../core/Json.ts"],"names":[],"mappings":"AAEA,MAAM,YAAY,GAAG,WAAW,CAAA;AAEhC;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,KAAK,CACnB,MAAc,EACd,OAAmE;IAEnE,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE;QACxC,MAAM,KAAK,GAAG,MAAM,CAAA;QACpB,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,CAAC;YAC3D,OAAO,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAA;QACrD,OAAO,OAAO,OAAO,KAAK,UAAU,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;IACpE,CAAC,CAAC,CAAA;AACJ,CAAC;AAMD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,SAAS,CACvB,KAAU,EACV,QAA2E,EAC3E,KAAmC;IAEnC,OAAO,IAAI,CAAC,SAAS,CACnB,KAAK,EACL,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QACb,IAAI,OAAO,QAAQ,KAAK,UAAU;YAAE,OAAO,QAAQ,CAAC,GAAG,EAAE,KAAK,CAAC,CAAA;QAC/D,IAAI,OAAO,KAAK,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC,QAAQ,EAAE,GAAG,YAAY,CAAA;QACrE,OAAO,KAAK,CAAA;IACd,CAAC,EACD,KAAK,CACN,CAAA;AACH,CAAC"}
|
|
1
|
+
{"version":3,"file":"Json.js","sourceRoot":"","sources":["../../core/Json.ts"],"names":[],"mappings":"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"}
|
package/_esm/version.js
CHANGED
package/_types/core/Json.d.ts
CHANGED
|
@@ -1,4 +1,35 @@
|
|
|
1
1
|
import type * as Errors from './Errors.js';
|
|
2
|
+
/**
|
|
3
|
+
* Serializes a value to a canonical JSON string as defined by
|
|
4
|
+
* [RFC 8785 (JSON Canonicalization Scheme)](https://www.rfc-editor.org/rfc/rfc8785).
|
|
5
|
+
*
|
|
6
|
+
* - Object keys are sorted recursively by UTF-16 code unit comparison.
|
|
7
|
+
* - Primitives are serialized per ECMAScript rules (no trailing zeros on numbers, etc.).
|
|
8
|
+
* - No whitespace is inserted.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts twoslash
|
|
12
|
+
* import { Json } from 'ox'
|
|
13
|
+
*
|
|
14
|
+
* const json = Json.canonicalize({ b: 2, a: 1 })
|
|
15
|
+
* // @log: '{"a":1,"b":2}'
|
|
16
|
+
* ```
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts twoslash
|
|
20
|
+
* import { Json } from 'ox'
|
|
21
|
+
*
|
|
22
|
+
* const json = Json.canonicalize({ z: [3, { y: 1, x: 2 }], a: 'hello' })
|
|
23
|
+
* // @log: '{"a":"hello","z":[3,{"x":2,"y":1}]}'
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* @param value - The value to canonicalize.
|
|
27
|
+
* @returns The canonical JSON string.
|
|
28
|
+
*/
|
|
29
|
+
export declare function canonicalize(value: unknown): string;
|
|
30
|
+
export declare namespace canonicalize {
|
|
31
|
+
type ErrorType = Errors.GlobalErrorType;
|
|
32
|
+
}
|
|
2
33
|
/**
|
|
3
34
|
* Parses a JSON string, with support for `bigint`.
|
|
4
35
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Json.d.ts","sourceRoot":"","sources":["../../core/Json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,MAAM,aAAa,CAAA;AAI1C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,KAAK,CACnB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC,GAAG,SAAS,OAQpE;AAED,MAAM,CAAC,OAAO,WAAW,KAAK,CAAC;IAC7B,KAAK,SAAS,GAAG,MAAM,CAAC,eAAe,CAAA;CACxC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,GAAG,EACV,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3E,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,UAWpC;AAED,MAAM,CAAC,OAAO,WAAW,SAAS,CAAC;IACjC,KAAK,SAAS,GAAG,MAAM,CAAC,eAAe,CAAA;CACxC"}
|
|
1
|
+
{"version":3,"file":"Json.d.ts","sourceRoot":"","sources":["../../core/Json.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,MAAM,MAAM,aAAa,CAAA;AAI1C;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAwBnD;AAED,MAAM,CAAC,OAAO,WAAW,YAAY,CAAC;IACpC,KAAK,SAAS,GAAG,MAAM,CAAC,eAAe,CAAA;CACxC;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,KAAK,CACnB,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC,GAAG,SAAS,OAQpE;AAED,MAAM,CAAC,OAAO,WAAW,KAAK,CAAC;IAC7B,KAAK,SAAS,GAAG,MAAM,CAAC,eAAe,CAAA;CACxC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,GAAG,EACV,QAAQ,CAAC,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,GAAG,CAAC,GAAG,IAAI,GAAG,SAAS,EAC3E,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,UAWpC;AAED,MAAM,CAAC,OAAO,WAAW,SAAS,CAAC;IACjC,KAAK,SAAS,GAAG,MAAM,CAAC,eAAe,CAAA;CACxC"}
|
package/_types/version.d.ts
CHANGED
package/core/Json.ts
CHANGED
|
@@ -2,6 +2,63 @@ import type * as Errors from './Errors.js'
|
|
|
2
2
|
|
|
3
3
|
const bigIntSuffix = '#__bigint'
|
|
4
4
|
|
|
5
|
+
/**
|
|
6
|
+
* Serializes a value to a canonical JSON string as defined by
|
|
7
|
+
* [RFC 8785 (JSON Canonicalization Scheme)](https://www.rfc-editor.org/rfc/rfc8785).
|
|
8
|
+
*
|
|
9
|
+
* - Object keys are sorted recursively by UTF-16 code unit comparison.
|
|
10
|
+
* - Primitives are serialized per ECMAScript rules (no trailing zeros on numbers, etc.).
|
|
11
|
+
* - No whitespace is inserted.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts twoslash
|
|
15
|
+
* import { Json } from 'ox'
|
|
16
|
+
*
|
|
17
|
+
* const json = Json.canonicalize({ b: 2, a: 1 })
|
|
18
|
+
* // @log: '{"a":1,"b":2}'
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts twoslash
|
|
23
|
+
* import { Json } from 'ox'
|
|
24
|
+
*
|
|
25
|
+
* const json = Json.canonicalize({ z: [3, { y: 1, x: 2 }], a: 'hello' })
|
|
26
|
+
* // @log: '{"a":"hello","z":[3,{"x":2,"y":1}]}'
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* @param value - The value to canonicalize.
|
|
30
|
+
* @returns The canonical JSON string.
|
|
31
|
+
*/
|
|
32
|
+
export function canonicalize(value: unknown): string {
|
|
33
|
+
if (value === null || typeof value === 'boolean' || typeof value === 'string')
|
|
34
|
+
return JSON.stringify(value)
|
|
35
|
+
if (typeof value === 'number') {
|
|
36
|
+
if (!Number.isFinite(value))
|
|
37
|
+
throw new TypeError('Cannot canonicalize non-finite number')
|
|
38
|
+
return Object.is(value, -0) ? '0' : JSON.stringify(value)
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === 'bigint')
|
|
41
|
+
throw new TypeError('Cannot canonicalize bigint')
|
|
42
|
+
if (Array.isArray(value))
|
|
43
|
+
return `[${value.map((item) => canonicalize(item)).join(',')}]`
|
|
44
|
+
if (typeof value === 'object') {
|
|
45
|
+
const entries = Object.keys(value as Record<string, unknown>)
|
|
46
|
+
.sort()
|
|
47
|
+
.reduce<string[]>((acc, key) => {
|
|
48
|
+
const v = (value as Record<string, unknown>)[key]
|
|
49
|
+
if (v !== undefined)
|
|
50
|
+
acc.push(`${JSON.stringify(key)}:${canonicalize(v)}`)
|
|
51
|
+
return acc
|
|
52
|
+
}, [])
|
|
53
|
+
return `{${entries.join(',')}}`
|
|
54
|
+
}
|
|
55
|
+
return undefined as never
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export declare namespace canonicalize {
|
|
59
|
+
type ErrorType = Errors.GlobalErrorType
|
|
60
|
+
}
|
|
61
|
+
|
|
5
62
|
/**
|
|
6
63
|
* Parses a JSON string, with support for `bigint`.
|
|
7
64
|
*
|
package/package.json
CHANGED
package/version.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
/** @internal */
|
|
2
|
-
export const version = '0.12.
|
|
2
|
+
export const version = '0.12.2'
|