Skip to content

Commit

Permalink
fix: import resolve support relative path
Browse files Browse the repository at this point in the history
  • Loading branch information
fengmk2 committed Dec 30, 2024
1 parent 82471cb commit 9b3a0de
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 16 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
"scripts": {
"lint": "eslint src test --ext ts",
"pretest": "npm run clean && npm run lint -- --fix && npm run prepublishOnly",
"test": "npm run test-local",
"test": "egg-bin test",
"posttest": "npm run clean",
"test-local": "egg-bin test",
"preci": "npm run clean && npm run lint && npm run prepublishOnly",
Expand Down
57 changes: 42 additions & 15 deletions src/import.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,33 +150,60 @@ function tryToResolveByDirname(dirname: string): string | undefined {
return tryToResolveByDirnameFromPackage(dirname, pkg);
}

function isRelativePath(filepath: string): boolean {
return filepath.startsWith('./')
|| filepath.startsWith('../')
|| filepath.startsWith('.\\')
|| filepath.startsWith('..\\');
}

function tryToResolveFromAbsoluteFile(filepath: string): string | undefined {
let moduleFilePath: string | undefined;
const stat = fs.statSync(filepath, { throwIfNoEntry: false });
// try to resolve from directory
if (stat?.isDirectory()) {
moduleFilePath = tryToResolveByDirname(filepath);
if (moduleFilePath) {
return moduleFilePath;
}
} else if (stat?.isFile()) {
return filepath;
}
// try to resolve from file
moduleFilePath = tryToResolveFromFile(filepath);
if (moduleFilePath) {
return moduleFilePath;
}
}

export function importResolve(filepath: string, options?: ImportResolveOptions) {
// find *.json or CommonJS module by require.resolve
// e.g.: importResolve('egg/package.json', { paths })
const cwd = process.cwd();
const paths = options?.paths ?? [ cwd ];

let moduleFilePath: string | undefined;
const isAbsolute = path.isAbsolute(filepath);
if (isAbsolute) {
const stat = fs.statSync(filepath, { throwIfNoEntry: false });
// try to resolve from directory
if (stat?.isDirectory()) {
moduleFilePath = tryToResolveByDirname(filepath);
moduleFilePath = tryToResolveFromAbsoluteFile(filepath);
if (moduleFilePath) {
debug('[importResolve:isAbsolute] %o => %o', filepath, moduleFilePath);
return moduleFilePath;
}
} else if (isRelativePath(filepath)) {
for (const p of paths) {
const resolvedPath = path.resolve(p, filepath);
moduleFilePath = tryToResolveFromAbsoluteFile(resolvedPath);
if (moduleFilePath) {
debug('[importResolve] %o => %o', filepath, moduleFilePath);
debug('[importResolve:isRelativePath] %o => %o => %o',
filepath, resolvedPath, moduleFilePath);
return moduleFilePath;
}
}
// try to resolve from file
moduleFilePath = tryToResolveFromFile(filepath);
if (moduleFilePath) {
debug('[importResolve] %o => %o', filepath, moduleFilePath);
return moduleFilePath;
}
}

const extname = path.extname(filepath);
if ((!isAbsolute && extname === '.json') || !isESM) {
// find *.json or CommonJS module by require.resolve
// e.g.: importResolve('egg/package.json', { paths })
const cwd = process.cwd();
const paths = options?.paths ?? [ cwd ];
moduleFilePath = getRequire().resolve(filepath, {
paths,
});
Expand Down
28 changes: 28 additions & 0 deletions test/import.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,24 @@ describe('test/import.test.ts', () => {
describe('importResolve()', () => {
it('should work on cjs', () => {
assert.equal(importResolve(getFilepath('cjs')), getFilepath('cjs/index.js'));
assert.equal(importResolve('./index.js', {
paths: [ getFilepath('cjs') ],
}), getFilepath('cjs/index.js'));
assert.equal(importResolve(getFilepath('cjs/exports')), getFilepath('cjs/exports.js'));
assert.equal(importResolve('./exports', {
paths: [ getFilepath('cjs') ],
}), getFilepath('cjs/exports.js'));
assert.equal(importResolve(getFilepath('cjs-index')), getFilepath('cjs-index/index.cjs'));
assert.equal(importResolve(getFilepath('cjs/extend')), getFilepath('cjs/extend/index.js'));
assert.equal(importResolve('./extend', {
paths: [ getFilepath('cjs') ],
}), getFilepath('cjs/extend/index.js'));
assert.equal(importResolve('../index', {
paths: [ getFilepath('cjs/extend') ],
}), getFilepath('cjs/index.js'));
assert.equal(importResolve('../../index', {
paths: [ getFilepath('cjs/extend/foo') ],
}), getFilepath('cjs/index.js'));
});

it('should work on commonjs and require exists', () => {
Expand All @@ -21,8 +36,14 @@ describe('test/import.test.ts', () => {

it('should work on esm', () => {
assert.equal(importResolve(getFilepath('esm')), getFilepath('esm/index.js'));
assert.equal(importResolve('./index.js', {
paths: [ getFilepath('esm') ],
}), getFilepath('esm/index.js'));
assert.equal(importResolve(getFilepath('esm-index')), getFilepath('esm-index/index.mjs'));
assert.equal(importResolve(getFilepath('esm/config/plugin')), getFilepath('esm/config/plugin.js'));
assert.equal(importResolve('./config/plugin', {
paths: [ getFilepath('esm') ],
}), getFilepath('esm/config/plugin.js'));
assert.throws(() => {
importResolve(getFilepath('esm/config/plugin.default'));
}, /Cannot find module/);
Expand Down Expand Up @@ -129,6 +150,13 @@ describe('test/import.test.ts', () => {
assert.equal(obj.one, 1);
assert.deepEqual(obj.default, { foo: 'bar' });

obj = await importModule('./index.js', {
paths: [ getFilepath('esm') ],
});
assert.deepEqual(Object.keys(obj), [ 'default', 'one' ]);
assert.equal(obj.one, 1);
assert.deepEqual(obj.default, { foo: 'bar' });

obj = await importModule(getFilepath('esm'), { importDefaultOnly: true });
assert.deepEqual(obj, { foo: 'bar' });

Expand Down

0 comments on commit 9b3a0de

Please sign in to comment.