cspell-lib 8.2.3 → 8.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.
@@ -49,6 +49,7 @@ export interface IConfigLoader {
49
49
  * @returns the resulting settings
50
50
  */
51
51
  searchForConfig(searchFrom: URL | string | undefined, pnpSettings?: PnPSettingsOptional): Promise<CSpellSettingsI | undefined>;
52
+ resolveConfigFileLocation(filenameOrURL: string | URL, relativeTo?: string | URL): Promise<URL | undefined>;
52
53
  getGlobalSettingsAsync(): Promise<CSpellSettingsI>;
53
54
  /**
54
55
  * The loader caches configuration files for performance. This method clears the cache.
@@ -71,12 +72,15 @@ export interface IConfigLoader {
71
72
  */
72
73
  dispose(): void;
73
74
  getStats(): Readonly<Record<string, Readonly<Record<string, number>>>>;
75
+ readonly isTrusted: boolean;
76
+ setIsTrusted(isTrusted: boolean): void;
74
77
  }
75
78
  export declare class ConfigLoader implements IConfigLoader {
76
79
  readonly fs: VFileSystem;
77
80
  readonly templateVariables: Record<string, string>;
78
81
  onReady: Promise<void>;
79
82
  readonly fileResolver: FileResolver;
83
+ private _isTrusted;
80
84
  /**
81
85
  * Use `createConfigLoader`
82
86
  * @param virtualFs - virtual file system to use.
@@ -107,7 +111,9 @@ export declare class ConfigLoader implements IConfigLoader {
107
111
  getGlobalSettings(): CSpellSettingsI;
108
112
  getGlobalSettingsAsync(): Promise<CSpellSettingsI>;
109
113
  clearCachedSettingsFiles(): void;
114
+ protected init(): Promise<void>;
110
115
  protected prefetchGlobalSettingsAsync(): Promise<void>;
116
+ protected resolveDefaultConfig(): Promise<URL>;
111
117
  protected importSettings(fileRef: ImportFileRef, pnpSettings: PnPSettingsOptional | undefined, backReferences: string[]): ImportedConfigEntry;
112
118
  private setupPnp;
113
119
  mergeConfigFileWithImports(cfgFile: CSpellConfigFile, pnpSettings: PnPSettingsOptional | undefined, referencedBy?: string[] | undefined): Promise<CSpellSettingsI>;
@@ -124,7 +130,10 @@ export declare class ConfigLoader implements IConfigLoader {
124
130
  cacheMergeListUnique: Readonly<import("../../../util/AutoResolve.js").CacheStats>;
125
131
  cacheMergeLists: Readonly<import("../../../util/AutoResolve.js").CacheStats>;
126
132
  };
133
+ resolveConfigFileLocation(filenameOrURL: string | URL, relativeTo: string | URL): Promise<URL | undefined>;
127
134
  private resolveFilename;
135
+ get isTrusted(): boolean;
136
+ setIsTrusted(isTrusted: boolean): void;
128
137
  }
129
138
  declare class ConfigLoaderInternal extends ConfigLoader {
130
139
  constructor(vfs: VFileSystem);
@@ -4,6 +4,7 @@ import { isUrlLike, toFileURL } from 'cspell-io';
4
4
  import path from 'path';
5
5
  import { fileURLToPath, pathToFileURL } from 'url';
6
6
  import { URI, Utils as UriUtils } from 'vscode-uri';
7
+ import { srcDirectory } from '../../../../lib-cjs/index.cjs';
7
8
  import { onClearCache } from '../../../events/index.js';
8
9
  import { getVirtualFS } from '../../../fileSystem.js';
9
10
  import { createCSpellSettingsInternal as csi } from '../../../Models/CSpellSettingsInternalDef.js';
@@ -12,7 +13,7 @@ import { logError, logWarning } from '../../../util/logger.js';
12
13
  import { FileResolver } from '../../../util/resolveFile.js';
13
14
  import { envToTemplateVars } from '../../../util/templates.js';
14
15
  import { addTrailingSlash, cwdURL, resolveFileWithURL, toFilePathOrHref, windowsDriveLetterToUpper, } from '../../../util/url.js';
15
- import { configSettingsFileVersion0_1, configSettingsFileVersion0_2, currentSettingsFileVersion, ENV_CSPELL_GLOB_ROOT, } from '../../constants.js';
16
+ import { configSettingsFileVersion0_1, configSettingsFileVersion0_2, currentSettingsFileVersion, defaultConfigFileModuleRef, ENV_CSPELL_GLOB_ROOT, } from '../../constants.js';
16
17
  import { getMergeStats, mergeSettings } from '../../CSpellSettingsServer.js';
17
18
  import { getGlobalConfig } from '../../GlobalSettings.js';
18
19
  import { ImportError } from '../ImportError.js';
@@ -28,11 +29,19 @@ const setOfSupportedConfigVersions = Object.freeze(new Set(supportedCSpellConfig
28
29
  export const sectionCSpell = 'cSpell';
29
30
  export const defaultFileName = 'cspell.json';
30
31
  let defaultConfigLoader = undefined;
32
+ const defaultExtensions = ['.json', '.yaml', '.yml', '.jsonc'];
33
+ const defaultJsExtensions = ['.js', '.cjs', '.mjs'];
34
+ const trustedSearch = new Map([
35
+ ['*', defaultExtensions],
36
+ ['file:', [...defaultExtensions, ...defaultJsExtensions]],
37
+ ]);
38
+ const unTrustedSearch = new Map([['*', defaultExtensions]]);
31
39
  export class ConfigLoader {
32
40
  fs;
33
41
  templateVariables;
34
42
  onReady;
35
43
  fileResolver;
44
+ _isTrusted = true;
36
45
  /**
37
46
  * Use `createConfigLoader`
38
47
  * @param virtualFs - virtual file system to use.
@@ -40,10 +49,10 @@ export class ConfigLoader {
40
49
  constructor(fs, templateVariables = envToTemplateVars(process.env)) {
41
50
  this.fs = fs;
42
51
  this.templateVariables = templateVariables;
43
- this.configSearch = new ConfigSearch(searchPlaces, fs);
52
+ this.configSearch = new ConfigSearch(searchPlaces, trustedSearch, fs);
44
53
  this.cspellConfigFileReaderWriter = createReaderWriter(undefined, undefined, createIO(fs));
45
54
  this.fileResolver = new FileResolver(fs, this.templateVariables);
46
- this.onReady = this.prefetchGlobalSettingsAsync();
55
+ this.onReady = this.init();
47
56
  this.subscribeToEvents();
48
57
  }
49
58
  subscribeToEvents() {
@@ -140,10 +149,19 @@ export class ConfigLoader {
140
149
  this.cachedMergedConfig = new WeakMap();
141
150
  this.prefetchGlobalSettingsAsync();
142
151
  }
143
- prefetchGlobalSettingsAsync() {
144
- this.onReady = this.getGlobalSettingsAsync().then(() => undefined, (e) => logError(e));
152
+ init() {
153
+ this.onReady = Promise.all([this.prefetchGlobalSettingsAsync(), this.resolveDefaultConfig()]).then(() => undefined);
145
154
  return this.onReady;
146
155
  }
156
+ async prefetchGlobalSettingsAsync() {
157
+ await this.getGlobalSettingsAsync().catch((e) => logError(e));
158
+ }
159
+ async resolveDefaultConfig() {
160
+ const r = await this.fileResolver.resolveFile(defaultConfigFileModuleRef, srcDirectory);
161
+ const url = toFileURL(r.filename);
162
+ this.cspellConfigFileReaderWriter.setTrustedUrls([new URL('../..', url)]);
163
+ return url;
164
+ }
147
165
  importSettings(fileRef, pnpSettings, backReferences) {
148
166
  const url = toFileURL(fileRef.filename);
149
167
  const cacheKey = url.href;
@@ -318,6 +336,10 @@ export class ConfigLoader {
318
336
  getStats() {
319
337
  return { ...getMergeStats() };
320
338
  }
339
+ async resolveConfigFileLocation(filenameOrURL, relativeTo) {
340
+ const r = await this.fileResolver.resolveFile(filenameOrURL, relativeTo);
341
+ return r.found ? toFileURL(r.filename) : undefined;
342
+ }
321
343
  async resolveFilename(filename, relativeTo) {
322
344
  if (filename instanceof URL)
323
345
  return { filename: toFilePathOrHref(filename) };
@@ -332,6 +354,15 @@ export class ConfigLoader {
332
354
  error: r.found ? undefined : new Error(`Failed to resolve file: "${filename}"`),
333
355
  };
334
356
  }
357
+ get isTrusted() {
358
+ return this._isTrusted;
359
+ }
360
+ setIsTrusted(isTrusted) {
361
+ this._isTrusted = isTrusted;
362
+ this.clearCachedSettingsFiles();
363
+ this.configSearch = new ConfigSearch(searchPlaces, isTrusted ? trustedSearch : unTrustedSearch, this.fs);
364
+ this.cspellConfigFileReaderWriter.setUntrustedExtensions(isTrusted ? [] : defaultJsExtensions);
365
+ }
335
366
  }
336
367
  class ConfigLoaderInternal extends ConfigLoader {
337
368
  constructor(vfs) {
@@ -1,15 +1,23 @@
1
1
  import type { VFileSystem } from '../../../fileSystem.js';
2
2
  export declare class ConfigSearch {
3
3
  readonly searchPlaces: readonly string[];
4
+ readonly allowedExtensionsByProtocol: Map<string, readonly string[]>;
4
5
  private fs;
5
6
  private searchCache;
6
7
  private searchDirCache;
7
- constructor(searchPlaces: readonly string[], fs: VFileSystem);
8
+ private searchPlacesByProtocol;
9
+ /**
10
+ * @param searchPlaces - The list of file names to search for.
11
+ * @param allowedExtensionsByProtocol - Map of allowed extensions by protocol, '*' is used to match all protocols.
12
+ * @param fs - The file system to use.
13
+ */
14
+ constructor(searchPlaces: readonly string[], allowedExtensionsByProtocol: Map<string, readonly string[]>, fs: VFileSystem);
8
15
  searchForConfig(searchFromURL: URL): Promise<URL | undefined>;
9
16
  clearCache(): void;
10
17
  private findUpConfigPath;
11
18
  private hasConfig;
12
19
  private createHasFileDirSearch;
20
+ private readDir;
13
21
  private createHasFileStatCheck;
14
22
  private hasConfigDir;
15
23
  }
@@ -1,15 +1,25 @@
1
+ import { extname } from 'node:path/posix';
1
2
  import { urlBasename } from 'cspell-io';
2
3
  import { createAutoResolveCache } from '../../../util/AutoResolve.js';
3
4
  import { findUpFromUrl } from '../../../util/findUpFromUrl.js';
4
5
  export class ConfigSearch {
5
6
  searchPlaces;
7
+ allowedExtensionsByProtocol;
6
8
  fs;
7
9
  searchCache = new Map();
8
10
  searchDirCache = new Map();
9
- constructor(searchPlaces, fs) {
11
+ searchPlacesByProtocol;
12
+ /**
13
+ * @param searchPlaces - The list of file names to search for.
14
+ * @param allowedExtensionsByProtocol - Map of allowed extensions by protocol, '*' is used to match all protocols.
15
+ * @param fs - The file system to use.
16
+ */
17
+ constructor(searchPlaces, allowedExtensionsByProtocol, fs) {
10
18
  this.searchPlaces = searchPlaces;
19
+ this.allowedExtensionsByProtocol = allowedExtensionsByProtocol;
11
20
  this.fs = fs;
12
- this.searchPlaces = searchPlaces;
21
+ this.searchPlacesByProtocol = setupSearchPlacesByProtocol(searchPlaces, allowedExtensionsByProtocol);
22
+ this.searchPlaces = this.searchPlacesByProtocol.get('*') || searchPlaces;
13
23
  }
14
24
  searchForConfig(searchFromURL) {
15
25
  const dirUrl = new URL('.', searchFromURL);
@@ -74,17 +84,26 @@ export class ConfigSearch {
74
84
  const parentInfo = await parentInfoP;
75
85
  const name = urlBasename(dir).slice(0, -1);
76
86
  const found = parentInfo.get(name);
77
- if (!found?.isDirectory())
87
+ if (!found?.isDirectory() && !found?.isSymbolicLink())
78
88
  return false;
79
89
  }
80
90
  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])));
91
+ const dirInfo = await dirInfoCache.get(dirUrlHref, async () => await this.readDir(dir));
82
92
  const name = urlBasename(filename);
83
93
  const found = dirInfo.get(name);
84
- return !!found?.isFile();
94
+ return found?.isFile() || found?.isSymbolicLink() || false;
85
95
  };
86
96
  return hasFile;
87
97
  }
98
+ async readDir(dir) {
99
+ try {
100
+ const dirInfo = await this.fs.readDirectory(dir);
101
+ return new Map(dirInfo.map((ent) => [ent.name, ent]));
102
+ }
103
+ catch (e) {
104
+ return new Map();
105
+ }
106
+ }
88
107
  createHasFileStatCheck() {
89
108
  const hasFile = async (filename) => {
90
109
  const stat = await this.fs.stat(filename).catch(() => undefined);
@@ -96,7 +115,8 @@ export class ConfigSearch {
96
115
  const hasFile = this.fs.getCapabilities(dir).readDirectory
97
116
  ? this.createHasFileDirSearch()
98
117
  : this.createHasFileStatCheck();
99
- for (const searchPlace of this.searchPlaces) {
118
+ const searchPlaces = this.searchPlacesByProtocol.get(dir.protocol) || this.searchPlaces;
119
+ for (const searchPlace of searchPlaces) {
100
120
  const file = new URL(searchPlace, dir);
101
121
  const found = await hasFile(file);
102
122
  if (found) {
@@ -109,6 +129,12 @@ export class ConfigSearch {
109
129
  return undefined;
110
130
  }
111
131
  }
132
+ function setupSearchPlacesByProtocol(searchPlaces, allowedExtensionsByProtocol) {
133
+ const map = new Map([...allowedExtensionsByProtocol.entries()]
134
+ .map(([k, v]) => [k, new Set(v)])
135
+ .map(([protocol, exts]) => [protocol, searchPlaces.filter((url) => exts.has(extname(url)))]));
136
+ return map;
137
+ }
112
138
  async function checkPackageJson(fs, filename) {
113
139
  try {
114
140
  const file = await fs.readFile(filename);
@@ -3,11 +3,11 @@ import { srcDirectory } from '../../lib-cjs/index.cjs';
3
3
  import { createCSpellSettingsInternal } from '../Models/CSpellSettingsInternalDef.js';
4
4
  import { PatternRegExp } from '../Models/PatternRegExp.js';
5
5
  import { resolveFile } from '../util/resolveFile.js';
6
+ import { defaultConfigFileModuleRef } from './constants.js';
6
7
  import { readSettings } from './Controller/configLoader/index.js';
7
8
  import { mergeSettings } from './CSpellSettingsServer.js';
8
9
  import * as LanguageSettings from './LanguageSettings.js';
9
10
  import * as RegPat from './RegExpPatterns.js';
10
- const defaultConfigFileModuleRef = '@cspell/cspell-bundled-dicts/cspell-default.json';
11
11
  // Do not use require.resolve because webpack will mess it up.
12
12
  const defaultConfigFile = () => resolveConfigModule(defaultConfigFileModuleRef);
13
13
  const regExpSpellCheckerDisable = [
@@ -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
  }
@@ -2,4 +2,5 @@ export declare const configSettingsFileVersion0_1 = "0.1";
2
2
  export declare const configSettingsFileVersion0_2 = "0.2";
3
3
  export declare const currentSettingsFileVersion = "0.2";
4
4
  export declare const ENV_CSPELL_GLOB_ROOT = "CSPELL_GLOB_ROOT";
5
+ export declare const defaultConfigFileModuleRef = "@cspell/cspell-bundled-dicts/cspell-default.json";
5
6
  //# sourceMappingURL=constants.d.ts.map
@@ -2,4 +2,5 @@ export const configSettingsFileVersion0_1 = '0.1';
2
2
  export const configSettingsFileVersion0_2 = '0.2';
3
3
  export const currentSettingsFileVersion = configSettingsFileVersion0_2;
4
4
  export const ENV_CSPELL_GLOB_ROOT = 'CSPELL_GLOB_ROOT';
5
+ export const defaultConfigFileModuleRef = '@cspell/cspell-bundled-dicts/cspell-default.json';
5
6
  //# sourceMappingURL=constants.js.map
@@ -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.3.0",
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.3.0",
61
+ "@cspell/cspell-pipe": "8.3.0",
62
+ "@cspell/cspell-resolver": "8.3.0",
63
+ "@cspell/cspell-types": "8.3.0",
64
+ "@cspell/dynamic-import": "8.3.0",
65
+ "@cspell/strong-weak-map": "8.3.0",
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.3.0",
70
+ "cspell-dictionary": "8.3.0",
71
+ "cspell-glob": "8.3.0",
72
+ "cspell-grammar": "8.3.0",
73
+ "cspell-io": "8.3.0",
74
+ "cspell-trie-lib": "8.3.0",
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": "019c7ccd326b7fc9e106069ddf6008d5079bbd12"
99
99
  }