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

streetsidesoftware / cspell / 22751848386

06 Mar 2026 06:22AM UTC coverage: 92.854% (-0.05%) from 92.904%
22751848386

Pull #8680

github

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

9661 of 11520 branches covered (83.86%)

1316 of 1398 new or added lines in 13 files covered. (94.13%)

6 existing lines in 1 file now uncovered.

19192 of 20669 relevant lines covered (92.85%)

30068.3 hits per line

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

45.21
/packages/flatpack-json/src/stringTable.mts
1
import { Trie } from './Trie.mjs';
2
import { ElementType, type StringTableElement, type StringTableEntry } from './types.mjs';
3

4
export class StringTable {
5
    constructor(readonly stringTableElement: StringTableElement) {}
95✔
6

7
    get(index: number): string {
8
        if (!index) return '';
152,983!
9
        index = index < 0 ? -index : index;
152,983!
10
        return this.#getCompoundString(index);
152,983✔
11
    }
12

13
    #getCompoundString(index: number, visited = new Set<number>()): string {
152,983✔
14
        if (visited.has(index)) {
152,983!
NEW
15
            throw new Error(`Circular reference in string table at index ${index}`);
×
16
        }
17
        visited.add(index);
152,983✔
18
        const entry = this.stringTableElement[index];
152,983✔
19
        if (typeof entry === 'string') {
152,983!
20
            return entry;
152,983✔
21
        }
NEW
22
        if (Array.isArray(entry)) {
×
NEW
23
            return entry.map((i) => this.#getCompoundString(i, visited)).join('');
×
24
        }
NEW
25
        throw new Error(`Invalid string table entry at index ${index}`);
×
26
    }
27
}
28

29
interface TrieData {
30
    idx: number;
31
    value: string;
32
}
33

34
interface BuilderEntry {
35
    value: string;
36
    entry: StringTableEntry;
37
}
38

39
const useSplits = false;
6✔
40

41
export class StringTableBuilder {
42
    private stringToIndex = new Map<string, number>();
64✔
43
    private entries: BuilderEntry[] = [{ value: '', entry: '' }];
64✔
44
    private knownStrings = new Trie<TrieData>();
64✔
45

46
    add(str: string): number {
47
        const found = this.stringToIndex.get(str);
33,016✔
48
        if (found !== undefined) {
33,016!
NEW
49
            return found;
×
50
        }
51
        if (!str) {
33,016✔
52
            return this.#append('');
2✔
53
        }
54
        const foundInTrie = this.knownStrings.find(str);
33,014✔
55
        if (!foundInTrie) {
33,014!
NEW
56
            const idx = this.#append(str);
×
NEW
57
            return idx;
×
58
        }
59
        const idx = this.#append(str);
33,014✔
60
        this.#splitStrings(foundInTrie.found);
33,014✔
61
        return idx;
33,014✔
62
    }
63

64
    get(str: string): number | undefined {
NEW
65
        return this.stringToIndex.get(str);
×
66
    }
67

68
    #append(str: string): number {
69
        const found = this.stringToIndex.get(str);
33,016✔
70
        if (found !== undefined) {
33,016!
NEW
71
            return found;
×
72
        }
73
        const entry: BuilderEntry = { value: str, entry: str };
33,016✔
74
        const idx = this.entries.push(entry) - 1;
33,016✔
75
        this.stringToIndex.set(str, idx);
33,016✔
76
        this.knownStrings.add(str, { idx, value: str });
33,016✔
77
        return idx;
33,016✔
78
    }
79

80
    #splitStrings(prefix: string): void {
81
        if (!prefix) return;
33,014✔
82
        console.log(`Splitting strings with prefix: ${prefix}`);
32,742✔
83
        if (!useSplits) return;
32,742!
NEW
84
        const indexes = stringIndexesToSplit(this.knownStrings, prefix);
×
NEW
85
        for (const idx of indexes) {
×
NEW
86
            const entry = this.entries[idx];
×
NEW
87
            if (entry.value === prefix) {
×
NEW
88
                continue;
×
89
            }
NEW
90
            this.#splitEntry(this.entries[idx], prefix);
×
91
        }
92
    }
93

94
    #splitEntry(entry: BuilderEntry, prefix: string): void {
NEW
95
        let prefixIdx = this.stringToIndex.get(prefix) ?? this.entries.length;
×
NEW
96
        const suffix = entry.value.slice(prefix.length);
×
97

NEW
98
        const currentCost = entryCost(entry.entry);
×
NEW
99
        const suffixCost = this.stringToIndex.get(suffix) ? 0 : entryCost(suffix);
×
NEW
100
        const prefixCost = this.stringToIndex.get(prefix) ? 0 : entryCost(prefix);
×
101

NEW
102
        if (typeof entry.entry === 'string') {
×
NEW
103
            const cost = entryCost([prefixIdx, this.entries.length]) + suffixCost + prefixCost;
×
NEW
104
            if (cost > currentCost) return;
×
NEW
105
            prefixIdx = this.#append(prefix);
×
NEW
106
            const suffixIdx = this.add(suffix);
×
NEW
107
            entry.entry = [prefixIdx, suffixIdx];
×
NEW
108
            return;
×
109
        }
110

NEW
111
        const cost = entryCost([prefixIdx, ...entry.entry]) + suffixCost;
×
NEW
112
        if (cost > currentCost) return;
×
113
        // @todo: split concatenated entries.
114
    }
115

116
    build(): StringTableElement {
117
        return [ElementType.StringTable, ...this.entries.slice(1).map((e) => e.entry)];
33,016✔
118
    }
119
}
120

121
function entryCost(entry: StringTableEntry): number {
NEW
122
    if (typeof entry === 'string') {
×
NEW
123
        return entry.length + 2;
×
124
    }
NEW
125
    let cost = 1 + entry.length; // array overhead + index size
×
NEW
126
    for (const idx of entry) {
×
NEW
127
        cost += Math.log10(idx); // index size
×
128
    }
NEW
129
    return cost;
×
130
}
131

132
function stringIndexesToSplit(trie: Trie<TrieData>, prefix: string): number[] {
NEW
133
    const result: number[] = [];
×
NEW
134
    for (const { node, found } of trie.walk(prefix)) {
×
NEW
135
        if (node.d?.value !== found) continue;
×
NEW
136
        result.push(node.d.idx);
×
137
    }
NEW
138
    return result;
×
139
}
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