cspell-lib 10.3.4 → 10.3.5
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/Transform/SourceMap.js +3 -2
- package/dist/lib/Transform/SubstitutionTransformer.js +2 -3
- package/dist/lib/spellCheckFile.d.ts +4 -0
- package/dist/lib/textValidation/docValidator.js +2 -2
- package/dist/lib/textValidation/lineValidatorFactory.js +23 -11
- package/dist/lib/util/text.d.ts +7 -0
- package/dist/lib/util/text.js +16 -0
- package/package.json +19 -19
|
@@ -335,9 +335,10 @@ function advanceCursors(cursor1, cursor2, target) {
|
|
|
335
335
|
assert(cursor1.p1 === cursor2.p0, 'The shared edge must match between the two cursors.');
|
|
336
336
|
if (cursor1.linear && cursor2.linear) {
|
|
337
337
|
const p = Math.min(cursor1.end1, cursor2.end0);
|
|
338
|
+
// Both segments are linear, so all three positions advance by the same amount from the current position.
|
|
338
339
|
const dB = p - cursor1.p1;
|
|
339
|
-
const pA = cursor1.
|
|
340
|
-
const pC = cursor2.
|
|
340
|
+
const pA = cursor1.p0 + dB;
|
|
341
|
+
const pC = cursor2.p1 + dB;
|
|
341
342
|
const dA = pA - cursor1.p0;
|
|
342
343
|
const dC = pC - cursor2.p1;
|
|
343
344
|
cursor1.p0 = pA;
|
|
@@ -95,9 +95,8 @@ function buildDefinitionMap(defs) {
|
|
|
95
95
|
* @returns
|
|
96
96
|
*/
|
|
97
97
|
export function createSubstitutionTransformer(info) {
|
|
98
|
-
const {
|
|
99
|
-
|
|
100
|
-
: {};
|
|
98
|
+
const { substitutions, substitutionDefinitions } = info;
|
|
99
|
+
const { subMap, missing } = substitutions ? calcSubMap(substitutions, substitutionDefinitions ?? []) : {};
|
|
101
100
|
return {
|
|
102
101
|
transformer: new SubstitutionTransformer(subMap),
|
|
103
102
|
missing: missing && missing.length > 0 ? missing : undefined,
|
|
@@ -25,6 +25,10 @@ export interface SpellCheckFileOptions extends ValidateTextOptions, Pick<CSpellU
|
|
|
25
25
|
* @defaultValue undefined
|
|
26
26
|
*/
|
|
27
27
|
noConfigSearch?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* If true, the document will be checked even if it would normally be excluded.
|
|
30
|
+
*/
|
|
31
|
+
forceCheck?: boolean;
|
|
28
32
|
}
|
|
29
33
|
export interface SpellCheckFileOptionsRPC extends SpellCheckFileOptions {
|
|
30
34
|
measurePerf?: boolean;
|
|
@@ -509,11 +509,11 @@ export async function shouldCheckDocument(doc, options, settings) {
|
|
|
509
509
|
const config = mergeSettings(settings, localConfig);
|
|
510
510
|
const matcher = getGlobMatcherForExcluding(localConfig?.ignorePaths);
|
|
511
511
|
// eslint-disable-next-line unicorn/prefer-regexp-test
|
|
512
|
-
if (matcher.match(uriToFilePath(doc.uri))) {
|
|
512
|
+
if (!options.forceCheck && matcher.match(uriToFilePath(doc.uri))) {
|
|
513
513
|
return { errors, shouldCheck: false, settings: localConfig, reason: 'Excluded by ignorePaths.' };
|
|
514
514
|
}
|
|
515
515
|
const docSettings = await determineTextDocumentSettings(doc, config);
|
|
516
|
-
const shouldCheck = docSettings.enabled ?? true;
|
|
516
|
+
const shouldCheck = options.forceCheck || (docSettings.enabled ?? true);
|
|
517
517
|
const reason = shouldCheck ? undefined : 'Excluded by overrides or languageSettings.';
|
|
518
518
|
return { errors, shouldCheck, settings: docSettings, reason };
|
|
519
519
|
}
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import assert from 'node:assert';
|
|
2
1
|
import { opConcatMap, opFilter, pipe } from '@cspell/cspell-pipe/sync';
|
|
3
2
|
import { defaultCSpellSettings, unknownWordsChoices } from '@cspell/cspell-types';
|
|
4
3
|
import { createCachingDictionary } from 'cspell-dictionary';
|
|
5
4
|
import * as RxPat from '../Settings/RegExpPatterns.js';
|
|
6
5
|
import { mapRangeBackToOriginalPos } from '../Transform/index.js';
|
|
7
6
|
import { autoResolve } from '../util/AutoResolve.js';
|
|
8
|
-
import { extractPossibleWordsFromTextOffset, extractText, extractWordsFromTextOffset, splitWordWithOffset, } from '../util/text.js';
|
|
7
|
+
import { extractPossibleWordsFromTextOffset, extractText, extractWordsFromTextOffset, numCharacters, splitWordWithOffset, } from '../util/text.js';
|
|
9
8
|
import { regExpCamelCaseWordBreaksWithEnglishSuffix } from '../util/textRegex.js';
|
|
10
9
|
import { split } from '../util/wordSplitter/index.js';
|
|
11
10
|
import { defaultMinWordLength } from './defaultConstants.js';
|
|
@@ -131,22 +130,31 @@ export function lineValidatorFactory(sDict, options) {
|
|
|
131
130
|
return issue;
|
|
132
131
|
}
|
|
133
132
|
const regExUpperCaseWithTrailingCommonEnglishSuffix = /^([\p{Lu}\p{M}]{2,})['’]?(?:s|ing|ies|es|ings|ize|ed|ning)$/u; // cspell:disable-line
|
|
134
|
-
|
|
133
|
+
// Sticky: test the text at `lastIndex` without creating substrings.
|
|
134
|
+
const regExpIsLetterBefore = /(?<=\p{L})/uy;
|
|
135
|
+
const regExpIsLetterAt = /\p{L}/uy;
|
|
135
136
|
const fn = (lineSegment) => {
|
|
136
137
|
const line = lineSegment.line;
|
|
138
|
+
/**
|
|
139
|
+
* A short word is ok if it stands alone in the line, i.e. it is not next to other letters.
|
|
140
|
+
*/
|
|
137
141
|
function isWordTooShort(word, ignoreSuffix = false) {
|
|
138
|
-
|
|
142
|
+
const tLen = word.text.length;
|
|
143
|
+
const wLen = word.length ?? tLen;
|
|
144
|
+
if (tLen >= minWordLength * 2 || numCharacters(word.text) >= minWordLength)
|
|
145
|
+
return false;
|
|
146
|
+
// A word joined across soft hyphens does not stand alone in the line.
|
|
147
|
+
if (wLen !== tLen)
|
|
139
148
|
return false;
|
|
140
149
|
const offset = word.offset - line.offset;
|
|
141
|
-
|
|
142
|
-
const
|
|
143
|
-
const hasLetterPrefix = !!prefix.length && regExpIsLetter.test(prefix[prefix.length - 1]);
|
|
150
|
+
regExpIsLetterBefore.lastIndex = offset;
|
|
151
|
+
const hasLetterPrefix = regExpIsLetterBefore.test(line.text);
|
|
144
152
|
if (hasLetterPrefix)
|
|
145
153
|
return false;
|
|
146
154
|
if (ignoreSuffix)
|
|
147
155
|
return true;
|
|
148
|
-
|
|
149
|
-
const hasLetterSuffix =
|
|
156
|
+
regExpIsLetterAt.lastIndex = offset + wLen;
|
|
157
|
+
const hasLetterSuffix = regExpIsLetterAt.test(line.text);
|
|
150
158
|
return !hasLetterSuffix;
|
|
151
159
|
}
|
|
152
160
|
function splitterIsValid(word) {
|
|
@@ -173,6 +181,9 @@ export function lineValidatorFactory(sDict, options) {
|
|
|
173
181
|
return false;
|
|
174
182
|
if (check.isFound)
|
|
175
183
|
return true;
|
|
184
|
+
// A word joined across soft hyphens does not stand alone in the line.
|
|
185
|
+
if (tWord.length !== undefined && tWord.length !== tWord.text.length)
|
|
186
|
+
return false;
|
|
176
187
|
if (isWordTooShort(v, true))
|
|
177
188
|
return true;
|
|
178
189
|
return false;
|
|
@@ -374,8 +385,9 @@ export function textValidatorFactory(dict, options) {
|
|
|
374
385
|
const segment = { text, offset: 0 };
|
|
375
386
|
const lineSegment = { line: segment, segment };
|
|
376
387
|
function mapBackToOriginSimple(vr) {
|
|
377
|
-
const { text, offset, isFlagged, isFound, suggestionsEx, hasPreferredSuggestions, hasSimpleSuggestions } = vr;
|
|
378
|
-
const
|
|
388
|
+
const { text, length, offset, isFlagged, isFound, suggestionsEx, hasPreferredSuggestions, hasSimpleSuggestions, } = vr;
|
|
389
|
+
const wLen = length ?? text.length;
|
|
390
|
+
const r = mapRangeBackToOriginalPos([offset, offset + wLen], map);
|
|
379
391
|
const range = [r[0] + srcOffset, r[1] + srcOffset];
|
|
380
392
|
return {
|
|
381
393
|
text,
|
package/dist/lib/util/text.d.ts
CHANGED
|
@@ -52,6 +52,13 @@ export declare function textOffset(text: string, offset?: number): TextOffset;
|
|
|
52
52
|
export declare function extractText(textOffset: TextOffset, startPos: number, endPos: number): string;
|
|
53
53
|
export declare function calculateTextDocumentOffsets<T extends TextOffset>(uri: string | Uri | URL, doc: string, wordOffsets: T[]): (TextDocumentOffset & T)[];
|
|
54
54
|
export declare function removeAccents(text: string): string;
|
|
55
|
+
/**
|
|
56
|
+
* Count the number of characters (Unicode code points) in a string.
|
|
57
|
+
* Surrogate pairs count as one character. Same result as `[...text].length`, without creating an array.
|
|
58
|
+
* @param text - the string to count.
|
|
59
|
+
* @returns the number of characters.
|
|
60
|
+
*/
|
|
61
|
+
export declare function numCharacters(text: string): number;
|
|
55
62
|
export declare const __testing__: {
|
|
56
63
|
regExWords: RegExp;
|
|
57
64
|
regExWordsAndDigits: RegExp;
|
package/dist/lib/util/text.js
CHANGED
|
@@ -204,6 +204,22 @@ export function removeAccents(text) {
|
|
|
204
204
|
regExAccents.lastIndex = 0;
|
|
205
205
|
return text.normalize('NFD').replace(regExAccents, '');
|
|
206
206
|
}
|
|
207
|
+
/**
|
|
208
|
+
* Count the number of characters (Unicode code points) in a string.
|
|
209
|
+
* Surrogate pairs count as one character. Same result as `[...text].length`, without creating an array.
|
|
210
|
+
* @param text - the string to count.
|
|
211
|
+
* @returns the number of characters.
|
|
212
|
+
*/
|
|
213
|
+
export function numCharacters(text) {
|
|
214
|
+
const len = text.length;
|
|
215
|
+
let n = 0;
|
|
216
|
+
for (let i = 0; i < len; ++i, ++n) {
|
|
217
|
+
// A code point above 0xFFFF is a surrogate pair, skip the second half.
|
|
218
|
+
if ((text.codePointAt(i) || 0) > 0xffff)
|
|
219
|
+
++i;
|
|
220
|
+
}
|
|
221
|
+
return n;
|
|
222
|
+
}
|
|
207
223
|
export const __testing__ = {
|
|
208
224
|
regExWords: regExWords,
|
|
209
225
|
regExWordsAndDigits: regExWordsAndDigits,
|
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public",
|
|
5
5
|
"provenance": true
|
|
6
6
|
},
|
|
7
|
-
"version": "10.3.
|
|
7
|
+
"version": "10.3.5",
|
|
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.3.
|
|
79
|
-
"@cspell/cspell-performance-monitor": "10.3.
|
|
80
|
-
"@cspell/cspell-pipe": "10.3.
|
|
81
|
-
"@cspell/cspell-resolver": "10.3.
|
|
82
|
-
"@cspell/cspell-types": "10.3.
|
|
83
|
-
"@cspell/dynamic-import": "10.3.
|
|
84
|
-
"@cspell/filetypes": "10.3.
|
|
85
|
-
"@cspell/rpc": "10.3.
|
|
86
|
-
"@cspell/strong-weak-map": "10.3.
|
|
87
|
-
"@cspell/url": "10.3.
|
|
88
|
-
"cspell-config-lib": "10.3.
|
|
89
|
-
"cspell-dictionary": "10.3.
|
|
90
|
-
"cspell-glob": "10.3.
|
|
91
|
-
"cspell-grammar": "10.3.
|
|
92
|
-
"cspell-io": "10.3.
|
|
93
|
-
"cspell-trie-lib": "10.3.
|
|
78
|
+
"@cspell/cspell-bundled-dicts": "10.3.5",
|
|
79
|
+
"@cspell/cspell-performance-monitor": "10.3.5",
|
|
80
|
+
"@cspell/cspell-pipe": "10.3.5",
|
|
81
|
+
"@cspell/cspell-resolver": "10.3.5",
|
|
82
|
+
"@cspell/cspell-types": "10.3.5",
|
|
83
|
+
"@cspell/dynamic-import": "10.3.5",
|
|
84
|
+
"@cspell/filetypes": "10.3.5",
|
|
85
|
+
"@cspell/rpc": "10.3.5",
|
|
86
|
+
"@cspell/strong-weak-map": "10.3.5",
|
|
87
|
+
"@cspell/url": "10.3.5",
|
|
88
|
+
"cspell-config-lib": "10.3.5",
|
|
89
|
+
"cspell-dictionary": "10.3.5",
|
|
90
|
+
"cspell-glob": "10.3.5",
|
|
91
|
+
"cspell-grammar": "10.3.5",
|
|
92
|
+
"cspell-io": "10.3.5",
|
|
93
|
+
"cspell-trie-lib": "10.3.5",
|
|
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.3.
|
|
106
|
+
"@cspell/cspell-tools": "10.3.5",
|
|
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": "
|
|
126
|
+
"gitHead": "f37a244a54b686fc1ac11272d6019b9a059b062a"
|
|
127
127
|
}
|