ts-data-forge 14.11.0 → 14.11.1
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/json/json.d.mts +20 -2
- package/dist/json/json.d.mts.map +1 -1
- package/dist/json/json.mjs +18 -0
- package/dist/json/json.mjs.map +1 -1
- package/package.json +6 -6
- package/src/array/impl/array-utils-transformation.test.mts +44 -1
- package/src/json/json.mts +20 -2
- package/src/json/json.test.mts +63 -0
- package/src/others/replace-equal-deep.test.mts +0 -2
package/dist/json/json.d.mts
CHANGED
|
@@ -41,6 +41,15 @@ export declare namespace Json {
|
|
|
41
41
|
* );
|
|
42
42
|
*
|
|
43
43
|
* assert.isTrue(Result.isOk(withReviver));
|
|
44
|
+
*
|
|
45
|
+
* // With a reviver, the result is whatever the reviver returned, not JSON:
|
|
46
|
+
* // `created` is a `Date` here although it is typed `JsonValue`. Widen it to
|
|
47
|
+
* // `unknown` before narrowing it.
|
|
48
|
+
* const revived: unknown = withReviver.value;
|
|
49
|
+
*
|
|
50
|
+
* assert.isTrue(isRecord(revived));
|
|
51
|
+
*
|
|
52
|
+
* assert.instanceOf(revived['created'], Date);
|
|
44
53
|
* ```
|
|
45
54
|
*
|
|
46
55
|
* @param text - A valid JSON string to parse. Can contain any valid JSON data
|
|
@@ -48,10 +57,19 @@ export declare namespace Json {
|
|
|
48
57
|
* @param reviver - Optional function that transforms parsed values. Called
|
|
49
58
|
* for each key-value pair in the JSON. The function receives the key name
|
|
50
59
|
* and parsed value, and should return the transformed value. For nested
|
|
51
|
-
* objects, inner objects are processed before outer objects
|
|
60
|
+
* objects, inner objects are processed before outer objects, so the
|
|
61
|
+
* `value` an outer object is passed holds what the reviver already
|
|
62
|
+
* returned for its children, which need not be JSON (see `@returns`).
|
|
63
|
+
* Returning
|
|
64
|
+
* `undefined` for a child deletes that property from an object and leaves
|
|
65
|
+
* a hole in an array. The root is passed with the key `''`.
|
|
52
66
|
* @returns A `Result<JsonValue, string>` containing:
|
|
53
67
|
*
|
|
54
|
-
* - On success: `Result.ok(parsedValue)` where `parsedValue` is the parsed
|
|
68
|
+
* - On success: `Result.ok(parsedValue)` where `parsedValue` is the parsed
|
|
69
|
+
* JSON. With a reviver it is whatever the reviver returned for the root
|
|
70
|
+
* (a `Date`, `undefined`, ...), which is not checked to be JSON although
|
|
71
|
+
* it is typed `JsonValue`; widen it to `unknown` before narrowing it,
|
|
72
|
+
* as the example does.
|
|
55
73
|
* - On failure: `Result.err(errorMessage)` where `errorMessage` describes the
|
|
56
74
|
* parsing error
|
|
57
75
|
*/
|
package/dist/json/json.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.d.mts","sourceRoot":"","sources":["../../src/json/json.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,kBAAkB,EAClB,aAAa,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAIjD;;;;GAIG;AACH,yBAAiB,IAAI,CAAC;IACpB
|
|
1
|
+
{"version":3,"file":"json.d.mts","sourceRoot":"","sources":["../../src/json/json.mts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,kBAAkB,EAClB,aAAa,EACd,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AAIjD;;;;GAIG;AACH,yBAAiB,IAAI,CAAC;IACpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAkEG;IACI,MAAM,KAAK,SACV,MAAM,YACF,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,SAAS,KAAK,OAAO,KAClE,MAAM,CAAC,SAAS,EAAE,MAAM,CAc1B,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgEG;IACI,MAAM,SAAS,UACb,OAAO,aACH,CAAC,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,KAAK,OAAO,UACxD,kBAAkB,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,KACzC,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,MAAM,CAQnC,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OAgEG;IACI,MAAM,iBAAiB,UACrB,OAAO,2BACW,SAAS,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,UAC7C,kBAAkB,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,KACzC,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,MAAM,CAUnC,CAAC;IAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4EG;IACI,MAAM,kBAAkB,UACtB,aAAa,UACZ,kBAAkB,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,MAAM,KACzC,MAAM,CAAC,MAAM,GAAG,SAAS,EAAE,MAAM,CAoBnC,CAAC;CACH"}
|
package/dist/json/json.mjs
CHANGED
package/dist/json/json.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"json.mjs","sourceRoot":"","sources":["../../src/json/json.mts"],"names":[],"mappings":"AAKA,OAAO,EAAE,MAAM,EAAE,MAAM,yBAAyB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAEnE;;;;GAIG;AACH,MAAM,KAAW,IAAI,
|
|
1
|
+
{"version":3,"file":"json.mjs","sourceRoot":"","sources":["../../src/json/json.mts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ts-data-forge",
|
|
3
|
-
"version": "14.11.
|
|
3
|
+
"version": "14.11.1",
|
|
4
4
|
"private": false,
|
|
5
5
|
"keywords": [
|
|
6
6
|
"typescript",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
],
|
|
50
50
|
"dependencies": {
|
|
51
51
|
"ts-std-forge": "^0.5.3",
|
|
52
|
-
"ts-type-forge": "~9.2.
|
|
52
|
+
"ts-type-forge": "~9.2.3"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@emotion/react": "11.14.0",
|
|
@@ -59,16 +59,16 @@
|
|
|
59
59
|
"@types/react": "19.3.0",
|
|
60
60
|
"@vitest/browser-playwright": "5.0.5",
|
|
61
61
|
"eslint": "10.13.0",
|
|
62
|
-
"eslint-config-typed": "7.
|
|
63
|
-
"eslint-plugin-ts-fortress": "1.3.
|
|
64
|
-
"eslint-plugin-ts-type-forge": "0.8.
|
|
62
|
+
"eslint-config-typed": "7.6.0",
|
|
63
|
+
"eslint-plugin-ts-fortress": "1.3.15",
|
|
64
|
+
"eslint-plugin-ts-type-forge": "0.8.20",
|
|
65
65
|
"immer": "11.2.7",
|
|
66
66
|
"playwright": "1.64.1",
|
|
67
67
|
"prettier": "3.9.10",
|
|
68
68
|
"prettier-plugin-organize-imports": "4.3.0",
|
|
69
69
|
"prettier-plugin-packagejson": "3.0.2",
|
|
70
70
|
"react": "19.3.1",
|
|
71
|
-
"ts-repo-utils": "10.7.
|
|
71
|
+
"ts-repo-utils": "10.7.4",
|
|
72
72
|
"typedoc": "0.28.20",
|
|
73
73
|
"typedoc-github-theme": "0.4.0",
|
|
74
74
|
"vite": "8.3.5"
|
|
@@ -1107,13 +1107,56 @@ describe('Arr transformations', () => {
|
|
|
1107
1107
|
|
|
1108
1108
|
const zipped = zip(xs, ys);
|
|
1109
1109
|
|
|
1110
|
-
|
|
1110
|
+
// `ys` may be shorter than `xs`, so the pair is optional.
|
|
1111
|
+
expectType<typeof zipped, readonly [(readonly [1, number])?]>('=');
|
|
1111
1112
|
|
|
1112
1113
|
test('case 3', () => {
|
|
1113
1114
|
assert.deepStrictEqual(zipped, [[1, 4]]);
|
|
1114
1115
|
});
|
|
1115
1116
|
}
|
|
1116
1117
|
|
|
1118
|
+
{
|
|
1119
|
+
const xs = [1, 2] as const;
|
|
1120
|
+
|
|
1121
|
+
const ys: readonly number[] = [] as const;
|
|
1122
|
+
|
|
1123
|
+
const zipped = zip(xs, ys);
|
|
1124
|
+
|
|
1125
|
+
expectType<
|
|
1126
|
+
typeof zipped,
|
|
1127
|
+
readonly [(readonly [1, number])?, (readonly [2, number])?]
|
|
1128
|
+
>('=');
|
|
1129
|
+
|
|
1130
|
+
test('a tuple zipped with an empty plain array is empty', () => {
|
|
1131
|
+
assert.deepStrictEqual(zipped, []);
|
|
1132
|
+
|
|
1133
|
+
expectType<(typeof zipped)[0], readonly [1, number] | undefined>('=');
|
|
1134
|
+
|
|
1135
|
+
assert.isUndefined(zipped[0]);
|
|
1136
|
+
});
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
{
|
|
1140
|
+
const xs: readonly number[] = [] as const;
|
|
1141
|
+
|
|
1142
|
+
const ys = [1, 2] as const;
|
|
1143
|
+
|
|
1144
|
+
const zipped = zip(xs, ys);
|
|
1145
|
+
|
|
1146
|
+
expectType<
|
|
1147
|
+
typeof zipped,
|
|
1148
|
+
readonly [(readonly [number, 1])?, (readonly [number, 2])?]
|
|
1149
|
+
>('=');
|
|
1150
|
+
|
|
1151
|
+
test('an empty plain array zipped with a tuple is empty', () => {
|
|
1152
|
+
assert.deepStrictEqual(zipped, []);
|
|
1153
|
+
|
|
1154
|
+
expectType<(typeof zipped)[0], readonly [number, 1] | undefined>('=');
|
|
1155
|
+
|
|
1156
|
+
assert.isUndefined(zipped[0]);
|
|
1157
|
+
});
|
|
1158
|
+
}
|
|
1159
|
+
|
|
1117
1160
|
// testArrayEquality({
|
|
1118
1161
|
// testName: 'zip',
|
|
1119
1162
|
// target: zip([0, 1, 2, 3, 4], [5, 6, 7, 8, 9]),
|
package/src/json/json.mts
CHANGED
|
@@ -48,6 +48,15 @@ export namespace Json {
|
|
|
48
48
|
* );
|
|
49
49
|
*
|
|
50
50
|
* assert.isTrue(Result.isOk(withReviver));
|
|
51
|
+
*
|
|
52
|
+
* // With a reviver, the result is whatever the reviver returned, not JSON:
|
|
53
|
+
* // `created` is a `Date` here although it is typed `JsonValue`. Widen it to
|
|
54
|
+
* // `unknown` before narrowing it.
|
|
55
|
+
* const revived: unknown = withReviver.value;
|
|
56
|
+
*
|
|
57
|
+
* assert.isTrue(isRecord(revived));
|
|
58
|
+
*
|
|
59
|
+
* assert.instanceOf(revived['created'], Date);
|
|
51
60
|
* ```
|
|
52
61
|
*
|
|
53
62
|
* @param text - A valid JSON string to parse. Can contain any valid JSON data
|
|
@@ -55,10 +64,19 @@ export namespace Json {
|
|
|
55
64
|
* @param reviver - Optional function that transforms parsed values. Called
|
|
56
65
|
* for each key-value pair in the JSON. The function receives the key name
|
|
57
66
|
* and parsed value, and should return the transformed value. For nested
|
|
58
|
-
* objects, inner objects are processed before outer objects
|
|
67
|
+
* objects, inner objects are processed before outer objects, so the
|
|
68
|
+
* `value` an outer object is passed holds what the reviver already
|
|
69
|
+
* returned for its children, which need not be JSON (see `@returns`).
|
|
70
|
+
* Returning
|
|
71
|
+
* `undefined` for a child deletes that property from an object and leaves
|
|
72
|
+
* a hole in an array. The root is passed with the key `''`.
|
|
59
73
|
* @returns A `Result<JsonValue, string>` containing:
|
|
60
74
|
*
|
|
61
|
-
* - On success: `Result.ok(parsedValue)` where `parsedValue` is the parsed
|
|
75
|
+
* - On success: `Result.ok(parsedValue)` where `parsedValue` is the parsed
|
|
76
|
+
* JSON. With a reviver it is whatever the reviver returned for the root
|
|
77
|
+
* (a `Date`, `undefined`, ...), which is not checked to be JSON although
|
|
78
|
+
* it is typed `JsonValue`; widen it to `unknown` before narrowing it,
|
|
79
|
+
* as the example does.
|
|
62
80
|
* - On failure: `Result.err(errorMessage)` where `errorMessage` describes the
|
|
63
81
|
* parsing error
|
|
64
82
|
*/
|
package/src/json/json.test.mts
CHANGED
|
@@ -180,6 +180,69 @@ describe('parse', () => {
|
|
|
180
180
|
|
|
181
181
|
expect(result.value.text).toBe('hello');
|
|
182
182
|
});
|
|
183
|
+
|
|
184
|
+
test('should return what the reviver returns for the root, even if it is not JSON', () => {
|
|
185
|
+
const result = Json.parse('{"a":1}', (key, value) =>
|
|
186
|
+
key === '' ? undefined : value,
|
|
187
|
+
);
|
|
188
|
+
|
|
189
|
+
assert.isTrue(Result.isOk(result));
|
|
190
|
+
|
|
191
|
+
expect(result.value).toBeUndefined();
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
test('should delete an object property and leave an array hole where the reviver returns undefined', () => {
|
|
195
|
+
const result = Json.parse('{"a":1,"b":[1,2,3]}', (key, value) =>
|
|
196
|
+
key === 'a' || key === '1' ? undefined : value,
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
assert.isTrue(Result.isOk(result));
|
|
200
|
+
|
|
201
|
+
const revived: unknown = result.value;
|
|
202
|
+
|
|
203
|
+
assert.isTrue(isRecord(revived));
|
|
204
|
+
|
|
205
|
+
assert.isFalse(hasKey(revived, 'a'));
|
|
206
|
+
|
|
207
|
+
assert.isTrue(hasKey(revived, 'b'));
|
|
208
|
+
|
|
209
|
+
const arr = revived.b;
|
|
210
|
+
|
|
211
|
+
assert.isTrue(Array.isArray(arr));
|
|
212
|
+
|
|
213
|
+
expect(arr).toHaveLength(3);
|
|
214
|
+
|
|
215
|
+
expect(arr[0]).toBe(1);
|
|
216
|
+
|
|
217
|
+
expect(arr[1]).toBeUndefined();
|
|
218
|
+
|
|
219
|
+
expect(arr[2]).toBe(3);
|
|
220
|
+
|
|
221
|
+
// With the same elements, only a hole at index 1 makes these differ.
|
|
222
|
+
expect(arr).not.toStrictEqual([1, undefined, 3]);
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
test('should pass the reviver the children it has already revived', () => {
|
|
226
|
+
const mut_seen: unknown[] = [];
|
|
227
|
+
|
|
228
|
+
const result = Json.parse('{"inner":{"n":1}}', (key, value) => {
|
|
229
|
+
if (key === 'inner') {
|
|
230
|
+
mut_seen.push(structuredClone(value));
|
|
231
|
+
|
|
232
|
+
return 'replaced';
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (key === '') {
|
|
236
|
+
mut_seen.push(structuredClone(value));
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return value;
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
assert.isTrue(Result.isOk(result));
|
|
243
|
+
|
|
244
|
+
assert.deepStrictEqual(mut_seen, [{ n: 1 }, { inner: 'replaced' }]);
|
|
245
|
+
});
|
|
183
246
|
});
|
|
184
247
|
|
|
185
248
|
describe('stringify', () => {
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
// A `Date` is one of the values compared whole, so the cases build some.
|
|
2
|
-
/* eslint-disable unicorn/prefer-temporal */
|
|
3
1
|
import type { DeepReadonly, ReadonlyRecord } from 'ts-type-forge';
|
|
4
2
|
import { expectType } from '../expect-type.mjs';
|
|
5
3
|
import { hasKey, isRecord } from '../guard/index.mjs';
|