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.
- package/dist/esm/Settings/Controller/configLoader/configLoader.d.ts +9 -0
- package/dist/esm/Settings/Controller/configLoader/configLoader.js +36 -5
- package/dist/esm/Settings/Controller/configLoader/configSearch.d.ts +9 -1
- package/dist/esm/Settings/Controller/configLoader/configSearch.js +32 -6
- package/dist/esm/Settings/DefaultSettings.js +1 -1
- package/dist/esm/Settings/DictionarySettings.js +2 -2
- package/dist/esm/Settings/constants.d.ts +1 -0
- package/dist/esm/Settings/constants.js +1 -0
- package/dist/esm/SpellingDictionary/DictionaryController/DictionaryLoader.d.ts +3 -1
- package/dist/esm/SpellingDictionary/DictionaryController/DictionaryLoader.js +10 -3
- package/dist/esm/textValidation/docValidator.d.ts +15 -0
- package/dist/esm/textValidation/docValidator.js +34 -0
- package/dist/esm/trace.js +2 -5
- package/dist/esm/util/AutoResolve.d.ts +15 -0
- package/dist/esm/util/AutoResolve.js +53 -0
- package/dist/esm/util/TextRange.d.ts +4 -0
- package/dist/esm/util/simpleCache.d.ts +1 -0
- package/dist/esm/util/simpleCache.js +10 -1
- package/package.json +15 -15
|
@@ -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.
|
|
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
|
-
|
|
144
|
-
this.onReady = this.
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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 () =>
|
|
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
|
|
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
|
-
|
|
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 {
|
|
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 =
|
|
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
|
-
|
|
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
|
|
27
|
+
dictionaryCacheByDef = new AutoResolveWeakWeakCache();
|
|
27
28
|
reader;
|
|
28
|
-
|
|
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
|
-
|
|
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
|
|
@@ -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 =
|
|
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.
|
|
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.
|
|
61
|
-
"@cspell/cspell-pipe": "8.
|
|
62
|
-
"@cspell/cspell-resolver": "8.
|
|
63
|
-
"@cspell/cspell-types": "8.
|
|
64
|
-
"@cspell/dynamic-import": "8.
|
|
65
|
-
"@cspell/strong-weak-map": "8.
|
|
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.
|
|
70
|
-
"cspell-dictionary": "8.
|
|
71
|
-
"cspell-glob": "8.
|
|
72
|
-
"cspell-grammar": "8.
|
|
73
|
-
"cspell-io": "8.
|
|
74
|
-
"cspell-trie-lib": "8.
|
|
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.
|
|
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": "
|
|
98
|
+
"gitHead": "019c7ccd326b7fc9e106069ddf6008d5079bbd12"
|
|
99
99
|
}
|