cspell-lib 10.2.0-alpha.7 → 10.2.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/lib/Settings/LanguageSettings.js +17 -1
- package/dist/lib/Settings/sanitizeSettings.js +3 -0
- package/dist/lib/Transform/IntlSegmentTextTransformer.d.ts +11 -0
- package/dist/lib/Transform/IntlSegmentTextTransformer.js +41 -0
- package/dist/lib/Transform/SubstitutionTransformer.d.ts +3 -1
- package/dist/lib/Transform/SubstitutionTransformer.js +10 -28
- package/dist/lib/Transform/TextMapEdit.d.ts +5 -0
- package/dist/lib/Transform/TextMapEdit.js +42 -0
- package/dist/lib/Transform/Transformer.d.ts +25 -0
- package/dist/lib/Transform/Transformer.js +27 -0
- package/dist/lib/Transform/index.d.ts +3 -0
- package/dist/lib/Transform/index.js +2 -0
- package/dist/lib/textValidation/docValidator.d.ts +3 -2
- package/dist/lib/textValidation/docValidator.js +22 -20
- package/dist/lib/textValidation/isRandomString.js +4 -3
- package/dist/lib/textValidation/lineValidatorFactory.d.ts +2 -2
- package/dist/lib/textValidation/lineValidatorFactory.js +7 -2
- package/dist/lib/textValidation/textValidator.d.ts +2 -2
- package/dist/lib/textValidation/traceWord.js +1 -1
- package/dist/lib/util/textRegex.js +1 -1
- package/dist/lib/util/wordSplitter/generateWordBreaks.d.ts +32 -0
- package/dist/lib/util/wordSplitter/generateWordBreaks.js +120 -0
- package/dist/lib/util/wordSplitter/index.d.ts +4 -0
- package/dist/lib/util/wordSplitter/index.js +3 -0
- package/dist/lib/util/{wordSplitter.d.ts → wordSplitter/wordSplitter.d.ts} +13 -22
- package/dist/lib/util/wordSplitter/wordSplitter.js +338 -0
- package/dist/lib/util/{wordSplitter.perf.js → wordSplitter/wordSplitter.perf.js} +2 -2
- package/package.json +20 -19
- package/dist/lib/util/wordSplitter.js +0 -331
- /package/dist/lib/util/{wordSplitter.perf.d.ts → wordSplitter/wordSplitter.perf.d.ts} +0 -0
|
@@ -1,331 +0,0 @@
|
|
|
1
|
-
import { PairingHeap } from './PairingHeap.js';
|
|
2
|
-
import { escapeRegEx } from './regexHelper.js';
|
|
3
|
-
import { regExDanglingQuote, regExEscapeCharacters, regExNumericLiteral, regExPossibleWordBreaks, regExSplitWords, regExSplitWords2, regExTrailingEndings, regExWordsAndDigits, } from './textRegex.js';
|
|
4
|
-
const ignoreBreak = Object.freeze([]);
|
|
5
|
-
export function split(line, offset, isValidWord, options = {}) {
|
|
6
|
-
const relWordToSplit = findNextWordText({ text: line.text, offset: offset - line.offset });
|
|
7
|
-
const lineOffset = line.offset;
|
|
8
|
-
const requested = new Map();
|
|
9
|
-
const regExpIgnoreSegment = /^[-.+\d_eE'`\\\s]+$/;
|
|
10
|
-
if (!relWordToSplit.text) {
|
|
11
|
-
const text = rebaseTextOffset(relWordToSplit);
|
|
12
|
-
return {
|
|
13
|
-
line,
|
|
14
|
-
offset,
|
|
15
|
-
text: text,
|
|
16
|
-
words: [],
|
|
17
|
-
endOffset: text.offset + text.text.length,
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
const lineSegment = {
|
|
21
|
-
line,
|
|
22
|
-
relStart: relWordToSplit.offset,
|
|
23
|
-
relEnd: relWordToSplit.offset + relWordToSplit.text.length,
|
|
24
|
-
};
|
|
25
|
-
const possibleBreaks = generateWordBreaks(lineSegment, options);
|
|
26
|
-
if (!possibleBreaks.length) {
|
|
27
|
-
const text = rebaseTextOffset(relWordToSplit);
|
|
28
|
-
return {
|
|
29
|
-
line,
|
|
30
|
-
offset,
|
|
31
|
-
text: text,
|
|
32
|
-
words: [{ ...text, isFound: isValidWord(text) }],
|
|
33
|
-
endOffset: text.offset + text.text.length,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
function rebaseTextOffset(relText) {
|
|
37
|
-
return {
|
|
38
|
-
...relText,
|
|
39
|
-
offset: relText.offset + lineOffset,
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
function has(word) {
|
|
43
|
-
if (regExpIgnoreSegment.test(word.text)) {
|
|
44
|
-
return true;
|
|
45
|
-
}
|
|
46
|
-
const i = word.offset;
|
|
47
|
-
const j = word.text.length;
|
|
48
|
-
let v = i + (j << 20);
|
|
49
|
-
if (i < 1 << 20 && j < 1 << 11) {
|
|
50
|
-
const b = requested.get(v);
|
|
51
|
-
if (b !== undefined)
|
|
52
|
-
return b;
|
|
53
|
-
}
|
|
54
|
-
else {
|
|
55
|
-
v = -1;
|
|
56
|
-
}
|
|
57
|
-
const r = isValidWord(rebaseTextOffset(word));
|
|
58
|
-
if (v >= 0) {
|
|
59
|
-
requested.set(v, r);
|
|
60
|
-
}
|
|
61
|
-
return r;
|
|
62
|
-
}
|
|
63
|
-
// Add a dummy break at the end to avoid needing to check for last break.
|
|
64
|
-
possibleBreaks.push({
|
|
65
|
-
offset: lineSegment.relEnd,
|
|
66
|
-
breaks: [ignoreBreak],
|
|
67
|
-
});
|
|
68
|
-
const result = {
|
|
69
|
-
line,
|
|
70
|
-
offset,
|
|
71
|
-
text: rebaseTextOffset(relWordToSplit),
|
|
72
|
-
words: splitIntoWords(lineSegment, possibleBreaks, has).map(rebaseTextOffset),
|
|
73
|
-
endOffset: lineOffset + lineSegment.relEnd,
|
|
74
|
-
};
|
|
75
|
-
return result;
|
|
76
|
-
}
|
|
77
|
-
function findNextWordText({ text, offset }) {
|
|
78
|
-
const reg = new RegExp(regExWordsAndDigits);
|
|
79
|
-
reg.lastIndex = offset;
|
|
80
|
-
const m = reg.exec(text);
|
|
81
|
-
if (!m) {
|
|
82
|
-
return {
|
|
83
|
-
text: '',
|
|
84
|
-
offset: offset + text.length,
|
|
85
|
-
};
|
|
86
|
-
}
|
|
87
|
-
// Skip numeric literals.
|
|
88
|
-
if (regExNumericLiteral.test(m[0])) {
|
|
89
|
-
return findNextWordText({ text, offset: offset + m[0].length });
|
|
90
|
-
}
|
|
91
|
-
return {
|
|
92
|
-
text: m[0],
|
|
93
|
-
offset: m.index,
|
|
94
|
-
};
|
|
95
|
-
}
|
|
96
|
-
function generateWordBreaks(line, options) {
|
|
97
|
-
const camelBreaks = genWordBreakCamel(line);
|
|
98
|
-
const symbolBreaks = genSymbolBreaks(line);
|
|
99
|
-
const optionalBreaks = genOptionalWordBreaks(line, options.optionalWordBreakCharacters);
|
|
100
|
-
return mergeSortedBreaks(...camelBreaks, ...symbolBreaks, ...optionalBreaks);
|
|
101
|
-
}
|
|
102
|
-
function offsetRegEx(reg, offset) {
|
|
103
|
-
const r = new RegExp(reg);
|
|
104
|
-
r.lastIndex = offset;
|
|
105
|
-
return r;
|
|
106
|
-
}
|
|
107
|
-
function genWordBreakCamel(line) {
|
|
108
|
-
const breaksCamel1 = [];
|
|
109
|
-
const text = line.line.text.slice(0, line.relEnd);
|
|
110
|
-
// lower,Upper: camelCase -> camel|Case
|
|
111
|
-
for (const m of text.matchAll(offsetRegEx(regExSplitWords, line.relStart))) {
|
|
112
|
-
if (m.index === undefined)
|
|
113
|
-
break;
|
|
114
|
-
const i = m.index + m[1].length;
|
|
115
|
-
breaksCamel1.push({
|
|
116
|
-
offset: m.index,
|
|
117
|
-
breaks: [[i, i], ignoreBreak],
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
const breaksCamel2 = [];
|
|
121
|
-
// cspell:ignore ERRORC
|
|
122
|
-
// Upper,Upper,lower: ERRORCodes -> ERROR|Codes, ERRORC|odes
|
|
123
|
-
for (const m of text.matchAll(offsetRegEx(regExSplitWords2, line.relStart))) {
|
|
124
|
-
if (m.index === undefined)
|
|
125
|
-
break;
|
|
126
|
-
const i = m.index + m[1].length;
|
|
127
|
-
const j = i + m[3].length;
|
|
128
|
-
breaksCamel2.push({
|
|
129
|
-
offset: m.index,
|
|
130
|
-
breaks: [[i, i], [j, j], ignoreBreak],
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
return [breaksCamel1, breaksCamel2];
|
|
134
|
-
}
|
|
135
|
-
function calcBreaksForRegEx(line, reg, calcBreak) {
|
|
136
|
-
const sb = [];
|
|
137
|
-
const text = line.line.text.slice(0, line.relEnd);
|
|
138
|
-
for (const m of text.matchAll(offsetRegEx(reg, line.relStart))) {
|
|
139
|
-
const b = calcBreak(m);
|
|
140
|
-
if (b) {
|
|
141
|
-
sb.push(b);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
return sb;
|
|
145
|
-
}
|
|
146
|
-
function genOptionalWordBreaks(line, optionalBreakCharacters) {
|
|
147
|
-
function calcBreaks(m) {
|
|
148
|
-
const i = m.index;
|
|
149
|
-
if (i === undefined)
|
|
150
|
-
return;
|
|
151
|
-
const j = i + m[0].length;
|
|
152
|
-
return {
|
|
153
|
-
offset: i,
|
|
154
|
-
breaks: [
|
|
155
|
-
[i, j], // Remove the characters
|
|
156
|
-
ignoreBreak,
|
|
157
|
-
],
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
const breaks = [
|
|
161
|
-
calcBreaksForRegEx(line, regExDanglingQuote, calcBreaks),
|
|
162
|
-
calcBreaksForRegEx(line, regExTrailingEndings, calcBreaks),
|
|
163
|
-
];
|
|
164
|
-
if (optionalBreakCharacters) {
|
|
165
|
-
const regex = new RegExp(`[${escapeRegEx(optionalBreakCharacters)}]`, 'gu');
|
|
166
|
-
breaks.push(calcBreaksForRegEx(line, regex, calcBreaks));
|
|
167
|
-
}
|
|
168
|
-
return breaks;
|
|
169
|
-
}
|
|
170
|
-
function genSymbolBreaks(line) {
|
|
171
|
-
function calcBreaks(m) {
|
|
172
|
-
const i = m.index;
|
|
173
|
-
if (i === undefined)
|
|
174
|
-
return;
|
|
175
|
-
const j = i + m[0].length;
|
|
176
|
-
return {
|
|
177
|
-
offset: i,
|
|
178
|
-
breaks: [
|
|
179
|
-
[i, j], // Remove the characters
|
|
180
|
-
[i, i], // keep characters with word to right
|
|
181
|
-
[j, j], // keep characters with word to left
|
|
182
|
-
ignoreBreak,
|
|
183
|
-
],
|
|
184
|
-
};
|
|
185
|
-
}
|
|
186
|
-
return [
|
|
187
|
-
calcBreaksForRegEx(line, regExPossibleWordBreaks, calcBreaks),
|
|
188
|
-
calcBreaksForRegEx(line, /\d+/g, calcBreaks),
|
|
189
|
-
calcBreaksForRegEx(line, regExEscapeCharacters, calcBreaks),
|
|
190
|
-
];
|
|
191
|
-
}
|
|
192
|
-
function splitIntoWords(lineSeg, breaks, has) {
|
|
193
|
-
const maxIndex = lineSeg.relEnd;
|
|
194
|
-
const maxAttempts = 1000;
|
|
195
|
-
const knownPathsByIndex = new Map();
|
|
196
|
-
/**
|
|
197
|
-
* Create a set of possible candidate to consider
|
|
198
|
-
* @param p - prev candidate that lead to this one
|
|
199
|
-
* @param i - offset within the string
|
|
200
|
-
* @param bi - current index into the set of breaks
|
|
201
|
-
* @param currentCost - current cost accrued
|
|
202
|
-
*/
|
|
203
|
-
function makeCandidates(p, i, bi, currentCost) {
|
|
204
|
-
const len = maxIndex;
|
|
205
|
-
while (bi < breaks.length && breaks[bi].offset < i) {
|
|
206
|
-
bi += 1;
|
|
207
|
-
}
|
|
208
|
-
if (bi >= breaks.length) {
|
|
209
|
-
return [];
|
|
210
|
-
}
|
|
211
|
-
const br = breaks[bi];
|
|
212
|
-
function c(bp) {
|
|
213
|
-
const d = bp.length < 2 ? len - i : (bp[0] - i) * 0.5 + len - bp[1];
|
|
214
|
-
const ec = currentCost + d;
|
|
215
|
-
return {
|
|
216
|
-
p,
|
|
217
|
-
i,
|
|
218
|
-
bi,
|
|
219
|
-
bp,
|
|
220
|
-
c: currentCost,
|
|
221
|
-
ec,
|
|
222
|
-
text: undefined,
|
|
223
|
-
};
|
|
224
|
-
}
|
|
225
|
-
return br.breaks.map(c);
|
|
226
|
-
}
|
|
227
|
-
function checkTextOffset(text, offset) {
|
|
228
|
-
const valid = has({ text, offset });
|
|
229
|
-
return {
|
|
230
|
-
text,
|
|
231
|
-
offset,
|
|
232
|
-
isFound: valid,
|
|
233
|
-
};
|
|
234
|
-
}
|
|
235
|
-
function compare(a, b) {
|
|
236
|
-
return a.ec - b.ec || b.i - a.i;
|
|
237
|
-
}
|
|
238
|
-
function pathToWords(node) {
|
|
239
|
-
const results = [];
|
|
240
|
-
for (let p = node; p; p = p.n) {
|
|
241
|
-
if (p.text) {
|
|
242
|
-
results.push(p.text);
|
|
243
|
-
}
|
|
244
|
-
}
|
|
245
|
-
return results;
|
|
246
|
-
}
|
|
247
|
-
function addToKnownPaths(candidate, path) {
|
|
248
|
-
for (let can = candidate; can !== undefined; can = can.p) {
|
|
249
|
-
const t = can.text;
|
|
250
|
-
const i = can.i;
|
|
251
|
-
const cost = (!t || t.isFound ? 0 : t.text.length) + (path?.c ?? 0);
|
|
252
|
-
const exitingPath = knownPathsByIndex.get(i);
|
|
253
|
-
// Keep going only if this is a better candidate than the existing path
|
|
254
|
-
if (exitingPath && exitingPath.c <= cost) {
|
|
255
|
-
return undefined;
|
|
256
|
-
}
|
|
257
|
-
const node = {
|
|
258
|
-
n: path,
|
|
259
|
-
i,
|
|
260
|
-
c: cost,
|
|
261
|
-
text: t,
|
|
262
|
-
};
|
|
263
|
-
knownPathsByIndex.set(i, node);
|
|
264
|
-
path = node;
|
|
265
|
-
}
|
|
266
|
-
return path;
|
|
267
|
-
}
|
|
268
|
-
let maxCost = lineSeg.relEnd - lineSeg.relStart;
|
|
269
|
-
const candidates = new PairingHeap(compare);
|
|
270
|
-
const text = lineSeg.line.text;
|
|
271
|
-
candidates.append(makeCandidates(undefined, lineSeg.relStart, 0, 0));
|
|
272
|
-
let attempts = 0;
|
|
273
|
-
let bestPath;
|
|
274
|
-
while (maxCost && candidates.length && attempts++ < maxAttempts) {
|
|
275
|
-
/** Best Candidate Index */
|
|
276
|
-
const best = candidates.dequeue();
|
|
277
|
-
if (!best || best.c >= maxCost) {
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
// Does it have a split?
|
|
281
|
-
if (best.bp.length) {
|
|
282
|
-
// yes
|
|
283
|
-
const i = best.bp[0];
|
|
284
|
-
const j = best.bp[1];
|
|
285
|
-
const t = i > best.i ? checkTextOffset(text.slice(best.i, i), best.i) : undefined;
|
|
286
|
-
const cost = !t || t.isFound ? 0 : t.text.length;
|
|
287
|
-
const mc = maxIndex - j;
|
|
288
|
-
best.c += cost;
|
|
289
|
-
best.ec = best.c + mc;
|
|
290
|
-
best.text = t;
|
|
291
|
-
const possiblePath = knownPathsByIndex.get(j);
|
|
292
|
-
if (possiblePath) {
|
|
293
|
-
// We found a known apply to candidate
|
|
294
|
-
const f = addToKnownPaths(best, possiblePath);
|
|
295
|
-
bestPath = !bestPath || (f && f.c < bestPath.c) ? f : bestPath;
|
|
296
|
-
}
|
|
297
|
-
else if (best.c < maxCost) {
|
|
298
|
-
const c = makeCandidates(t ? best : best.p, j, best.bi + 1, best.c);
|
|
299
|
-
candidates.append(c);
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
else {
|
|
303
|
-
// It is a pass through
|
|
304
|
-
const c = makeCandidates(best.p, best.i, best.bi + 1, best.c);
|
|
305
|
-
candidates.append(c);
|
|
306
|
-
if (!c.length) {
|
|
307
|
-
const t = maxIndex > best.i ? checkTextOffset(text.slice(best.i, maxIndex), best.i) : undefined;
|
|
308
|
-
const cost = !t || t.isFound ? 0 : t.text.length;
|
|
309
|
-
best.c += cost;
|
|
310
|
-
best.ec = best.c;
|
|
311
|
-
best.text = t;
|
|
312
|
-
const segText = t || best.p?.text || checkTextOffset('', best.i);
|
|
313
|
-
const can = t ? { ...best, text: segText } : { ...best, ...best.p, text: segText };
|
|
314
|
-
const f = addToKnownPaths(can, undefined);
|
|
315
|
-
bestPath = !bestPath || (f && f.c < bestPath.c) ? f : bestPath;
|
|
316
|
-
}
|
|
317
|
-
}
|
|
318
|
-
if (bestPath && bestPath.c < maxCost) {
|
|
319
|
-
maxCost = bestPath.c;
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
return pathToWords(bestPath);
|
|
323
|
-
}
|
|
324
|
-
function mergeSortedBreaks(...maps) {
|
|
325
|
-
return maps.flat().sort((a, b) => a.offset - b.offset);
|
|
326
|
-
}
|
|
327
|
-
export const __testing__ = {
|
|
328
|
-
generateWordBreaks,
|
|
329
|
-
findNextWordText,
|
|
330
|
-
};
|
|
331
|
-
//# sourceMappingURL=wordSplitter.js.map
|
|
File without changes
|