From ed7b25cf4ccb3f27bf89993a7fc8c706e3491ad5 Mon Sep 17 00:00:00 2001 From: scagood <2230835+scagood@users.noreply.github.com> Date: Mon, 8 Apr 2024 19:06:22 +0100 Subject: [PATCH] feat(import-target): Add resolution error reason --- lib/util/check-existence.js | 3 ++- lib/util/import-target.js | 25 ++++++++++++++--- .../misconfigured-default/build/index.js | 1 + .../misconfigured-default/package.json | 9 +++++++ .../misconfigured-default/src/index.ts | 1 + tests/lib/rules/no-missing-import.js | 27 ++++++++++++++++++- 6 files changed, 61 insertions(+), 5 deletions(-) create mode 100644 tests/fixtures/no-missing/node_modules/misconfigured-default/build/index.js create mode 100644 tests/fixtures/no-missing/node_modules/misconfigured-default/package.json create mode 100644 tests/fixtures/no-missing/node_modules/misconfigured-default/src/index.ts diff --git a/lib/util/check-existence.js b/lib/util/check-existence.js index a7899a75..a015d3a4 100644 --- a/lib/util/check-existence.js +++ b/lib/util/check-existence.js @@ -22,7 +22,7 @@ function markMissing(context, target) { loc: /** @type {import('eslint').AST.SourceLocation} */ ( target.node.loc ), - messageId: "notFound", + messageId: target.resolveError ? "notFoundBecause" : "notFound", data: /** @type {Record} */ (target), }) } @@ -86,4 +86,5 @@ exports.checkExistence = function checkExistence(context, targets) { exports.messages = { notFound: '"{{name}}" is not found.', + notFoundBecause: '"{{name}}" is not found.\n{{resolveError}}', } diff --git a/lib/util/import-target.js b/lib/util/import-target.js index 93f72c74..36c2dfd3 100644 --- a/lib/util/import-target.js +++ b/lib/util/import-target.js @@ -131,6 +131,12 @@ module.exports = class ImportTarget { */ this.moduleName = this.getModuleName() + /** + * This is the full resolution failure reasons + * @type {string | null} + */ + this.resolveError = null + /** * The full path of this import target. * If the target is a module and it does not exist then this is `null`. @@ -286,12 +292,25 @@ module.exports = class ImportTarget { const cwd = this.context.settings?.cwd ?? process.cwd() for (const directory of this.getPaths()) { + const baseDir = resolve(cwd, directory) + try { - const baseDir = resolve(cwd, directory) const resolved = requireResolve(baseDir, this.name) if (typeof resolved === "string") return resolved - } catch { - continue + } catch (error) { + if (error instanceof Error === false) { + throw error + } + + // This is the usual error + if ( + error.message === + `Can't resolve '${this.name}' in '${baseDir}'` + ) { + continue + } + + this.resolveError = error.message } } diff --git a/tests/fixtures/no-missing/node_modules/misconfigured-default/build/index.js b/tests/fixtures/no-missing/node_modules/misconfigured-default/build/index.js new file mode 100644 index 00000000..336ce12b --- /dev/null +++ b/tests/fixtures/no-missing/node_modules/misconfigured-default/build/index.js @@ -0,0 +1 @@ +export {} diff --git a/tests/fixtures/no-missing/node_modules/misconfigured-default/package.json b/tests/fixtures/no-missing/node_modules/misconfigured-default/package.json new file mode 100644 index 00000000..34cec732 --- /dev/null +++ b/tests/fixtures/no-missing/node_modules/misconfigured-default/package.json @@ -0,0 +1,9 @@ +{ + "name": "misconfigured-default", + "exports": { + ".": { + "default": "./build/index.js", + "types": "./src/index.ts" + } + } +} diff --git a/tests/fixtures/no-missing/node_modules/misconfigured-default/src/index.ts b/tests/fixtures/no-missing/node_modules/misconfigured-default/src/index.ts new file mode 100644 index 00000000..336ce12b --- /dev/null +++ b/tests/fixtures/no-missing/node_modules/misconfigured-default/src/index.ts @@ -0,0 +1 @@ +export {} diff --git a/tests/lib/rules/no-missing-import.js b/tests/lib/rules/no-missing-import.js index 2f6ea3f0..1ca7f6c6 100644 --- a/tests/lib/rules/no-missing-import.js +++ b/tests/lib/rules/no-missing-import.js @@ -39,6 +39,7 @@ function fixture(name) { return path.resolve(__dirname, "../../fixtures/no-missing", name) } +/** @type {import('eslint').RuleTester} */ const ruleTester = new RuleTester({ languageOptions: { sourceType: "module", @@ -313,7 +314,17 @@ ruleTester.run("no-missing-import", rule, { { filename: fixture("test.js"), code: "import abcdef from 'esm-module/sub.mjs';", - errors: ['"esm-module/sub.mjs" is not found.'], + // errors: ['"esm-module/sub.mjs" is not found.'], + errors: [ + { + messageId: "notFoundBecause", + data: { + name: "esm-module/sub.mjs", + resolveError: + "Package path ./sub.mjs is not exported from package /home/scagood/github/open-source/eslint-plugin-n/tests/fixtures/no-missing/node_modules/esm-module (see exports field in /home/scagood/github/open-source/eslint-plugin-n/tests/fixtures/no-missing/node_modules/esm-module/package.json)", + }, + }, + ], }, { filename: fixture("test.js"), @@ -393,6 +404,20 @@ ruleTester.run("no-missing-import", rule, { errors: ['"./A.js" is not found.'], }, + { + filename: fixture("test.js"), + code: "import 'misconfigured-default';", + errors: [ + { + messageId: "notFoundBecause", + data: { + name: "misconfigured-default", + resolveError: "Default condition should be last one", + }, + }, + ], + }, + // import() ...(DynamicImportSupported ? [