Skip to content

Commit

Permalink
fix: Improve the Configuration Loader Error Message (#5337)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason3S committed Mar 4, 2024
1 parent 5d0a2c5 commit dc297b5
Show file tree
Hide file tree
Showing 4 changed files with 82 additions and 8 deletions.
Expand Up @@ -16,12 +16,17 @@ import {
pathRepoTestFixturesURL,
} from '../../../../test-util/test.locations.cjs';
import { logError, logWarning } from '../../../util/logger.js';
import { resolveFileWithURL, toFilePathOrHref, toFileUrl } from '../../../util/url.js';
import { cwdURL, resolveFileWithURL, toFilePathOrHref, toFileUrl } from '../../../util/url.js';
import { currentSettingsFileVersion, defaultConfigFileModuleRef, ENV_CSPELL_GLOB_ROOT } from '../../constants.js';
import type { ImportFileRefWithError } from '../../CSpellSettingsServer.js';
import { extractDependencies, getSources, mergeSettings } from '../../CSpellSettingsServer.js';
import { _defaultSettings, getDefaultBundledSettingsAsync } from '../../DefaultSettings.js';
import { __testing__ as __configLoader_testing__, createConfigLoader, loadPnP } from './configLoader.js';
import {
__testing__ as __configLoader_testing__,
ConfigurationLoaderFailedToResolveError,
createConfigLoader,
loadPnP,
} from './configLoader.js';
import { configToRawSettings } from './configToRawSettings.js';
import {
clearCachedSettingsFiles,
Expand All @@ -38,7 +43,7 @@ import { extractImportErrors, extractImports } from './extractImportErrors.js';
import { readSettings } from './readSettings.js';
import { readSettingsFiles } from './readSettingsFiles.js';

const { validateRawConfigVersion, resolveGlobRoot } = __configLoader_testing__;
const { validateRawConfigVersion, resolveGlobRoot, relativeToCwd } = __configLoader_testing__;

const rootCspellLib = path.join(pathPackageRoot, '.');
const root = pathRepoRoot;
Expand Down Expand Up @@ -337,10 +342,10 @@ describe('Validate search/load config files', () => {
clearCachedSettingsFiles();
});

function resolveError(filename: string): ImportFileRefWithError {
function resolveError(filename: string, relativeTo = cwdURL()): ImportFileRefWithError {
return {
filename,
error: new Error(`Failed to resolve file: "${filename}"`),
error: new ConfigurationLoaderFailedToResolveError(filename, relativeTo),
};
}

Expand Down Expand Up @@ -803,6 +808,22 @@ describe('Validate Dependencies', () => {
});
});

describe('relativeToCwd', () => {
test.each`
filename | expected
${cwdURL()} | ${'./'}
${'../../cspell.json'} | ${'../../cspell.json'}
${'../../cspell.json'} | ${'../../cspell.json'}
${'../../../cspell.json'} | ${'../../../cspell.json'}
${pathToFileURL('../../../../cspell.json')} | ${path.resolve('../../../../cspell.json')}
${pathToFileURL('./samples/cspell.json')} | ${'./samples/cspell.json'}
${pathToFileURL('../samples/cspell.json')} | ${'../samples/cspell.json'}
${new URL('https://example.com/cspell.json')} | ${'https://example.com/cspell.json'}
`('relativeToCwd', ({ filename, expected }) => {
expect(relativeToCwd(filename)).toEqual(expected);
});
});

/**
* Resolve relative to src/lib
*/
Expand Down
Expand Up @@ -21,6 +21,7 @@ import {
cwdURL,
resolveFileWithURL,
toFilePathOrHref,
toFileUrl,
windowsDriveLetterToUpper,
} from '../../../util/url.js';
import {
Expand Down Expand Up @@ -550,7 +551,7 @@ export class ConfigLoader implements IConfigLoader {

return {
filename: r.filename.startsWith('file:/') ? fileURLToPath(r.filename) : r.filename,
error: r.found ? undefined : new Error(`Failed to resolve file: "${filename}"`),
error: r.found ? undefined : new ConfigurationLoaderFailedToResolveError(filename, relativeTo),
};
}

Expand Down Expand Up @@ -677,9 +678,59 @@ async function isDirectory(fs: VFileSystem, path: URL): Promise<boolean> {
}
}

export class ConfigurationLoaderError extends Error {
constructor(
message: string,
public readonly configurationFile?: string,
public readonly relativeTo?: string | URL,
cause?: unknown,
) {
super(message);
this.name = 'Configuration Loader Error';
if (cause) {
this.cause = cause;
}
}
}

export class ConfigurationLoaderFailedToResolveError extends ConfigurationLoaderError {
constructor(
public readonly configurationFile: string,
public readonly relativeTo: string | URL,
cause?: unknown,
) {
const filename = configurationFile.startsWith('file:/') ? fileURLToPath(configurationFile) : configurationFile;
const relSource = relativeToCwd(relativeTo);

const message = `Failed to resolve configuration file: "${filename}" referenced from "${relSource}"`;
super(message, configurationFile, relativeTo, cause);
// this.name = 'Configuration Loader Error';
}
}

function relativeToCwd(file: string | URL): string {
const url = toFileUrl(file);
const cwdPath = cwdURL().pathname.split('/').slice(0, -1);
const urlPath = url.pathname.split('/');
if (urlPath[0] !== cwdPath[0]) return toFilePathOrHref(file);
let i = 0;
for (; i < cwdPath.length; ++i) {
if (cwdPath[i] !== urlPath[i]) break;
}
const segments = cwdPath.length - i;
if (segments > 3) return toFilePathOrHref(file);
const prefix = '.'
.repeat(segments)
.split('')
.map(() => '..')
.join('/');
return [prefix || '.', ...urlPath.slice(i)].join('/');
}

export const __testing__ = {
getDefaultConfigLoaderInternal,
normalizeCacheSettings,
validateRawConfigVersion,
resolveGlobRoot,
relativeToCwd,
};
4 changes: 3 additions & 1 deletion packages/cspell-lib/src/lib/spellCheckFile.test.ts
Expand Up @@ -276,7 +276,9 @@ function errNoEnt(file: string): Error {

function eFailed(file: string): Error {
return oc({
message: expectToEqualCaseInsensitive(`Failed to resolve file: "${rpS(file)}"`),
message: expectToEqualCaseInsensitive(
`Failed to resolve configuration file: "${rpS(file)}" referenced from "./"`,
),
});
}

Expand Down
2 changes: 1 addition & 1 deletion packages/cspell/src/app/__snapshots__/app.test.ts.snap
Expand Up @@ -328,7 +328,7 @@ exports[`Validate cli > app 'cspell-bad.json' Expect Error: undefined 3`] = `
exports[`Validate cli > app 'cspell-import-missing.json' Expect Error: [Function CheckFailed] 1`] = `[]`;
exports[`Validate cli > app 'cspell-import-missing.json' Expect Error: [Function CheckFailed] 2`] = `
"error Configuration Error: Failed to resolve file: "../intentionally-missing-file.json"
"error Configuration Configuration Loader Error: Failed to resolve configuration file: "../intentionally-missing-file.json" referenced from "./samples/linked/cspell-import-missing.json"
error CSpell: Files checked: 0, Issues found: 0 in 0 files"
`;
Expand Down

0 comments on commit dc297b5

Please sign in to comment.