@ac-kit/core 0.1.0 → 0.3.0
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 +130 -0
- package/dist/big-int/from-bytes-be.d.ts +14 -0
- package/dist/big-int/from-bytes-be.d.ts.map +1 -0
- package/dist/big-int/from-bytes-be.js +20 -0
- package/dist/big-int/from-bytes-be.js.map +1 -0
- package/dist/big-int/from-bytes-le.d.ts +15 -0
- package/dist/big-int/from-bytes-le.d.ts.map +1 -0
- package/dist/big-int/from-bytes-le.js +21 -0
- package/dist/big-int/from-bytes-le.js.map +1 -0
- package/dist/big-int/is-safe-number.d.ts +20 -0
- package/dist/big-int/is-safe-number.d.ts.map +1 -0
- package/dist/big-int/is-safe-number.js +24 -0
- package/dist/big-int/is-safe-number.js.map +1 -0
- package/dist/big-int/to-bytes-be.d.ts +19 -0
- package/dist/big-int/to-bytes-be.d.ts.map +1 -0
- package/dist/big-int/to-bytes-be.js +60 -0
- package/dist/big-int/to-bytes-be.js.map +1 -0
- package/dist/big-int/to-bytes-le.d.ts +19 -0
- package/dist/big-int/to-bytes-le.d.ts.map +1 -0
- package/dist/big-int/to-bytes-le.js +22 -0
- package/dist/big-int/to-bytes-le.js.map +1 -0
- package/dist/buffer/bytes-combine.d.ts +18 -0
- package/dist/buffer/bytes-combine.d.ts.map +1 -0
- package/dist/buffer/bytes-combine.js +25 -0
- package/dist/buffer/bytes-combine.js.map +1 -0
- package/dist/buffer/bytes-map.d.ts +14 -0
- package/dist/buffer/bytes-map.d.ts.map +1 -0
- package/dist/buffer/bytes-map.js +21 -0
- package/dist/buffer/bytes-map.js.map +1 -0
- package/dist/buffer/text/next-utf8-boundary.d.ts +17 -0
- package/dist/buffer/text/next-utf8-boundary.d.ts.map +1 -0
- package/dist/buffer/text/next-utf8-boundary.js +27 -0
- package/dist/buffer/text/next-utf8-boundary.js.map +1 -0
- package/dist/guards/has-object-prototype.d.ts +27 -0
- package/dist/guards/has-object-prototype.d.ts.map +1 -0
- package/dist/guards/has-object-prototype.js +30 -0
- package/dist/guards/has-object-prototype.js.map +1 -0
- package/dist/guards/is-object.d.ts +28 -2
- package/dist/guards/is-object.d.ts.map +1 -1
- package/dist/guards/is-object.js +28 -2
- package/dist/guards/is-object.js.map +1 -1
- package/dist/guards/is-pojo.d.ts +27 -2
- package/dist/guards/is-pojo.d.ts.map +1 -1
- package/dist/guards/is-pojo.js +27 -2
- package/dist/guards/is-pojo.js.map +1 -1
- package/dist/index.d.ts +22 -13
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -13
- package/dist/index.js.map +1 -1
- package/dist/json/replacers/big-int.d.ts.map +1 -1
- package/dist/json/replacers/big-int.js +2 -5
- package/dist/json/replacers/big-int.js.map +1 -1
- package/dist/number/parse-number-or-big-int.d.ts +30 -0
- package/dist/number/parse-number-or-big-int.d.ts.map +1 -0
- package/dist/number/parse-number-or-big-int.js +44 -0
- package/dist/number/parse-number-or-big-int.js.map +1 -0
- package/dist/object/defaults.d.ts.map +1 -1
- package/dist/object/defaults.js +11 -4
- package/dist/object/defaults.js.map +1 -1
- package/dist/object/flatten-record.d.ts +67 -0
- package/dist/object/flatten-record.d.ts.map +1 -0
- package/dist/object/flatten-record.js +81 -0
- package/dist/object/flatten-record.js.map +1 -0
- package/dist/object/get-at-path.d.ts +5 -0
- package/dist/object/get-at-path.d.ts.map +1 -1
- package/dist/object/get-at-path.js +5 -0
- package/dist/object/get-at-path.js.map +1 -1
- package/dist/object/is-unsafe-record-key.d.ts +26 -0
- package/dist/object/is-unsafe-record-key.d.ts.map +1 -0
- package/dist/object/is-unsafe-record-key.js +28 -0
- package/dist/object/is-unsafe-record-key.js.map +1 -0
- package/dist/object/merge-inplace.d.ts.map +1 -1
- package/dist/object/merge-inplace.js +4 -2
- package/dist/object/merge-inplace.js.map +1 -1
- package/dist/object/merge.d.ts.map +1 -1
- package/dist/object/merge.js +4 -2
- package/dist/object/merge.js.map +1 -1
- package/dist/object/null-if-empty.d.ts +12 -0
- package/dist/object/null-if-empty.d.ts.map +1 -0
- package/dist/object/null-if-empty.js +17 -0
- package/dist/object/null-if-empty.js.map +1 -0
- package/dist/object/set-at-path.d.ts +5 -0
- package/dist/object/set-at-path.d.ts.map +1 -1
- package/dist/object/set-at-path.js +10 -3
- package/dist/object/set-at-path.js.map +1 -1
- package/dist/object/set-record-entry.d.ts +32 -0
- package/dist/object/set-record-entry.d.ts.map +1 -0
- package/dist/object/set-record-entry.js +43 -0
- package/dist/object/set-record-entry.js.map +1 -0
- package/dist/object/traverse.js +3 -3
- package/dist/object/traverse.js.map +1 -1
- package/dist/object/unflatten-record.d.ts +63 -0
- package/dist/object/unflatten-record.d.ts.map +1 -0
- package/dist/object/unflatten-record.js +71 -0
- package/dist/object/unflatten-record.js.map +1 -0
- package/dist/string/ascii/is-ascii-blank.d.ts +8 -0
- package/dist/string/ascii/is-ascii-blank.d.ts.map +1 -0
- package/dist/string/ascii/is-ascii-blank.js +11 -0
- package/dist/string/ascii/is-ascii-blank.js.map +1 -0
- package/dist/string/ascii/is-ascii-control.d.ts +6 -0
- package/dist/string/ascii/is-ascii-control.d.ts.map +1 -0
- package/dist/string/ascii/is-ascii-control.js +9 -0
- package/dist/string/ascii/is-ascii-control.js.map +1 -0
- package/dist/string/ascii/is-ascii-graphic.d.ts +7 -0
- package/dist/string/ascii/is-ascii-graphic.d.ts.map +1 -0
- package/dist/string/ascii/is-ascii-graphic.js +10 -0
- package/dist/string/ascii/is-ascii-graphic.js.map +1 -0
- package/dist/string/ascii/is-ascii-printable.d.ts +7 -0
- package/dist/string/ascii/is-ascii-printable.d.ts.map +1 -0
- package/dist/string/ascii/is-ascii-printable.js +10 -0
- package/dist/string/ascii/is-ascii-printable.js.map +1 -0
- package/dist/string/ascii/is-ascii-punctuation.d.ts +6 -0
- package/dist/string/ascii/is-ascii-punctuation.d.ts.map +1 -0
- package/dist/string/ascii/is-ascii-punctuation.js +10 -0
- package/dist/string/ascii/is-ascii-punctuation.js.map +1 -0
- package/dist/system/fs/escape-posix-path.d.ts.map +1 -0
- package/dist/system/fs/escape-posix-path.js.map +1 -0
- package/dist/system/fs/escape-win32-path.d.ts.map +1 -0
- package/dist/system/fs/escape-win32-path.js.map +1 -0
- package/package.json +2 -2
- package/dist/guards/is-plain-object.d.ts +0 -8
- package/dist/guards/is-plain-object.d.ts.map +0 -1
- package/dist/guards/is-plain-object.js +0 -11
- package/dist/guards/is-plain-object.js.map +0 -1
- package/dist/net/ephemeral-port.d.ts +0 -13
- package/dist/net/ephemeral-port.d.ts.map +0 -1
- package/dist/net/ephemeral-port.js +0 -19
- package/dist/net/ephemeral-port.js.map +0 -1
- package/dist/net/inet-address.d.ts +0 -20
- package/dist/net/inet-address.d.ts.map +0 -1
- package/dist/net/inet-address.js +0 -42
- package/dist/net/inet-address.js.map +0 -1
- package/dist/net/inet-endpoint.d.ts +0 -7
- package/dist/net/inet-endpoint.d.ts.map +0 -1
- package/dist/net/inet-endpoint.js +0 -2
- package/dist/net/inet-endpoint.js.map +0 -1
- package/dist/shell/fs/escape-posix-path.d.ts.map +0 -1
- package/dist/shell/fs/escape-posix-path.js.map +0 -1
- package/dist/shell/fs/escape-win32-path.d.ts.map +0 -1
- package/dist/shell/fs/escape-win32-path.js.map +0 -1
- package/dist/shell/process/parse-env-variable.d.ts +0 -43
- package/dist/shell/process/parse-env-variable.d.ts.map +0 -1
- package/dist/shell/process/parse-env-variable.js +0 -109
- package/dist/shell/process/parse-env-variable.js.map +0 -1
- package/dist/shell/process/stringify-env-variable.d.ts +0 -50
- package/dist/shell/process/stringify-env-variable.d.ts.map +0 -1
- package/dist/shell/process/stringify-env-variable.js +0 -86
- package/dist/shell/process/stringify-env-variable.js.map +0 -1
- package/dist/shell/process/types.d.ts +0 -7
- package/dist/shell/process/types.d.ts.map +0 -1
- package/dist/shell/process/types.js +0 -2
- package/dist/shell/process/types.js.map +0 -1
- package/dist/shell/shell/escape-posix-sh-command-arg.d.ts +0 -20
- package/dist/shell/shell/escape-posix-sh-command-arg.d.ts.map +0 -1
- package/dist/shell/shell/escape-posix-sh-command-arg.js +0 -26
- package/dist/shell/shell/escape-posix-sh-command-arg.js.map +0 -1
- package/dist/shell/shell/escape-posix-sh-command.d.ts +0 -19
- package/dist/shell/shell/escape-posix-sh-command.d.ts.map +0 -1
- package/dist/shell/shell/escape-posix-sh-command.js +0 -55
- package/dist/shell/shell/escape-posix-sh-command.js.map +0 -1
- package/dist/shell/shell/escape-posix-sh-sqe.d.ts +0 -13
- package/dist/shell/shell/escape-posix-sh-sqe.d.ts.map +0 -1
- package/dist/shell/shell/escape-posix-sh-sqe.js +0 -15
- package/dist/shell/shell/escape-posix-sh-sqe.js.map +0 -1
- package/dist/shell/shell/escape-win32-cmd-command-arg.d.ts +0 -20
- package/dist/shell/shell/escape-win32-cmd-command-arg.d.ts.map +0 -1
- package/dist/shell/shell/escape-win32-cmd-command-arg.js +0 -29
- package/dist/shell/shell/escape-win32-cmd-command-arg.js.map +0 -1
- package/dist/shell/shell/escape-win32-cmd-command.d.ts +0 -18
- package/dist/shell/shell/escape-win32-cmd-command.d.ts.map +0 -1
- package/dist/shell/shell/escape-win32-cmd-command.js +0 -20
- package/dist/shell/shell/escape-win32-cmd-command.js.map +0 -1
- /package/dist/{shell → system}/fs/escape-posix-path.d.ts +0 -0
- /package/dist/{shell → system}/fs/escape-posix-path.js +0 -0
- /package/dist/{shell → system}/fs/escape-win32-path.d.ts +0 -0
- /package/dist/{shell → system}/fs/escape-win32-path.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/object/defaults.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,QAAQ,CACvB,GAAG,IAAsC;IAEzC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,MAAa,EAAE,GAAG,EAAE,EAAE;QACzC,IAAI,GAAG,EAAE,CAAC;YACT,KAAK,MAAM,GAAG,IAAI,GAAG,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"defaults.js","sourceRoot":"","sources":["../../src/object/defaults.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,QAAQ,CACvB,GAAG,IAAsC;IAEzC,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC,MAAa,EAAE,GAAG,EAAE,EAAE;QACzC,IAAI,GAAG,EAAE,CAAC;YACT,yEAAyE;YACzE,yEAAyE;YACzE,mCAAmC;YACnC,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpC,MAAM,KAAK,GAAI,GAAqB,CAAC,GAAG,CAAC,CAAC;gBAC1C,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC;oBACzC,CAAC,CAAE,MAAwB,CAAC,GAAG,CAAC;oBAChC,CAAC,CAAC,SAAS,CAAC;gBAEb,IAAI,OAAO,KAAK,SAAS,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBAClD,cAAc,CAAC,MAAuB,EAAE,GAAG,EAAE,KAAK,CAAC,CAAC;gBACrD,CAAC;YACF,CAAC;QACF,CAAC;QACD,OAAO,MAAM,CAAC;IACf,CAAC,EAAE,EAAO,CAAM,CAAC;AAClB,CAAC"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export type FlattenRecordOptions = {
|
|
2
|
+
/**
|
|
3
|
+
* Separator joining the segments of an output key. Default `"."`.
|
|
4
|
+
*
|
|
5
|
+
* Must not be empty: `unflattenRecord` splits on it, and splitting on `""`
|
|
6
|
+
* would take every key apart character by character.
|
|
7
|
+
*/
|
|
8
|
+
readonly delimiter?: string | null;
|
|
9
|
+
/**
|
|
10
|
+
* Descends into arrays, numbering their elements. Default `false`, which
|
|
11
|
+
* leaves an array whole as a leaf value.
|
|
12
|
+
*
|
|
13
|
+
* Off by default because an index is the one segment a flattened key cannot
|
|
14
|
+
* tell apart from an ordinary key spelled `"0"`, so numbering costs the round
|
|
15
|
+
* trip its only ambiguity-free case.
|
|
16
|
+
*/
|
|
17
|
+
readonly flattenArrays?: boolean | null;
|
|
18
|
+
/**
|
|
19
|
+
* Greatest number of segments an output key may have. Default: unbounded.
|
|
20
|
+
*
|
|
21
|
+
* A value below that depth is copied across whole, still nested. `1` copies
|
|
22
|
+
* the record's own entries without flattening anything.
|
|
23
|
+
*/
|
|
24
|
+
readonly maxDepth?: number | null;
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Collapse a nested record into a one-level one, naming each leaf by the
|
|
28
|
+
* delimiter-joined path that reached it.
|
|
29
|
+
*
|
|
30
|
+
* A leaf is anything that is not a plain object — a `Date`, a `Map`, a class
|
|
31
|
+
* instance and, by default, an array are all copied across whole. So is an
|
|
32
|
+
* empty plain object, which has no entry to name and would otherwise vanish.
|
|
33
|
+
*
|
|
34
|
+
* **A key that contains the delimiter is not escaped.** `{ "a.b": 1 }` flattens
|
|
35
|
+
* to `{ "a.b": 1 }`, exactly as `{ a: { b: 1 } }` does, and
|
|
36
|
+
* {@link unflattenRecord} reads both back as `{ a: { b: 1 } }` — the delimiter
|
|
37
|
+
* always wins over a literal occurrence of it. Two inputs colliding onto one
|
|
38
|
+
* output key leave the last one written, in `Object.keys` order. Pick a
|
|
39
|
+
* delimiter the keys cannot contain when the round trip has to hold.
|
|
40
|
+
*
|
|
41
|
+
* Keys are written with `setRecordEntry`, so an input key named `__proto__`
|
|
42
|
+
* becomes an own entry of the result instead of reaching the prototype setter.
|
|
43
|
+
*
|
|
44
|
+
* Time is linear in the number of nodes visited, plus the cost of building the
|
|
45
|
+
* keys, which is the total length of the output's keys. Memory is the output
|
|
46
|
+
* record plus one stack frame per level of nesting, so a record nested deeper
|
|
47
|
+
* than the engine's stack overflows rather than degrading.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```ts
|
|
51
|
+
* flattenRecord({ key1: { keyA: "v" }, key2: { a: { b: 2 } } });
|
|
52
|
+
* // { "key1.keyA": "v", "key2.a.b": 2 }
|
|
53
|
+
*
|
|
54
|
+
* flattenRecord({ host: { tags: ["a", "b"] } });
|
|
55
|
+
* // { "host.tags": ["a", "b"] } — an array is a leaf
|
|
56
|
+
*
|
|
57
|
+
* flattenRecord({ a: { b: { c: 1 } } }, { delimiter: "/", maxDepth: 2 });
|
|
58
|
+
* // { "a/b": { c: 1 } }
|
|
59
|
+
* ```;
|
|
60
|
+
*
|
|
61
|
+
* @param source The record to flatten; it is not modified.
|
|
62
|
+
* @param options Delimiter, array handling and depth cap.
|
|
63
|
+
* @returns A new one-level record.
|
|
64
|
+
* @throws RangeError If the delimiter is empty or `maxDepth` is below 1.
|
|
65
|
+
*/
|
|
66
|
+
export declare function flattenRecord(source: Readonly<Record<string, unknown>>, options?: FlattenRecordOptions): Record<string, unknown>;
|
|
67
|
+
//# sourceMappingURL=flatten-record.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flatten-record.d.ts","sourceRoot":"","sources":["../../src/object/flatten-record.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,oBAAoB,GAAG;IAClC;;;;;OAKG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAEnC;;;;;;;OAOG;IACH,QAAQ,CAAC,aAAa,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC;IAExC;;;;;OAKG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;CAClC,CAAC;AA4CF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,wBAAgB,aAAa,CAC5B,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,EACzC,OAAO,CAAC,EAAE,oBAAoB,GAC5B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAkBzB"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { isPojo } from "../guards/is-pojo.js";
|
|
2
|
+
import { setRecordEntry } from "./set-record-entry.js";
|
|
3
|
+
/** An empty container has no entry to name, so flattening it would lose the key. */
|
|
4
|
+
function isDescendable_(value, options) {
|
|
5
|
+
if (Array.isArray(value)) {
|
|
6
|
+
return options.flattenArrays && value.length > 0;
|
|
7
|
+
}
|
|
8
|
+
return isPojo(value) && Object.keys(value).length > 0;
|
|
9
|
+
}
|
|
10
|
+
function step_(source, prefix, depth, output, options) {
|
|
11
|
+
// Own keys only: `for...in` would walk a hostile source's prototype too.
|
|
12
|
+
for (const key of Object.keys(source)) {
|
|
13
|
+
const value = source[key];
|
|
14
|
+
// `null` rather than `""` for the root: a top-level key may itself be empty.
|
|
15
|
+
const outputKey = prefix === null ? key : prefix + options.delimiter + key;
|
|
16
|
+
if (depth < options.maxDepth && isDescendable_(value, options)) {
|
|
17
|
+
step_(value, outputKey, depth + 1, output, options);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
setRecordEntry(output, outputKey, value);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Collapse a nested record into a one-level one, naming each leaf by the
|
|
26
|
+
* delimiter-joined path that reached it.
|
|
27
|
+
*
|
|
28
|
+
* A leaf is anything that is not a plain object — a `Date`, a `Map`, a class
|
|
29
|
+
* instance and, by default, an array are all copied across whole. So is an
|
|
30
|
+
* empty plain object, which has no entry to name and would otherwise vanish.
|
|
31
|
+
*
|
|
32
|
+
* **A key that contains the delimiter is not escaped.** `{ "a.b": 1 }` flattens
|
|
33
|
+
* to `{ "a.b": 1 }`, exactly as `{ a: { b: 1 } }` does, and
|
|
34
|
+
* {@link unflattenRecord} reads both back as `{ a: { b: 1 } }` — the delimiter
|
|
35
|
+
* always wins over a literal occurrence of it. Two inputs colliding onto one
|
|
36
|
+
* output key leave the last one written, in `Object.keys` order. Pick a
|
|
37
|
+
* delimiter the keys cannot contain when the round trip has to hold.
|
|
38
|
+
*
|
|
39
|
+
* Keys are written with `setRecordEntry`, so an input key named `__proto__`
|
|
40
|
+
* becomes an own entry of the result instead of reaching the prototype setter.
|
|
41
|
+
*
|
|
42
|
+
* Time is linear in the number of nodes visited, plus the cost of building the
|
|
43
|
+
* keys, which is the total length of the output's keys. Memory is the output
|
|
44
|
+
* record plus one stack frame per level of nesting, so a record nested deeper
|
|
45
|
+
* than the engine's stack overflows rather than degrading.
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```ts
|
|
49
|
+
* flattenRecord({ key1: { keyA: "v" }, key2: { a: { b: 2 } } });
|
|
50
|
+
* // { "key1.keyA": "v", "key2.a.b": 2 }
|
|
51
|
+
*
|
|
52
|
+
* flattenRecord({ host: { tags: ["a", "b"] } });
|
|
53
|
+
* // { "host.tags": ["a", "b"] } — an array is a leaf
|
|
54
|
+
*
|
|
55
|
+
* flattenRecord({ a: { b: { c: 1 } } }, { delimiter: "/", maxDepth: 2 });
|
|
56
|
+
* // { "a/b": { c: 1 } }
|
|
57
|
+
* ```;
|
|
58
|
+
*
|
|
59
|
+
* @param source The record to flatten; it is not modified.
|
|
60
|
+
* @param options Delimiter, array handling and depth cap.
|
|
61
|
+
* @returns A new one-level record.
|
|
62
|
+
* @throws RangeError If the delimiter is empty or `maxDepth` is below 1.
|
|
63
|
+
*/
|
|
64
|
+
export function flattenRecord(source, options) {
|
|
65
|
+
const resolved = {
|
|
66
|
+
delimiter: options?.delimiter ?? ".",
|
|
67
|
+
flattenArrays: options?.flattenArrays ?? false,
|
|
68
|
+
maxDepth: options?.maxDepth ?? Number.POSITIVE_INFINITY,
|
|
69
|
+
};
|
|
70
|
+
if (resolved.delimiter.length === 0) {
|
|
71
|
+
throw new RangeError("flattenRecord: delimiter must not be empty");
|
|
72
|
+
}
|
|
73
|
+
// Negated so a `NaN` depth is rejected rather than silently flattening nothing.
|
|
74
|
+
if (!(resolved.maxDepth >= 1)) {
|
|
75
|
+
throw new RangeError("flattenRecord: maxDepth must be at least 1");
|
|
76
|
+
}
|
|
77
|
+
const output = {};
|
|
78
|
+
step_(source, null, 1, output, resolved);
|
|
79
|
+
return output;
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=flatten-record.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flatten-record.js","sourceRoot":"","sources":["../../src/object/flatten-record.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAoCvD,oFAAoF;AACpF,SAAS,cAAc,CAAC,KAAc,EAAE,OAAkB;IACzD,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC,aAAa,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IAClD,CAAC;IAED,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC;AACvD,CAAC;AAED,SAAS,KAAK,CACb,MAAyC,EACzC,MAAqB,EACrB,KAAa,EACb,MAA+B,EAC/B,OAAkB;IAElB,yEAAyE;IACzE,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QACvC,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,6EAA6E;QAC7E,MAAM,SAAS,GAAG,MAAM,KAAK,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,GAAG,OAAO,CAAC,SAAS,GAAG,GAAG,CAAC;QAE3E,IAAI,KAAK,GAAG,OAAO,CAAC,QAAQ,IAAI,cAAc,CAAC,KAAK,EAAE,OAAO,CAAC,EAAE,CAAC;YAChE,KAAK,CACJ,KAA0C,EAC1C,SAAS,EACT,KAAK,GAAG,CAAC,EACT,MAAM,EACN,OAAO,CACP,CAAC;QACH,CAAC;aAAM,CAAC;YACP,cAAc,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAC1C,CAAC;IACF,CAAC;AACF,CAAC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,MAAM,UAAU,aAAa,CAC5B,MAAyC,EACzC,OAA8B;IAE9B,MAAM,QAAQ,GAAc;QAC3B,SAAS,EAAE,OAAO,EAAE,SAAS,IAAI,GAAG;QACpC,aAAa,EAAE,OAAO,EAAE,aAAa,IAAI,KAAK;QAC9C,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,MAAM,CAAC,iBAAiB;KACvD,CAAC;IAEF,IAAI,QAAQ,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACrC,MAAM,IAAI,UAAU,CAAC,4CAA4C,CAAC,CAAC;IACpE,CAAC;IACD,gFAAgF;IAChF,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,IAAI,CAAC,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,UAAU,CAAC,4CAA4C,CAAC,CAAC;IACpE,CAAC;IAED,MAAM,MAAM,GAA4B,EAAE,CAAC;IAC3C,KAAK,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;IACzC,OAAO,MAAM,CAAC;AACf,CAAC"}
|
|
@@ -6,6 +6,11 @@ export type PropertyPath = readonly (string | number)[];
|
|
|
6
6
|
/**
|
|
7
7
|
* Gets the value at `path` inside `root`.
|
|
8
8
|
*
|
|
9
|
+
* Unlike `setAtPath`, this does not refuse a path through `__proto__`,
|
|
10
|
+
* `constructor` or `prototype`: reading one hands back a prototype the caller
|
|
11
|
+
* could already reach through any object it holds, so refusing it would cost an
|
|
12
|
+
* honest lookup and prevent nothing.
|
|
13
|
+
*
|
|
9
14
|
* @param root The root object/array to traverse
|
|
10
15
|
* @param path The path to traverse
|
|
11
16
|
* @returns The value at the path, or `undefined` if the path does not exist.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-at-path.d.ts","sourceRoot":"","sources":["../../src/object/get-at-path.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AAExD
|
|
1
|
+
{"version":3,"file":"get-at-path.d.ts","sourceRoot":"","sources":["../../src/object/get-at-path.ts"],"names":[],"mappings":"AAIA;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;AAExD;;;;;;;;;;;GAWG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,YAAY,GAAG,OAAO,CAkBpE"}
|
|
@@ -2,6 +2,11 @@ import { isObject } from "../guards/is-object.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Gets the value at `path` inside `root`.
|
|
4
4
|
*
|
|
5
|
+
* Unlike `setAtPath`, this does not refuse a path through `__proto__`,
|
|
6
|
+
* `constructor` or `prototype`: reading one hands back a prototype the caller
|
|
7
|
+
* could already reach through any object it holds, so refusing it would cost an
|
|
8
|
+
* honest lookup and prevent nothing.
|
|
9
|
+
*
|
|
5
10
|
* @param root The root object/array to traverse
|
|
6
11
|
* @param path The path to traverse
|
|
7
12
|
* @returns The value at the path, or `undefined` if the path does not exist.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-at-path.js","sourceRoot":"","sources":["../../src/object/get-at-path.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAQlD
|
|
1
|
+
{"version":3,"file":"get-at-path.js","sourceRoot":"","sources":["../../src/object/get-at-path.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAQlD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,SAAS,CAAC,IAAa,EAAE,IAAkB;IAC1D,IAAI,OAAO,GAAG,IAAI,CAAC;IAEnB,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACxB,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC;YACnB,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO;YACR,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,OAAO,GAAI,OAAyB,CAAC,GAAG,CAAC,CAAC;QAC3C,CAAC;aAAM,CAAC;YACP,OAAO;QACR,CAAC;IACF,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check whether a key may be followed while walking a record built from
|
|
3
|
+
* untrusted input.
|
|
4
|
+
*
|
|
5
|
+
* `__proto__` reaches the prototype setter when assigned to; `constructor`
|
|
6
|
+
* followed by `prototype` reaches `Object.prototype` when merely read, and a
|
|
7
|
+
* path-walking writer then mutates it. All three names are rejected together
|
|
8
|
+
* because a walk cannot tell which position it is in until the damage is done.
|
|
9
|
+
*
|
|
10
|
+
* Use this for a **path**. A single leaf assignment wants `setRecordEntry`
|
|
11
|
+
* instead, which stores such a key rather than refusing it — a record of
|
|
12
|
+
* environment variables or INI settings should still be able to hold one named
|
|
13
|
+
* `constructor`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* isUnsafeRecordKey("__proto__"); // true
|
|
18
|
+
* isUnsafeRecordKey("constructor"); // true
|
|
19
|
+
* isUnsafeRecordKey("toString"); // false — shadowing is not pollution
|
|
20
|
+
* ```;
|
|
21
|
+
*
|
|
22
|
+
* @param key The key to check.
|
|
23
|
+
* @returns True if following the key can reach a shared prototype.
|
|
24
|
+
*/
|
|
25
|
+
export declare function isUnsafeRecordKey(key: PropertyKey): boolean;
|
|
26
|
+
//# sourceMappingURL=is-unsafe-record-key.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-unsafe-record-key.d.ts","sourceRoot":"","sources":["../../src/object/is-unsafe-record-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAE3D"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Check whether a key may be followed while walking a record built from
|
|
3
|
+
* untrusted input.
|
|
4
|
+
*
|
|
5
|
+
* `__proto__` reaches the prototype setter when assigned to; `constructor`
|
|
6
|
+
* followed by `prototype` reaches `Object.prototype` when merely read, and a
|
|
7
|
+
* path-walking writer then mutates it. All three names are rejected together
|
|
8
|
+
* because a walk cannot tell which position it is in until the damage is done.
|
|
9
|
+
*
|
|
10
|
+
* Use this for a **path**. A single leaf assignment wants `setRecordEntry`
|
|
11
|
+
* instead, which stores such a key rather than refusing it — a record of
|
|
12
|
+
* environment variables or INI settings should still be able to hold one named
|
|
13
|
+
* `constructor`.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```ts
|
|
17
|
+
* isUnsafeRecordKey("__proto__"); // true
|
|
18
|
+
* isUnsafeRecordKey("constructor"); // true
|
|
19
|
+
* isUnsafeRecordKey("toString"); // false — shadowing is not pollution
|
|
20
|
+
* ```;
|
|
21
|
+
*
|
|
22
|
+
* @param key The key to check.
|
|
23
|
+
* @returns True if following the key can reach a shared prototype.
|
|
24
|
+
*/
|
|
25
|
+
export function isUnsafeRecordKey(key) {
|
|
26
|
+
return key === "__proto__" || key === "constructor" || key === "prototype";
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=is-unsafe-record-key.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"is-unsafe-record-key.js","sourceRoot":"","sources":["../../src/object/is-unsafe-record-key.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAgB;IACjD,OAAO,GAAG,KAAK,WAAW,IAAI,GAAG,KAAK,aAAa,IAAI,GAAG,KAAK,WAAW,CAAC;AAC5E,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-inplace.d.ts","sourceRoot":"","sources":["../../src/object/merge-inplace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOlD,OAAO,EAEN,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"merge-inplace.d.ts","sourceRoot":"","sources":["../../src/object/merge-inplace.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOlD,OAAO,EAEN,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,MAAM,oBAAoB,CAAC;AA6B5B;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EACvD,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,YAAY,GAAG;IAAE,SAAS,CAAC,EAAE,KAAK,CAAA;CAAE,GAC5C,CAAC,CAAC;AACL,wBAAgB,YAAY,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EAC3D,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,YAAY,GAAG;IAAE,SAAS,EAAE,IAAI,CAAA;CAAE,GACzC,CAAC,CAAC;AASL;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,QAAQ,SAAS,SAAS,OAAO,EAAE,EAC3E,MAAM,EAAE,OAAO,EACf,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE,YAAY,GACpB,OAAO,GAAG,aAAa,CAAC,QAAQ,CAAC,CASnC"}
|
|
@@ -4,6 +4,7 @@ import { isPojo } from "../guards/is-pojo.js";
|
|
|
4
4
|
import { isSet } from "../guards/is-set.js";
|
|
5
5
|
import { clone } from "./clone.js";
|
|
6
6
|
import { MERGE_DEFAULT_OPTIONS, } from "./merge-options.js";
|
|
7
|
+
import { setRecordEntry } from "./set-record-entry.js";
|
|
7
8
|
function resolve_(options) {
|
|
8
9
|
return {
|
|
9
10
|
recursive: options?.recursive ?? MERGE_DEFAULT_OPTIONS.recursive,
|
|
@@ -65,8 +66,9 @@ function mergeInplace_(target, source, options) {
|
|
|
65
66
|
return fromSource_(source, options);
|
|
66
67
|
}
|
|
67
68
|
function mergePojoInplace_(target, source, options) {
|
|
68
|
-
|
|
69
|
-
|
|
69
|
+
// Own keys only: `for...in` would walk a hostile source's prototype too.
|
|
70
|
+
for (const key of Object.keys(source)) {
|
|
71
|
+
setRecordEntry(target, key, nested_(target[key], source[key], options));
|
|
70
72
|
}
|
|
71
73
|
}
|
|
72
74
|
function mergeSetInplace_(target, source, options) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge-inplace.js","sourceRoot":"","sources":["../../src/object/merge-inplace.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EACN,qBAAqB,GAGrB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"merge-inplace.js","sourceRoot":"","sources":["../../src/object/merge-inplace.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../src/object/merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOlD,OAAO,EAEN,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"merge.d.ts","sourceRoot":"","sources":["../../src/object/merge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOlD,OAAO,EAEN,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,MAAM,oBAAoB,CAAC;AA6B5B;;;;;;;;;;;GAWG;AACH,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,EAChD,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,YAAY,GAAG;IAAE,SAAS,CAAC,EAAE,KAAK,CAAA;CAAE,GAC5C,CAAC,CAAC;AACL,wBAAgB,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,SAAS,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,EACpD,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,CAAC,EACT,OAAO,EAAE,YAAY,GAAG;IAAE,SAAS,EAAE,IAAI,CAAA;CAAE,GACzC,CAAC,CAAC;AASL;;;;;;;;;GASG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,SAAS,SAAS,OAAO,EAAE,EAC3D,OAAO,EAAE,QAAQ,EACjB,OAAO,CAAC,EAAE,YAAY,GACpB,aAAa,CAAC,QAAQ,CAAC,CASzB"}
|
package/dist/object/merge.js
CHANGED
|
@@ -4,6 +4,7 @@ import { isPojo } from "../guards/is-pojo.js";
|
|
|
4
4
|
import { isSet } from "../guards/is-set.js";
|
|
5
5
|
import { clone } from "./clone.js";
|
|
6
6
|
import { MERGE_DEFAULT_OPTIONS, } from "./merge-options.js";
|
|
7
|
+
import { setRecordEntry } from "./set-record-entry.js";
|
|
7
8
|
function resolve_(options) {
|
|
8
9
|
return {
|
|
9
10
|
recursive: options?.recursive ?? MERGE_DEFAULT_OPTIONS.recursive,
|
|
@@ -60,8 +61,9 @@ function merge_(target, source, options) {
|
|
|
60
61
|
}
|
|
61
62
|
function mergePojo_(target, source, options) {
|
|
62
63
|
const output = { ...target };
|
|
63
|
-
|
|
64
|
-
|
|
64
|
+
// Own keys only: `for...in` would walk a hostile source's prototype too.
|
|
65
|
+
for (const key of Object.keys(source)) {
|
|
66
|
+
setRecordEntry(output, key, nested_(target[key], source[key], options));
|
|
65
67
|
}
|
|
66
68
|
return output;
|
|
67
69
|
}
|
package/dist/object/merge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/object/merge.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAClD,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,KAAK,EAAE,MAAM,qBAAqB,CAAC;AAC5C,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACnC,OAAO,EACN,qBAAqB,GAGrB,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"merge.js","sourceRoot":"","sources":["../../src/object/merge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes an object with no own enumerable property to `null`.
|
|
3
|
+
*
|
|
4
|
+
* Useful against APIs that report "no value" as an empty object rather than as
|
|
5
|
+
* `null` or `undefined`, so that callers only have one absent form to test.
|
|
6
|
+
*
|
|
7
|
+
* @param value The object to normalize.
|
|
8
|
+
* @returns The object, or `null` when it is absent or has no own enumerable
|
|
9
|
+
* property.
|
|
10
|
+
*/
|
|
11
|
+
export declare function nullIfEmpty<T extends object>(value: T | null | undefined): T | null;
|
|
12
|
+
//# sourceMappingURL=null-if-empty.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"null-if-empty.d.ts","sourceRoot":"","sources":["../../src/object/null-if-empty.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,EAC3C,KAAK,EAAE,CAAC,GAAG,IAAI,GAAG,SAAS,GACzB,CAAC,GAAG,IAAI,CAMV"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalizes an object with no own enumerable property to `null`.
|
|
3
|
+
*
|
|
4
|
+
* Useful against APIs that report "no value" as an empty object rather than as
|
|
5
|
+
* `null` or `undefined`, so that callers only have one absent form to test.
|
|
6
|
+
*
|
|
7
|
+
* @param value The object to normalize.
|
|
8
|
+
* @returns The object, or `null` when it is absent or has no own enumerable
|
|
9
|
+
* property.
|
|
10
|
+
*/
|
|
11
|
+
export function nullIfEmpty(value) {
|
|
12
|
+
if (value === null || value === undefined) {
|
|
13
|
+
return null;
|
|
14
|
+
}
|
|
15
|
+
return Object.keys(value).length === 0 ? null : value;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=null-if-empty.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"null-if-empty.js","sourceRoot":"","sources":["../../src/object/null-if-empty.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,UAAU,WAAW,CAC1B,KAA2B;IAE3B,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC3C,OAAO,IAAI,CAAC;IACb,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC;AACvD,CAAC"}
|
|
@@ -6,6 +6,11 @@ import { PropertyPath } from "./get-at-path.js";
|
|
|
6
6
|
* the next key (`number` → array, `string` → object). Existing `null` or
|
|
7
7
|
* `undefined` intermediates are replaced.
|
|
8
8
|
*
|
|
9
|
+
* A path containing `__proto__`, `constructor` or `prototype` is refused
|
|
10
|
+
* outright and nothing is written, because walking one reaches a prototype
|
|
11
|
+
* shared with every other object. The refusal is silent, like the one for a
|
|
12
|
+
* non-numeric index into an array.
|
|
13
|
+
*
|
|
9
14
|
* @param root The root object/array to mutate
|
|
10
15
|
* @param path The path to traverse
|
|
11
16
|
* @param value The value to set at the path
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set-at-path.d.ts","sourceRoot":"","sources":["../../src/object/set-at-path.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"set-at-path.d.ts","sourceRoot":"","sources":["../../src/object/set-at-path.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAIhD;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,SAAS,CACxB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE,EACzC,IAAI,EAAE,YAAY,EAClB,KAAK,EAAE,OAAO,GACZ,IAAI,CAyCN"}
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { isObject } from "../guards/is-object.js";
|
|
2
|
+
import { isUnsafeRecordKey } from "./is-unsafe-record-key.js";
|
|
3
|
+
import { setRecordEntry } from "./set-record-entry.js";
|
|
2
4
|
/**
|
|
3
5
|
* Mutates `root` by setting the value at `path`.
|
|
4
6
|
*
|
|
@@ -6,12 +8,17 @@ import { isObject } from "../guards/is-object.js";
|
|
|
6
8
|
* the next key (`number` → array, `string` → object). Existing `null` or
|
|
7
9
|
* `undefined` intermediates are replaced.
|
|
8
10
|
*
|
|
11
|
+
* A path containing `__proto__`, `constructor` or `prototype` is refused
|
|
12
|
+
* outright and nothing is written, because walking one reaches a prototype
|
|
13
|
+
* shared with every other object. The refusal is silent, like the one for a
|
|
14
|
+
* non-numeric index into an array.
|
|
15
|
+
*
|
|
9
16
|
* @param root The root object/array to mutate
|
|
10
17
|
* @param path The path to traverse
|
|
11
18
|
* @param value The value to set at the path
|
|
12
19
|
*/
|
|
13
20
|
export function setAtPath(root, path, value) {
|
|
14
|
-
if (path.length === 0) {
|
|
21
|
+
if (path.length === 0 || path.some(isUnsafeRecordKey)) {
|
|
15
22
|
return;
|
|
16
23
|
}
|
|
17
24
|
let current = root;
|
|
@@ -31,7 +38,7 @@ export function setAtPath(root, path, value) {
|
|
|
31
38
|
else {
|
|
32
39
|
const obj = current;
|
|
33
40
|
if (!isObject(obj[key]) && !Array.isArray(obj[key])) {
|
|
34
|
-
obj
|
|
41
|
+
setRecordEntry(obj, String(key), typeof nextKey === "number" ? [] : {});
|
|
35
42
|
}
|
|
36
43
|
current = obj[key];
|
|
37
44
|
}
|
|
@@ -45,7 +52,7 @@ export function setAtPath(root, path, value) {
|
|
|
45
52
|
current[lastIndex] = value;
|
|
46
53
|
}
|
|
47
54
|
else {
|
|
48
|
-
current
|
|
55
|
+
setRecordEntry(current, String(lastKey), value);
|
|
49
56
|
}
|
|
50
57
|
}
|
|
51
58
|
//# sourceMappingURL=set-at-path.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"set-at-path.js","sourceRoot":"","sources":["../../src/object/set-at-path.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"set-at-path.js","sourceRoot":"","sources":["../../src/object/set-at-path.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAElD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,SAAS,CACxB,IAAyC,EACzC,IAAkB,EAClB,KAAc;IAEd,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACvD,OAAO;IACR,CAAC;IAED,IAAI,OAAO,GAAY,IAAI,CAAC;IAE5B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QAC1C,MAAM,GAAG,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;QACrB,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,GAAG,CAAC,CAAE,CAAC;QAE7B,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;YAC5B,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC;YACnB,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;gBACzB,OAAO;YACR,CAAC;YAED,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;gBACjE,OAAO,CAAC,KAAK,CAAC,GAAG,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxD,CAAC;YACD,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;aAAM,CAAC;YACP,MAAM,GAAG,GAAG,OAAwB,CAAC;YAErC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;gBACrD,cAAc,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,CAAC,EAAE,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACzE,CAAC;YACD,OAAO,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACpB,CAAC;IACF,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC;IACvC,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC5B,MAAM,SAAS,GAAG,CAAC,OAAO,CAAC;QAC3B,IAAI,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,CAAC;YAC7B,OAAO;QACR,CAAC;QACD,OAAO,CAAC,SAAS,CAAC,GAAG,KAAK,CAAC;IAC5B,CAAC;SAAM,CAAC;QACP,cAAc,CAAC,OAAwB,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,CAAC;IAClE,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assign into a record whose keys come from untrusted input.
|
|
3
|
+
*
|
|
4
|
+
* `record[key] = value` runs the `__proto__` setter inherited from
|
|
5
|
+
* `Object.prototype`, so one key out of parsed text can replace the prototype
|
|
6
|
+
* of every object built afterwards. Defining the property instead stores an
|
|
7
|
+
* ordinary own `__proto__` entry and reaches no setter, leaving the record an
|
|
8
|
+
* otherwise normal object: same prototype, same spread, same `deepEqual`.
|
|
9
|
+
*
|
|
10
|
+
* Costs one string comparison over a plain assignment for every other key, so
|
|
11
|
+
* it is safe to call from a parser loop — `Object.defineProperty` is far slower
|
|
12
|
+
* and is taken only for the single key that needs it.
|
|
13
|
+
*
|
|
14
|
+
* This guards a **write**. A caller walking a path of untrusted keys must also
|
|
15
|
+
* guard its reads with `isUnsafeRecordKey`: stepping through `constructor` and
|
|
16
|
+
* then `prototype` pollutes without ever assigning to `__proto__`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const parsed: Record<string, unknown> = {};
|
|
21
|
+
* setRecordEntry(parsed, "__proto__", { polluted: true });
|
|
22
|
+
*
|
|
23
|
+
* parsed["__proto__"]; // { polluted: true } — an own entry
|
|
24
|
+
* Object.getPrototypeOf(parsed) === Object.prototype; // true — untouched
|
|
25
|
+
* ```;
|
|
26
|
+
*
|
|
27
|
+
* @param record The record to assign into.
|
|
28
|
+
* @param key The key, which may come from untrusted input.
|
|
29
|
+
* @param value The value to store.
|
|
30
|
+
*/
|
|
31
|
+
export declare function setRecordEntry<T>(record: Record<string, T>, key: string, value: NoInfer<T>): void;
|
|
32
|
+
//# sourceMappingURL=set-record-entry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-record-entry.d.ts","sourceRoot":"","sources":["../../src/object/set-record-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC/B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,EACzB,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC,GACf,IAAI,CAYN"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Assign into a record whose keys come from untrusted input.
|
|
3
|
+
*
|
|
4
|
+
* `record[key] = value` runs the `__proto__` setter inherited from
|
|
5
|
+
* `Object.prototype`, so one key out of parsed text can replace the prototype
|
|
6
|
+
* of every object built afterwards. Defining the property instead stores an
|
|
7
|
+
* ordinary own `__proto__` entry and reaches no setter, leaving the record an
|
|
8
|
+
* otherwise normal object: same prototype, same spread, same `deepEqual`.
|
|
9
|
+
*
|
|
10
|
+
* Costs one string comparison over a plain assignment for every other key, so
|
|
11
|
+
* it is safe to call from a parser loop — `Object.defineProperty` is far slower
|
|
12
|
+
* and is taken only for the single key that needs it.
|
|
13
|
+
*
|
|
14
|
+
* This guards a **write**. A caller walking a path of untrusted keys must also
|
|
15
|
+
* guard its reads with `isUnsafeRecordKey`: stepping through `constructor` and
|
|
16
|
+
* then `prototype` pollutes without ever assigning to `__proto__`.
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```ts
|
|
20
|
+
* const parsed: Record<string, unknown> = {};
|
|
21
|
+
* setRecordEntry(parsed, "__proto__", { polluted: true });
|
|
22
|
+
*
|
|
23
|
+
* parsed["__proto__"]; // { polluted: true } — an own entry
|
|
24
|
+
* Object.getPrototypeOf(parsed) === Object.prototype; // true — untouched
|
|
25
|
+
* ```;
|
|
26
|
+
*
|
|
27
|
+
* @param record The record to assign into.
|
|
28
|
+
* @param key The key, which may come from untrusted input.
|
|
29
|
+
* @param value The value to store.
|
|
30
|
+
*/
|
|
31
|
+
export function setRecordEntry(record, key, value) {
|
|
32
|
+
if (key === "__proto__") {
|
|
33
|
+
Object.defineProperty(record, key, {
|
|
34
|
+
value,
|
|
35
|
+
enumerable: true,
|
|
36
|
+
writable: true,
|
|
37
|
+
configurable: true,
|
|
38
|
+
});
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
record[key] = value;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=set-record-entry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"set-record-entry.js","sourceRoot":"","sources":["../../src/object/set-record-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,MAAM,UAAU,cAAc,CAC7B,MAAyB,EACzB,GAAW,EACX,KAAiB;IAEjB,IAAI,GAAG,KAAK,WAAW,EAAE,CAAC;QACzB,MAAM,CAAC,cAAc,CAAC,MAAM,EAAE,GAAG,EAAE;YAClC,KAAK;YACL,UAAU,EAAE,IAAI;YAChB,QAAQ,EAAE,IAAI;YACd,YAAY,EAAE,IAAI;SAClB,CAAC,CAAC;QACH,OAAO;IACR,CAAC;IAED,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;AACrB,CAAC"}
|
package/dist/object/traverse.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
+
import { hasObjectPrototype } from "../guards/has-object-prototype.js";
|
|
1
2
|
import { isMap } from "../guards/is-map.js";
|
|
2
|
-
import { isPlainObject } from "../guards/is-plain-object.js";
|
|
3
3
|
import { isSet } from "../guards/is-set.js";
|
|
4
4
|
import { defaults } from "./defaults.js";
|
|
5
5
|
import { getObjectKeys, } from "./get-object-keys.js";
|
|
@@ -95,8 +95,8 @@ function traverseValue_(value, visitor, options, context) {
|
|
|
95
95
|
return value;
|
|
96
96
|
}
|
|
97
97
|
// Check if we should traverse this object's properties
|
|
98
|
-
const shouldTraverseObject = (
|
|
99
|
-
(!
|
|
98
|
+
const shouldTraverseObject = (hasObjectPrototype(value) && options.traversePlainObjects) ||
|
|
99
|
+
(!hasObjectPrototype(value) &&
|
|
100
100
|
shouldTraverseCustomObject(value, options.traverseCustomObjects));
|
|
101
101
|
if (shouldTraverseObject) {
|
|
102
102
|
return traverseObjectProperties_(value, visitor, options, parentPath);
|