From ff019309acf0078ba827769bdb4a6bf58becfbb4 Mon Sep 17 00:00:00 2001 From: Sebastian Good <2230835+scagood@users.noreply.github.com> Date: Tue, 7 Nov 2023 07:10:26 +0100 Subject: [PATCH] feat: Export the moduleType from ImportTarget (#132) --- lib/rules/file-extension-in-import.js | 15 +++++------- lib/util/import-target.js | 27 +++++++++++++++++++++ tests/lib/rules/file-extension-in-import.js | 17 +++++++++++++ 3 files changed, 50 insertions(+), 9 deletions(-) diff --git a/lib/rules/file-extension-in-import.js b/lib/rules/file-extension-in-import.js index a7999a6d..b74a4b55 100644 --- a/lib/rules/file-extension-in-import.js +++ b/lib/rules/file-extension-in-import.js @@ -8,9 +8,6 @@ const path = require("path") const fs = require("fs") const mapTypescriptExtension = require("../util/map-typescript-extension") const visitImport = require("../util/visit-import") -const packageNamePattern = /^(?:@[^/\\]+[/\\])?[^/\\]+$/u -const corePackageOverridePattern = - /^(?:assert|async_hooks|buffer|child_process|cluster|console|constants|crypto|dgram|dns|domain|events|fs|http|http2|https|inspector|module|net|os|path|perf_hooks|process|punycode|querystring|readline|repl|stream|string_decoder|sys|timers|tls|trace_events|tty|url|util|v8|vm|worker_threads|zlib)[/\\]$/u /** * Get all file extensions of the files which have the same basename. @@ -67,13 +64,13 @@ module.exports = { const defaultStyle = context.options[0] || "always" const overrideStyle = context.options[1] || {} - function verify({ filePath, name, node }) { + /** + * @param {import("../util/import-target.js")} target + * @returns {void} + */ + function verify({ filePath, name, node, moduleType }) { // Ignore if it's not resolved to a file or it's a bare module. - if ( - !filePath || - packageNamePattern.test(name) || - corePackageOverridePattern.test(name) - ) { + if (moduleType !== "relative" && moduleType !== "absolute") { return } diff --git a/lib/util/import-target.js b/lib/util/import-target.js index 9f62a11a..b987b3ca 100644 --- a/lib/util/import-target.js +++ b/lib/util/import-target.js @@ -6,6 +6,7 @@ const path = require("path") const { pathToFileURL, fileURLToPath } = require("url") +const { isBuiltin } = require("module") const resolve = require("resolve") const { defaultResolve: importResolve, @@ -72,6 +73,14 @@ function getFilePath(isModule, id, options, moduleType) { } } +function isNodeModule(name, options) { + try { + return require.resolve(name, options).startsWith(path.sep) + } catch { + return false + } +} + /** * Gets the module name of a given path. * @@ -115,6 +124,24 @@ module.exports = class ImportTarget { */ this.name = name + /** + * What type of module is this + * @type {'unknown'|'relative'|'absolute'|'node'|'npm'|'http'|void} + */ + this.moduleType = "unknown" + + if (name.startsWith("./") || name.startsWith(".\\")) { + this.moduleType = "relative" + } else if (name.startsWith("/") || name.startsWith("\\")) { + this.moduleType = "absolute" + } else if (isBuiltin(name)) { + this.moduleType = "node" + } else if (isNodeModule(name, options)) { + this.moduleType = "npm" + } else if (name.startsWith("http://") || name.startsWith("https://")) { + this.moduleType = "http" + } + /** * The full path of this import target. * If the target is a module and it does not exist then this is `null`. diff --git a/tests/lib/rules/file-extension-in-import.js b/tests/lib/rules/file-extension-in-import.js index 6d3661c1..54dde82c 100644 --- a/tests/lib/rules/file-extension-in-import.js +++ b/tests/lib/rules/file-extension-in-import.js @@ -155,6 +155,23 @@ new RuleTester({ options: ["never", { ".json": "always" }], }, + // Ignore sub-paths of modules + { + filename: fixture("test.js"), + code: "import '@apollo/client/core'", + options: ["always"], + }, + { + filename: fixture("test.js"), + code: "import 'yargs/helpers'", + options: ["always"], + }, + { + filename: fixture("test.js"), + code: "import 'firebase-functions/v1/auth'", + options: ["always"], + }, + // typescriptExtensionMap { filename: fixture("test.tsx"),