• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

streetsidesoftware / cspell / 22750958649

06 Mar 2026 05:47AM UTC coverage: 92.832% (-0.07%) from 92.904%
22750958649

Pull #8680

github

web-flow
Merge 05a108095 into b7ea1f10d
Pull Request #8680: fix: crate Flatpack V2 that is diff friendly

9649 of 11508 branches covered (83.85%)

1303 of 1389 new or added lines in 13 files covered. (93.81%)

6 existing lines in 1 file now uncovered.

19181 of 20662 relevant lines covered (92.83%)

30083.92 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

97.85
/packages/flatpack-json/src/unpack.mts
1
import assert from 'node:assert';
2

3
import { StringTable } from './stringTable.mjs';
4
import type {
5
    ArrayBasedElements,
6
    ArrayElement,
7
    BigIntElement,
8
    DateElement,
9
    Flatpacked,
10
    FlattenedElement,
11
    MapElement,
12
    ObjectElement,
13
    Primitive,
14
    PrimitiveArray,
15
    PrimitiveMap,
16
    PrimitiveObject,
17
    PrimitiveSet,
18
    RegExpElement,
19
    Serializable,
20
    SetElement,
21
    StringElement,
22
    StringTableElement,
23
    SubStringElement,
24
    Unpacked,
25
} from './types.mjs';
26
import { ElementType, supportedHeaders } from './types.mjs';
27

28
export function fromJSON(data: Flatpacked): Unpacked {
29
    const [header] = data;
1,025✔
30

31
    let stringTable: StringTable | undefined;
32

33
    if (!supportedHeaders.has(header)) {
1,025!
34
        throw new Error('Invalid header');
×
35
    }
36

37
    const cache = new Map<number | number[], Unpacked>([[0, undefined]]);
1,025✔
38
    /**
39
     * indexes that have been referenced by other objects.
40
     */
41
    const referenced = new Set<number>();
1,025✔
42

43
    function mergeKeysValues<K>(keys: readonly K[], values: PrimitiveArray): [K, Serializable][] {
44
        return keys.map((key, i) => [key, values[i]]);
54,225✔
45
    }
46

47
    function toSet(idx: number, elem: SetElement): PrimitiveSet {
48
        const [_, k] = elem;
131✔
49
        const s: PrimitiveSet = k ? (new Set(idxToArr(k)) as PrimitiveSet) : new Set();
131!
50
        cache.set(idx, s);
131✔
51
        return s;
131✔
52
    }
53

54
    function toMap(idx: number, elem: MapElement): PrimitiveMap {
55
        const [_, k, v] = elem;
79✔
56
        const m: PrimitiveMap =
57
            !k || !v ? new Map() : (new Map(mergeKeysValues(idxToArr(k), idxToArr(v))) as PrimitiveMap);
79!
58
        cache.set(idx, m);
79✔
59
        return m;
79✔
60
    }
61

62
    function toRegExp(idx: number, elem: RegExpElement): RegExp {
63
        const [_, pattern, flags] = elem;
166✔
64
        const p = idxToValue(pattern) as string;
166✔
65
        const f = idxToValue(flags) as string;
166✔
66
        const r = new RegExp(p, f);
166✔
67
        cache.set(idx, r);
166✔
68
        return r;
166✔
69
    }
70

71
    function toBigInt(idx: number, elem: BigIntElement): bigint {
72
        const [_, vIdx] = elem;
182✔
73
        const r = BigInt(idxToValue(vIdx) as string | number);
182✔
74
        cache.set(idx, r);
182✔
75
        return r;
182✔
76
    }
77

78
    function toDate(idx: number, elem: DateElement): Date {
79
        const [_, value] = elem;
64✔
80
        const r = new Date(value);
64✔
81
        cache.set(idx, r);
64✔
82
        return r;
64✔
83
    }
84

85
    function toString(idx: number, elem: StringElement | string): string {
86
        const s = typeof elem === 'string' ? elem : idxToString(elem.slice(1) as number[]);
17,880!
87
        cache.set(idx, s);
17,880✔
88
        return s;
17,880✔
89
    }
90

91
    function toObj(idx: number, elem: ObjectElement): PrimitiveObject {
92
        const [_, k, v] = elem;
13,697✔
93

94
        // Object Wrapper
95
        if (!k && v) {
13,697✔
96
            const obj = Object(idxToValue(v));
62✔
97
            cache.set(idx, obj);
62✔
98
            return obj as PrimitiveObject;
62✔
99
        }
100

101
        const obj = {};
13,635✔
102
        cache.set(idx, obj);
13,635✔
103

104
        if (!k || !v) return obj;
13,635✔
105
        const keys = idxToArr(k) as string[];
13,599✔
106
        const values = idxToArr(v);
13,599✔
107
        Object.assign(obj, Object.fromEntries(mergeKeysValues(keys, values)));
13,599✔
108
        return obj;
13,599✔
109
    }
110

111
    function idxToArr(idx: number): PrimitiveArray {
112
        const element = data[idx];
27,487✔
113
        assert(isArrayElement(element));
27,487✔
114
        return toArr(idx, element);
27,487✔
115
    }
116

117
    function toArr(idx: number, element: ArrayElement): PrimitiveArray {
118
        const placeHolder: Serializable[] = [];
45,782✔
119
        const refs = element.slice(1);
45,782✔
120
        cache.set(idx, placeHolder);
45,782✔
121
        const arr = refs.map(idxToValue);
45,782✔
122
        // check if the array has been referenced by another object.
123
        if (!referenced.has(idx)) {
45,782✔
124
            // It has not, just replace the placeholder with the array.
125
            cache.set(idx, arr);
45,693✔
126
            return arr;
45,693✔
127
        }
128
        placeHolder.push(...arr);
89✔
129
        return placeHolder;
89✔
130
    }
131

132
    function handleSubStringElement(idx: number, refs: SubStringElement): string {
133
        const [_t, sIdx, len, offset = 0] = refs;
9,735✔
134
        const s = `${idxToValue(sIdx)}`.slice(offset, offset + len);
9,735✔
135
        cache.set(idx, s);
9,735✔
136
        return s;
9,735✔
137
    }
138

139
    function handleArrayElement(
140
        idx: number,
141
        element: ArrayBasedElements,
142
    ): PrimitiveArray | Primitive | PrimitiveObject | PrimitiveSet | PrimitiveMap {
143
        switch (element[0]) {
60,324✔
144
            case ElementType.Array: {
145
                break;
18,295✔
146
            }
147
            case ElementType.Object: {
148
                return toObj(idx, element as ObjectElement);
13,697✔
149
            }
150
            case ElementType.String: {
151
                return toString(idx, element as StringElement);
17,880✔
152
            }
153
            case ElementType.SubString: {
154
                return handleSubStringElement(idx, element as SubStringElement);
9,735✔
155
            }
156
            case ElementType.Set: {
157
                return toSet(idx, element as SetElement);
131✔
158
            }
159
            case ElementType.Map: {
160
                return toMap(idx, element as MapElement);
79✔
161
            }
162
            case ElementType.RegExp: {
163
                return toRegExp(idx, element as RegExpElement);
166✔
164
            }
165
            case ElementType.Date: {
166
                return toDate(idx, element as DateElement);
64✔
167
            }
168
            case ElementType.BigInt: {
169
                return toBigInt(idx, element as BigIntElement);
182✔
170
            }
171
            case ElementType.StringTable: {
172
                stringTable = new StringTable(element as StringTableElement);
95✔
173
                return idxToValue(idx + 1);
95✔
174
            }
175
        }
176
        return toArr(idx, element as ArrayElement);
18,295✔
177
    }
178

179
    function idxToString(idx: number | number[]): string {
180
        if (!idx) return '';
17,880!
181
        if (Array.isArray(idx)) {
17,880!
182
            return joinToString(idx.map((i) => idxToValue(i)));
36,272✔
183
        }
NEW
184
        return idxToValue(idx) as string;
×
185
    }
186

187
    function idxToValue(idx: number): Serializable {
188
        if (!idx) return undefined;
360,111✔
189
        if (idx < 0) {
356,457✔
190
            return stringTable ? stringTable.get(-idx) : undefined;
152,983!
191
        }
192
        const found = cache.get(idx);
203,474✔
193
        if (found !== undefined) {
203,474✔
194
            if (typeof idx === 'number') referenced.add(idx);
46,604!
195
            return found as Serializable;
46,604✔
196
        }
197

198
        const element = data[idx];
156,870✔
199

200
        if (typeof element === 'object') {
156,870✔
201
            // eslint-disable-next-line unicorn/no-null
202
            if (element === null) return null;
60,444✔
203
            if (Array.isArray(element)) return handleArrayElement(idx, element as ArrayBasedElements);
60,407✔
204
            return {};
83✔
205
        }
206
        return element;
96,426✔
207
    }
208

209
    return idxToValue(1);
1,025✔
210
}
211

212
function joinToString(parts: PrimitiveArray): string {
213
    return parts.map((a) => (Array.isArray(a) ? joinToString(a) : a)).join('');
36,272!
214
}
215

216
function isArrayElement(value: FlattenedElement): value is ArrayElement {
217
    return Array.isArray(value) && value[0] === ElementType.Array;
27,487✔
218
}
219

220
export function parse(data: string): Unpacked {
221
    return fromJSON(JSON.parse(data));
5✔
222
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc