diff --git a/packages/cspell-io/src/node/file/fetch.test.ts b/packages/cspell-io/src/node/file/fetch.test.ts index f4e37e35374..bdf6dc22157 100644 --- a/packages/cspell-io/src/node/file/fetch.test.ts +++ b/packages/cspell-io/src/node/file/fetch.test.ts @@ -3,19 +3,31 @@ import { describe, expect, test } from 'vitest'; import { fetchHead, fetchURL } from './fetch.js'; // import {} from './_fetch.js'; +const timeout = 20000; + +const testOptions = { timeout }; + describe('fetch', () => { - test('fetch url', async () => { - const url = new URL('https://example.com/'); - const response = await fetch(url); - expect(response.ok).toBe(true); - expect(await response.text()).toMatch('Example Domain'); - }); - - test('fetchURL', async () => { - const url = new URL('https://example.com/'); - const response = await fetchURL(url); - expect(response).toBeInstanceOf(Buffer); - }); + test( + 'fetch url', + async () => { + const url = new URL('https://example.com/'); + const response = await fetch(url); + expect(response.ok).toBe(true); + expect(await response.text()).toMatch('Example Domain'); + }, + testOptions, + ); + + test( + 'fetchURL', + async () => { + const url = new URL('https://example.com/'); + const response = await fetchURL(url); + expect(response).toBeInstanceOf(Buffer); + }, + testOptions, + ); /* test.each` @@ -29,27 +41,35 @@ describe('fetch', () => { // console.log('%o', toObj(response)); expect(response.get('etag')).toEqual(expect.any(String)); expect(Number.parseInt(response.get('content-length') || '', 10)).toBeGreaterThan(0); - }); + }, testOptions); */ test.each` url ${'https://example.com/'} - `('fetchHead $url', async ({ url }) => { - const response = await fetchHead(url); - // console.log('%o', toObj(response)); - expect(response.get('etag')).toEqual(expect.any(String)); - expect(Number.parseInt(response.get('content-length') || '', 10)).toBeGreaterThan(0); - }); + `( + 'fetchHead $url', + async ({ url }) => { + const response = await fetchHead(url); + // console.log('%o', toObj(response)); + expect(response.get('etag')).toEqual(expect.any(String)); + expect(Number.parseInt(response.get('content-length') || '', 10)).toBeGreaterThan(0); + }, + testOptions, + ); test.each` url | expected ${'https://x.example.com/'} | ${'getaddrinfo ENOTFOUND x.example.com'} ${'https://interglot.com/not_found/file.txt'} | ${/URL not found|getaddrinfo EAI_AGAIN/} - `('fetchURL with error', async ({ url, expected }) => { - url = new URL(url); - await expect(fetchURL(url)).rejects.toThrowError(expected); - }); + `( + 'fetchURL with error', + async ({ url, expected }) => { + url = new URL(url); + await expect(fetchURL(url)).rejects.toThrowError(expected); + }, + testOptions, + ); }); // function toObj(m: Iterable<[string, string]>): Record { diff --git a/packages/cspell-lib/api/api.d.ts b/packages/cspell-lib/api/api.d.ts index d7b2a6dc2b1..8688fc8792c 100644 --- a/packages/cspell-lib/api/api.d.ts +++ b/packages/cspell-lib/api/api.d.ts @@ -409,8 +409,8 @@ interface ImportFileRefWithError$1 extends ImportFileRef { * - relative path `./path/to/file` (relative to the current working directory) * - package `@cspell/dict-typescript/cspell-ext.json` */ -declare function readSettings(filename: string): CSpellSettingsI$1; -declare function readSettings(filename: string, defaultValues: CSpellSettingsWST$1): CSpellSettingsI$1; +declare function readSettings(filename: string | URL): Promise; +declare function readSettings(filename: string | URL, pnpSettings: PnPSettingsOptional): Promise; /** * Read / import a cspell configuration file. * @param filename - the path to the file. @@ -420,8 +420,8 @@ declare function readSettings(filename: string, defaultValues: CSpellSettingsWST * - package `@cspell/dict-typescript/cspell-ext.json` searches for node_modules relative to `relativeTo` * @param relativeTo - absolute path to start searching for relative files or node_modules. */ -declare function readSettings(filename: string, relativeTo: string): CSpellSettingsI$1; -declare function readSettings(filename: string, relativeTo: string, defaultValues: CSpellSettingsWST$1): CSpellSettingsI$1; +declare function readSettings(filename: string | URL, relativeTo: string | URL): Promise; +declare function readSettings(filename: string | URL, relativeTo: string | URL, pnpSettings: PnPSettingsOptional): Promise; /** * @@ -429,7 +429,7 @@ declare function readSettings(filename: string, relativeTo: string, defaultValue * @returns combined configuration * @deprecated true */ -declare function readSettingsFiles(filenames: string[]): CSpellSettingsI$1; +declare function readSettingsFiles(filenames: string[]): Promise; type CSpellSettingsWST = AdvancedCSpellSettingsWithSourceTrace; type CSpellSettingsWSTO = OptionalOrUndefined; @@ -466,7 +466,7 @@ interface ConfigurationDependencies { declare function extractDependencies(settings: CSpellSettingsWSTO | CSpellSettingsI): ConfigurationDependencies; declare function getDefaultSettings(useDefaultDictionaries?: boolean): CSpellSettingsInternal; -declare function getDefaultBundledSettings(): CSpellSettingsInternal; +declare function getDefaultBundledSettingsAsync(): Promise; declare function combineTextAndLanguageSettings(settings: CSpellUserSettings, text: string | undefined, languageId: string | string[]): CSpellSettingsInternal; @@ -668,14 +668,6 @@ declare class DocumentValidator { */ constructor(doc: TextDocument, options: DocumentValidatorOptions, settings: CSpellUserSettings); get ready(): boolean; - /** - * Prepare to validate a document. - * This will load all the necessary configuration and dictionaries. - * - * @deprecated - * @deprecationMessage Use the async `prepare` method. - */ - prepareSync(): void; prepare(): Promise; private _prepareAsync; private _updatePrep; @@ -845,7 +837,7 @@ interface DetermineFinalDocumentSettingsResult { * `languageId` - if defined will be used to select appropriate file type dictionaries. * @param settings - The near final settings. Should already be the combination of all configuration files. */ -declare function determineFinalDocumentSettings(document: DocumentWithText, settings: CSpellUserSettings): DetermineFinalDocumentSettingsResult; +declare function determineFinalDocumentSettings(document: DocumentWithText, settings: CSpellUserSettings): Promise; interface TraceResult { word: string; @@ -908,4 +900,4 @@ declare function clearCachedFiles(): Promise; */ declare function getDictionary(settings: CSpellUserSettings): Promise; -export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCachedSettingsFiles, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettings, getDefaultSettings, getDictionary, getGlobalSettings, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, loadPnPSync, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; +export { type CheckTextInfo, type ConfigurationDependencies, type CreateTextDocumentParams, type DetermineFinalDocumentSettingsResult, type Document, DocumentValidator, type DocumentValidatorOptions, ENV_CSPELL_GLOB_ROOT, type ExcludeFilesGlobMap, type ExclusionFunction, exclusionHelper_d as ExclusionHelper, type FeatureFlag, FeatureFlags, ImportError, type ImportFileRefWithError, IncludeExcludeFlag, type IncludeExcludeOptions, index_link_d as Link, type Logger, type SpellCheckFileOptions, type SpellCheckFileResult, SpellingDictionaryLoadError, type SuggestedWord, SuggestionError, type SuggestionOptions, type SuggestionsForWordResult, text_d as Text, type TextDocument, type TextDocumentLine, type TextDocumentRef, type TextInfoItem, type TraceOptions, type TraceResult, UnknownFeatureFlagError, type ValidationIssue, calcOverrideSettings, checkFilenameMatchesGlob, checkText, checkTextDocument, clearCachedFiles, clearCachedSettingsFiles, combineTextAndLanguageSettings, combineTextAndLanguageSettings as constructSettingsForText, createTextDocument, currentSettingsFileVersion, defaultConfigFilenames, defaultFileName, defaultFileName as defaultSettingsFilename, determineFinalDocumentSettings, extractDependencies, extractImportErrors, fileToDocument, fileToTextDocument, finalizeSettings, getCachedFileSize, getDefaultBundledSettingsAsync, getDefaultSettings, getDictionary, getGlobalSettings, getLanguagesForBasename as getLanguageIdsForBaseFilename, getLanguagesForExt, getLogger, getSources, getSystemFeatureFlags, isBinaryFile, isSpellingDictionaryLoadError, loadConfig, loadPnP, loadPnPSync, mergeInDocSettings, mergeSettings, readRawSettings, readSettings, readSettingsFiles, refreshDictionaryCache, resolveFile, searchForConfig, sectionCSpell, setLogger, shouldCheckDocument, spellCheckDocument, spellCheckFile, suggestionsForWord, suggestionsForWords, traceWords, traceWordsAsync, updateTextDocument, validateText }; diff --git a/packages/cspell-lib/src/lib/Settings/CSpellSettingsServer.test.ts b/packages/cspell-lib/src/lib/Settings/CSpellSettingsServer.test.ts index f15d9f00ab6..34b8dbc5fa5 100644 --- a/packages/cspell-lib/src/lib/Settings/CSpellSettingsServer.test.ts +++ b/packages/cspell-lib/src/lib/Settings/CSpellSettingsServer.test.ts @@ -15,7 +15,7 @@ import { readSettingsFiles, } from './Controller/configLoader/index.js'; import { calcOverrideSettings, checkFilenameMatchesGlob, getSources, mergeSettings } from './CSpellSettingsServer.js'; -import { _defaultSettings, getDefaultBundledSettings } from './DefaultSettings.js'; +import { _defaultSettings, getDefaultBundledSettingsAsync } from './DefaultSettings.js'; const samplesDir = pathPackageSamples; const pathSrc = path.join(pathPackageRoot, 'src'); @@ -186,37 +186,37 @@ describe('Validate CSpellSettingsServer', () => { ${rpr('./cspell.config.json')} | ${pathSrc} | ${rpr('./cspell.config.json')} ${'@cspell/cspell-bundled-dicts/cspell-default.json'} | ${pathSrc} | ${require.resolve('@cspell/cspell-bundled-dicts/cspell-default.json')} ${'@cspell/cspell-bundled-dicts/cspell-default.json'} | ${undefined} | ${require.resolve('@cspell/cspell-bundled-dicts/cspell-default.json')} - `('tests readSettings $filename $relativeTo', ({ filename, relativeTo, refFilename }) => { - const settings = readSettings(filename, relativeTo); + `('tests readSettings $filename $relativeTo', async ({ filename, relativeTo, refFilename }) => { + const settings = await readSettings(filename, relativeTo); expect(settings.__importRef?.filename).toBe(refFilename); expect(settings.__importRef?.error).toBeUndefined(); expect(settings.import).toBeUndefined(); }); - test('tests loading project cspell.json file', () => { + test('tests loading project cspell.json file', async () => { const filename = path.join(pathPackageSamples, 'linked/cspell-missing.json'); - const settings = readSettings(filename); + const settings = await readSettings(filename); expect(Object.keys(settings)).not.toHaveLength(0); expect(settings.words).toBeUndefined(); }); - test('tests loading a cSpell.json file', () => { + test('tests loading a cSpell.json file', async () => { const filename = path.join(pathPackageSamples, 'linked/cspell-import.json'); - const settings = readSettings(filename); + const settings = await readSettings(filename); expect(Object.keys(settings)).not.toHaveLength(0); expect(settings.words).toEqual(expect.arrayContaining(['import'])); }); - test('readSettingsFiles cSpell.json', () => { + test('readSettingsFiles cSpell.json', async () => { const filename = path.join(pathPackageSamples, 'linked/cspell-import.json'); - const settings = readSettingsFiles([filename]); + const settings = await readSettingsFiles([filename]); expect(Object.keys(settings)).not.toHaveLength(0); expect(settings.words).toEqual(expect.arrayContaining(['import'])); }); - test('tests loading a cSpell.json with multiple imports file', () => { + test('tests loading a cSpell.json with multiple imports file', async () => { const filename = path.join(pathPackageSamples, 'linked/cspell-imports.json'); - const settings = readSettings(filename); + const settings = await readSettings(filename); expect(Object.keys(settings)).not.toHaveLength(0); expect(settings.words).toEqual(expect.arrayContaining(['import'])); expect(settings.words).toEqual(expect.arrayContaining(['imports'])); @@ -224,9 +224,9 @@ describe('Validate CSpellSettingsServer', () => { expect(settings.words).toEqual(expect.arrayContaining(['leuk'])); }); - test('tests loading a cSpell.json with a missing import file', () => { + test('tests loading a cSpell.json with a missing import file', async () => { const filename = path.join(pathPackageSamples, 'linked/cspell-import-missing.json'); - const settings = readSettings(filename); + const settings = await readSettings(filename); expect(settings.__importRef?.filename).toBe(path.resolve(filename)); expect(settings.__imports?.size).toBe(2); const errors = extractImportErrors(settings); @@ -237,22 +237,22 @@ describe('Validate CSpellSettingsServer', () => { expect(errors.map((ref) => ref.error.toString())).toContainEqual(expect.stringMatching('Failed to read')); }); - test('makes sure global settings is an object', () => { + test('makes sure global settings is an object', async () => { const settings = getGlobalSettings(); expect(Object.keys(settings)).not.toHaveLength(0); - const merged = mergeSettings(getDefaultBundledSettings(), getGlobalSettings()); + const merged = mergeSettings(await getDefaultBundledSettingsAsync(), getGlobalSettings()); expect(Object.keys(merged)).not.toHaveLength(0); }); - test('verify clearing the file cache works', () => { - mergeSettings(getDefaultBundledSettings(), getGlobalSettings()); + test('verify clearing the file cache works', async () => { + mergeSettings(await getDefaultBundledSettingsAsync(), getGlobalSettings()); expect(getCachedFileSize()).toBeGreaterThan(0); clearCachedSettingsFiles(); expect(getCachedFileSize()).toBe(0); }); - test('the loaded defaults contain expected settings', () => { - const settings = getDefaultBundledSettings(); + test('the loaded defaults contain expected settings', async () => { + const settings = await getDefaultBundledSettingsAsync(); const sources = getSources(settings); const sourceNames = sources.map((s) => s.name || '?'); expect(sourceNames).toEqual(expect.arrayContaining([_defaultSettings.name])); @@ -260,7 +260,7 @@ describe('Validate CSpellSettingsServer', () => { test('loading circular imports (readSettings)', async () => { const configFile = path.join(samplesDir, 'linked/cspell.circularA.json'); - const config = readSettings(configFile); + const config = await readSettings(configFile); expect(config?.ignorePaths).toEqual( expect.arrayContaining([ { diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts index 22dcd5f3fe3..a84bc405a4a 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.test.ts @@ -13,7 +13,7 @@ import * as URI from '../../../util/Uri.js'; import { currentSettingsFileVersion, ENV_CSPELL_GLOB_ROOT } from '../../constants.js'; import type { ImportFileRefWithError } from '../../CSpellSettingsServer.js'; import { extractDependencies, getSources, mergeSettings } from '../../CSpellSettingsServer.js'; -import { _defaultSettings, getDefaultBundledSettings } from '../../DefaultSettings.js'; +import { _defaultSettings, getDefaultBundledSettingsAsync } from '../../DefaultSettings.js'; import { __testing__ as __configLoader_testing__, clearCachedSettingsFiles, @@ -64,37 +64,37 @@ describe('Validate CSpellSettingsServer', () => { ${rp('cspell.config.json')} | ${rp('src')} | ${rp('cspell.config.json')} ${'@cspell/cspell-bundled-dicts/cspell-default.json'} | ${rp()} | ${require.resolve('@cspell/cspell-bundled-dicts/cspell-default.json')} ${'@cspell/cspell-bundled-dicts/cspell-default.json'} | ${undefined} | ${require.resolve('@cspell/cspell-bundled-dicts/cspell-default.json')} - `('tests readSettings $filename $relativeTo', ({ filename, relativeTo, refFilename }) => { - const settings = readSettings(filename, relativeTo); + `('tests readSettings $filename $relativeTo', async ({ filename, relativeTo, refFilename }) => { + const settings = await readSettings(filename, relativeTo); expect(settings.__importRef?.filename).toBe(refFilename); expect(settings.__importRef?.error).toBeUndefined(); expect(settings.import).toBeUndefined(); }); - test('tests loading project cspell.json file', () => { + test('tests loading project cspell.json file', async () => { const filename = path.join(samplesDir, 'linked/cspell-missing.json'); - const settings = readSettings(filename); + const settings = await readSettings(filename); expect(Object.keys(settings)).not.toHaveLength(0); expect(settings.words).toBeUndefined(); }); - test('tests loading a cSpell.json file', () => { + test('tests loading a cSpell.json file', async () => { const filename = path.join(samplesDir, 'linked/cspell-import.json'); - const settings = readSettings(filename); + const settings = await readSettings(filename); expect(Object.keys(settings)).not.toHaveLength(0); expect(settings.words).toEqual(expect.arrayContaining(['import'])); }); - test('readSettingsFiles cSpell.json', () => { + test('readSettingsFiles cSpell.json', async () => { const filename = path.join(samplesDir, 'linked/cspell-import.json'); - const settings = readSettingsFiles([filename]); + const settings = await readSettingsFiles([filename]); expect(Object.keys(settings)).not.toHaveLength(0); expect(settings.words).toEqual(expect.arrayContaining(['import'])); }); - test('tests loading a cSpell.json with multiple imports file', () => { + test('tests loading a cSpell.json with multiple imports file', async () => { const filename = path.join(samplesDir, 'linked/cspell-imports.json'); - const settings = readSettings(filename); + const settings = await readSettings(filename); expect(Object.keys(settings)).not.toHaveLength(0); expect(settings.words).toEqual(expect.arrayContaining(['import'])); expect(settings.words).toEqual(expect.arrayContaining(['imports'])); @@ -102,9 +102,9 @@ describe('Validate CSpellSettingsServer', () => { expect(settings.words).toEqual(expect.arrayContaining(['leuk'])); }); - test('tests loading a cSpell.json with a missing import file', () => { + test('tests loading a cSpell.json with a missing import file', async () => { const filename = path.join(samplesDir, 'linked/cspell-import-missing.json'); - const settings = readSettings(filename); + const settings = await readSettings(filename); expect(settings.__importRef?.filename).toBe(path.resolve(filename)); expect(settings.__imports?.size).toBe(2); const errors = extractImportErrors(settings); @@ -115,22 +115,22 @@ describe('Validate CSpellSettingsServer', () => { expect(errors.map((ref) => ref.error.toString())).toContainEqual(expect.stringMatching('Failed to read')); }); - test('makes sure global settings is an object', () => { + test('makes sure global settings is an object', async () => { const settings = getGlobalSettings(); expect(Object.keys(settings)).not.toHaveLength(0); - const merged = mergeSettings(getDefaultBundledSettings(), getGlobalSettings()); + const merged = mergeSettings(await getDefaultBundledSettingsAsync(), getGlobalSettings()); expect(Object.keys(merged)).not.toHaveLength(0); }); - test('verify clearing the file cache works', () => { - mergeSettings(getDefaultBundledSettings(), getGlobalSettings()); + test('verify clearing the file cache works', async () => { + mergeSettings(await getDefaultBundledSettingsAsync(), getGlobalSettings()); expect(getCachedFileSize()).toBeGreaterThan(0); clearCachedSettingsFiles(); expect(getCachedFileSize()).toBe(0); }); - test('the loaded defaults contain expected settings', () => { - const settings = getDefaultBundledSettings(); + test('the loaded defaults contain expected settings', async () => { + const settings = await getDefaultBundledSettingsAsync(); const sources = getSources(settings); const sourceNames = sources.map((s) => s.name || '?'); expect(sourceNames).toEqual(expect.arrayContaining([_defaultSettings.name])); @@ -138,7 +138,7 @@ describe('Validate CSpellSettingsServer', () => { test('loading circular imports (readSettings)', async () => { const configFile = path.join(samplesDir, 'linked/cspell.circularA.json'); - const config = readSettings(configFile); + const config = await readSettings(configFile); expect(config?.ignorePaths).toEqual( expect.arrayContaining([ { @@ -288,7 +288,7 @@ describe('Validate Glob resolution', () => { test('globs from config file (readSettings)', async () => { const configFile = path.join(rootCspellLib, 'cspell.config.json'); - const config = readSettings(configFile); + const config = await readSettings(configFile); expect(config?.ignorePaths).toEqual( expect.arrayContaining([ { @@ -599,8 +599,8 @@ describe('Validate Dependencies', () => { test.each` filename | relativeTo | expected ${rp('cspell.config.json')} | ${undefined} | ${{ configFiles: [rr('cspell.json'), rp('cspell.config.json')], dictionaryFiles: [rr('cspell-dict.txt'), rr('cspell-ignore-words.txt')] }} - `('tests readSettings $filename $relativeTo', ({ filename, relativeTo, expected }) => { - const settings = readSettings(filename, relativeTo); + `('tests readSettings $filename $relativeTo', async ({ filename, relativeTo, expected }) => { + const settings = await readSettings(filename, relativeTo); const dependencies = extractDependencies(settings); expect(dependencies).toEqual(expected); }); diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts index 40eb71c20c7..645042c5872 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/configLoader.ts @@ -177,8 +177,8 @@ export class ConfigLoader { } public async readSettingsAsync( - filename: string, - relativeTo?: string, + filename: string | URL, + relativeTo?: string | URL, pnpSettings?: PnPSettingsOptional, ): Promise { const ref = resolveFilename(filename, relativeTo || process.cwd()); @@ -584,7 +584,8 @@ function toURL(filename: string | URL | Uri): URL { return new URL(toUri(filename).toString()); } -function resolveFilename(filename: string, relativeTo: string | URL): ImportFileRef { +function resolveFilename(filename: string | URL, relativeTo: string | URL): ImportFileRef { + if (filename instanceof URL) return { filename: filename.href }; const r = resolveFile(filename, relativeTo); return { diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettings.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettings.ts index 59ff5b60bcc..7dfcfc63feb 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettings.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettings.ts @@ -1,5 +1,6 @@ import { getDefaultConfigLoader } from './configLoader.js'; -import type { CSpellSettingsI, CSpellSettingsWST } from './types.js'; +import type { PnPSettingsOptional } from './PnPSettings.js'; +import type { CSpellSettingsI } from './types.js'; /** * Read / import a cspell configuration file. @@ -9,8 +10,8 @@ import type { CSpellSettingsI, CSpellSettingsWST } from './types.js'; * - relative path `./path/to/file` (relative to the current working directory) * - package `@cspell/dict-typescript/cspell-ext.json` */ -export function readSettings(filename: string): CSpellSettingsI; -export function readSettings(filename: string, defaultValues: CSpellSettingsWST): CSpellSettingsI; +export function readSettings(filename: string | URL): Promise; +export function readSettings(filename: string | URL, pnpSettings: PnPSettingsOptional): Promise; /** * Read / import a cspell configuration file. * @param filename - the path to the file. @@ -20,15 +21,24 @@ export function readSettings(filename: string, defaultValues: CSpellSettingsWST) * - package `@cspell/dict-typescript/cspell-ext.json` searches for node_modules relative to `relativeTo` * @param relativeTo - absolute path to start searching for relative files or node_modules. */ -export function readSettings(filename: string, relativeTo: string): CSpellSettingsI; -export function readSettings(filename: string, relativeTo: string, defaultValues: CSpellSettingsWST): CSpellSettingsI; +export function readSettings(filename: string | URL, relativeTo: string | URL): Promise; export function readSettings( - filename: string, - relativeToOrDefault?: CSpellSettingsWST | string, - defaultValue?: CSpellSettingsWST, -): CSpellSettingsI { + filename: string | URL, + relativeTo: string | URL, + pnpSettings: PnPSettingsOptional, +): Promise; +export function readSettings( + filename: string | URL, + relativeToOrPnP?: PnPSettingsOptional | string | URL, + pnpSettings?: PnPSettingsOptional, +): Promise { const loader = getDefaultConfigLoader(); - if (typeof relativeToOrDefault !== 'string' || defaultValue === undefined) - return loader.readSettings(filename, relativeToOrDefault); - return loader.readSettings(filename, relativeToOrDefault, defaultValue); + const relativeTo = + typeof relativeToOrPnP === 'string' || relativeToOrPnP instanceof URL ? relativeToOrPnP : undefined; + const pnp = pnpSettings + ? pnpSettings + : !(typeof relativeToOrPnP === 'string' || relativeToOrPnP instanceof URL) + ? relativeToOrPnP + : undefined; + return loader.readSettingsAsync(filename, relativeTo, pnp); } diff --git a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettingsFiles.ts b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettingsFiles.ts index 28393c147cb..fe33210bb78 100644 --- a/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettingsFiles.ts +++ b/packages/cspell-lib/src/lib/Settings/Controller/configLoader/readSettingsFiles.ts @@ -10,6 +10,7 @@ import type { CSpellSettingsI } from './types.js'; * @deprecated true */ -export function readSettingsFiles(filenames: string[]): CSpellSettingsI { - return filenames.map((filename) => readSettings(filename)).reduce((a, b) => mergeSettings(a, b), defaultSettings); +export async function readSettingsFiles(filenames: string[]): Promise { + const settings = await Promise.all(filenames.map((filename) => readSettings(filename))); + return settings.reduce((a, b) => mergeSettings(a, b), defaultSettings); } diff --git a/packages/cspell-lib/src/lib/Settings/DefaultSettings.test.ts b/packages/cspell-lib/src/lib/Settings/DefaultSettings.test.ts index 94d02f944e3..b57de4659cf 100644 --- a/packages/cspell-lib/src/lib/Settings/DefaultSettings.test.ts +++ b/packages/cspell-lib/src/lib/Settings/DefaultSettings.test.ts @@ -8,12 +8,14 @@ describe('Validate Default Settings', () => { expect(df.name).toBe('Static Defaults'); }); - test('tests the default setting file is loaded', () => { - const defaultSetting = DefaultSettings.getDefaultBundledSettings(); + test('tests the default setting file is loaded', async () => { + const defaultSetting = await DefaultSettings.getDefaultBundledSettingsAsync(); expect(defaultSetting.name).toBe('cspell default settings'); }); - test('default', () => { - expect(DefaultSettings.getDefaultBundledSettings()).toEqual(DefaultSettings.getDefaultSettings(undefined)); + test('default', async () => { + expect(await DefaultSettings.getDefaultBundledSettingsAsync()).toEqual( + DefaultSettings.getDefaultSettings(undefined), + ); }); }); diff --git a/packages/cspell-lib/src/lib/Settings/DefaultSettings.ts b/packages/cspell-lib/src/lib/Settings/DefaultSettings.ts index 7024cbbd894..0ac3ddcbaa9 100644 --- a/packages/cspell-lib/src/lib/Settings/DefaultSettings.ts +++ b/packages/cspell-lib/src/lib/Settings/DefaultSettings.ts @@ -1,3 +1,5 @@ +import assert from 'node:assert'; + import type { PredefinedPatterns, RegExpPatternDefinition } from '@cspell/cspell-types'; import { parsers } from 'cspell-grammar'; @@ -145,25 +147,6 @@ export const _defaultSettings: Readonly = Object.freeze( }), ); -const getSettings = (function () { - let settings: CSpellSettingsInternal | undefined = undefined; - return function (useDefaultDictionaries: boolean) { - if (!useDefaultDictionaries) { - return _defaultSettingsBasis; - } - if (!settings) { - const jsonSettings = readSettings(defaultConfigFile); - settings = mergeSettings(_defaultSettings, jsonSettings); - if (jsonSettings.name !== undefined) { - settings.name = jsonSettings.name; - } else { - delete settings.name; - } - } - return settings; - }; -})(); - function resolveConfigModule(configModuleName: string) { return resolveFile(configModuleName, srcDirectory).filename; } @@ -179,10 +162,61 @@ function normalizePattern(pat: RegExpPatternDefinition): RegExpPatternDefinition }; } +class DefaultSettingsLoader { + settings: CSpellSettingsInternal | undefined = undefined; + pending: Promise | undefined = undefined; + private _ready = false; + + constructor() { + // start loading. + this.getDefaultSettingsAsync().catch(() => undefined); + } + + getDefaultSettings(useDefaultDictionaries = true): CSpellSettingsInternal { + if (!useDefaultDictionaries) { + return _defaultSettingsBasis; + } + assert(this.settings); + return this.settings; + } + + getDefaultSettingsAsync(useDefaultDictionaries = true): Promise { + if (!useDefaultDictionaries) { + return Promise.resolve(_defaultSettingsBasis); + } + if (this.settings) return Promise.resolve(this.settings); + if (this.pending) return this.pending; + + this.pending = (async () => { + const jsonSettings = await readSettings(defaultConfigFile); + this.settings = mergeSettings(_defaultSettings, jsonSettings); + if (jsonSettings.name !== undefined) { + this.settings.name = jsonSettings.name; + } else { + delete this.settings.name; + } + return this.settings; + })(); + return this.pending; + } + + ready(): boolean { + return this._ready; + } + + async onReady(): Promise { + await this.getDefaultSettingsAsync(); + this._ready = true; + return undefined; + } +} + +export const defaultSettingsLoader = new DefaultSettingsLoader(); + export function getDefaultSettings(useDefaultDictionaries = true): CSpellSettingsInternal { - return getSettings(useDefaultDictionaries); + return defaultSettingsLoader.getDefaultSettings(useDefaultDictionaries); } -export function getDefaultBundledSettings(): CSpellSettingsInternal { - return getDefaultSettings(); +export function getDefaultBundledSettingsAsync(): Promise { + return defaultSettingsLoader.getDefaultSettingsAsync(); } diff --git a/packages/cspell-lib/src/lib/Settings/DictionarySettings.test.ts b/packages/cspell-lib/src/lib/Settings/DictionarySettings.test.ts index 026e9b00a29..0a94954e133 100644 --- a/packages/cspell-lib/src/lib/Settings/DictionarySettings.test.ts +++ b/packages/cspell-lib/src/lib/Settings/DictionarySettings.test.ts @@ -7,11 +7,11 @@ import { describe, expect, test } from 'vitest'; import { isDictionaryDefinitionInlineInternal } from '../Models/CSpellSettingsInternalDef.js'; import { isDefined } from '../util/util.js'; -import { getDefaultBundledSettings } from './DefaultSettings.js'; +import { getDefaultBundledSettingsAsync } from './DefaultSettings.js'; import { createDictionaryReferenceCollection as createRefCol } from './DictionaryReferenceCollection.js'; import * as DictSettings from './DictionarySettings.js'; -const defaultSettings = getDefaultBundledSettings(); +const defaultSettings = await getDefaultBundledSettingsAsync(); const oc = expect.objectContaining; describe('Validate DictionarySettings', () => { diff --git a/packages/cspell-lib/src/lib/Settings/LanguageSettings.test.ts b/packages/cspell-lib/src/lib/Settings/LanguageSettings.test.ts index 42b28819030..c6a720512e1 100644 --- a/packages/cspell-lib/src/lib/Settings/LanguageSettings.test.ts +++ b/packages/cspell-lib/src/lib/Settings/LanguageSettings.test.ts @@ -3,7 +3,7 @@ import { describe, expect, test } from 'vitest'; import { getGlobalSettings } from './Controller/configLoader/index.js'; import { mergeSettings } from './CSpellSettingsServer.js'; -import { getDefaultBundledSettings } from './DefaultSettings.js'; +import { getDefaultBundledSettingsAsync } from './DefaultSettings.js'; import * as LS from './LanguageSettings.js'; import { calcSettingsForLanguage, calcUserSettingsForLanguage } from './LanguageSettings.js'; @@ -26,12 +26,12 @@ const extraSettings: CSpellUserSettings = { ], }; -const defaultSettings = getDefaultBundledSettings(); +const defaultSettings = await getDefaultBundledSettingsAsync(); const defaultLanguageSettings = defaultSettings.languageSettings; describe('Validate LanguageSettings', () => { - test('tests merging language settings', () => { - const defaultSettings = getDefaultBundledSettings(); + test('tests merging language settings', async () => { + const defaultSettings = await getDefaultBundledSettingsAsync(); const languageSettings = defaultSettings.languageSettings || []; const sPython = calcSettingsForLanguage(languageSettings, 'python', 'en'); expect(sPython.allowCompoundWords).toBeUndefined(); @@ -99,8 +99,8 @@ describe('Validate LanguageSettings', () => { }, ); - test('merged settings with global', () => { - const merged = mergeSettings(getDefaultBundledSettings(), getGlobalSettings()); + test('merged settings with global', async () => { + const merged = mergeSettings(await getDefaultBundledSettingsAsync(), getGlobalSettings()); const sPHP = calcSettingsForLanguage(merged.languageSettings || [], 'php', 'en'); expect(Object.keys(sPHP)).not.toHaveLength(0); }); diff --git a/packages/cspell-lib/src/lib/Settings/index.ts b/packages/cspell-lib/src/lib/Settings/index.ts index ba0b6c5984c..538ce513b62 100644 --- a/packages/cspell-lib/src/lib/Settings/index.ts +++ b/packages/cspell-lib/src/lib/Settings/index.ts @@ -26,4 +26,4 @@ export { mergeInDocSettings, mergeSettings, } from './CSpellSettingsServer.js'; -export { getDefaultBundledSettings, getDefaultSettings } from './DefaultSettings.js'; +export { defaultSettingsLoader, getDefaultBundledSettingsAsync, getDefaultSettings } from './DefaultSettings.js'; diff --git a/packages/cspell-lib/src/lib/SpellingDictionary/Dictionaries.test.ts b/packages/cspell-lib/src/lib/SpellingDictionary/Dictionaries.test.ts index 9ee4d0f9f9e..1402c14720c 100644 --- a/packages/cspell-lib/src/lib/SpellingDictionary/Dictionaries.test.ts +++ b/packages/cspell-lib/src/lib/SpellingDictionary/Dictionaries.test.ts @@ -7,7 +7,7 @@ import { pathPackageRoot } from '../../test-util/test.locations.cjs'; import { createCSpellSettingsInternal as csi } from '../Models/CSpellSettingsInternalDef.js'; import { createDictionaryReferenceCollection } from '../Settings/DictionaryReferenceCollection.js'; import { filterDictDefsToLoad, mapDictDefToInternal } from '../Settings/DictionarySettings.js'; -import { getDefaultBundledSettings, loadConfig } from '../Settings/index.js'; +import { getDefaultBundledSettingsAsync, loadConfig } from '../Settings/index.js'; import * as Dictionaries from './Dictionaries.js'; import { isSpellingDictionaryLoadError } from './SpellingDictionaryError.js'; @@ -51,7 +51,7 @@ describe('Validate getDictionary', () => { ${'snarf'} | ${ignoreCaseTrue} | ${false} `('tests that userWords are included in the dictionary $word', async ({ word, opts, expected }) => { const settings = csi({ - ...getDefaultBundledSettings(), + ...(await getDefaultBundledSettingsAsync()), dictionaries: [], words: ['one', 'two', 'three', 'café', '!snarf'], userWords: ['four', 'five', 'six', 'Rhône'], @@ -94,7 +94,7 @@ describe('Validate getDictionary', () => { ${'colour'} | ${{ found: 'colour', forbidden: true, noSuggest: false }} `('find words $word', async ({ word, expected }) => { const settings = csi({ - ...getDefaultBundledSettings(), + ...(await getDefaultBundledSettingsAsync()), noSuggestDictionaries: ['companies'], words: ['one', 'two', 'three', 'café', '!snarf'], userWords: ['four', 'five', 'six', 'Rhône'], @@ -123,7 +123,7 @@ describe('Validate getDictionary', () => { ${'cafe'} | ${ignoreCaseTrue} | ${true} `('Case sensitive "$word" $opts', async ({ word, opts, expected }) => { const settings = { - ...getDefaultBundledSettings(), + ...(await getDefaultBundledSettingsAsync()), dictionaries: [], words: ['one', 'two', 'three', 'café'], userWords: ['four', 'five', 'six', 'Rhône'], @@ -195,7 +195,7 @@ describe('Validate Refresh', () => { const tempDictPathNotFound = tempPath('not-found.txt'); await mkdirp(path.dirname(tempDictPath)); await fs.writeFile(tempDictPath, 'one\ntwo\nthree\n'); - const settings = getDefaultBundledSettings(); + const settings = await getDefaultBundledSettingsAsync(); const defs = (settings.dictionaryDefinitions || []).concat([ di({ name: 'temp', path: tempDictPath }, __filename), di({ name: 'not_found', path: tempDictPathNotFound }, __filename), @@ -242,7 +242,7 @@ describe('Validate Refresh', () => { const tempDictPath = tempPath('words_sync.txt'); await mkdirp(path.dirname(tempDictPath)); await fs.writeFile(tempDictPath, 'one\ntwo\nthree\n'); - const settings = getDefaultBundledSettings(); + const settings = await getDefaultBundledSettingsAsync(); const defs = (settings.dictionaryDefinitions || []).concat([ di({ name: 'temp', path: tempDictPath }, __filename), ]); diff --git a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap index e9e2fce4845..c5b29c819f1 100644 --- a/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap +++ b/packages/cspell-lib/src/lib/__snapshots__/index.test.ts.snap @@ -204,7 +204,7 @@ exports[`Validate the cspell API > Verify API exports 1`] = ` "fileToTextDocument": [Function], "finalizeSettings": [Function], "getCachedFileSize": [Function], - "getDefaultBundledSettings": [Function], + "getDefaultBundledSettingsAsync": [Function], "getDefaultSettings": [Function], "getDictionary": [Function], "getGlobalSettings": [Function], diff --git a/packages/cspell-lib/src/lib/index.test.ts b/packages/cspell-lib/src/lib/index.test.ts index 926719b0de2..b3cb0fadf48 100644 --- a/packages/cspell-lib/src/lib/index.test.ts +++ b/packages/cspell-lib/src/lib/index.test.ts @@ -3,10 +3,10 @@ import { describe, expect, test } from 'vitest'; import * as cspell from './index.js'; describe('Validate the cspell API', () => { - test('Tests the default configuration', () => { + test('Tests the default configuration', async () => { const ext = '.json'; const languageIds = cspell.getLanguagesForExt(ext); - const settings = cspell.getDefaultBundledSettings(); + const settings = await cspell.getDefaultBundledSettingsAsync(); // cspell:ignore jansons const text = '{ "name": "Jansons"}'; const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); diff --git a/packages/cspell-lib/src/lib/index.ts b/packages/cspell-lib/src/lib/index.ts index 11e550e0ad0..e7574033b6d 100644 --- a/packages/cspell-lib/src/lib/index.ts +++ b/packages/cspell-lib/src/lib/index.ts @@ -27,7 +27,7 @@ export { extractImportErrors, finalizeSettings, getCachedFileSize, - getDefaultBundledSettings, + getDefaultBundledSettingsAsync, getDefaultSettings, getGlobalSettings, getSources, diff --git a/packages/cspell-lib/src/lib/spellCheckFile.test.ts b/packages/cspell-lib/src/lib/spellCheckFile.test.ts index 2858f9af5e7..a1d1bbdecbf 100644 --- a/packages/cspell-lib/src/lib/spellCheckFile.test.ts +++ b/packages/cspell-lib/src/lib/spellCheckFile.test.ts @@ -73,13 +73,16 @@ describe('Validate Determine settings', () => { ${doc(u('README.md'), '# README\n \x63spell:locale fr', undefined, 'en')} | ${{}} | ${{ languageId: 'markdown', language: 'fr' }} | ${'In doc locale wins'} ${doc(u('README.md'), '# README\n')} | ${{ language: 'fr' }} | ${{ languageId: 'markdown', language: 'fr' }} | ${'Language from settings'} ${doc(u('README.md'), '# README\n', undefined, 'en')} | ${{ language: 'fr' }} | ${{ languageId: 'markdown', language: 'en' }} | ${'passed with doc'} - `('determineFinalDocumentSettings($document, $settings) $expected $comment', ({ document, settings, expected }) => { - const settingsResult = sanitizeSettings(determineFinalDocumentSettings(document, settings).settings, [ - 'languageId', - 'language', - ]); - expect(settingsResult).toEqual(expect.objectContaining(expected)); - }); + `( + 'determineFinalDocumentSettings($document, $settings) $expected $comment', + async ({ document, settings, expected }) => { + const settingsResult = sanitizeSettings( + (await determineFinalDocumentSettings(document, settings)).settings, + ['languageId', 'language'], + ); + expect(settingsResult).toEqual(expect.objectContaining(expected)); + }, + ); }); describe('Validate Spell Checking Documents', () => { diff --git a/packages/cspell-lib/src/lib/spellCheckFile.ts b/packages/cspell-lib/src/lib/spellCheckFile.ts index ef34833cfb3..ae4853b2163 100644 --- a/packages/cspell-lib/src/lib/spellCheckFile.ts +++ b/packages/cspell-lib/src/lib/spellCheckFile.ts @@ -155,10 +155,10 @@ export interface DetermineFinalDocumentSettingsResult { * `languageId` - if defined will be used to select appropriate file type dictionaries. * @param settings - The near final settings. Should already be the combination of all configuration files. */ -export function determineFinalDocumentSettings( +export async function determineFinalDocumentSettings( document: DocumentWithText, settings: CSpellUserSettings, -): DetermineFinalDocumentSettingsResult { +): Promise { const doc = createTextDocument({ uri: document.uri, content: document.text, @@ -167,6 +167,6 @@ export function determineFinalDocumentSettings( }); return { document, - settings: determineTextDocumentSettings(doc, settings), + settings: await determineTextDocumentSettings(doc, settings), }; } diff --git a/packages/cspell-lib/src/lib/suggestions.ts b/packages/cspell-lib/src/lib/suggestions.ts index c905014a1ba..d04bae01c1f 100644 --- a/packages/cspell-lib/src/lib/suggestions.ts +++ b/packages/cspell-lib/src/lib/suggestions.ts @@ -2,7 +2,13 @@ import type { CSpellSettings, LocaleId } from '@cspell/cspell-types'; import assert from 'assert'; import type { LanguageId } from './LanguageIds.js'; -import { finalizeSettings, getDefaultSettings, getGlobalSettings, mergeSettings } from './Settings/index.js'; +import { + defaultSettingsLoader, + finalizeSettings, + getDefaultSettings, + getGlobalSettings, + mergeSettings, +} from './Settings/index.js'; import { calcSettingsForLanguageId, isValidLocaleIntlFormat, @@ -155,6 +161,7 @@ async function _suggestionsForWord( }; } + await defaultSettingsLoader.onReady(); await refreshDictionaryCache(); const config = includeDefaultConfig @@ -162,16 +169,16 @@ async function _suggestionsForWord( : settings; const { dictionaryCollection, allDictionaryCollection } = await determineDictionaries(config); - return _suggestionsForWordSync(word, options, settings, dictionaryCollection, allDictionaryCollection); + return _suggestionsForWordAsync(word, options, settings, dictionaryCollection, allDictionaryCollection); } -function _suggestionsForWordSync( +async function _suggestionsForWordAsync( word: string, options: SuggestionOptions, settings: CSpellSettings, dictionaryCollection: SpellingDictionaryCollection, allDictionaryCollection?: SpellingDictionaryCollection, -): SuggestionsForWordResult { +): Promise { const extendsDictionaryCollection = allDictionaryCollection || dictionaryCollection; const { locale: language, diff --git a/packages/cspell-lib/src/lib/test/bugs.spec.ts b/packages/cspell-lib/src/lib/test/bugs.spec.ts index bbcf8aa667f..bbe3dfa5815 100644 --- a/packages/cspell-lib/src/lib/test/bugs.spec.ts +++ b/packages/cspell-lib/src/lib/test/bugs.spec.ts @@ -22,8 +22,8 @@ describe('Validate Against Bug Fixes', () => { const text = await fsp.readFile(fullFilename, 'utf-8'); const languageIds = cspell.getLanguagesForExt(ext); const settings = cspell.mergeSettings( - cspell.getDefaultBundledSettings(), - cspell.readSettings(configFile), + await cspell.getDefaultBundledSettingsAsync(), + await cspell.readSettings(configFile), ); const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); const result = await cspell.validateText(text, fileSettings); diff --git a/packages/cspell-lib/src/lib/test/dutch.spec.ts b/packages/cspell-lib/src/lib/test/dutch.spec.ts index db8ff50c5f8..edbdc3a07fb 100644 --- a/packages/cspell-lib/src/lib/test/dutch.spec.ts +++ b/packages/cspell-lib/src/lib/test/dutch.spec.ts @@ -19,8 +19,8 @@ describe('Validate that Dutch text is correctly checked.', () => { expect(Object.keys(text)).not.toHaveLength(0); const ext = path.extname(sampleFilename); const languageIds = cspell.getLanguagesForExt(ext); - const dutchSettings = cspell.readSettings(dutchConfig); - const settings = cspell.mergeSettings(cspell.getDefaultBundledSettings(), dutchSettings, { + const dutchSettings = await cspell.readSettings(dutchConfig); + const settings = cspell.mergeSettings(await cspell.getDefaultBundledSettingsAsync(), dutchSettings, { language: 'en,nl', }); const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); diff --git a/packages/cspell-lib/src/lib/test/english.spec.ts b/packages/cspell-lib/src/lib/test/english.spec.ts index 11758e51a26..cf6daa5b3ec 100644 --- a/packages/cspell-lib/src/lib/test/english.spec.ts +++ b/packages/cspell-lib/src/lib/test/english.spec.ts @@ -13,7 +13,7 @@ describe('Validate English', () => { async () => { const ext = '.txt'; const languageIds = cspell.getLanguagesForExt(ext); - const settings = cspell.getDefaultBundledSettings(); + const settings = await cspell.getDefaultBundledSettingsAsync(); // cspell:ignore jansons const text = '{ "name": "Jansons"}'; const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); @@ -39,13 +39,12 @@ describe('Validate English', () => { async () => { const ext = '.txt'; const languageIds = cspell.getLanguagesForExt(ext); - const settings = { ...cspell.getDefaultBundledSettings(), words: ['é', 'î'] }; + const settings = { ...(await cspell.getDefaultBundledSettingsAsync()), words: ['é', 'î'] }; const text = ` Here are some words. thing and cpp are words. é'thing and î'cpp are ok. `; - const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); const finalSettings = cspell.finalizeSettings(fileSettings); @@ -61,7 +60,7 @@ describe('Validate English', () => { async () => { const ext = '.json'; const languageIds = cspell.getLanguagesForExt(ext); - const settings = { ...cspell.getDefaultBundledSettings() }; + const settings = { ...(await cspell.getDefaultBundledSettingsAsync()) }; const text = ` { 'bidi': False, @@ -85,7 +84,7 @@ describe('Validate English', () => { async () => { const ext = '.py'; const languageIds = cspell.getLanguagesForExt(ext); - const settings = { ...cspell.getDefaultBundledSettings() }; + const settings = { ...(await cspell.getDefaultBundledSettingsAsync()) }; // cspell:ignore setsid isinstance const text = ` setsid = 'R' diff --git a/packages/cspell-lib/src/lib/test/fa.spec.ts b/packages/cspell-lib/src/lib/test/fa.spec.ts index d62ded88c8d..8a95a5e0237 100644 --- a/packages/cspell-lib/src/lib/test/fa.spec.ts +++ b/packages/cspell-lib/src/lib/test/fa.spec.ts @@ -19,8 +19,8 @@ describe('Validate that Persian text is correctly checked.', () => { expect(Object.keys(text)).not.toHaveLength(0); const ext = path.extname(sampleFilename); const languageIds = cspell.getLanguagesForExt(ext); - const frenchSettings = cspell.readSettings(frenchConfig); - const settings = cspell.mergeSettings(cspell.getDefaultBundledSettings(), frenchSettings, { + const frenchSettings = await cspell.readSettings(frenchConfig); + const settings = cspell.mergeSettings(await cspell.getDefaultBundledSettingsAsync(), frenchSettings, { language: 'en,fa', }); const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); diff --git a/packages/cspell-lib/src/lib/test/french.spec.ts b/packages/cspell-lib/src/lib/test/french.spec.ts index c31baa7f7f7..ac3ef505b15 100644 --- a/packages/cspell-lib/src/lib/test/french.spec.ts +++ b/packages/cspell-lib/src/lib/test/french.spec.ts @@ -19,8 +19,8 @@ describe('Validate that French text is correctly checked.', () => { expect(Object.keys(text)).not.toHaveLength(0); const ext = path.extname(sampleFilename); const languageIds = cspell.getLanguagesForExt(ext); - const frenchSettings = cspell.readSettings(frenchConfig); - const settings = cspell.mergeSettings(cspell.getDefaultBundledSettings(), frenchSettings, { + const frenchSettings = await cspell.readSettings(frenchConfig); + const settings = cspell.mergeSettings(await cspell.getDefaultBundledSettingsAsync(), frenchSettings, { language: 'en,fr', }); const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); diff --git a/packages/cspell-lib/src/lib/test/golang.spec.ts b/packages/cspell-lib/src/lib/test/golang.spec.ts index 30472b111e9..6378ae9fb30 100644 --- a/packages/cspell-lib/src/lib/test/golang.spec.ts +++ b/packages/cspell-lib/src/lib/test/golang.spec.ts @@ -18,7 +18,7 @@ describe('Validate that Go files are correctly checked.', () => { expect(Object.keys(text)).not.toHaveLength(0); const ext = '.go'; const languageIds = cspell.getLanguagesForExt(ext); - const settings = cspell.getDefaultBundledSettings(); + const settings = await cspell.getDefaultBundledSettingsAsync(); const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); // cspell:ignore weirdd garbbage longname const results1 = await cspell.validateText('some weirdd garbbage', fileSettings); diff --git a/packages/cspell-lib/src/lib/test/python.spec.ts b/packages/cspell-lib/src/lib/test/python.spec.ts index 4fb49d11eb3..d65fb85c8fb 100644 --- a/packages/cspell-lib/src/lib/test/python.spec.ts +++ b/packages/cspell-lib/src/lib/test/python.spec.ts @@ -15,13 +15,13 @@ const timeout = 10000; describe('Validate that Python files are correctly checked.', () => { test( 'Tests the default configuration', - () => { + async () => { expect(Object.keys(text)).not.toHaveLength(0); const ext = path.extname(sampleFilename); const languageIds = cspell.getLanguagesForExt(ext); const settings = cspell.mergeSettings( - cspell.getDefaultBundledSettings(), - cspell.readSettings(sampleConfig), + await cspell.getDefaultBundledSettingsAsync(), + await cspell.readSettings(sampleConfig), ); const fileSettings = cspell.combineTextAndLanguageSettings(settings, text, languageIds); return cspell.validateText(text, fileSettings).then((results) => { diff --git a/packages/cspell-lib/src/lib/textValidation/determineTextDocumentSettings.test.ts b/packages/cspell-lib/src/lib/textValidation/determineTextDocumentSettings.test.ts index 71ca3cd8e7e..5854b39dcb5 100644 --- a/packages/cspell-lib/src/lib/textValidation/determineTextDocumentSettings.test.ts +++ b/packages/cspell-lib/src/lib/textValidation/determineTextDocumentSettings.test.ts @@ -17,7 +17,7 @@ describe('determineTextDocumentSettings', () => { `('determineTextDocumentSettings', async ({ file, configFile, expected }) => { const cfg = await loadConfig(configFile); const doc = await loadTextDocument(file); - const settings = determineTextDocumentSettings(doc, cfg); + const settings = await determineTextDocumentSettings(doc, cfg); expect(settings.dictionaries).toContain('Test Dictionary'); expect(settings).toEqual(expected); }); diff --git a/packages/cspell-lib/src/lib/textValidation/docValidator.test.ts b/packages/cspell-lib/src/lib/textValidation/docValidator.test.ts index b69e2a3488f..fbe4431b74b 100644 --- a/packages/cspell-lib/src/lib/textValidation/docValidator.test.ts +++ b/packages/cspell-lib/src/lib/textValidation/docValidator.test.ts @@ -86,7 +86,7 @@ describe('docValidator', () => { `('checkText sync $filename "$text"', async ({ filename, text, expected, configFile }) => { const doc = await loadDoc(filename); const dVal = new DocumentValidator(doc, { configFile }, {}); - dVal.prepareSync(); + await dVal.prepare(); const offset = doc.text.indexOf(text); assert(offset >= 0); const range = [offset, offset + text.length] as const; @@ -100,7 +100,7 @@ describe('docValidator', () => { `('checkText suggestions $filename "$text"', async ({ filename, text, expected }) => { const doc = await loadDoc(filename); const dVal = new DocumentValidator(doc, { generateSuggestions: true }, { suggestionsTimeout: 10000 }); - dVal.prepareSync(); + await dVal.prepare(); const offset = doc.text.indexOf(text); assert(offset >= 0); const range = [offset, offset + text.length] as const; @@ -181,7 +181,7 @@ describe('docValidator', () => { }, ); - test('updateDocumentText', () => { + test('updateDocumentText', async () => { // cspell:ignore foor const expectedIssues = [ oc({ @@ -193,10 +193,10 @@ describe('docValidator', () => { ]; const doc = td('files://words.txt', 'one\ntwo\nthree\nfoor\n', 'plaintext'); const dVal = new DocumentValidator(doc, { generateSuggestions: false }, {}); - dVal.prepareSync(); + await dVal.prepare(); const r = dVal.checkDocument(); expect(r).toEqual(expectedIssues); - dVal.updateDocumentText(doc.text + '# cspell:ignore foor\n'); + await dVal.updateDocumentText(doc.text + '# cspell:ignore foor\n'); expect(dVal.checkDocument()).toEqual([]); }); diff --git a/packages/cspell-lib/src/lib/textValidation/docValidator.ts b/packages/cspell-lib/src/lib/textValidation/docValidator.ts index 81804c41134..63bb6b1e7bb 100644 --- a/packages/cspell-lib/src/lib/textValidation/docValidator.ts +++ b/packages/cspell-lib/src/lib/textValidation/docValidator.ts @@ -16,7 +16,6 @@ import type { ExtendedSuggestion } from '../Models/Suggestion.js'; import type { TextDocument, TextDocumentLine, TextDocumentRef } from '../Models/TextDocument.js'; import { updateTextDocument } from '../Models/TextDocument.js'; import type { ValidationIssue } from '../Models/ValidationIssue.js'; -import { loadConfigSync, searchForConfigSync } from '../Settings/Controller/configLoader/index.js'; import { finalizeSettings, loadConfig, mergeSettings, searchForConfig } from '../Settings/index.js'; import type { DirectiveIssue } from '../Settings/InDocSettings.js'; import { validateInDocumentSettings } from '../Settings/InDocSettings.js'; @@ -24,7 +23,7 @@ import type { SpellingDictionaryCollection, SuggestionResult } from '../Spelling import { getDictionaryInternal, getDictionaryInternalSync } from '../SpellingDictionary/index.js'; import type { WordSuggestion } from '../suggestions.js'; import { calcSuggestionAdjustedToToMatchCase } from '../suggestions.js'; -import { catchPromiseError, toError, wrapCall } from '../util/errors.js'; +import { catchPromiseError, toError } from '../util/errors.js'; import { AutoCache } from '../util/simpleCache.js'; import type { MatchRange } from '../util/TextRange.js'; import { createTimer } from '../util/timer.js'; @@ -93,69 +92,6 @@ export class DocumentValidator { return this._ready; } - /** - * Prepare to validate a document. - * This will load all the necessary configuration and dictionaries. - * - * @deprecated - * @deprecationMessage Use the async `prepare` method. - */ - prepareSync(): void { - // @todo - // Determine doc settings. - // Calc include ranges - // Load dictionaries - if (this._ready) return; - - const timer = createTimer(); - - const { options, settings } = this; - - const useSearchForConfig = - (!options.noConfigSearch && !settings.noConfigSearch) || options.noConfigSearch === false; - const optionsConfigFile = options.configFile; - const localConfigFn = optionsConfigFile - ? () => loadConfigSync(optionsConfigFile, settings) - : useSearchForConfig - ? () => searchForDocumentConfigSync(this._document, settings, settings) - : undefined; - - const localConfig = localConfigFn && wrapCall(localConfigFn, (e) => this.addPossibleError(e))(); - this.addPossibleError(localConfig?.__importRef?.error); - - const config = mergeSettings(settings, localConfig); - const docSettings = determineTextDocumentSettings(this._document, config); - const dict = getDictionaryInternalSync(docSettings); - - const matcher = new GlobMatcher(localConfig?.ignorePaths || [], { root: process.cwd(), dot: true }); - const uri = this._document.uri; - - const shouldCheck = !matcher.match(uriToFilePath(uri)) && (docSettings.enabled ?? true); - const finalSettings = finalizeSettings(docSettings); - const validateOptions = settingsToValidateOptions(finalSettings); - const includeRanges = calcTextInclusionRanges(this._document.text, validateOptions); - const segmenter = createMappedTextSegmenter(includeRanges); - const textValidator = textValidatorFactory(dict, validateOptions); - - this._preparations = { - config, - dictionary: dict, - docSettings, - finalSettings, - shouldCheck, - validateOptions, - includeRanges, - segmenter, - textValidator, - localConfig, - localConfigFilepath: localConfig?.__importRef?.filename, - }; - - this._ready = true; - this._preparationTime = timer.elapsed(); - // console.error(`prepareSync ${this._preparationTime.toFixed(2)}ms`); - } - async prepare(): Promise { if (this._ready) return; if (this._prepared) return this._prepared; @@ -506,16 +442,6 @@ function mapSug(sug: ExtendedSuggestion | SuggestionResult): SuggestionResult { return { cost: 999, ...sug }; } -function searchForDocumentConfigSync( - document: TextDocumentRef, - defaultConfig: CSpellSettingsWithSourceTrace, - pnpSettings: PnPSettings, -): CSpellSettingsWithSourceTrace { - const { uri } = document; - if (uri.scheme !== 'file') defaultConfig; - return searchForConfigSync(uriToFilePath(uri), pnpSettings) || defaultConfig; -} - interface ShouldCheckDocumentResult { errors: Error[]; shouldCheck: boolean; diff --git a/packages/cspell-lib/src/lib/textValidation/validator.ts b/packages/cspell-lib/src/lib/textValidation/validator.ts index df0a94469b4..f3d2dcaa055 100644 --- a/packages/cspell-lib/src/lib/textValidation/validator.ts +++ b/packages/cspell-lib/src/lib/textValidation/validator.ts @@ -22,6 +22,7 @@ export async function validateText( settings: CSpellUserSettings, options: ValidateTextOptions = {}, ): Promise { + await Settings.defaultSettingsLoader.onReady(); const finalSettings = Settings.finalizeSettings(settings); const dict = await getDictionaryInternal(finalSettings); const spellingIssues = [...validateFullText(text, dict, settingsToValidateOptions(finalSettings))]; diff --git a/packages/cspell-lib/src/lib/trace.test.ts b/packages/cspell-lib/src/lib/trace.test.ts index 83bd04c7b01..79948fed117 100644 --- a/packages/cspell-lib/src/lib/trace.test.ts +++ b/packages/cspell-lib/src/lib/trace.test.ts @@ -12,7 +12,7 @@ describe('Verify trace', () => { 'tests tracing a word', async () => { const words = ['apple']; - const config = getSettings({ ignoreWords: ['apple'], flagWords: ['apple'] }); + const config = await getSettings({ ignoreWords: ['apple'], flagWords: ['apple'] }); const results = await traceWords(words, config, {}); expect(results.map(({ dictName, found }) => ({ dictName, found }))).toEqual( expect.arrayContaining([ @@ -53,7 +53,7 @@ describe('Verify trace', () => { const { word, languageId, ignoreCase, locale, allowCompoundWords } = params; const { dictName, dictActive, found, forbidden, noSuggest, foundWord } = params; const words = [word]; - const config = getSettings({ allowCompoundWords, flagWords: ['hte'], ignoreWords: ['colour'] }); + const config = await getSettings({ allowCompoundWords, flagWords: ['hte'], ignoreWords: ['colour'] }); const results = await traceWords(words, config, { locale, languageId, ignoreCase }); const byName = results.reduce( (a, b) => { @@ -84,7 +84,7 @@ describe('Verify trace', () => { 'tracing with missing dictionary.', async () => { const words = ['apple']; - const defaultConfig = getSettings(); + const defaultConfig = await getSettings(); const dictionaryDefinitions = (defaultConfig.dictionaryDefinitions || []).concat([ { name: 'bad dict',