Skip to content

Commit

Permalink
fix: improve file resolution (#601)
Browse files Browse the repository at this point in the history
  • Loading branch information
Jason3S committed Nov 17, 2020
1 parent 42d47cc commit b0de78e
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 26 deletions.
32 changes: 6 additions & 26 deletions packages/cspell-lib/src/Settings/CSpellSettingsServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { normalizePathForDictDefs } from './DictionarySettings';
import * as util from '../util/util';
import ConfigStore from 'configstore';
import minimatch from 'minimatch';
import resolveFrom from 'resolve-from';
import { resolveFile } from '../util/resolveFile';

const currentSettingsFileVersion = '0.1';

Expand Down Expand Up @@ -281,33 +281,13 @@ function applyPatterns(
return [...flatten(patternList)];
}

const testNodeModules = /^node_modules\//;

function resolveFilename(filename: string, relativeTo: string): ImportFileRef {
if (testNodeModules.test(filename)) {
filename = filename.replace(testNodeModules, '');
}

const try1 = tryResolve(filename, relativeTo);
if (!try1.error || filename.startsWith('.')) {
return try1;
}

// Try to resolve as a relative module
const normalizedFilename = './' + (path.sep === '/' ? filename : filename.split(path.sep).join('/'));
return tryResolve(normalizedFilename, relativeTo);
}
const r = resolveFile(filename, relativeTo);

function tryResolve(filename: string, relativeTo: string): ImportFileRef {
try {
return { filename: resolveFrom(relativeTo, filename) };
} catch (error) {
// Failed to resolve a relative module request
return {
filename: filename,
error: new Error(`Failed to resolve file: "${filename}"`),
};
}
return {
filename: r.filename,
error: r.found ? undefined : new Error(`Failed to resolve file: "${filename}"`),
};
}

export function getGlobalSettings(): CSpellSettings {
Expand Down
55 changes: 55 additions & 0 deletions packages/cspell-lib/src/util/resolveFile.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { resolveFile } from './resolveFile';
import * as path from 'path';
import { parse } from 'comment-json';
import * as fs from 'fs';

interface Config {
import: string[];
}

const config: Config = parse(
fs.readFileSync(path.join(__dirname, '..', '..', 'config', 'cspell-default.json'), 'utf-8')
);

const ext = path.extname(__filename);

describe('Validate resolveFile', () => {
interface ResolveFileTest {
filename: string;
relativeTo: string;
expected: string;
found: boolean;
}
test.each`
filename | relativeTo | expected | found
${__filename} | ${__dirname} | ${__filename} | ${true}
${path.relative(__dirname, __filename)} | ${__dirname} | ${__filename} | ${true}
${'cspell-dict-cpp/cspell-ext.json'} | ${__dirname} | ${require.resolve('cspell-dict-cpp/cspell-ext.json')} | ${true}
${'cspell-ext.json'} | ${__dirname} | ${'cspell-ext.json'} | ${false}
${`./resolveFile${ext}`} | ${__dirname} | ${require.resolve('./resolveFile')} | ${true}
${`resolveFile${ext}`} | ${__dirname} | ${require.resolve('./resolveFile')} | ${true}
${'lerna'} | ${__dirname} | ${require.resolve('lerna')} | ${true}
`('resolveFile "$filename" rel "$relativeTo"', validateResolveFile);

test.each(
config.import
.concat(config.import.map((f) => f.replace('node_modules/', '')))
.map((f) => ({
filename: f,
relativeTo: __dirname,
expected: require.resolve(f.replace('node_modules/', '')),
found: true,
}))
.map(({ filename, relativeTo, expected, found }) => [filename, relativeTo, expected, found])
)('resolveFile "%s" rel "%s"', validateResolveArgs);

function validateResolveFile({ filename, relativeTo, expected, found }: ResolveFileTest) {
validateResolveArgs(filename, relativeTo, expected, found);
}

function validateResolveArgs(filename: string, relativeTo: string, expected: string, found: boolean) {
const r = resolveFile(filename, relativeTo);
expect(r.filename).toBe(expected);
expect(r.found).toBe(found);
}
});
40 changes: 40 additions & 0 deletions packages/cspell-lib/src/util/resolveFile.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import * as fs from 'fs';
import * as path from 'path';
import resolveFrom from 'resolve-from';

export interface ResolveFileResult {
filename: string;
found: boolean;
}

const testNodeModules = /^node_modules\//;

export function resolveFile(filename: string, relativeTo: string): ResolveFileResult {
const methodResolveFrom = (filename: string) => tryResolveFrom(filename, relativeTo);
const steps: { filename: string; fn: (f: string) => ResolveFileResult }[] = [
{ filename: path.resolve(relativeTo, filename), fn: tryResolveExists },
{ filename: path.resolve(filename), fn: tryResolveExists },
{ filename: filename, fn: methodResolveFrom },
{ filename: filename.replace(testNodeModules, ''), fn: methodResolveFrom },
{ filename: './' + (path.sep === '/' ? filename : filename.split(path.sep).join('/')), fn: methodResolveFrom },
];

for (const step of steps) {
const r = step.fn(step.filename);
if (r.found) return r;
}
return { filename, found: false };
}

function tryResolveExists(filename: string): ResolveFileResult {
return { filename, found: fs.existsSync(filename) };
}

function tryResolveFrom(filename: string, relativeTo: string): ResolveFileResult {
try {
return { filename: resolveFrom(relativeTo, filename), found: true };
} catch (error) {
// Failed to resolve a relative module request
return { filename: filename, found: false };
}
}

0 comments on commit b0de78e

Please sign in to comment.