cspell-lib 8.0.0 → 8.1.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/CSpellSettingsServer.d.ts +3 -12
- package/dist/esm/Settings/CSpellSettingsServer.js +19 -55
- package/dist/esm/Settings/Controller/configLoader/configLoader.d.ts +55 -126
- package/dist/esm/Settings/Controller/configLoader/configLoader.js +241 -336
- package/dist/esm/Settings/Controller/configLoader/configLocations.d.ts +3 -0
- package/dist/esm/Settings/Controller/configLoader/configLocations.js +57 -0
- package/dist/esm/Settings/Controller/configLoader/configSearch.d.ts +12 -0
- package/dist/esm/Settings/Controller/configLoader/configSearch.js +116 -0
- package/dist/esm/Settings/Controller/configLoader/configToRawSettings.d.ts +5 -0
- package/dist/esm/Settings/Controller/configLoader/configToRawSettings.js +36 -0
- package/dist/esm/Settings/Controller/configLoader/defaultConfigLoader.d.ts +34 -0
- package/dist/esm/Settings/Controller/configLoader/defaultConfigLoader.js +67 -0
- package/dist/esm/Settings/Controller/configLoader/extractImportErrors.d.ts +1 -0
- package/dist/esm/Settings/Controller/configLoader/extractImportErrors.js +4 -0
- package/dist/esm/Settings/Controller/configLoader/index.d.ts +3 -1
- package/dist/esm/Settings/Controller/configLoader/index.js +3 -1
- package/dist/esm/Settings/Controller/configLoader/normalizeRawSettings.d.ts +8 -6
- package/dist/esm/Settings/Controller/configLoader/normalizeRawSettings.js +31 -14
- package/dist/esm/Settings/Controller/configLoader/readSettings.d.ts +6 -5
- package/dist/esm/Settings/Controller/configLoader/readSettings.js +10 -5
- package/dist/esm/Settings/Controller/configLoader/readSettingsFiles.d.ts +1 -1
- package/dist/esm/Settings/Controller/configLoader/readSettingsFiles.js +3 -2
- package/dist/esm/Settings/Controller/pnpLoader.d.ts +4 -12
- package/dist/esm/Settings/Controller/pnpLoader.js +22 -48
- package/dist/esm/Settings/DefaultSettings.d.ts +10 -2
- package/dist/esm/Settings/DefaultSettings.js +33 -22
- package/dist/esm/Settings/DictionarySettings.d.ts +4 -4
- package/dist/esm/Settings/DictionarySettings.js +8 -5
- package/dist/esm/Settings/GlobalSettings.d.ts +6 -3
- package/dist/esm/Settings/GlobalSettings.js +24 -19
- package/dist/esm/Settings/InDocSettings.js +2 -2
- package/dist/esm/Settings/LanguageSettings.js +10 -15
- package/dist/esm/Settings/TextDocumentSettings.js +4 -4
- package/dist/esm/Settings/calcOverrideSettings.d.ts +3 -0
- package/dist/esm/Settings/calcOverrideSettings.js +11 -0
- package/dist/esm/Settings/checkFilenameMatchesGlob.d.ts +10 -0
- package/dist/esm/Settings/checkFilenameMatchesGlob.js +10 -0
- package/dist/esm/Settings/index.d.ts +5 -3
- package/dist/esm/Settings/index.js +5 -3
- package/dist/esm/Settings/link.d.ts +3 -3
- package/dist/esm/Settings/link.js +20 -13
- package/dist/esm/Settings/mergeCache.d.ts +13 -0
- package/dist/esm/Settings/mergeCache.js +22 -0
- package/dist/esm/Settings/mergeList.d.ts +18 -0
- package/dist/esm/Settings/mergeList.js +34 -0
- package/dist/esm/Settings/patterns.js +13 -2
- package/dist/esm/SpellingDictionary/DictionaryController/DictionaryLoader.d.ts +1 -0
- package/dist/esm/SpellingDictionary/DictionaryController/DictionaryLoader.js +40 -38
- package/dist/esm/clearCachedFiles.d.ts +14 -0
- package/dist/esm/clearCachedFiles.js +29 -3
- package/dist/esm/events/events.d.ts +17 -0
- package/dist/esm/events/events.js +28 -0
- package/dist/esm/events/index.d.ts +3 -0
- package/dist/esm/events/index.js +2 -0
- package/dist/esm/getDictionary.js +1 -1
- package/dist/esm/globs/checkFilenameMatchesGlob.d.ts +8 -0
- package/dist/esm/globs/checkFilenameMatchesGlob.js +11 -0
- package/dist/esm/globs/getGlobMatcher.d.ts +4 -0
- package/dist/esm/globs/getGlobMatcher.js +31 -0
- package/dist/esm/index.d.ts +4 -2
- package/dist/esm/index.js +3 -2
- package/dist/esm/perf/index.d.ts +3 -0
- package/dist/esm/perf/index.js +2 -0
- package/dist/esm/perf/perf.d.ts +14 -0
- package/dist/esm/perf/perf.js +27 -0
- package/dist/esm/perf/timer.d.ts +11 -0
- package/dist/esm/perf/timer.js +37 -0
- package/dist/esm/spellCheckFile.d.ts +8 -1
- package/dist/esm/spellCheckFile.js +33 -4
- package/dist/esm/suggestions.js +5 -5
- package/dist/esm/textValidation/ValidateTextOptions.d.ts +5 -0
- package/dist/esm/textValidation/determineTextDocumentSettings.d.ts +1 -1
- package/dist/esm/textValidation/determineTextDocumentSettings.js +2 -2
- package/dist/esm/textValidation/docValidator.d.ts +4 -9
- package/dist/esm/textValidation/docValidator.js +53 -91
- package/dist/esm/trace.js +8 -1
- package/dist/esm/util/AutoResolve.d.ts +21 -4
- package/dist/esm/util/AutoResolve.js +25 -4
- package/dist/esm/util/errors.js +4 -4
- package/dist/esm/util/fileReader.d.ts +3 -3
- package/dist/esm/util/findUp.d.ts +9 -0
- package/dist/esm/util/findUp.js +43 -0
- package/dist/esm/util/resolveFile.d.ts +31 -1
- package/dist/esm/util/resolveFile.js +107 -27
- package/dist/esm/util/url.d.ts +29 -0
- package/dist/esm/util/url.js +91 -0
- package/dist/esm/util/wordSplitter.js +4 -4
- package/package.json +16 -17
- package/dist/esm/util/debugPerf.d.ts +0 -9
- package/dist/esm/util/debugPerf.js +0 -18
- package/dist/esm/util/timer.d.ts +0 -26
- package/dist/esm/util/timer.js +0 -51
|
@@ -1,237 +1,266 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import assert from 'assert';
|
|
2
|
+
import { createReaderWriter, CSpellConfigFileInMemory } from 'cspell-config-lib';
|
|
3
3
|
import { getDefaultCSpellIO } from 'cspell-io';
|
|
4
4
|
import * as path from 'path';
|
|
5
|
+
import { fileURLToPath } from 'url';
|
|
6
|
+
import { onClearCache } from '../../../events/index.js';
|
|
5
7
|
import { createCSpellSettingsInternal as csi } from '../../../Models/CSpellSettingsInternalDef.js';
|
|
6
|
-
import {
|
|
8
|
+
import { AutoResolveCache } from '../../../util/AutoResolve.js';
|
|
7
9
|
import { logError, logWarning } from '../../../util/logger.js';
|
|
8
10
|
import { resolveFile } from '../../../util/resolveFile.js';
|
|
9
|
-
import {
|
|
11
|
+
import { cwdURL, toFilePathOrHref } from '../../../util/url.js';
|
|
10
12
|
import { configSettingsFileVersion0_1, configSettingsFileVersion0_2, currentSettingsFileVersion, ENV_CSPELL_GLOB_ROOT, } from '../../constants.js';
|
|
11
13
|
import { mergeSettings } from '../../CSpellSettingsServer.js';
|
|
12
|
-
import {
|
|
14
|
+
import { getGlobalConfig } from '../../GlobalSettings.js';
|
|
13
15
|
import { ImportError } from '../ImportError.js';
|
|
14
16
|
import { pnpLoader } from '../pnpLoader.js';
|
|
17
|
+
import { searchPlaces } from './configLocations.js';
|
|
18
|
+
import { ConfigSearch } from './configSearch.js';
|
|
19
|
+
import { configToRawSettings } from './configToRawSettings.js';
|
|
15
20
|
import { defaultSettings } from './defaultSettings.js';
|
|
16
|
-
import { normalizeCacheSettings, normalizeDictionaryDefs, normalizeGitignoreRoot, normalizeLanguageSettings, normalizeOverrides,
|
|
21
|
+
import { normalizeCacheSettings, normalizeDictionaryDefs, normalizeGitignoreRoot, normalizeImport, normalizeLanguageSettings, normalizeOverrides, normalizeReporters, normalizeSettingsGlobs, } from './normalizeRawSettings.js';
|
|
17
22
|
import { defaultPnPSettings, normalizePnPSettings } from './PnPSettings.js';
|
|
18
23
|
const supportedCSpellConfigVersions = [configSettingsFileVersion0_2];
|
|
19
24
|
const setOfSupportedConfigVersions = Object.freeze(new Set(supportedCSpellConfigVersions));
|
|
20
25
|
export const sectionCSpell = 'cSpell';
|
|
21
26
|
export const defaultFileName = 'cspell.json';
|
|
22
|
-
const gcl = getDefaultConfigLoaderInternal;
|
|
23
|
-
const CACHE_SIZE_SEARCH_CONFIG = 32;
|
|
24
|
-
/**
|
|
25
|
-
* Logic of the locations:
|
|
26
|
-
* - Support backward compatibility with the VS Code Spell Checker
|
|
27
|
-
* the spell checker extension can only write to `.json` files because
|
|
28
|
-
* it would be too difficult to automatically modify a `.js` or `.cjs` file.
|
|
29
|
-
* - To support `cspell.config.js` in a VS Code environment, have a `cspell.json` import
|
|
30
|
-
* the `cspell.config.js`.
|
|
31
|
-
*/
|
|
32
|
-
const searchPlaces = Object.freeze([
|
|
33
|
-
'package.json',
|
|
34
|
-
// Original locations
|
|
35
|
-
'.cspell.json',
|
|
36
|
-
'cspell.json',
|
|
37
|
-
'.cSpell.json',
|
|
38
|
-
'cSpell.json',
|
|
39
|
-
// Original locations jsonc
|
|
40
|
-
'.cspell.jsonc',
|
|
41
|
-
'cspell.jsonc',
|
|
42
|
-
// Alternate locations
|
|
43
|
-
'.vscode/cspell.json',
|
|
44
|
-
'.vscode/cSpell.json',
|
|
45
|
-
'.vscode/.cspell.json',
|
|
46
|
-
// Standard Locations
|
|
47
|
-
'.cspell.config.json',
|
|
48
|
-
'.cspell.config.jsonc',
|
|
49
|
-
'.cspell.config.yaml',
|
|
50
|
-
'.cspell.config.yml',
|
|
51
|
-
'cspell.config.json',
|
|
52
|
-
'cspell.config.jsonc',
|
|
53
|
-
'cspell.config.yaml',
|
|
54
|
-
'cspell.config.yml',
|
|
55
|
-
'.cspell.yaml',
|
|
56
|
-
'.cspell.yml',
|
|
57
|
-
'cspell.yaml',
|
|
58
|
-
'cspell.yml',
|
|
59
|
-
// Dynamic config is looked for last
|
|
60
|
-
'cspell.config.js',
|
|
61
|
-
'cspell.config.cjs',
|
|
62
|
-
// .config
|
|
63
|
-
'.config/.cspell.json',
|
|
64
|
-
'.config/cspell.json',
|
|
65
|
-
'.config/.cSpell.json',
|
|
66
|
-
'.config/cSpell.json',
|
|
67
|
-
'.config/.cspell.jsonc',
|
|
68
|
-
'.config/cspell.jsonc',
|
|
69
|
-
'.config/cspell.config.json',
|
|
70
|
-
'.config/cspell.config.jsonc',
|
|
71
|
-
'.config/cspell.config.yaml',
|
|
72
|
-
'.config/cspell.config.yml',
|
|
73
|
-
'.config/cspell.yaml',
|
|
74
|
-
'.config/cspell.yml',
|
|
75
|
-
'.config/cspell.config.js',
|
|
76
|
-
'.config/cspell.config.cjs',
|
|
77
|
-
]);
|
|
78
|
-
const cspellCosmiconfig = {
|
|
79
|
-
searchPlaces: searchPlaces.concat(),
|
|
80
|
-
loaders: {
|
|
81
|
-
'.json': parseJson,
|
|
82
|
-
'.jsonc': parseJson,
|
|
83
|
-
},
|
|
84
|
-
};
|
|
85
|
-
function parseJson(_filename, content) {
|
|
86
|
-
return json.parse(content);
|
|
87
|
-
}
|
|
88
|
-
export const defaultConfigFilenames = Object.freeze(searchPlaces.concat());
|
|
89
27
|
let defaultConfigLoader = undefined;
|
|
90
28
|
export class ConfigLoader {
|
|
91
29
|
cspellIO;
|
|
30
|
+
onReady;
|
|
92
31
|
/**
|
|
93
32
|
* Use `createConfigLoader`
|
|
94
33
|
* @param cspellIO - CSpellIO interface for reading files.
|
|
95
34
|
*/
|
|
96
35
|
constructor(cspellIO) {
|
|
97
36
|
this.cspellIO = cspellIO;
|
|
37
|
+
this.cspellConfigFileReaderWriter = createReaderWriter(undefined, undefined, createIO(cspellIO));
|
|
38
|
+
this.onReady = this.getGlobalSettingsAsync().then(() => undefined, (e) => logError(e));
|
|
39
|
+
this.subscribeToEvents();
|
|
98
40
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
cspellConfigExplorerSync = cosmiconfigSync('cspell', cspellCosmiconfig);
|
|
102
|
-
globalSettings;
|
|
103
|
-
readSettings(filename, relativeToOrDefault, defaultValue) {
|
|
104
|
-
// console.log('Read Settings: %o', { filename, relativeToOrDefault });
|
|
105
|
-
const relativeTo = (typeof relativeToOrDefault === 'string' ? relativeToOrDefault : '') || process.cwd();
|
|
106
|
-
defaultValue = defaultValue || (typeof relativeToOrDefault !== 'string' ? relativeToOrDefault : undefined);
|
|
107
|
-
const ref = resolveFilename(filename, relativeTo);
|
|
108
|
-
return this.importSettings(ref, defaultValue, defaultValue || defaultPnPSettings);
|
|
41
|
+
subscribeToEvents() {
|
|
42
|
+
this.toDispose.push(onClearCache(() => this.clearCachedSettingsFiles()));
|
|
109
43
|
}
|
|
44
|
+
cachedConfig = new Map();
|
|
45
|
+
cachedConfigFiles = new Map();
|
|
46
|
+
cachedPendingConfigFile = new AutoResolveCache();
|
|
47
|
+
cachedMergedConfig = new WeakMap();
|
|
48
|
+
globalSettings;
|
|
49
|
+
cspellConfigFileReaderWriter;
|
|
50
|
+
configSearch = new ConfigSearch(searchPlaces);
|
|
51
|
+
toDispose = [];
|
|
110
52
|
async readSettingsAsync(filename, relativeTo, pnpSettings) {
|
|
111
53
|
const ref = resolveFilename(filename, relativeTo || process.cwd());
|
|
112
|
-
|
|
54
|
+
const entry = this.importSettings(ref, pnpSettings || defaultPnPSettings, []);
|
|
55
|
+
return entry.onReady;
|
|
56
|
+
}
|
|
57
|
+
async readConfigFile(filenameOrURL, relativeTo) {
|
|
58
|
+
const ref = resolveFilename(filenameOrURL.toString(), relativeTo || process.cwd());
|
|
59
|
+
const url = this.cspellIO.toFileURL(ref.filename);
|
|
60
|
+
const href = url.href;
|
|
61
|
+
if (ref.error)
|
|
62
|
+
return new ImportError(`Failed to read config file: "${ref.filename}"`, ref.error);
|
|
63
|
+
const cached = this.cachedConfigFiles.get(href);
|
|
64
|
+
if (cached)
|
|
65
|
+
return cached;
|
|
66
|
+
return this.cachedPendingConfigFile.get(href, async () => {
|
|
67
|
+
try {
|
|
68
|
+
const file = await this.cspellConfigFileReaderWriter.readConfig(href);
|
|
69
|
+
this.cachedConfigFiles.set(href, file);
|
|
70
|
+
// validateRawConfigVersion(file);
|
|
71
|
+
return file;
|
|
72
|
+
}
|
|
73
|
+
catch (error) {
|
|
74
|
+
// console.warn('Debug: %o', { href, error });
|
|
75
|
+
return new ImportError(`Failed to read config file: "${ref.filename}"`, error);
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
setTimeout(() => this.cachedPendingConfigFile.delete(href), 1);
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
searchForConfigFileLocation(searchFrom) {
|
|
83
|
+
const url = this.cspellIO.toFileURL(searchFrom || cwdURL());
|
|
84
|
+
return this.configSearch.searchForConfig(url);
|
|
85
|
+
}
|
|
86
|
+
async searchForConfigFile(searchFrom) {
|
|
87
|
+
const location = await this.searchForConfigFileLocation(searchFrom);
|
|
88
|
+
if (!location)
|
|
89
|
+
return undefined;
|
|
90
|
+
const file = await this.readConfigFile(location);
|
|
91
|
+
return file instanceof Error ? undefined : file;
|
|
113
92
|
}
|
|
114
93
|
/**
|
|
115
94
|
*
|
|
116
|
-
* @param searchFrom the directory / file to start searching from.
|
|
95
|
+
* @param searchFrom the directory / file URL to start searching from.
|
|
117
96
|
* @param pnpSettings - related to Using Yarn PNP.
|
|
118
97
|
* @returns the resulting settings
|
|
119
98
|
*/
|
|
120
|
-
searchForConfig(searchFrom, pnpSettings = defaultPnPSettings) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
_searchForConfig(params) {
|
|
126
|
-
// console.log('_searchForConfig: %o', { params, stats: this.searchConfigLRU.stats() });
|
|
127
|
-
return gcl()
|
|
128
|
-
.normalizeSearchForConfigResultAsync(params.searchFrom || process.cwd(), this.cspellConfigExplorer.search(params.searchFrom), params.pnpSettings)
|
|
129
|
-
.then((r) => (r.filepath ? r.config : undefined));
|
|
99
|
+
async searchForConfig(searchFrom, pnpSettings = defaultPnPSettings) {
|
|
100
|
+
const configFile = await this.searchForConfigFile(searchFrom);
|
|
101
|
+
if (!configFile)
|
|
102
|
+
return undefined;
|
|
103
|
+
return this.mergeConfigFileWithImports(configFile, pnpSettings);
|
|
130
104
|
}
|
|
131
105
|
getGlobalSettings() {
|
|
106
|
+
assert(this.globalSettings);
|
|
107
|
+
return this.globalSettings;
|
|
108
|
+
}
|
|
109
|
+
async getGlobalSettingsAsync() {
|
|
132
110
|
if (!this.globalSettings) {
|
|
133
|
-
const
|
|
134
|
-
this.
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
};
|
|
111
|
+
const globalConfFile = await getGlobalConfig();
|
|
112
|
+
const normalized = await this.mergeConfigFileWithImports(globalConfFile, undefined);
|
|
113
|
+
normalized.id ??= 'global_config';
|
|
114
|
+
this.globalSettings = normalized;
|
|
138
115
|
}
|
|
139
116
|
return this.globalSettings;
|
|
140
117
|
}
|
|
141
118
|
clearCachedSettingsFiles() {
|
|
142
|
-
this.searchConfigLRU.clear();
|
|
143
119
|
this.globalSettings = undefined;
|
|
144
|
-
this.
|
|
145
|
-
this.
|
|
146
|
-
this.
|
|
120
|
+
this.cachedConfig.clear();
|
|
121
|
+
this.cachedConfigFiles.clear();
|
|
122
|
+
this.configSearch.clearCache();
|
|
123
|
+
this.cachedPendingConfigFile.clear();
|
|
124
|
+
this.cspellConfigFileReaderWriter.clearCachedFiles();
|
|
125
|
+
this.cachedMergedConfig = new WeakMap();
|
|
147
126
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
if (error) {
|
|
156
|
-
fileRef.error =
|
|
157
|
-
error instanceof ImportError
|
|
158
|
-
? error
|
|
159
|
-
: new ImportError(`Failed to read config file: "${filename}"`, error);
|
|
160
|
-
return { __importRef: fileRef };
|
|
127
|
+
importSettings(fileRef, pnpSettings, backReferences) {
|
|
128
|
+
const url = this.cspellIO.toFileURL(fileRef.filename);
|
|
129
|
+
const cacheKey = url.href;
|
|
130
|
+
const cachedImport = this.cachedConfig.get(cacheKey);
|
|
131
|
+
if (cachedImport) {
|
|
132
|
+
backReferences.forEach((ref) => cachedImport.referencedSet.add(ref));
|
|
133
|
+
return cachedImport;
|
|
161
134
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
135
|
+
if (fileRef.error) {
|
|
136
|
+
const settings = csi({
|
|
137
|
+
__importRef: fileRef,
|
|
138
|
+
source: { name: fileRef.filename, filename: fileRef.filename },
|
|
139
|
+
});
|
|
140
|
+
const importedConfig = {
|
|
141
|
+
href: cacheKey,
|
|
142
|
+
fileRef,
|
|
143
|
+
configFile: undefined,
|
|
144
|
+
settings,
|
|
145
|
+
isReady: true,
|
|
146
|
+
onReady: Promise.resolve(settings),
|
|
147
|
+
onConfigFileReady: Promise.resolve(fileRef.error),
|
|
148
|
+
referencedSet: new Set(backReferences),
|
|
149
|
+
};
|
|
150
|
+
this.cachedConfig.set(cacheKey, importedConfig);
|
|
151
|
+
return importedConfig;
|
|
170
152
|
}
|
|
171
|
-
|
|
172
|
-
fileRef.
|
|
173
|
-
|
|
153
|
+
const source = {
|
|
154
|
+
name: fileRef.filename,
|
|
155
|
+
filename: fileRef.filename,
|
|
156
|
+
};
|
|
157
|
+
const mergeImports = (cfgFile) => {
|
|
158
|
+
if (cfgFile instanceof Error) {
|
|
159
|
+
fileRef.error = cfgFile;
|
|
160
|
+
return csi({ __importRef: fileRef, source });
|
|
161
|
+
}
|
|
162
|
+
return this.mergeConfigFileWithImports(cfgFile, pnpSettings, backReferences);
|
|
163
|
+
};
|
|
164
|
+
const referencedSet = new Set(backReferences);
|
|
165
|
+
const onConfigFileReady = onConfigFileReadyFixUp(this.readConfigFile(fileRef.filename));
|
|
166
|
+
const importedConfig = {
|
|
167
|
+
href: cacheKey,
|
|
168
|
+
fileRef,
|
|
169
|
+
configFile: undefined,
|
|
170
|
+
settings: undefined,
|
|
171
|
+
isReady: false,
|
|
172
|
+
onReady: onReadyFixUp(onConfigFileReady.then(mergeImports)),
|
|
173
|
+
onConfigFileReady,
|
|
174
|
+
referencedSet,
|
|
175
|
+
};
|
|
176
|
+
this.cachedConfig.set(cacheKey, importedConfig);
|
|
177
|
+
return importedConfig;
|
|
178
|
+
async function onReadyFixUp(pSettings) {
|
|
179
|
+
const settings = await pSettings;
|
|
180
|
+
settings.source ??= source;
|
|
181
|
+
settings.__importRef ??= fileRef;
|
|
182
|
+
importedConfig.isReady = true;
|
|
183
|
+
importedConfig.settings = settings;
|
|
184
|
+
return settings;
|
|
185
|
+
}
|
|
186
|
+
async function onConfigFileReadyFixUp(pCfgFile) {
|
|
187
|
+
const cfgFile = await pCfgFile;
|
|
188
|
+
if (cfgFile instanceof Error) {
|
|
189
|
+
importedConfig.fileRef.error = cfgFile;
|
|
190
|
+
return cfgFile;
|
|
191
|
+
}
|
|
192
|
+
source.name = cfgFile.settings.name || source.name;
|
|
193
|
+
importedConfig.configFile = cfgFile;
|
|
194
|
+
return cfgFile;
|
|
174
195
|
}
|
|
175
|
-
s.__importRef = fileRef;
|
|
176
|
-
return s;
|
|
177
196
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
197
|
+
async setupPnp(cfgFile, pnpSettings) {
|
|
198
|
+
if (!pnpSettings?.usePnP || pnpSettings === defaultPnPSettings)
|
|
199
|
+
return;
|
|
200
|
+
if (cfgFile.url.protocol !== 'file:')
|
|
201
|
+
return;
|
|
202
|
+
// Try to load any .pnp files before reading dictionaries or other config files.
|
|
203
|
+
const { usePnP = pnpSettings.usePnP, pnpFiles = pnpSettings.pnpFiles } = cfgFile.settings;
|
|
204
|
+
const pnpSettingsToUse = normalizePnPSettings({ usePnP, pnpFiles });
|
|
205
|
+
const pathToSettingsDir = new URL('.', cfgFile.url);
|
|
206
|
+
await loadPnP(pnpSettingsToUse, pathToSettingsDir);
|
|
207
|
+
}
|
|
208
|
+
mergeConfigFileWithImports(cfgFile, pnpSettings, referencedBy) {
|
|
209
|
+
const cached = this.cachedMergedConfig.get(cfgFile);
|
|
210
|
+
if (cached && cached.pnpSettings === pnpSettings && cached.referencedBy === referencedBy) {
|
|
211
|
+
return cached.result;
|
|
188
212
|
}
|
|
189
|
-
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
213
|
+
// console.warn('missing cache %o', cfgFile.url.href);
|
|
214
|
+
const result = this._mergeConfigFileWithImports(cfgFile, pnpSettings, referencedBy);
|
|
215
|
+
this.cachedMergedConfig.set(cfgFile, { pnpSettings, referencedBy, result });
|
|
216
|
+
return result;
|
|
217
|
+
}
|
|
218
|
+
async _mergeConfigFileWithImports(cfgFile, pnpSettings, referencedBy = []) {
|
|
219
|
+
await this.setupPnp(cfgFile, pnpSettings);
|
|
220
|
+
const href = cfgFile.url.href;
|
|
221
|
+
const referencedSet = new Set(referencedBy);
|
|
222
|
+
const imports = normalizeImport(cfgFile.settings.import);
|
|
223
|
+
const __imports = imports.map((name) => resolveFilename(name, cfgFile.url));
|
|
224
|
+
const toImport = __imports.map((ref) => this.importSettings(ref, pnpSettings, [...referencedBy, href]));
|
|
225
|
+
// Add ourselves to the import sources.
|
|
226
|
+
toImport.forEach((entry) => {
|
|
227
|
+
entry.referencedSet.add(href);
|
|
228
|
+
});
|
|
229
|
+
const pendingImports = toImport.map((entry) => {
|
|
230
|
+
// Detect circular references, return raw settings if circular.
|
|
231
|
+
return referencedSet.has(entry.href)
|
|
232
|
+
? entry.settings || configToRawSettings(entry.configFile)
|
|
233
|
+
: entry.onReady;
|
|
234
|
+
});
|
|
235
|
+
const importSettings = await Promise.all(pendingImports);
|
|
236
|
+
const cfg = this.mergeImports(cfgFile, importSettings);
|
|
237
|
+
return cfg;
|
|
199
238
|
}
|
|
200
239
|
/**
|
|
201
240
|
* normalizeSettings handles correcting all relative paths, anchoring globs, and importing other config files.
|
|
202
241
|
* @param rawSettings - raw configuration settings
|
|
203
242
|
* @param pathToSettingsFile - path to the source file of the configuration settings.
|
|
204
243
|
*/
|
|
205
|
-
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
const
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
const pathToSettingsDir = path.dirname(pathToSettingsFile);
|
|
213
|
-
loadPnPSync(pnpSettingsToUse, toUri(pathToSettingsDir));
|
|
244
|
+
mergeImports(cfgFile, importedSettings) {
|
|
245
|
+
const rawSettings = configToRawSettings(cfgFile);
|
|
246
|
+
const url = cfgFile.url;
|
|
247
|
+
const fileRef = rawSettings.__importRef;
|
|
248
|
+
const source = rawSettings.source;
|
|
249
|
+
assert(fileRef);
|
|
250
|
+
assert(source);
|
|
214
251
|
// Fix up dictionaryDefinitions
|
|
215
252
|
const settings = {
|
|
216
253
|
version: defaultSettings.version,
|
|
217
254
|
...rawSettings,
|
|
218
|
-
|
|
219
|
-
name,
|
|
220
|
-
globRoot: resolveGlobRoot(rawSettings, pathToSettingsFile),
|
|
255
|
+
globRoot: resolveGlobRoot(rawSettings, cfgFile.url),
|
|
221
256
|
languageSettings: normalizeLanguageSettings(rawSettings.languageSettings),
|
|
222
257
|
};
|
|
223
|
-
const
|
|
224
|
-
const
|
|
225
|
-
const
|
|
226
|
-
const
|
|
227
|
-
const
|
|
228
|
-
const
|
|
229
|
-
const normalizedCacheSettings = normalizeCacheSettings(settings, pathToSettingsDir);
|
|
230
|
-
const imports = typeof settings.import === 'string' ? [settings.import] : settings.import || [];
|
|
231
|
-
const source = settings.source || {
|
|
232
|
-
name: settings.name,
|
|
233
|
-
filename: pathToSettingsFile,
|
|
234
|
-
};
|
|
258
|
+
const normalizedDictionaryDefs = normalizeDictionaryDefs(settings, url);
|
|
259
|
+
const normalizedSettingsGlobs = normalizeSettingsGlobs(settings, url);
|
|
260
|
+
const normalizedOverrides = normalizeOverrides(settings, url);
|
|
261
|
+
const normalizedReporters = normalizeReporters(settings, url);
|
|
262
|
+
const normalizedGitignoreRoot = normalizeGitignoreRoot(settings, url);
|
|
263
|
+
const normalizedCacheSettings = normalizeCacheSettings(settings, url);
|
|
235
264
|
const fileSettings = csi({
|
|
236
265
|
...settings,
|
|
237
266
|
source,
|
|
@@ -242,132 +271,37 @@ export class ConfigLoader {
|
|
|
242
271
|
...normalizedGitignoreRoot,
|
|
243
272
|
...normalizedCacheSettings,
|
|
244
273
|
});
|
|
245
|
-
if (!
|
|
274
|
+
if (!importedSettings.length) {
|
|
246
275
|
return fileSettings;
|
|
247
276
|
}
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
.map((ref) => ((ref.referencedBy = [source]), ref))
|
|
251
|
-
.map((ref) => this.importSettings(ref, undefined, pnpSettingsToUse))
|
|
252
|
-
.reduce((a, b) => mergeSettings(a, b));
|
|
253
|
-
const finalizeSettings = mergeSettings(importedSettings, fileSettings);
|
|
277
|
+
const mergedImportedSettings = importedSettings.reduce((a, b) => mergeSettings(a, b));
|
|
278
|
+
const finalizeSettings = mergeSettings(mergedImportedSettings, fileSettings);
|
|
254
279
|
finalizeSettings.name = settings.name || finalizeSettings.name || '';
|
|
255
280
|
finalizeSettings.id = settings.id || finalizeSettings.id || '';
|
|
281
|
+
finalizeSettings.__importRef = fileRef;
|
|
256
282
|
return finalizeSettings;
|
|
257
283
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
constructor(cspellIO) {
|
|
261
|
-
super(cspellIO);
|
|
262
|
-
}
|
|
263
|
-
get _cachedFiles() {
|
|
264
|
-
return this.cachedFiles;
|
|
265
|
-
}
|
|
266
|
-
get _cspellConfigExplorer() {
|
|
267
|
-
return this.cspellConfigExplorer;
|
|
268
|
-
}
|
|
269
|
-
get _cspellConfigExplorerSync() {
|
|
270
|
-
return this.cspellConfigExplorerSync;
|
|
271
|
-
}
|
|
272
|
-
_readConfig = this.readConfig.bind(this);
|
|
273
|
-
_normalizeSettings = this.normalizeSettings.bind(this);
|
|
274
|
-
async normalizeSearchForConfigResultAsync(searchPath, searchResult, pnpSettings) {
|
|
275
|
-
let result;
|
|
276
|
-
try {
|
|
277
|
-
result = (await searchResult) || undefined;
|
|
278
|
-
}
|
|
279
|
-
catch (cause) {
|
|
280
|
-
result = new ImportError(`Failed to find config file at: "${searchPath}"`, cause);
|
|
281
|
-
}
|
|
282
|
-
return this.normalizeSearchForConfigResult(searchPath, result, pnpSettings);
|
|
284
|
+
createCSpellConfigFile(filename, settings) {
|
|
285
|
+
return new CSpellConfigFileInMemory(this.cspellIO.toFileURL(filename), settings);
|
|
283
286
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
return {
|
|
292
|
-
config: cached,
|
|
293
|
-
filepath,
|
|
294
|
-
error,
|
|
295
|
-
};
|
|
287
|
+
dispose() {
|
|
288
|
+
while (this.toDispose.length) {
|
|
289
|
+
try {
|
|
290
|
+
this.toDispose.pop()?.dispose();
|
|
291
|
+
}
|
|
292
|
+
catch (e) {
|
|
293
|
+
logError(e);
|
|
296
294
|
}
|
|
297
|
-
}
|
|
298
|
-
const { config = csi({}) } = result || {};
|
|
299
|
-
const filename = result?.filepath ?? searchPath;
|
|
300
|
-
const importRef = { filename: filename, error };
|
|
301
|
-
const id = [path.basename(path.dirname(filename)), path.basename(filename)].join('/');
|
|
302
|
-
const name = result?.filepath ? id : `Config not found: ${id}`;
|
|
303
|
-
const finalizeSettings = csi({ id, name, __importRef: importRef });
|
|
304
|
-
const settings = { id, ...config };
|
|
305
|
-
cachedFiles().set(filename, finalizeSettings); // add an empty entry to prevent circular references.
|
|
306
|
-
Object.assign(finalizeSettings, this.normalizeSettings(settings, filename, pnpSettings));
|
|
307
|
-
return {
|
|
308
|
-
config: finalizeSettings,
|
|
309
|
-
filepath,
|
|
310
|
-
error,
|
|
311
|
-
};
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
function mergeSourceList(orig, append) {
|
|
315
|
-
const collection = new Map(orig.map((s) => [s.name + (s.filename || ''), s]));
|
|
316
|
-
for (const s of append || []) {
|
|
317
|
-
const key = s.name + (s.filename || '');
|
|
318
|
-
if (!collection.has(key)) {
|
|
319
|
-
collection.set(key, s);
|
|
320
295
|
}
|
|
321
296
|
}
|
|
322
|
-
return [...collection.values()];
|
|
323
297
|
}
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
* @param pnpSettings - related to Using Yarn PNP.
|
|
328
|
-
* @returns the resulting settings
|
|
329
|
-
*/
|
|
330
|
-
export function searchForConfig(searchFrom, pnpSettings = defaultPnPSettings) {
|
|
331
|
-
return gcl().searchForConfig(searchFrom, pnpSettings);
|
|
332
|
-
}
|
|
333
|
-
/**
|
|
334
|
-
*
|
|
335
|
-
* @param searchFrom the directory / file to start searching from.
|
|
336
|
-
* @param pnpSettings - related to Using Yarn PNP.
|
|
337
|
-
* @returns the resulting settings
|
|
338
|
-
* @deprecated
|
|
339
|
-
* @deprecationMessage Use `searchForConfig`. It is very difficult to support Sync files when settings include web requests.
|
|
340
|
-
*/
|
|
341
|
-
export function searchForConfigSync(searchFrom, pnpSettings = defaultPnPSettings) {
|
|
342
|
-
pnpSettings = normalizePnPSettings(pnpSettings);
|
|
343
|
-
let searchResult;
|
|
344
|
-
try {
|
|
345
|
-
searchResult = cspellConfigExplorerSync().search(searchFrom) || undefined;
|
|
298
|
+
class ConfigLoaderInternal extends ConfigLoader {
|
|
299
|
+
constructor(cspellIO) {
|
|
300
|
+
super(cspellIO);
|
|
346
301
|
}
|
|
347
|
-
|
|
348
|
-
|
|
302
|
+
get _cachedFiles() {
|
|
303
|
+
return this.cachedConfig;
|
|
349
304
|
}
|
|
350
|
-
return gcl().normalizeSearchForConfigResult(searchFrom || process.cwd(), searchResult, pnpSettings).config;
|
|
351
|
-
}
|
|
352
|
-
/**
|
|
353
|
-
* Load a CSpell configuration files.
|
|
354
|
-
* @param file - path or package reference to load.
|
|
355
|
-
* @param pnpSettings - PnP settings
|
|
356
|
-
* @returns normalized CSpellSettings
|
|
357
|
-
*/
|
|
358
|
-
export async function loadConfig(file, pnpSettings = defaultPnPSettings) {
|
|
359
|
-
return gcl().readSettingsAsync(file, undefined, pnpSettings);
|
|
360
|
-
}
|
|
361
|
-
/**
|
|
362
|
-
* Load a CSpell configuration files.
|
|
363
|
-
* @param filename - path or package reference to load.
|
|
364
|
-
* @param pnpSettings - PnP settings
|
|
365
|
-
* @returns normalized CSpellSettings
|
|
366
|
-
* @deprecated
|
|
367
|
-
*/
|
|
368
|
-
export function loadConfigSync(filename, pnpSettings = defaultPnPSettings) {
|
|
369
|
-
const pnp = normalizePnPSettings(pnpSettings);
|
|
370
|
-
return gcl().readSettings(filename, pnp);
|
|
371
305
|
}
|
|
372
306
|
export function loadPnP(pnpSettings, searchFrom) {
|
|
373
307
|
if (!pnpSettings.usePnP) {
|
|
@@ -376,39 +310,21 @@ export function loadPnP(pnpSettings, searchFrom) {
|
|
|
376
310
|
const loader = pnpLoader(pnpSettings.pnpFiles);
|
|
377
311
|
return loader.load(searchFrom);
|
|
378
312
|
}
|
|
379
|
-
export function loadPnPSync(pnpSettings, searchFrom) {
|
|
380
|
-
if (!pnpSettings.usePnP) {
|
|
381
|
-
return undefined;
|
|
382
|
-
}
|
|
383
|
-
const loader = pnpLoader(pnpSettings.pnpFiles);
|
|
384
|
-
return loader.loadSync(searchFrom);
|
|
385
|
-
}
|
|
386
|
-
export function readRawSettings(filename, relativeTo) {
|
|
387
|
-
relativeTo = relativeTo || process.cwd();
|
|
388
|
-
const ref = resolveFilename(filename, relativeTo);
|
|
389
|
-
return gcl()._readConfig(ref);
|
|
390
|
-
}
|
|
391
313
|
function resolveFilename(filename, relativeTo) {
|
|
314
|
+
if (filename instanceof URL)
|
|
315
|
+
return { filename: toFilePathOrHref(filename) };
|
|
392
316
|
const r = resolveFile(filename, relativeTo);
|
|
393
317
|
return {
|
|
394
|
-
filename: r.filename,
|
|
318
|
+
filename: r.filename.startsWith('file:/') ? fileURLToPath(r.filename) : r.filename,
|
|
395
319
|
error: r.found ? undefined : new Error(`Failed to resolve file: "${filename}"`),
|
|
396
320
|
};
|
|
397
321
|
}
|
|
398
|
-
export function getGlobalSettings() {
|
|
399
|
-
return gcl().getGlobalSettings();
|
|
400
|
-
}
|
|
401
|
-
export function getCachedFileSize() {
|
|
402
|
-
return cachedFiles().size;
|
|
403
|
-
}
|
|
404
|
-
export function clearCachedSettingsFiles() {
|
|
405
|
-
return gcl().clearCachedSettingsFiles();
|
|
406
|
-
}
|
|
407
322
|
const nestedConfigDirectories = {
|
|
408
323
|
'.vscode': true,
|
|
409
324
|
'.config': true,
|
|
410
325
|
};
|
|
411
|
-
function resolveGlobRoot(settings,
|
|
326
|
+
function resolveGlobRoot(settings, urlSettingsFile) {
|
|
327
|
+
const pathToSettingsFile = fileURLToPath(urlSettingsFile);
|
|
412
328
|
const settingsFileDirRaw = path.dirname(pathToSettingsFile);
|
|
413
329
|
const settingsFileDirName = path.basename(settingsFileDirRaw);
|
|
414
330
|
const isNestedConfig = settingsFileDirName in nestedConfigDirectories;
|
|
@@ -425,36 +341,27 @@ function resolveGlobRoot(settings, pathToSettingsFile) {
|
|
|
425
341
|
const globRoot = rawRoot.startsWith('${cwd}') ? rawRoot : path.resolve(settingsFileDir, rawRoot);
|
|
426
342
|
return globRoot;
|
|
427
343
|
}
|
|
428
|
-
function validationMessage(msg,
|
|
429
|
-
return msg + `\n File: "${
|
|
344
|
+
function validationMessage(msg, url) {
|
|
345
|
+
return msg + `\n File: "${toFilePathOrHref(url)}"`;
|
|
430
346
|
}
|
|
431
|
-
function validateRawConfigVersion(config
|
|
432
|
-
const { version } = config;
|
|
347
|
+
function validateRawConfigVersion(config) {
|
|
348
|
+
const { version } = config.settings;
|
|
433
349
|
if (version === undefined)
|
|
434
350
|
return;
|
|
435
351
|
if (typeof version !== 'string') {
|
|
436
|
-
logError(validationMessage(`Unsupported config file version: "${version}", string expected`,
|
|
352
|
+
logError(validationMessage(`Unsupported config file version: "${version}", string expected`, config.url));
|
|
437
353
|
return;
|
|
438
354
|
}
|
|
439
355
|
if (setOfSupportedConfigVersions.has(version))
|
|
440
356
|
return;
|
|
441
357
|
if (!/^\d+(\.\d+)*$/.test(version)) {
|
|
442
|
-
logError(validationMessage(`Unsupported config file version: "${version}"`,
|
|
358
|
+
logError(validationMessage(`Unsupported config file version: "${version}"`, config.url));
|
|
443
359
|
return;
|
|
444
360
|
}
|
|
445
361
|
const msg = version > currentSettingsFileVersion
|
|
446
362
|
? `Newer config file version found: "${version}". Supported version is "${currentSettingsFileVersion}"`
|
|
447
363
|
: `Legacy config file version found: "${version}", upgrade to "${currentSettingsFileVersion}"`;
|
|
448
|
-
logWarning(validationMessage(msg,
|
|
449
|
-
}
|
|
450
|
-
function validateRawConfigExports(config, fileRef) {
|
|
451
|
-
if (config.default) {
|
|
452
|
-
throw new ImportError(validationMessage('Module `export default` is not supported.\n Use `module.exports =` instead.', fileRef));
|
|
453
|
-
}
|
|
454
|
-
}
|
|
455
|
-
function validateRawConfig(config, fileRef) {
|
|
456
|
-
const validations = [validateRawConfigExports, validateRawConfigVersion];
|
|
457
|
-
validations.forEach((fn) => fn(config, fileRef));
|
|
364
|
+
logWarning(validationMessage(msg, config.url));
|
|
458
365
|
}
|
|
459
366
|
function createConfigLoaderInternal(cspellIO) {
|
|
460
367
|
return new ConfigLoaderInternal(cspellIO ?? getDefaultCSpellIO());
|
|
@@ -462,24 +369,22 @@ function createConfigLoaderInternal(cspellIO) {
|
|
|
462
369
|
export function createConfigLoader(cspellIO) {
|
|
463
370
|
return createConfigLoaderInternal(cspellIO);
|
|
464
371
|
}
|
|
465
|
-
function getDefaultConfigLoaderInternal() {
|
|
372
|
+
export function getDefaultConfigLoaderInternal() {
|
|
466
373
|
if (defaultConfigLoader)
|
|
467
374
|
return defaultConfigLoader;
|
|
468
375
|
return (defaultConfigLoader = createConfigLoaderInternal());
|
|
469
376
|
}
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
return gcl()._cspellConfigExplorerSync;
|
|
377
|
+
function createIO(cspellIO) {
|
|
378
|
+
const readFile = (url) => cspellIO.readFile(url).then((file) => ({ url: file.url, content: file.getText() }));
|
|
379
|
+
const writeFile = (file) => cspellIO.writeFile(file.url, file.content);
|
|
380
|
+
return {
|
|
381
|
+
readFile,
|
|
382
|
+
writeFile,
|
|
383
|
+
};
|
|
478
384
|
}
|
|
479
385
|
export const __testing__ = {
|
|
480
386
|
getDefaultConfigLoaderInternal,
|
|
481
387
|
normalizeCacheSettings,
|
|
482
|
-
validateRawConfigExports,
|
|
483
388
|
validateRawConfigVersion,
|
|
484
389
|
};
|
|
485
390
|
//# sourceMappingURL=configLoader.js.map
|