@cspell/normalize-json 8.14.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/LICENSE +21 -0
- package/README.md +17 -0
- package/dist/dehydrate.d.mts +53 -0
- package/dist/dehydrate.mjs +524 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Jason Dent
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# `@cspell/normalize-json`
|
|
2
|
+
|
|
3
|
+
A library to reduce the size of JSON data by flattening and normalizing the values.
|
|
4
|
+
|
|
5
|
+
It is similar to [flatted](https://www.npmjs.com/package/flatted).
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
npm install -S @cspell/normalize-json
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
```ts
|
|
16
|
+
import { parse, stringify } from '@cspell/normalize-json';
|
|
17
|
+
```
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
type Primitive = string | number | boolean | null | undefined | RegExp | Date | bigint;
|
|
2
|
+
type PrimitiveSet = Set<Primitive | PrimitiveObject | PrimitiveArray | PrimitiveSet | PrimitiveMap>;
|
|
3
|
+
type PrimitiveMap = Map<Primitive | PrimitiveObject | PrimitiveArray | PrimitiveSet | PrimitiveMap, Primitive | PrimitiveObject | PrimitiveArray | PrimitiveSet | PrimitiveMap>;
|
|
4
|
+
interface PrimitiveObject {
|
|
5
|
+
readonly [key: string]: Primitive | PrimitiveObject | PrimitiveArray | PrimitiveSet | PrimitiveMap;
|
|
6
|
+
}
|
|
7
|
+
type PrimitiveArray = readonly (Primitive | PrimitiveObject | PrimitiveArray | PrimitiveSet | PrimitiveMap)[];
|
|
8
|
+
type PrimitiveElement = Primitive;
|
|
9
|
+
type Serializable = Primitive | PrimitiveObject | PrimitiveArray | PrimitiveSet | PrimitiveMap;
|
|
10
|
+
declare enum ElementType {
|
|
11
|
+
Array = 0,
|
|
12
|
+
Object = 1,
|
|
13
|
+
String = 2,
|
|
14
|
+
SubString = 3,
|
|
15
|
+
Set = 4,
|
|
16
|
+
Map = 5,
|
|
17
|
+
RegExp = 6,
|
|
18
|
+
Date = 7,
|
|
19
|
+
BigInt = 8
|
|
20
|
+
}
|
|
21
|
+
interface EmptyObject {
|
|
22
|
+
readonly t?: ElementType.Object;
|
|
23
|
+
}
|
|
24
|
+
type ObjectBasedElements = EmptyObject;
|
|
25
|
+
type ArrayBasedElements = ArrayElement | BigIntElement | DateElement | MapElement | ObjectElement | RegExpElement | SetElement | StringElement | SubStringElement;
|
|
26
|
+
type Index = number;
|
|
27
|
+
type StringElement = readonly [type: ElementType.String, ...Index[]];
|
|
28
|
+
type SubStringElement = readonly [type: ElementType.SubString, Index, len: number, offset?: number];
|
|
29
|
+
type ObjectElement = readonly [type: ElementType.Object, keys: Index, values: Index];
|
|
30
|
+
type SetElement = readonly [type: ElementType.Set, keys: Index];
|
|
31
|
+
type MapElement = readonly [type: ElementType.Map, keys: Index, values: Index];
|
|
32
|
+
type RegExpElement = readonly [type: ElementType.RegExp, pattern: Index, flags: Index];
|
|
33
|
+
type DateElement = readonly [type: ElementType.Date, value: number];
|
|
34
|
+
type BigIntElement = readonly [type: ElementType.BigInt, value: Index];
|
|
35
|
+
type ArrayElement = readonly [type: ElementType.Array, ...Index[]];
|
|
36
|
+
type Element = Readonly<PrimitiveElement | ObjectBasedElements | ArrayBasedElements>;
|
|
37
|
+
type Header = string;
|
|
38
|
+
type Dehydrated = [Header, ...Element[]];
|
|
39
|
+
type Hydrated = Readonly<Serializable>;
|
|
40
|
+
export interface NormalizeJsonOptions {
|
|
41
|
+
sortKeys?: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Dedupe objects and arrays.
|
|
44
|
+
* Implies `sortKeys`.
|
|
45
|
+
*/
|
|
46
|
+
dedupe?: boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare function toJSON<V extends Serializable>(json: V, options?: NormalizeJsonOptions): Dehydrated;
|
|
49
|
+
export declare function fromJSON(data: Dehydrated): Hydrated;
|
|
50
|
+
export declare function parse(data: string): Hydrated;
|
|
51
|
+
export declare function stringify(data: Hydrated): string;
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=dehydrate.d.mts.map
|
|
@@ -0,0 +1,524 @@
|
|
|
1
|
+
import assert from 'node:assert';
|
|
2
|
+
var ElementType;
|
|
3
|
+
(function (ElementType) {
|
|
4
|
+
ElementType[ElementType["Array"] = 0] = "Array";
|
|
5
|
+
ElementType[ElementType["Object"] = 1] = "Object";
|
|
6
|
+
ElementType[ElementType["String"] = 2] = "String";
|
|
7
|
+
ElementType[ElementType["SubString"] = 3] = "SubString";
|
|
8
|
+
ElementType[ElementType["Set"] = 4] = "Set";
|
|
9
|
+
ElementType[ElementType["Map"] = 5] = "Map";
|
|
10
|
+
ElementType[ElementType["RegExp"] = 6] = "RegExp";
|
|
11
|
+
ElementType[ElementType["Date"] = 7] = "Date";
|
|
12
|
+
ElementType[ElementType["BigInt"] = 8] = "BigInt";
|
|
13
|
+
})(ElementType || (ElementType = {}));
|
|
14
|
+
const blockSplitRegex = /^sha\d/;
|
|
15
|
+
const dataHeader = 'Dehydrated JSON v1';
|
|
16
|
+
const collator = new Intl.Collator('en', {
|
|
17
|
+
usage: 'sort',
|
|
18
|
+
numeric: true,
|
|
19
|
+
sensitivity: 'variant',
|
|
20
|
+
caseFirst: 'upper',
|
|
21
|
+
ignorePunctuation: false,
|
|
22
|
+
});
|
|
23
|
+
const compare = collator.compare;
|
|
24
|
+
const forceStringPrimitives = false;
|
|
25
|
+
const minSubStringLen = 4;
|
|
26
|
+
export function toJSON(json, options) {
|
|
27
|
+
const data = [dataHeader];
|
|
28
|
+
const dedupe = options?.dedupe ?? true;
|
|
29
|
+
const sortKeys = options?.sortKeys || dedupe;
|
|
30
|
+
let emptyObjIdx = 0;
|
|
31
|
+
const cache = new Map([[undefined, 0]]);
|
|
32
|
+
const referenced = new Set();
|
|
33
|
+
const cachedArrays = new Map();
|
|
34
|
+
const knownStrings = new Trie();
|
|
35
|
+
const cachedElements = new Map();
|
|
36
|
+
function primitiveToIdx(value) {
|
|
37
|
+
if (typeof value === 'string')
|
|
38
|
+
return stringToIdx(value);
|
|
39
|
+
if (typeof value === 'bigint')
|
|
40
|
+
return bigintToIdx(value);
|
|
41
|
+
const found = cache.get(value);
|
|
42
|
+
if (found !== undefined) {
|
|
43
|
+
return found;
|
|
44
|
+
}
|
|
45
|
+
const idx = data.push(value) - 1;
|
|
46
|
+
cache.set(value, idx);
|
|
47
|
+
return idx;
|
|
48
|
+
}
|
|
49
|
+
function addSubStringRef(idxString, value, offset) {
|
|
50
|
+
const found = cache.get(value);
|
|
51
|
+
if (found !== undefined) {
|
|
52
|
+
return found;
|
|
53
|
+
}
|
|
54
|
+
const sub = offset
|
|
55
|
+
? [ElementType.SubString, idxString, value.length, offset]
|
|
56
|
+
: [ElementType.SubString, idxString, value.length];
|
|
57
|
+
const idx = data.push(sub) - 1;
|
|
58
|
+
cache.set(value, idx);
|
|
59
|
+
return idx;
|
|
60
|
+
}
|
|
61
|
+
function addKnownString(idx, value) {
|
|
62
|
+
if (value.length >= minSubStringLen) {
|
|
63
|
+
knownStrings.add(value.length > 256 ? value.slice(0, 256) : value, { idx });
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
function addStringPrimitive(value) {
|
|
67
|
+
const idx = data.push(value) - 1;
|
|
68
|
+
addKnownString(idx, value);
|
|
69
|
+
cache.set(value, idx);
|
|
70
|
+
return idx;
|
|
71
|
+
}
|
|
72
|
+
function duplicateIndex(idx) {
|
|
73
|
+
const element = data[idx];
|
|
74
|
+
const duplicate = data.push(element) - 1;
|
|
75
|
+
return duplicate;
|
|
76
|
+
}
|
|
77
|
+
function stringToIdx(value) {
|
|
78
|
+
const found = cache.get(value);
|
|
79
|
+
if (found !== undefined) {
|
|
80
|
+
return found;
|
|
81
|
+
}
|
|
82
|
+
if (forceStringPrimitives || value.length < minSubStringLen || blockSplitRegex.test(value)) {
|
|
83
|
+
return addStringPrimitive(value);
|
|
84
|
+
}
|
|
85
|
+
const trieFound = knownStrings.find(value);
|
|
86
|
+
if (!trieFound || !trieFound.data || trieFound.found.length < minSubStringLen) {
|
|
87
|
+
return addStringPrimitive(value);
|
|
88
|
+
}
|
|
89
|
+
const { data: tData, found: subStr } = trieFound;
|
|
90
|
+
const sIdx = addSubStringRef(tData.idx, subStr, tData.offset);
|
|
91
|
+
if (subStr === value)
|
|
92
|
+
return sIdx;
|
|
93
|
+
const v = [sIdx, stringToIdx(value.slice(subStr.length))];
|
|
94
|
+
const idx = data.push([ElementType.String, ...v]) - 1;
|
|
95
|
+
cache.set(value, idx);
|
|
96
|
+
addKnownString(idx, value);
|
|
97
|
+
return idx;
|
|
98
|
+
}
|
|
99
|
+
function objSetToIdx(value) {
|
|
100
|
+
const found = cache.get(value);
|
|
101
|
+
if (found !== undefined) {
|
|
102
|
+
referenced.add(found);
|
|
103
|
+
return found;
|
|
104
|
+
}
|
|
105
|
+
const idx = data.push(0) - 1;
|
|
106
|
+
cache.set(value, idx);
|
|
107
|
+
const keys = [...value];
|
|
108
|
+
const k = createUniqueKeys(keys);
|
|
109
|
+
const element = [ElementType.Set, k];
|
|
110
|
+
return storeElement(value, idx, element);
|
|
111
|
+
}
|
|
112
|
+
function createUniqueKeys(keys) {
|
|
113
|
+
let k = arrToIdx(keys);
|
|
114
|
+
const elementKeys = data[k];
|
|
115
|
+
const uniqueKeys = new Set(elementKeys.slice(1));
|
|
116
|
+
if (uniqueKeys.size !== keys.length) {
|
|
117
|
+
// one or more of the keys got deduped. We need to duplicate it.
|
|
118
|
+
uniqueKeys.clear();
|
|
119
|
+
const indexes = elementKeys.slice(1).map((idx) => {
|
|
120
|
+
if (uniqueKeys.has(idx)) {
|
|
121
|
+
return duplicateIndex(idx);
|
|
122
|
+
}
|
|
123
|
+
uniqueKeys.add(idx);
|
|
124
|
+
return idx;
|
|
125
|
+
});
|
|
126
|
+
k = createArrayElementFromIndexValues(data.length, indexes);
|
|
127
|
+
}
|
|
128
|
+
return k;
|
|
129
|
+
}
|
|
130
|
+
function objMapToIdx(value) {
|
|
131
|
+
const found = cache.get(value);
|
|
132
|
+
if (found !== undefined) {
|
|
133
|
+
referenced.add(found);
|
|
134
|
+
return found;
|
|
135
|
+
}
|
|
136
|
+
const idx = data.push(0) - 1;
|
|
137
|
+
cache.set(value, idx);
|
|
138
|
+
const entries = [...value.entries()];
|
|
139
|
+
const k = createUniqueKeys(entries.map(([key]) => key));
|
|
140
|
+
const v = arrToIdx(entries.map(([, value]) => value));
|
|
141
|
+
const element = [ElementType.Map, k, v];
|
|
142
|
+
return storeElement(value, idx, element);
|
|
143
|
+
}
|
|
144
|
+
function objRegExpToIdx(value) {
|
|
145
|
+
const found = cache.get(value);
|
|
146
|
+
if (found !== undefined) {
|
|
147
|
+
return found;
|
|
148
|
+
}
|
|
149
|
+
const idx = data.push(0) - 1;
|
|
150
|
+
cache.set(value, idx);
|
|
151
|
+
const element = [ElementType.RegExp, stringToIdx(value.source), stringToIdx(value.flags)];
|
|
152
|
+
return storeElement(value, idx, element);
|
|
153
|
+
}
|
|
154
|
+
function objDateToIdx(value) {
|
|
155
|
+
const found = cache.get(value);
|
|
156
|
+
if (found !== undefined) {
|
|
157
|
+
return found;
|
|
158
|
+
}
|
|
159
|
+
const idx = data.push(0) - 1;
|
|
160
|
+
cache.set(value, idx);
|
|
161
|
+
const element = [ElementType.Date, value.getTime()];
|
|
162
|
+
return storeElement(value, idx, element);
|
|
163
|
+
}
|
|
164
|
+
function bigintToIdx(value) {
|
|
165
|
+
const found = cache.get(value);
|
|
166
|
+
if (found !== undefined) {
|
|
167
|
+
return found;
|
|
168
|
+
}
|
|
169
|
+
const idx = data.push(0) - 1;
|
|
170
|
+
cache.set(value, idx);
|
|
171
|
+
const element = [
|
|
172
|
+
ElementType.BigInt,
|
|
173
|
+
primitiveToIdx(value <= Number.MAX_SAFE_INTEGER && value >= -Number.MAX_SAFE_INTEGER
|
|
174
|
+
? Number(value)
|
|
175
|
+
: value.toString()),
|
|
176
|
+
];
|
|
177
|
+
return storeElement(value, idx, element);
|
|
178
|
+
}
|
|
179
|
+
function objToIdx(value) {
|
|
180
|
+
const found = cache.get(value);
|
|
181
|
+
if (found !== undefined) {
|
|
182
|
+
referenced.add(found);
|
|
183
|
+
return found;
|
|
184
|
+
}
|
|
185
|
+
if (isObjectWrapper(value)) {
|
|
186
|
+
const idx = data.push({}) - 1;
|
|
187
|
+
cache.set(value, idx);
|
|
188
|
+
const element = [ElementType.Object, 0, valueToIdx(value.valueOf())];
|
|
189
|
+
return storeElement(value, idx, element);
|
|
190
|
+
}
|
|
191
|
+
const entries = Object.entries(value);
|
|
192
|
+
if (!entries.length) {
|
|
193
|
+
if (emptyObjIdx) {
|
|
194
|
+
return emptyObjIdx;
|
|
195
|
+
}
|
|
196
|
+
const idx = data.push({}) - 1;
|
|
197
|
+
emptyObjIdx = idx;
|
|
198
|
+
return idx;
|
|
199
|
+
}
|
|
200
|
+
const idx = data.push(0) - 1;
|
|
201
|
+
cache.set(value, idx);
|
|
202
|
+
if (sortKeys) {
|
|
203
|
+
entries.sort(([a], [b]) => compare(a, b));
|
|
204
|
+
}
|
|
205
|
+
const k = arrToIdx(entries.map(([key]) => key));
|
|
206
|
+
const v = arrToIdx(entries.map(([, value]) => value));
|
|
207
|
+
const element = [ElementType.Object, k, v];
|
|
208
|
+
return storeElement(value, idx, element);
|
|
209
|
+
}
|
|
210
|
+
function storeElement(value, idx, element) {
|
|
211
|
+
const useIdx = dedupe ? cacheElement(idx, element) : idx;
|
|
212
|
+
if (useIdx !== idx && idx === data.length - 1) {
|
|
213
|
+
data.length = idx;
|
|
214
|
+
cache.set(value, useIdx);
|
|
215
|
+
return useIdx;
|
|
216
|
+
}
|
|
217
|
+
data[idx] = element;
|
|
218
|
+
return idx;
|
|
219
|
+
}
|
|
220
|
+
function cacheElement(elemIdx, element) {
|
|
221
|
+
let map = cachedElements;
|
|
222
|
+
for (let i = 0; i < element.length - 1; i++) {
|
|
223
|
+
const idx = element[i];
|
|
224
|
+
let found = map.get(idx);
|
|
225
|
+
if (!found) {
|
|
226
|
+
found = new Map();
|
|
227
|
+
map.set(idx, found);
|
|
228
|
+
}
|
|
229
|
+
assert(found instanceof Map);
|
|
230
|
+
map = found;
|
|
231
|
+
}
|
|
232
|
+
const idx = element[element.length - 1];
|
|
233
|
+
const foundIdx = map.get(idx);
|
|
234
|
+
if (typeof foundIdx === 'number') {
|
|
235
|
+
return referenced.has(elemIdx) ? elemIdx : foundIdx;
|
|
236
|
+
}
|
|
237
|
+
map.set(idx, elemIdx);
|
|
238
|
+
return elemIdx;
|
|
239
|
+
}
|
|
240
|
+
function stashArray(idx, element) {
|
|
241
|
+
const indexHash = simpleHash(element);
|
|
242
|
+
let found = cachedArrays.get(indexHash);
|
|
243
|
+
if (!found) {
|
|
244
|
+
found = [];
|
|
245
|
+
cachedArrays.set(indexHash, found);
|
|
246
|
+
}
|
|
247
|
+
const foundIdx = found.find((entry) => isEqual(entry.v, element));
|
|
248
|
+
if (foundIdx) {
|
|
249
|
+
return referenced.has(idx) ? idx : foundIdx.idx;
|
|
250
|
+
}
|
|
251
|
+
found.push({ idx, v: element });
|
|
252
|
+
return idx;
|
|
253
|
+
}
|
|
254
|
+
function createArrayElementFromIndexValues(idx, indexValues) {
|
|
255
|
+
const element = [ElementType.Array, ...indexValues];
|
|
256
|
+
const useIdx = dedupe ? stashArray(idx, element) : idx;
|
|
257
|
+
if (useIdx !== idx) {
|
|
258
|
+
assert(data.length == idx + 1, `Expected ${idx + 1} but got ${data.length}`);
|
|
259
|
+
data.length = idx;
|
|
260
|
+
return useIdx;
|
|
261
|
+
}
|
|
262
|
+
data[idx] = element;
|
|
263
|
+
return idx;
|
|
264
|
+
}
|
|
265
|
+
function arrToIdx(value) {
|
|
266
|
+
const found = cache.get(value);
|
|
267
|
+
if (found !== undefined) {
|
|
268
|
+
referenced.add(found);
|
|
269
|
+
return found;
|
|
270
|
+
}
|
|
271
|
+
const idx = data.push(0) - 1;
|
|
272
|
+
cache.set(value, idx);
|
|
273
|
+
const useIdx = createArrayElementFromIndexValues(idx, value.map((idx) => valueToIdx(idx)));
|
|
274
|
+
cache.set(value, useIdx);
|
|
275
|
+
return useIdx;
|
|
276
|
+
}
|
|
277
|
+
function valueToIdx(value) {
|
|
278
|
+
if (value === null) {
|
|
279
|
+
// eslint-disable-next-line unicorn/no-null
|
|
280
|
+
return primitiveToIdx(null);
|
|
281
|
+
}
|
|
282
|
+
if (typeof value === 'object') {
|
|
283
|
+
if (value instanceof Set) {
|
|
284
|
+
return objSetToIdx(value);
|
|
285
|
+
}
|
|
286
|
+
if (value instanceof Map) {
|
|
287
|
+
return objMapToIdx(value);
|
|
288
|
+
}
|
|
289
|
+
if (value instanceof RegExp) {
|
|
290
|
+
return objRegExpToIdx(value);
|
|
291
|
+
}
|
|
292
|
+
if (Array.isArray(value)) {
|
|
293
|
+
return arrToIdx(value);
|
|
294
|
+
}
|
|
295
|
+
if (value instanceof Date) {
|
|
296
|
+
return objDateToIdx(value);
|
|
297
|
+
}
|
|
298
|
+
return objToIdx(value);
|
|
299
|
+
}
|
|
300
|
+
return primitiveToIdx(value);
|
|
301
|
+
}
|
|
302
|
+
valueToIdx(json);
|
|
303
|
+
return data;
|
|
304
|
+
}
|
|
305
|
+
function isEqual(a, b) {
|
|
306
|
+
if (a.length !== b.length)
|
|
307
|
+
return false;
|
|
308
|
+
for (let i = 0; i < a.length; i++) {
|
|
309
|
+
if (a[i] !== b[i])
|
|
310
|
+
return false;
|
|
311
|
+
}
|
|
312
|
+
return true;
|
|
313
|
+
}
|
|
314
|
+
function simpleHash(values) {
|
|
315
|
+
let hash = Math.sqrt(values.length);
|
|
316
|
+
for (const value of values) {
|
|
317
|
+
hash += value * value;
|
|
318
|
+
}
|
|
319
|
+
return hash;
|
|
320
|
+
}
|
|
321
|
+
export function fromJSON(data) {
|
|
322
|
+
const [header] = data;
|
|
323
|
+
if (header !== dataHeader) {
|
|
324
|
+
throw new Error('Invalid header');
|
|
325
|
+
}
|
|
326
|
+
const cache = new Map([[0, undefined]]);
|
|
327
|
+
/**
|
|
328
|
+
* indexes that have been referenced by other objects.
|
|
329
|
+
*/
|
|
330
|
+
const referenced = new Set();
|
|
331
|
+
function mergeKeysValues(keys, values) {
|
|
332
|
+
return keys.map((key, i) => [key, values[i]]);
|
|
333
|
+
}
|
|
334
|
+
function toSet(idx, elem) {
|
|
335
|
+
const [_, k] = elem;
|
|
336
|
+
const s = k ? new Set(idxToArr(k)) : new Set();
|
|
337
|
+
cache.set(idx, s);
|
|
338
|
+
return s;
|
|
339
|
+
}
|
|
340
|
+
function toMap(idx, elem) {
|
|
341
|
+
const [_, k, v] = elem;
|
|
342
|
+
const m = !k || !v ? new Map() : new Map(mergeKeysValues(idxToArr(k), idxToArr(v)));
|
|
343
|
+
cache.set(idx, m);
|
|
344
|
+
return m;
|
|
345
|
+
}
|
|
346
|
+
function toRegExp(idx, elem) {
|
|
347
|
+
const [_, pattern, flags] = elem;
|
|
348
|
+
const p = idxToValue(pattern);
|
|
349
|
+
const f = idxToValue(flags);
|
|
350
|
+
const r = new RegExp(p, f);
|
|
351
|
+
cache.set(idx, r);
|
|
352
|
+
return r;
|
|
353
|
+
}
|
|
354
|
+
function toBigInt(idx, elem) {
|
|
355
|
+
const [_, vIdx] = elem;
|
|
356
|
+
const r = BigInt(idxToValue(vIdx));
|
|
357
|
+
cache.set(idx, r);
|
|
358
|
+
return r;
|
|
359
|
+
}
|
|
360
|
+
function toDate(idx, elem) {
|
|
361
|
+
const [_, value] = elem;
|
|
362
|
+
const r = new Date(value);
|
|
363
|
+
cache.set(idx, r);
|
|
364
|
+
return r;
|
|
365
|
+
}
|
|
366
|
+
function toString(idx, elem) {
|
|
367
|
+
const s = typeof elem === 'string' ? elem : idxToValue(elem.slice(1));
|
|
368
|
+
cache.set(idx, s);
|
|
369
|
+
return s;
|
|
370
|
+
}
|
|
371
|
+
function toObj(idx, elem) {
|
|
372
|
+
const [_, k, v] = elem;
|
|
373
|
+
// Object Wrapper
|
|
374
|
+
if (!k && v) {
|
|
375
|
+
const obj = Object(idxToValue(v));
|
|
376
|
+
cache.set(idx, obj);
|
|
377
|
+
return obj;
|
|
378
|
+
}
|
|
379
|
+
const obj = {};
|
|
380
|
+
cache.set(idx, obj);
|
|
381
|
+
if (!k || !v)
|
|
382
|
+
return obj;
|
|
383
|
+
const keys = idxToArr(k);
|
|
384
|
+
const values = idxToArr(v);
|
|
385
|
+
Object.assign(obj, Object.fromEntries(mergeKeysValues(keys, values)));
|
|
386
|
+
return obj;
|
|
387
|
+
}
|
|
388
|
+
function idxToArr(idx) {
|
|
389
|
+
const element = data[idx];
|
|
390
|
+
assert(isArrayElement(element));
|
|
391
|
+
return toArr(idx, element);
|
|
392
|
+
}
|
|
393
|
+
function toArr(idx, element) {
|
|
394
|
+
const placeHolder = [];
|
|
395
|
+
const refs = element.slice(1);
|
|
396
|
+
cache.set(idx, placeHolder);
|
|
397
|
+
const arr = refs.map(idxToValue);
|
|
398
|
+
// check if the array has been referenced by another object.
|
|
399
|
+
if (!referenced.has(idx)) {
|
|
400
|
+
// It has not, just replace the placeholder with the array.
|
|
401
|
+
cache.set(idx, arr);
|
|
402
|
+
return arr;
|
|
403
|
+
}
|
|
404
|
+
placeHolder.push(...arr);
|
|
405
|
+
return placeHolder;
|
|
406
|
+
}
|
|
407
|
+
function handleSubStringElement(idx, refs) {
|
|
408
|
+
const [_t, sIdx, len, offset = 0] = refs;
|
|
409
|
+
const s = `${idxToValue(sIdx)}`.slice(offset, offset + len);
|
|
410
|
+
cache.set(idx, s);
|
|
411
|
+
return s;
|
|
412
|
+
}
|
|
413
|
+
function handleArrayElement(idx, element) {
|
|
414
|
+
switch (element[0]) {
|
|
415
|
+
case ElementType.Array: {
|
|
416
|
+
break;
|
|
417
|
+
}
|
|
418
|
+
case ElementType.Object: {
|
|
419
|
+
return toObj(idx, element);
|
|
420
|
+
}
|
|
421
|
+
case ElementType.String: {
|
|
422
|
+
return toString(idx, element);
|
|
423
|
+
}
|
|
424
|
+
case ElementType.SubString: {
|
|
425
|
+
return handleSubStringElement(idx, element);
|
|
426
|
+
}
|
|
427
|
+
case ElementType.Set: {
|
|
428
|
+
return toSet(idx, element);
|
|
429
|
+
}
|
|
430
|
+
case ElementType.Map: {
|
|
431
|
+
return toMap(idx, element);
|
|
432
|
+
}
|
|
433
|
+
case ElementType.RegExp: {
|
|
434
|
+
return toRegExp(idx, element);
|
|
435
|
+
}
|
|
436
|
+
case ElementType.Date: {
|
|
437
|
+
return toDate(idx, element);
|
|
438
|
+
}
|
|
439
|
+
case ElementType.BigInt: {
|
|
440
|
+
return toBigInt(idx, element);
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
return toArr(idx, element);
|
|
444
|
+
}
|
|
445
|
+
function idxToValue(idx) {
|
|
446
|
+
if (!idx)
|
|
447
|
+
return undefined;
|
|
448
|
+
const found = cache.get(idx);
|
|
449
|
+
if (found !== undefined) {
|
|
450
|
+
if (typeof idx === 'number')
|
|
451
|
+
referenced.add(idx);
|
|
452
|
+
return found;
|
|
453
|
+
}
|
|
454
|
+
if (Array.isArray(idx)) {
|
|
455
|
+
// it is a nested string;
|
|
456
|
+
const parts = idx.map((i) => idxToValue(i));
|
|
457
|
+
return joinToString(parts);
|
|
458
|
+
}
|
|
459
|
+
const element = data[idx];
|
|
460
|
+
if (typeof element === 'object') {
|
|
461
|
+
// eslint-disable-next-line unicorn/no-null
|
|
462
|
+
if (element === null)
|
|
463
|
+
return null;
|
|
464
|
+
if (Array.isArray(element))
|
|
465
|
+
return handleArrayElement(idx, element);
|
|
466
|
+
return {};
|
|
467
|
+
}
|
|
468
|
+
return element;
|
|
469
|
+
}
|
|
470
|
+
return idxToValue(1);
|
|
471
|
+
}
|
|
472
|
+
function joinToString(parts) {
|
|
473
|
+
return parts.map((a) => (Array.isArray(a) ? joinToString(a) : a)).join('');
|
|
474
|
+
}
|
|
475
|
+
function isArrayElement(value) {
|
|
476
|
+
return Array.isArray(value) && value[0] === ElementType.Array;
|
|
477
|
+
}
|
|
478
|
+
function isObjectWrapper(value) {
|
|
479
|
+
return (typeof value === 'object' &&
|
|
480
|
+
value !== null &&
|
|
481
|
+
typeof value.valueOf === 'function' &&
|
|
482
|
+
value.valueOf() !== value);
|
|
483
|
+
}
|
|
484
|
+
class Trie {
|
|
485
|
+
root = { d: undefined, c: new Map() };
|
|
486
|
+
add(key, data) {
|
|
487
|
+
let node = this.root;
|
|
488
|
+
for (const k of key) {
|
|
489
|
+
let c = node.c;
|
|
490
|
+
if (!c) {
|
|
491
|
+
node.c = c = new Map();
|
|
492
|
+
}
|
|
493
|
+
let n = c.get(k);
|
|
494
|
+
if (!n) {
|
|
495
|
+
c.set(k, (n = { d: data }));
|
|
496
|
+
}
|
|
497
|
+
node = n;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
find(key) {
|
|
501
|
+
let node = this.root;
|
|
502
|
+
let found = '';
|
|
503
|
+
for (const k of key) {
|
|
504
|
+
const c = node.c;
|
|
505
|
+
if (!c) {
|
|
506
|
+
break;
|
|
507
|
+
}
|
|
508
|
+
const n = c.get(k);
|
|
509
|
+
if (!n) {
|
|
510
|
+
break;
|
|
511
|
+
}
|
|
512
|
+
found += k;
|
|
513
|
+
node = n;
|
|
514
|
+
}
|
|
515
|
+
return { data: node.d, found };
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
export function parse(data) {
|
|
519
|
+
return fromJSON(JSON.parse(data));
|
|
520
|
+
}
|
|
521
|
+
export function stringify(data) {
|
|
522
|
+
return JSON.stringify(toJSON(data));
|
|
523
|
+
}
|
|
524
|
+
//# sourceMappingURL=dehydrate.mjs.map
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cspell/normalize-json",
|
|
3
|
+
"publishConfig": {
|
|
4
|
+
"access": "public"
|
|
5
|
+
},
|
|
6
|
+
"version": "8.14.1",
|
|
7
|
+
"description": "A library to normalize JSON objects to reduce the size.",
|
|
8
|
+
"keywords": [
|
|
9
|
+
"cspell",
|
|
10
|
+
"json",
|
|
11
|
+
"normalize",
|
|
12
|
+
"flatten"
|
|
13
|
+
],
|
|
14
|
+
"author": "Jason Dent <jason@streetsidesoftware.nl>",
|
|
15
|
+
"homepage": "https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell-filetypes#readme",
|
|
16
|
+
"license": "MIT",
|
|
17
|
+
"type": "module",
|
|
18
|
+
"sideEffects": false,
|
|
19
|
+
"exports": {
|
|
20
|
+
".": "./dist/index.js"
|
|
21
|
+
},
|
|
22
|
+
"directories": {
|
|
23
|
+
"dist": "dist"
|
|
24
|
+
},
|
|
25
|
+
"typings": "dist/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"dist",
|
|
28
|
+
"!**/*.tsbuildInfo",
|
|
29
|
+
"!**/__mocks__",
|
|
30
|
+
"!**/*.test.*",
|
|
31
|
+
"!**/*.spec.*",
|
|
32
|
+
"!**/*.map"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsc -p .",
|
|
36
|
+
"watch": "tsc -p . -w",
|
|
37
|
+
"clean": "shx rm -rf dist temp coverage \"*.tsbuildInfo\"",
|
|
38
|
+
"clean-build": "pnpm run clean && pnpm run build",
|
|
39
|
+
"coverage": "vitest run --coverage",
|
|
40
|
+
"test-watch": "vitest",
|
|
41
|
+
"test": "vitest run"
|
|
42
|
+
},
|
|
43
|
+
"repository": {
|
|
44
|
+
"type": "git",
|
|
45
|
+
"url": "https://github.com/streetsidesoftware/cspell.git",
|
|
46
|
+
"directory": "packages/cspell-filetypes"
|
|
47
|
+
},
|
|
48
|
+
"bugs": {
|
|
49
|
+
"url": "https://github.com/streetsidesoftware/cspell/labels/filetype"
|
|
50
|
+
},
|
|
51
|
+
"engines": {
|
|
52
|
+
"node": ">=18"
|
|
53
|
+
},
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@cspell/filetypes": "8.14.1"
|
|
56
|
+
},
|
|
57
|
+
"gitHead": "5552bdba15adc8c073dd33791f30329147c5c64b"
|
|
58
|
+
}
|