cspell-lib 10.2.2 → 10.3.0

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.
@@ -107,7 +107,7 @@ class _DictionaryDefinitionInternalWithSource {
107
107
  this.__source = sourceURL.href;
108
108
  // this bit of assignment is to have the compiler help use if any new fields are added.
109
109
  const defAll = def;
110
- const { path: relPath = '', file = '', btrie, addWords, description, dictionaryInformation, type, repMap, noSuggest, ignoreForbiddenWords, scope, supportNonStrictSearches, useCompounds, } = defAll;
110
+ const { path: relPath = '', file = '', btrie, addWords, description, dictionaryInformation, type, repMap, noSuggest, kind, ignoreForbiddenWords, scope, supportNonStrictSearches, useCompounds, } = defAll;
111
111
  const defaultPath = sourceURL;
112
112
  const filePath = fixDicPath(relPath, file);
113
113
  const name = determineName(filePath, def);
@@ -125,6 +125,7 @@ class _DictionaryDefinitionInternalWithSource {
125
125
  type,
126
126
  repMap,
127
127
  noSuggest,
128
+ kind,
128
129
  ignoreForbiddenWords,
129
130
  supportNonStrictSearches,
130
131
  scope,
@@ -52,7 +52,7 @@ var __disposeResources = (this && this.__disposeResources) || (function (Suppres
52
52
  });
53
53
  import { opConcatMap, opFilter, opMap, pipe } from '@cspell/cspell-pipe/sync';
54
54
  import { StrongWeakMap } from '@cspell/strong-weak-map';
55
- import { createFailedToLoadDictionary, createInlineSpellingDictionary, createSpellingDictionary, createSpellingDictionaryFromTrieFile, } from 'cspell-dictionary';
55
+ import { createFailedToLoadDictionary, createFlagWordsDictionary, createFlagWordsDictionaryFromTrieFile, createInlineSpellingDictionary, createSpellingDictionary, createSpellingDictionaryFromTrieFile, createSuggestDictionary, createSuggestDictionaryFromTrieFile, } from 'cspell-dictionary';
56
56
  import { compareStats, toFileURL, urlBasename } from 'cspell-io';
57
57
  import { measurePerf } from '../../perf/index.js';
58
58
  import { isDictionaryDefinitionInlineInternal, isDictionaryFileDefinitionInternal } from '../../Settings/index.js';
@@ -221,7 +221,13 @@ function toReader(fs) {
221
221
  readLines: async (filename) => toLines(await readText(filename)),
222
222
  };
223
223
  }
224
- const importantOptionKeys = ['name', 'noSuggest', 'useCompounds', 'type'];
224
+ const importantOptionKeys = [
225
+ 'name',
226
+ 'noSuggest',
227
+ 'kind',
228
+ 'useCompounds',
229
+ 'type',
230
+ ];
225
231
  function isError(e) {
226
232
  const err = e;
227
233
  return !!err.message;
@@ -248,7 +254,13 @@ async function legacyWordList(reader, filename, options) {
248
254
  opMap((line) => line.replaceAll(/#.*/g, '')),
249
255
  // Split on everything else
250
256
  opConcatMap((line) => line.split(/[^\w\p{L}\p{M}'’]+/gu)), opFilter((word) => !!word));
251
- return createSpellingDictionary(words, options.name, filename.toString(), options, true);
257
+ if (options.kind === 'flag-words') {
258
+ return createFlagWordsDictionary([...words], options.name, filename.toString());
259
+ }
260
+ if (options.kind === 'suggest-words') {
261
+ return createSuggestDictionary([...words], options.name, filename.toString());
262
+ }
263
+ return createSpellingDictionary(words, options.name, filename.toString(), applyKind(options), true);
252
264
  }
253
265
  catch (e_1) {
254
266
  env_1.error = e_1;
@@ -265,14 +277,26 @@ async function wordsPerLineWordList(reader, filename, options) {
265
277
  opMap((line) => line.replaceAll(/#.*/g, '')),
266
278
  // Split on everything else
267
279
  opConcatMap((line) => line.split(/\s+/gu)), opFilter((word) => !!word));
268
- return createSpellingDictionary(words, options.name, filename.href, options, true);
280
+ if (options.kind === 'flag-words') {
281
+ return createFlagWordsDictionary([...words], options.name, filename.href);
282
+ }
283
+ if (options.kind === 'suggest-words') {
284
+ return createSuggestDictionary([...words], options.name, filename.href);
285
+ }
286
+ return createSpellingDictionary(words, options.name, filename.href, applyKind(options), true);
269
287
  }
270
288
  async function loadSimpleWordList(reader, filename, options) {
271
289
  const env_2 = { stack: [], error: void 0, hasError: false };
272
290
  try {
273
291
  const lines = await reader.readLines(filename);
274
292
  const _ = __addDisposableResource(env_2, measurePerf('loadSimpleWordList'), false);
275
- return createSpellingDictionary(lines, options.name, filename.href, options);
293
+ if (options.kind === 'flag-words') {
294
+ return createFlagWordsDictionary(lines, options.name, filename.href);
295
+ }
296
+ if (options.kind === 'suggest-words') {
297
+ return createSuggestDictionary(lines, options.name, filename.href);
298
+ }
299
+ return createSpellingDictionary(lines, options.name, filename.href, applyKind(options));
276
300
  }
277
301
  catch (e_2) {
278
302
  env_2.error = e_2;
@@ -287,7 +311,13 @@ async function loadTrie(reader, filename, options) {
287
311
  try {
288
312
  const content = await reader.read(filename);
289
313
  const _ = __addDisposableResource(env_3, measurePerf('loadTrie'), false);
290
- return createSpellingDictionaryFromTrieFile(content, options.name, filename.href, options);
314
+ if (options.kind === 'flag-words') {
315
+ return createFlagWordsDictionaryFromTrieFile(content, options.name, filename.href);
316
+ }
317
+ if (options.kind === 'suggest-words') {
318
+ return createSuggestDictionaryFromTrieFile(content, options.name, filename.href);
319
+ }
320
+ return createSpellingDictionaryFromTrieFile(content, options.name, filename.href, applyKind(options));
291
321
  }
292
322
  catch (e_3) {
293
323
  env_3.error = e_3;
@@ -297,6 +327,14 @@ async function loadTrie(reader, filename, options) {
297
327
  __disposeResources(env_3);
298
328
  }
299
329
  }
330
+ /**
331
+ * Apply the effect of `kind` on the options passed to a normal `words` dictionary loader.
332
+ * `flag-words` and `suggest-words` are handled by the callers directly since they use a different
333
+ * dictionary implementation.
334
+ */
335
+ function applyKind(options) {
336
+ return options.kind === 'ignore-words' && !options.noSuggest ? { ...options, noSuggest: true } : options;
337
+ }
300
338
  function toLines(content) {
301
339
  return content.split(/\n|\r\n|\r/);
302
340
  }
@@ -329,10 +329,16 @@ export function lineValidatorFactory(sDict, options) {
329
329
  });
330
330
  // Ignore 1 or 2 letter segments.
331
331
  const minWordLen = Math.min(3, minWordLength);
332
+ const keepIssue = (w) => w.isFlagged ||
333
+ w.text.length >= minWordLen ||
334
+ // eslint-disable-next-line unicorn/prefer-code-point
335
+ (w.text.charCodeAt(0) & 0xff80) !== 0 || // Keep if Non-ASCII
336
+ // eslint-disable-next-line unicorn/prefer-code-point
337
+ (w.text.charCodeAt(1) & 0xff80) !== 0; // Keep if Non-ASCII
332
338
  const filtered = filterExcludedTextOffsets(nonMatching
333
339
  .map((w) => ({ ...w, line: lineSegment.line }))
334
340
  .map(annotateIsFlagged)
335
- .filter((w) => w.isFlagged || w.text.length >= minWordLen), hexSequences);
341
+ .filter(keepIssue), hexSequences);
336
342
  if (filtered.length < mismatches.length) {
337
343
  return filtered;
338
344
  }
@@ -1,3 +1,56 @@
1
+ var __addDisposableResource = (this && this.__addDisposableResource) || function (env, value, async) {
2
+ if (value !== null && value !== void 0) {
3
+ if (typeof value !== "object" && typeof value !== "function") throw new TypeError("Object expected.");
4
+ var dispose, inner;
5
+ if (async) {
6
+ if (!Symbol.asyncDispose) throw new TypeError("Symbol.asyncDispose is not defined.");
7
+ dispose = value[Symbol.asyncDispose];
8
+ }
9
+ if (dispose === void 0) {
10
+ if (!Symbol.dispose) throw new TypeError("Symbol.dispose is not defined.");
11
+ dispose = value[Symbol.dispose];
12
+ if (async) inner = dispose;
13
+ }
14
+ if (typeof dispose !== "function") throw new TypeError("Object not disposable.");
15
+ if (inner) dispose = function() { try { inner.call(this); } catch (e) { return Promise.reject(e); } };
16
+ env.stack.push({ value: value, dispose: dispose, async: async });
17
+ }
18
+ else if (async) {
19
+ env.stack.push({ async: true });
20
+ }
21
+ return value;
22
+ };
23
+ var __disposeResources = (this && this.__disposeResources) || (function (SuppressedError) {
24
+ return function (env) {
25
+ function fail(e) {
26
+ env.error = env.hasError ? new SuppressedError(e, env.error, "An error was suppressed during disposal.") : e;
27
+ env.hasError = true;
28
+ }
29
+ var r, s = 0;
30
+ function next() {
31
+ while (r = env.stack.pop()) {
32
+ try {
33
+ if (!r.async && s === 1) return s = 0, env.stack.push(r), Promise.resolve().then(next);
34
+ if (r.dispose) {
35
+ var result = r.dispose.call(r.value);
36
+ if (r.async) return s |= 2, Promise.resolve(result).then(next, function(e) { fail(e); return next(); });
37
+ }
38
+ else s |= 1;
39
+ }
40
+ catch (e) {
41
+ fail(e);
42
+ }
43
+ }
44
+ if (s === 1) return env.hasError ? Promise.reject(env.error) : Promise.resolve();
45
+ if (env.hasError) throw env.error;
46
+ }
47
+ return next();
48
+ };
49
+ })(typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
50
+ var e = new Error(message);
51
+ return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
52
+ });
53
+ import { counter, measurePerf } from '@cspell/cspell-performance-monitor';
1
54
  import { PairingHeap } from '../PairingHeap.js';
2
55
  import { regExFirstUpper, regExNumericLiteral, regExWordsAndDigits } from '../textRegex.js';
3
56
  import { generateWordBreaks, softHyphen } from './generateWordBreaks.js';
@@ -17,98 +70,110 @@ const regExTrailingTrimCharacters = /['’`\\-]+$/;
17
70
  * @returns SplitResult
18
71
  */
19
72
  export function split(line, offset, isValidWord, options = {}) {
20
- const relWordToSplit = findNextWordText({ text: line.text, offset: offset - line.offset });
21
- const hasSoftHyphen = relWordToSplit.text.includes(softHyphen);
22
- const lineOffset = line.offset;
23
- const requested = new Map();
24
- const regExpIgnoreSegment = /^[-.+\d_eE'`\\\s\u00AD]+$/;
25
- if (!relWordToSplit.text) {
26
- const text = rebaseTextOffsetToAbsolute(relWordToSplit);
27
- return {
28
- line,
29
- offset,
30
- text: text,
31
- words: [],
32
- endOffset: text.offset + (text.length ?? text.text.length),
33
- };
34
- }
35
- const lineSegment = {
36
- line,
37
- relStart: relWordToSplit.offset,
38
- relEnd: relWordToSplit.offset + relWordToSplit.text.length,
39
- };
40
- const possibleBreaks = generateWordBreaks(lineSegment, options);
41
- if (!possibleBreaks.length) {
42
- const text = rebaseTextOffsetToAbsolute(relWordToSplit);
43
- return {
73
+ const env_1 = { stack: [], error: void 0, hasError: false };
74
+ try {
75
+ const _x = __addDisposableResource(env_1, measurePerf('wordSplitter.split'), false);
76
+ counter('wordSplitter.split').inc();
77
+ const relWordToSplit = findNextWordText({ text: line.text, offset: offset - line.offset });
78
+ const hasSoftHyphen = relWordToSplit.text.includes(softHyphen);
79
+ const lineOffset = line.offset;
80
+ const requested = new Map();
81
+ const regExpIgnoreSegment = /^[-.+\d_eE'`\\\s\u00AD]+$/;
82
+ if (!relWordToSplit.text) {
83
+ const text = rebaseTextOffsetToAbsolute(relWordToSplit);
84
+ return {
85
+ line,
86
+ offset,
87
+ text: text,
88
+ words: [],
89
+ endOffset: text.offset + (text.length ?? text.text.length),
90
+ };
91
+ }
92
+ const lineSegment = {
44
93
  line,
45
- offset,
46
- text: text,
47
- words: [{ ...text, length: text.length || text.text.length, isFound: isValidWord(text) }],
48
- endOffset: text.offset + (text.length ?? text.text.length),
49
- };
50
- }
51
- function rebaseTextOffsetToAbsolute(relText) {
52
- relText.offset += lineOffset;
53
- return relText;
54
- }
55
- function rebaseTextOffsetToRelative(relText) {
56
- relText.offset -= lineOffset;
57
- return relText;
58
- }
59
- function createTextOffsetWithValid(start, end, isFound) {
60
- const word = {
61
- offset: start,
62
- length: end - start,
63
- text: line.text.slice(start, end),
64
- isFound,
94
+ relStart: relWordToSplit.offset,
95
+ relEnd: relWordToSplit.offset + relWordToSplit.text.length,
65
96
  };
66
- return word;
67
- }
68
- function calcKey(start, end) {
69
- const i = start;
70
- const j = end - start;
71
- const v = i + (j << 20);
72
- return i < 1 << 20 && j < 1 << 11 ? v : -1;
73
- }
74
- function checkTextRange(start, end) {
75
- const v = calcKey(start, end);
76
- const f = v >= 0 ? requested.get(v) : undefined;
77
- if (f)
78
- return f;
79
- const validated = createTextOffsetWithValid(start, end, false);
80
- if (regExpIgnoreSegment.test(validated.text)) {
81
- validated.isFound = true;
97
+ const possibleBreaks = generateWordBreaks(lineSegment, options);
98
+ if (!possibleBreaks.length) {
99
+ const text = rebaseTextOffsetToAbsolute(relWordToSplit);
100
+ return {
101
+ line,
102
+ offset,
103
+ text: text,
104
+ words: [{ ...text, length: text.length || text.text.length, isFound: isValidWord(text) }],
105
+ endOffset: text.offset + (text.length ?? text.text.length),
106
+ };
107
+ }
108
+ function rebaseTextOffsetToAbsolute(relText) {
109
+ relText.offset += lineOffset;
110
+ return relText;
111
+ }
112
+ function rebaseTextOffsetToRelative(relText) {
113
+ relText.offset -= lineOffset;
114
+ return relText;
115
+ }
116
+ function createTextOffsetWithValid(start, end, isFound) {
117
+ const word = {
118
+ offset: start,
119
+ length: end - start,
120
+ text: line.text.slice(start, end),
121
+ isFound,
122
+ };
123
+ return word;
124
+ }
125
+ function calcKey(start, end) {
126
+ const i = start;
127
+ const j = end - start;
128
+ const v = i + (j << 20);
129
+ return i < 1 << 20 && j < 1 << 11 ? v : -1;
130
+ }
131
+ function checkTextRange(start, end) {
132
+ const v = calcKey(start, end);
133
+ const f = v >= 0 ? requested.get(v) : undefined;
134
+ if (f)
135
+ return f;
136
+ const validated = createTextOffsetWithValid(start, end, false);
137
+ if (regExpIgnoreSegment.test(validated.text)) {
138
+ validated.isFound = true;
139
+ if (v >= 0) {
140
+ requested.set(v, validated);
141
+ }
142
+ return validated;
143
+ }
144
+ rebaseTextOffsetToAbsolute(validated);
145
+ validated.isFound = isValidWord(validated);
146
+ if (hasSoftHyphen && !validated.isFound && validated.text.includes(softHyphen)) {
147
+ removeSoftHyphen(validated);
148
+ validated.isFound = isValidWord(validated);
149
+ }
150
+ rebaseTextOffsetToRelative(validated);
82
151
  if (v >= 0) {
83
152
  requested.set(v, validated);
84
153
  }
85
154
  return validated;
86
155
  }
87
- rebaseTextOffsetToAbsolute(validated);
88
- validated.isFound = isValidWord(validated);
89
- if (hasSoftHyphen && !validated.isFound && validated.text.includes(softHyphen)) {
90
- removeSoftHyphen(validated);
91
- validated.isFound = isValidWord(validated);
92
- }
93
- rebaseTextOffsetToRelative(validated);
94
- if (v >= 0) {
95
- requested.set(v, validated);
96
- }
97
- return validated;
156
+ // Add a dummy break at the end to avoid needing to check for last break.
157
+ possibleBreaks.push({
158
+ offset: lineSegment.relEnd,
159
+ breaks: [ignoreBreak],
160
+ });
161
+ const result = {
162
+ line,
163
+ offset,
164
+ text: rebaseTextOffsetToAbsolute(relWordToSplit),
165
+ words: splitIntoWords(lineSegment, possibleBreaks, checkTextRange).map(rebaseTextOffsetToAbsolute),
166
+ endOffset: lineOffset + lineSegment.relEnd,
167
+ };
168
+ return result;
169
+ }
170
+ catch (e_1) {
171
+ env_1.error = e_1;
172
+ env_1.hasError = true;
173
+ }
174
+ finally {
175
+ __disposeResources(env_1);
98
176
  }
99
- // Add a dummy break at the end to avoid needing to check for last break.
100
- possibleBreaks.push({
101
- offset: lineSegment.relEnd,
102
- breaks: [ignoreBreak],
103
- });
104
- const result = {
105
- line,
106
- offset,
107
- text: rebaseTextOffsetToAbsolute(relWordToSplit),
108
- words: splitIntoWords(lineSegment, possibleBreaks, checkTextRange).map(rebaseTextOffsetToAbsolute),
109
- endOffset: lineOffset + lineSegment.relEnd,
110
- };
111
- return result;
112
177
  }
113
178
  function removeSoftHyphen(word) {
114
179
  word.text = word.text.replaceAll(softHyphen, '');
@@ -182,6 +247,7 @@ function splitIntoWords(lineSeg, breaks, checkTextRange) {
182
247
  * @param currentCost - current cost accrued
183
248
  */
184
249
  function makeCandidates(p, i, bi, bs, currentCost) {
250
+ counter('wordSplitter.makeCandidates').inc();
185
251
  const len = maxIndex;
186
252
  const nBi = findNearestBreakIndex(i, bi);
187
253
  const nBs = findNearestBreakIndex(i, bs);
@@ -195,6 +261,7 @@ function splitIntoWords(lineSeg, breaks, checkTextRange) {
195
261
  }
196
262
  const br = breaks[bi];
197
263
  function calcBreakCost(bp) {
264
+ counter('wordSplitter.calcBreakCost').inc();
198
265
  if (bp.length < 2) {
199
266
  // We are skipping this break pair.
200
267
  return { p, i, j: len, bi, bs, bp, c: currentCost, ec: currentCost + len - i, text: undefined };
package/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "access": "public",
5
5
  "provenance": true
6
6
  },
7
- "version": "10.2.2",
7
+ "version": "10.3.0",
8
8
  "description": "A library of useful functions used across various cspell tools.",
9
9
  "type": "module",
10
10
  "sideEffects": false,
@@ -75,22 +75,22 @@
75
75
  },
76
76
  "homepage": "https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell-lib#readme",
77
77
  "dependencies": {
78
- "@cspell/cspell-bundled-dicts": "10.2.2",
79
- "@cspell/cspell-performance-monitor": "10.2.2",
80
- "@cspell/cspell-pipe": "10.2.2",
81
- "@cspell/cspell-resolver": "10.2.2",
82
- "@cspell/cspell-types": "10.2.2",
83
- "@cspell/dynamic-import": "10.2.2",
84
- "@cspell/filetypes": "10.2.2",
85
- "@cspell/rpc": "10.2.2",
86
- "@cspell/strong-weak-map": "10.2.2",
87
- "@cspell/url": "10.2.2",
88
- "cspell-config-lib": "10.2.2",
89
- "cspell-dictionary": "10.2.2",
90
- "cspell-glob": "10.2.2",
91
- "cspell-grammar": "10.2.2",
92
- "cspell-io": "10.2.2",
93
- "cspell-trie-lib": "10.2.2",
78
+ "@cspell/cspell-bundled-dicts": "10.3.0",
79
+ "@cspell/cspell-performance-monitor": "10.3.0",
80
+ "@cspell/cspell-pipe": "10.3.0",
81
+ "@cspell/cspell-resolver": "10.3.0",
82
+ "@cspell/cspell-types": "10.3.0",
83
+ "@cspell/dynamic-import": "10.3.0",
84
+ "@cspell/filetypes": "10.3.0",
85
+ "@cspell/rpc": "10.3.0",
86
+ "@cspell/strong-weak-map": "10.3.0",
87
+ "@cspell/url": "10.3.0",
88
+ "cspell-config-lib": "10.3.0",
89
+ "cspell-dictionary": "10.3.0",
90
+ "cspell-glob": "10.3.0",
91
+ "cspell-grammar": "10.3.0",
92
+ "cspell-io": "10.3.0",
93
+ "cspell-trie-lib": "10.3.0",
94
94
  "env-paths": "^4.0.0",
95
95
  "gensequence": "^8.0.8",
96
96
  "import-fresh": "^4.0.0",
@@ -103,7 +103,7 @@
103
103
  "node": ">=22.18.0"
104
104
  },
105
105
  "devDependencies": {
106
- "@cspell/cspell-tools": "10.2.2",
106
+ "@cspell/cspell-tools": "10.3.0",
107
107
  "@cspell/dict-cpp": "^7.1.0",
108
108
  "@cspell/dict-csharp": "^4.0.8",
109
109
  "@cspell/dict-css": "^4.1.2",
@@ -123,5 +123,5 @@
123
123
  "lorem-ipsum": "^3.0.0",
124
124
  "perf-insight": "^2.0.1"
125
125
  },
126
- "gitHead": "22fae7ac63d4330c52fe97eebee743e3541f2e36"
126
+ "gitHead": "d8abd59fa15da6da47955eb6fcca180e8b5cbdbf"
127
127
  }