cspell-lib 8.2.3 → 8.2.4

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.
@@ -10,6 +10,7 @@ export declare class ConfigSearch {
10
10
  private findUpConfigPath;
11
11
  private hasConfig;
12
12
  private createHasFileDirSearch;
13
+ private readDir;
13
14
  private createHasFileStatCheck;
14
15
  private hasConfigDir;
15
16
  }
@@ -74,17 +74,26 @@ export class ConfigSearch {
74
74
  const parentInfo = await parentInfoP;
75
75
  const name = urlBasename(dir).slice(0, -1);
76
76
  const found = parentInfo.get(name);
77
- if (!found?.isDirectory())
77
+ if (!found?.isDirectory() && !found?.isSymbolicLink())
78
78
  return false;
79
79
  }
80
80
  const dirUrlHref = dir.href;
81
- const dirInfo = await dirInfoCache.get(dirUrlHref, async () => new Map((await this.fs.readDirectory(dir).catch(() => [])).map((ent) => [ent.name, ent])));
81
+ const dirInfo = await dirInfoCache.get(dirUrlHref, async () => await this.readDir(dir));
82
82
  const name = urlBasename(filename);
83
83
  const found = dirInfo.get(name);
84
- return !!found?.isFile();
84
+ return found?.isFile() || found?.isSymbolicLink() || false;
85
85
  };
86
86
  return hasFile;
87
87
  }
88
+ async readDir(dir) {
89
+ try {
90
+ const dirInfo = await this.fs.readDirectory(dir);
91
+ return new Map(dirInfo.map((ent) => [ent.name, ent]));
92
+ }
93
+ catch (e) {
94
+ return new Map();
95
+ }
96
+ }
88
97
  createHasFileStatCheck() {
89
98
  const hasFile = async (filename) => {
90
99
  const stat = await this.fs.stat(filename).catch(() => undefined);
@@ -1,7 +1,7 @@
1
1
  import { mapDictionaryInformationToWeightMap } from 'cspell-trie-lib';
2
2
  import * as path from 'path';
3
3
  import { isDictionaryDefinitionInlineInternal } from '../Models/CSpellSettingsInternalDef.js';
4
- import { AutoResolveWeakCache } from '../util/AutoResolve.js';
4
+ import { createAutoResolveWeakWeakCache } from '../util/AutoResolve.js';
5
5
  import { resolveRelativeTo } from '../util/resolveFile.js';
6
6
  import { toFilePathOrHref } from '../util/url.js';
7
7
  import { clean } from '../util/util.js';
@@ -40,7 +40,7 @@ function fixDicPath(defPath, defFile) {
40
40
  export function mapDictDefsToInternal(defs, pathToSettingsFile) {
41
41
  return defs?.map((def) => mapDictDefToInternal(def, pathToSettingsFile));
42
42
  }
43
- const internalDefs = new AutoResolveWeakCache();
43
+ const internalDefs = createAutoResolveWeakWeakCache();
44
44
  export function mapDictDefToInternal(def, pathToSettingsFile) {
45
45
  return internalDefs.get(def, (def) => _mapDictDefToInternal(def, pathToSettingsFile));
46
46
  }
@@ -8,7 +8,9 @@ export declare class DictionaryLoader {
8
8
  private inlineDictionaryCache;
9
9
  private dictionaryCacheByDef;
10
10
  private reader;
11
- constructor(fs: VFileSystem);
11
+ /** The keepAliveCache is to hold onto the most recently loaded dictionaries. */
12
+ private keepAliveCache;
13
+ constructor(fs: VFileSystem, keepAliveSize?: number);
12
14
  loadDictionary(def: DictionaryDefinitionInternal): Promise<SpellingDictionary>;
13
15
  /**
14
16
  * Check to see if any of the cached dictionaries have changed. If one has changed, reload it.
@@ -3,8 +3,9 @@ import { StrongWeakMap } from '@cspell/strong-weak-map';
3
3
  import { createFailedToLoadDictionary, createInlineSpellingDictionary, createSpellingDictionary, createSpellingDictionaryFromTrieFile, } from 'cspell-dictionary';
4
4
  import { compareStats, toFileURL, urlBasename } from 'cspell-io';
5
5
  import { isDictionaryDefinitionInlineInternal } from '../../Models/CSpellSettingsInternalDef.js';
6
- import { AutoResolveWeakCache } from '../../util/AutoResolve.js';
6
+ import { AutoResolveWeakCache, AutoResolveWeakWeakCache } from '../../util/AutoResolve.js';
7
7
  import { toError } from '../../util/errors.js';
8
+ import { SimpleCache } from '../../util/simpleCache.js';
8
9
  import { SpellingDictionaryLoadError } from '../SpellingDictionaryError.js';
9
10
  const MAX_AGE = 10000;
10
11
  const loaders = {
@@ -23,11 +24,14 @@ export class DictionaryLoader {
23
24
  fs;
24
25
  dictionaryCache = new StrongWeakMap();
25
26
  inlineDictionaryCache = new AutoResolveWeakCache();
26
- dictionaryCacheByDef = new StrongWeakMap();
27
+ dictionaryCacheByDef = new AutoResolveWeakWeakCache();
27
28
  reader;
28
- constructor(fs) {
29
+ /** The keepAliveCache is to hold onto the most recently loaded dictionaries. */
30
+ keepAliveCache;
31
+ constructor(fs, keepAliveSize = 10) {
29
32
  this.fs = fs;
30
33
  this.reader = toReader(fs);
34
+ this.keepAliveCache = new SimpleCache(keepAliveSize);
31
35
  }
32
36
  loadDictionary(def) {
33
37
  if (isDictionaryDefinitionInlineInternal(def)) {
@@ -39,6 +43,7 @@ export class DictionaryLoader {
39
43
  }
40
44
  const loadedEntry = this.loadEntry(def.path, def);
41
45
  this.setCacheEntry(key, loadedEntry, def);
46
+ this.keepAliveCache.set(def, loadedEntry);
42
47
  return loadedEntry.pending.then(([dictionary]) => dictionary);
43
48
  }
44
49
  /**
@@ -52,6 +57,7 @@ export class DictionaryLoader {
52
57
  getCacheEntry(def) {
53
58
  const defEntry = this.dictionaryCacheByDef.get(def);
54
59
  if (defEntry) {
60
+ this.keepAliveCache.get(def);
55
61
  return defEntry;
56
62
  }
57
63
  const key = this.calcKey(def);
@@ -59,6 +65,7 @@ export class DictionaryLoader {
59
65
  if (entry) {
60
66
  // replace old entry so it can be released.
61
67
  entry.options = def;
68
+ this.keepAliveCache.set(def, entry);
62
69
  }
63
70
  return { key, entry };
64
71
  }
@@ -72,6 +72,21 @@ export declare class DocumentValidator {
72
72
  checkDocumentDirectives(forceCheck?: boolean): ValidationIssue[];
73
73
  get document(): TextDocument;
74
74
  updateDocumentText(text: string): Promise<void>;
75
+ /**
76
+ * Get the calculated ranges of text that should be included in the spell checking.
77
+ * @returns MatchRanges of text to include.
78
+ */
79
+ getCheckedTextRanges(): MatchRange[];
80
+ traceWord(word: string): {
81
+ word: string;
82
+ found: boolean;
83
+ foundWord: string | undefined;
84
+ forbidden: boolean;
85
+ noSuggest: boolean;
86
+ dictName: string;
87
+ dictSource: string;
88
+ errors: Error[] | undefined;
89
+ }[];
75
90
  private defaultParser;
76
91
  private _checkParsedText;
77
92
  private addPossibleError;
@@ -11,6 +11,7 @@ import { calcSuggestionAdjustedToToMatchCase } from '../suggestions.js';
11
11
  import { catchPromiseError, toError } from '../util/errors.js';
12
12
  import { AutoCache } from '../util/simpleCache.js';
13
13
  import { uriToFilePath } from '../util/Uri.js';
14
+ import { toFilePathOrHref } from '../util/url.js';
14
15
  import { defaultMaxDuplicateProblems, defaultMaxNumberOfProblems } from './defaultConstants.js';
15
16
  import { determineTextDocumentSettings } from './determineTextDocumentSettings.js';
16
17
  import { textValidatorFactory } from './lineValidatorFactory.js';
@@ -237,6 +238,36 @@ export class DocumentValidator {
237
238
  updateTextDocument(this._document, [{ text }]);
238
239
  await this._updatePrep();
239
240
  }
241
+ /**
242
+ * Get the calculated ranges of text that should be included in the spell checking.
243
+ * @returns MatchRanges of text to include.
244
+ */
245
+ getCheckedTextRanges() {
246
+ assert(this._preparations, ERROR_NOT_PREPARED);
247
+ return this._preparations.includeRanges;
248
+ }
249
+ traceWord(word) {
250
+ assert(this._preparations, ERROR_NOT_PREPARED);
251
+ const dictCollection = this._preparations.dictionary;
252
+ const config = this._preparations.config;
253
+ const opts = {
254
+ ignoreCase: true,
255
+ allowCompoundWords: config.allowCompoundWords || false,
256
+ };
257
+ const trace = dictCollection.dictionaries
258
+ .map((dict) => ({ dict, findResult: dict.find(word, opts) }))
259
+ .map(({ dict, findResult }) => ({
260
+ word,
261
+ found: !!findResult?.found,
262
+ foundWord: findResult?.found || undefined,
263
+ forbidden: findResult?.forbidden || false,
264
+ noSuggest: findResult?.noSuggest || false,
265
+ dictName: dict.name,
266
+ dictSource: toFilePathOrHref(dict.source),
267
+ errors: normalizeErrors(dict.getErrors?.()),
268
+ }));
269
+ return trace;
270
+ }
240
271
  defaultParser() {
241
272
  return pipeSync(this.document.getLines(), opMap((line) => {
242
273
  const { text, offset } = line;
@@ -378,4 +409,7 @@ function recordPerfTime(timings, name) {
378
409
  function timePromise(timings, name, p) {
379
410
  return p.finally(recordPerfTime(timings, name));
380
411
  }
412
+ function normalizeErrors(errors) {
413
+ return errors?.length ? errors : undefined;
414
+ }
381
415
  //# sourceMappingURL=docValidator.js.map
package/dist/esm/trace.js CHANGED
@@ -1,9 +1,9 @@
1
- import { fileURLToPath } from 'node:url';
2
1
  import { genSequence } from 'gensequence';
3
2
  import { toInternalSettings } from './Settings/CSpellSettingsServer.js';
4
3
  import { finalizeSettings, mergeSettings } from './Settings/index.js';
5
4
  import { calcSettingsForLanguageId } from './Settings/LanguageSettings.js';
6
5
  import { getDictionaryInternal, refreshDictionaryCache } from './SpellingDictionary/index.js';
6
+ import { toFilePathOrHref } from './util/url.js';
7
7
  import * as util from './util/util.js';
8
8
  export async function traceWords(words, settings, options) {
9
9
  const results = await util.asyncIterableToArray(traceWordsAsync(words, settings, options));
@@ -64,9 +64,6 @@ export async function* traceWordsAsync(words, settings, options) {
64
64
  }
65
65
  }
66
66
  function dictSourceToFilename(source) {
67
- if (source.startsWith('file:')) {
68
- return fileURLToPath(source);
69
- }
70
- return source;
67
+ return toFilePathOrHref(source);
71
68
  }
72
69
  //# sourceMappingURL=trace.js.map
@@ -46,5 +46,20 @@ export declare class AutoResolveWeakCache<K extends object, V> implements IWeakM
46
46
  stats(): AutoResolveCacheStats;
47
47
  }
48
48
  export declare function createAutoResolveWeakCache<K extends object, V>(): AutoResolveWeakCache<K, V>;
49
+ export declare class AutoResolveWeakWeakCache<K extends object, V extends object> implements IWeakMap<K, V> {
50
+ private _map;
51
+ private _stats;
52
+ get(k: K): V | undefined;
53
+ get(k: K, resolve: (k: K) => V): V;
54
+ get(k: K, resolve?: (k: K) => V): V | undefined;
55
+ get map(): WeakMap<K, WeakRef<V>>;
56
+ has(k: K): boolean;
57
+ set(k: K, v: V): this;
58
+ clear(): void;
59
+ delete(k: K): boolean;
60
+ dispose(): void;
61
+ stats(): AutoResolveCacheStats;
62
+ }
63
+ export declare function createAutoResolveWeakWeakCache<K extends object, V extends object>(): AutoResolveWeakWeakCache<K, V>;
49
64
  export {};
50
65
  //# sourceMappingURL=AutoResolve.d.ts.map
@@ -116,4 +116,57 @@ export class AutoResolveWeakCache {
116
116
  export function createAutoResolveWeakCache() {
117
117
  return new AutoResolveWeakCache();
118
118
  }
119
+ export class AutoResolveWeakWeakCache {
120
+ _map = new WeakMap();
121
+ _stats = new CacheStatsTracker();
122
+ get(k, resolve) {
123
+ const map = this._map;
124
+ const found = map.get(k);
125
+ const foundValue = found?.deref();
126
+ if (found !== undefined && foundValue) {
127
+ ++this._stats.hits;
128
+ return foundValue;
129
+ }
130
+ ++this._stats.misses;
131
+ if (!resolve) {
132
+ if (found) {
133
+ map.delete(k);
134
+ }
135
+ return undefined;
136
+ }
137
+ ++this._stats.resolved;
138
+ const value = resolve(k);
139
+ map.set(k, new WeakRef(value));
140
+ return value;
141
+ }
142
+ get map() {
143
+ return this._map;
144
+ }
145
+ has(k) {
146
+ return !!this._map.get(k)?.deref();
147
+ }
148
+ set(k, v) {
149
+ ++this._stats.sets;
150
+ this._map.set(k, new WeakRef(v));
151
+ return this;
152
+ }
153
+ clear() {
154
+ this._stats.clear();
155
+ this._map = new WeakMap();
156
+ }
157
+ delete(k) {
158
+ ++this._stats.deletes;
159
+ return this._map.delete(k);
160
+ }
161
+ dispose() {
162
+ ++this._stats.disposals;
163
+ this.clear();
164
+ }
165
+ stats() {
166
+ return this._stats.stats();
167
+ }
168
+ }
169
+ export function createAutoResolveWeakWeakCache() {
170
+ return new AutoResolveWeakWeakCache();
171
+ }
119
172
  //# sourceMappingURL=AutoResolve.js.map
@@ -1,3 +1,7 @@
1
+ /**
2
+ * A range of text in a document.
3
+ * The range is inclusive of the startPos and exclusive of the endPos.
4
+ */
1
5
  export interface MatchRange {
2
6
  startPos: number;
3
7
  endPos: number;
@@ -34,6 +34,7 @@ export declare class SimpleCache<K, T> {
34
34
  has(key: K): boolean;
35
35
  get(key: K): T | undefined;
36
36
  set(key: K, value: T): void;
37
+ delete(key: K): boolean;
37
38
  private _set;
38
39
  private caches;
39
40
  private rotate;
@@ -103,6 +103,13 @@ export class SimpleCache {
103
103
  set(key, value) {
104
104
  this._set(key, { v: value });
105
105
  }
106
+ delete(key) {
107
+ let deleted = false;
108
+ for (const c of this.caches()) {
109
+ deleted = c.delete(key) || deleted;
110
+ }
111
+ return deleted;
112
+ }
106
113
  _set(key, entry) {
107
114
  if (this.L0.has(key)) {
108
115
  this.L0.set(key, entry);
@@ -117,9 +124,11 @@ export class SimpleCache {
117
124
  return [this.L0, this.L1, this.L2];
118
125
  }
119
126
  rotate() {
127
+ const L2 = this.L2;
120
128
  this.L2 = this.L1;
121
129
  this.L1 = this.L0;
122
- this.L0 = new Map();
130
+ this.L0 = L2;
131
+ this.L0.clear();
123
132
  }
124
133
  }
125
134
  export class AutoCache extends SimpleCache {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cspell-lib",
3
- "version": "8.2.3",
3
+ "version": "8.2.4",
4
4
  "description": "A library of useful functions used across various cspell tools.",
5
5
  "type": "module",
6
6
  "sideEffects": false,
@@ -57,21 +57,21 @@
57
57
  },
58
58
  "homepage": "https://github.com/streetsidesoftware/cspell#readme",
59
59
  "dependencies": {
60
- "@cspell/cspell-bundled-dicts": "8.2.3",
61
- "@cspell/cspell-pipe": "8.2.3",
62
- "@cspell/cspell-resolver": "8.2.3",
63
- "@cspell/cspell-types": "8.2.3",
64
- "@cspell/dynamic-import": "8.2.3",
65
- "@cspell/strong-weak-map": "8.2.3",
60
+ "@cspell/cspell-bundled-dicts": "8.2.4",
61
+ "@cspell/cspell-pipe": "8.2.4",
62
+ "@cspell/cspell-resolver": "8.2.4",
63
+ "@cspell/cspell-types": "8.2.4",
64
+ "@cspell/dynamic-import": "8.2.4",
65
+ "@cspell/strong-weak-map": "8.2.4",
66
66
  "clear-module": "^4.1.2",
67
67
  "comment-json": "^4.2.3",
68
68
  "configstore": "^6.0.0",
69
- "cspell-config-lib": "8.2.3",
70
- "cspell-dictionary": "8.2.3",
71
- "cspell-glob": "8.2.3",
72
- "cspell-grammar": "8.2.3",
73
- "cspell-io": "8.2.3",
74
- "cspell-trie-lib": "8.2.3",
69
+ "cspell-config-lib": "8.2.4",
70
+ "cspell-dictionary": "8.2.4",
71
+ "cspell-glob": "8.2.4",
72
+ "cspell-grammar": "8.2.4",
73
+ "cspell-io": "8.2.4",
74
+ "cspell-trie-lib": "8.2.4",
75
75
  "fast-equals": "^5.0.1",
76
76
  "gensequence": "^6.0.0",
77
77
  "import-fresh": "^3.3.0",
@@ -90,10 +90,10 @@
90
90
  "@cspell/dict-fr-fr": "^2.2.2",
91
91
  "@cspell/dict-html": "^4.0.5",
92
92
  "@cspell/dict-nl-nl": "^2.3.0",
93
- "@cspell/dict-python": "^4.1.10",
93
+ "@cspell/dict-python": "^4.1.11",
94
94
  "@types/configstore": "^6.0.2",
95
95
  "cspell-dict-nl-nl": "^1.1.2",
96
96
  "lorem-ipsum": "^2.0.8"
97
97
  },
98
- "gitHead": "e3098b21e0a199d61226f8ff4989d48b385eddfa"
98
+ "gitHead": "d3c5ff685b3aa2bf984f557d81380f2c994547e0"
99
99
  }