UNPKG

eslint-plugin-import-x

Version:
1,573 lines (1,534 loc) 301 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var Module = require('node:module'); var path = require('node:path'); var unrsResolver = require('unrs-resolver'); var utils = require('@typescript-eslint/utils'); var fs = require('node:fs'); var debug = require('debug'); var eslint = require('eslint'); var getTsconfig = require('get-tsconfig'); var stableHash = require('stable-hash'); var node_url = require('node:url'); require('node:crypto'); var vm = require('node:vm'); var semver = require('semver'); var minimatch = require('minimatch'); var isGlob = require('is-glob'); var eslintUnsupportedApi = require('eslint/use-at-your-own-risk'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var semver__namespace = /*#__PURE__*/_interopNamespaceDefault(semver); var electron = { settings: { "import-x/core-modules": ["electron"] } }; var errors = { plugins: ["import-x"], rules: { "import-x/no-unresolved": 2, "import-x/named": 2, "import-x/namespace": 2, "import-x/default": 2, "import-x/export": 2 } }; var electronFlat = { settings: { "import-x/core-modules": ["electron"] } }; var errorsFlat = { rules: { "import-x/no-unresolved": 2, "import-x/named": 2, "import-x/namespace": 2, "import-x/default": 2, "import-x/export": 2 } }; var reactNativeFlat = { settings: { "import-x/resolver": { node: { // Note: will not complain if only _one_ of these files exists. extensions: [".js", ".web.js", ".ios.js", ".android.js"] } } } }; var reactFlat = { settings: { "import-x/extensions": [".js", ".jsx", ".mjs", ".cjs"] }, languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } } }; var recommendedFlat = { rules: { // analysis/correctness "import-x/no-unresolved": "error", "import-x/named": "error", "import-x/namespace": "error", "import-x/default": "error", "import-x/export": "error", // red flags (thus, warnings) "import-x/no-named-as-default": "warn", "import-x/no-named-as-default-member": "warn", "import-x/no-duplicates": "warn" }, // need all these for parsing dependencies (even if _your_ code doesn't need // all of them) languageOptions: { ecmaVersion: 2018, sourceType: "module" } }; var stage0Flat = { rules: { "import-x/no-deprecated": 1 } }; const typeScriptExtensions$1 = [".ts", ".tsx", ".cts", ".mts"]; const allExtensions$1 = [ ...typeScriptExtensions$1, ".js", ".jsx", ".cjs", ".mjs" ]; var typescriptFlat = { settings: { "import-x/extensions": allExtensions$1, "import-x/external-module-folders": ["node_modules", "node_modules/@types"], "import-x/parsers": { "@typescript-eslint/parser": [...typeScriptExtensions$1] }, "import-x/resolver": { typescript: true } }, rules: { // analysis/correctness // TypeScript compilation already ensures that named imports exist in the referenced module "import-x/named": "off" } }; var warningsFlat = { rules: { "import-x/no-named-as-default": 1, "import-x/no-named-as-default-member": 1, "import-x/no-rename-default": 1, "import-x/no-duplicates": 1 } }; var reactNative = { settings: { "import-x/resolver": { node: { // Note: will not complain if only _one_ of these files exists. extensions: [".js", ".web.js", ".ios.js", ".android.js"] } } } }; var react = { settings: { "import-x/extensions": [".js", ".jsx"] }, parserOptions: { ecmaFeatures: { jsx: true } } }; var recommended = { plugins: ["import-x"], rules: { // analysis/correctness "import-x/no-unresolved": "error", "import-x/named": "error", "import-x/namespace": "error", "import-x/default": "error", "import-x/export": "error", // red flags (thus, warnings) "import-x/no-named-as-default": "warn", "import-x/no-named-as-default-member": "warn", "import-x/no-duplicates": "warn" }, // need all these for parsing dependencies (even if _your_ code doesn't need // all of them) parserOptions: { sourceType: "module", ecmaVersion: 2018 } }; var stage0 = { plugins: ["import-x"], rules: { "import-x/no-deprecated": 1 } }; const typeScriptExtensions = [".ts", ".tsx", ".cts", ".mts"]; const allExtensions = [ ...typeScriptExtensions, ".js", ".jsx", ".cjs", ".mjs" ]; var typescript = { settings: { "import-x/extensions": allExtensions, "import-x/external-module-folders": ["node_modules", "node_modules/@types"], "import-x/parsers": { "@typescript-eslint/parser": [...typeScriptExtensions] }, "import-x/resolver": { typescript: true } }, rules: { // analysis/correctness // TypeScript compilation already ensures that named imports exist in the referenced module "import-x/named": "off" } }; var warnings = { plugins: ["import-x"], rules: { "import-x/no-named-as-default": 1, "import-x/no-named-as-default-member": 1, "import-x/no-rename-default": 1, "import-x/no-duplicates": 1 } }; const import_meta$1 = {}; const importMetaUrl$1 = import_meta$1.url; const cjsRequire = importMetaUrl$1 ? Module.createRequire(importMetaUrl$1) : ( /* istanbul ignore next */ require ); const { name, version } = cjsRequire( "../package.json" ); const meta = { name, version }; var __defProp$e = Object.defineProperty; var __getOwnPropSymbols$e = Object.getOwnPropertySymbols; var __hasOwnProp$e = Object.prototype.hasOwnProperty; var __propIsEnum$e = Object.prototype.propertyIsEnumerable; var __defNormalProp$e = (obj, key, value) => key in obj ? __defProp$e(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$e = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$e.call(b, prop)) __defNormalProp$e(a, prop, b[prop]); if (__getOwnPropSymbols$e) for (var prop of __getOwnPropSymbols$e(b)) { if (__propIsEnum$e.call(b, prop)) __defNormalProp$e(a, prop, b[prop]); } return a; }; var __objRest$1 = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp$e.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols$e) for (var prop of __getOwnPropSymbols$e(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum$e.call(source, prop)) target[prop] = source[prop]; } return target; }; function createNodeResolver(_a = {}) { var _b = _a, { extensions = [".mjs", ".cjs", ".js", ".json", ".node"], conditionNames = ["import", "require", "default"], mainFields = ["module", "main"] } = _b, restOptions = __objRest$1(_b, [ "extensions", "conditionNames", "mainFields" ]); const resolver = new unrsResolver.ResolverFactory(__spreadValues$e({ extensions, conditionNames, mainFields }, restOptions)); return { interfaceVersion: 3, name: "eslint-plugin-import-x:node", resolve(modulePath, sourceFile) { if (Module.isBuiltin(modulePath)) { return { found: true, path: null }; } if (modulePath.startsWith("data:")) { return { found: true, path: null }; } try { const resolved = resolver.sync(path.dirname(sourceFile), modulePath); if (resolved.path) { return { found: true, path: resolved.path }; } return { found: false }; } catch (e) { return { found: false }; } } }; } const repoUrl = "https://github.com/un-ts/eslint-plugin-import-x"; const docsUrl = (ruleName, commitish = `v${version}`) => `${repoUrl}/blob/${commitish}/docs/rules/${ruleName}.md`; const createRule = utils.ESLintUtils.RuleCreator(docsUrl); function declaredScope(context, node, name) { var _a; const references = context.sourceCode.getScope(node).references; const reference = references.find((x) => x.identifier.name === name); return (_a = reference == null ? void 0 : reference.resolved) == null ? void 0 : _a.scope.type; } const getValue = (node) => { switch (node.type) { case utils.TSESTree.AST_NODE_TYPES.Identifier: { return node.name; } case utils.TSESTree.AST_NODE_TYPES.Literal: { return node.value; } default: { throw new Error(`Unsupported node type: ${node.type}`); } } }; const log$5 = debug("eslint-plugin-import-x:utils:ignore"); let cachedSet; let lastSettings; function validExtensions(context) { if (cachedSet && context.settings === lastSettings) { return cachedSet; } lastSettings = context.settings; cachedSet = getFileExtensions(context.settings); return cachedSet; } function getFileExtensions(settings) { const exts = new Set( settings["import-x/extensions"] || [".js", ".mjs", ".cjs"] ); if ("import-x/parsers" in settings) { for (const parser in settings["import-x/parsers"]) { const parserSettings = settings["import-x/parsers"][parser]; if (!Array.isArray(parserSettings)) { throw new TypeError(`"settings" for ${parser} must be an array`); } for (const ext of parserSettings) exts.add(ext); } } return exts; } function ignore(filepath, context, skipExtensionCheck = false) { if (!skipExtensionCheck && !hasValidExtension(filepath, context)) { return true; } const ignoreStrings = context.settings["import-x/ignore"]; if (!(ignoreStrings == null ? void 0 : ignoreStrings.length)) { return false; } for (let i = 0, len = ignoreStrings.length; i < len; i++) { const ignoreString = ignoreStrings[i]; const regex = new RegExp(ignoreString); if (regex.test(filepath)) { log$5(`ignoring ${filepath}, matched pattern /${ignoreString}/`); return true; } } return false; } function hasValidExtension(filepath, context) { return validExtensions(context).has(path.extname(filepath)); } const lazy = (cb) => { let isCalled = false; let result; return () => { if (!isCalled) { isCalled = true; result = cb(); } return result; }; }; function defineLazyProperty(object, propertyName, valueGetter) { const define = (value) => Object.defineProperty(object, propertyName, { value, enumerable: true, writable: true }); Object.defineProperty(object, propertyName, { configurable: true, enumerable: true, get() { const result = valueGetter(); define(result); return result; }, set(value) { define(value); } }); return object; } function createModule(filename) { const mod = new Module(filename); mod.filename = filename; mod.paths = Module._nodeModulePaths(path.dirname(filename)); return mod; } function moduleRequire(p) { try { const eslintPath = cjsRequire.resolve("eslint"); const eslintModule = createModule(eslintPath); return cjsRequire( // @ts-expect-error _resolveFilename is undocumented Module._resolveFilename(p, eslintModule) ); } catch (e) { } try { return cjsRequire.main.require(p); } catch (e) { } return cjsRequire(p); } var __defProp$d = Object.defineProperty; var __getOwnPropSymbols$d = Object.getOwnPropertySymbols; var __hasOwnProp$d = Object.prototype.hasOwnProperty; var __propIsEnum$d = Object.prototype.propertyIsEnumerable; var __defNormalProp$d = (obj, key, value) => key in obj ? __defProp$d(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$d = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$d.call(b, prop)) __defNormalProp$d(a, prop, b[prop]); if (__getOwnPropSymbols$d) for (var prop of __getOwnPropSymbols$d(b)) { if (__propIsEnum$d.call(b, prop)) __defNormalProp$d(a, prop, b[prop]); } return a; }; var __objRest = (source, exclude) => { var target = {}; for (var prop in source) if (__hasOwnProp$d.call(source, prop) && exclude.indexOf(prop) < 0) target[prop] = source[prop]; if (source != null && __getOwnPropSymbols$d) for (var prop of __getOwnPropSymbols$d(source)) { if (exclude.indexOf(prop) < 0 && __propIsEnum$d.call(source, prop)) target[prop] = source[prop]; } return target; }; function withoutProjectParserOptions(opts) { const _a = opts, { EXPERIMENTAL_useProjectService, project, projectService } = _a, rest = __objRest(_a, ["EXPERIMENTAL_useProjectService", "project", "projectService"]); return rest; } const log$4 = debug("eslint-plugin-import-x:parse"); function keysFromParser(_parserPath, parserInstance, parsedResult) { if (parsedResult && parsedResult.visitorKeys) { return parsedResult.visitorKeys; } if (parserInstance && "VisitorKeys" in parserInstance && parserInstance.VisitorKeys) { return parserInstance.VisitorKeys; } return null; } function makeParseReturn(ast, visitorKeys) { return { ast, visitorKeys }; } function stripUnicodeBOM(text) { return text.codePointAt(0) === 65279 ? text.slice(1) : text; } function transformHashbang(text) { return text.replace(/^#!([^\r\n]+)/u, (_, captured) => `//${captured}`); } function parse(path2, content, context) { var _a, _b, _c, _d, _e; if (context == null) { throw new Error("need context to parse properly"); } let parserOptions = ((_a = context.languageOptions) == null ? void 0 : _a.parserOptions) || context.parserOptions; const parserOrPath = getParser(path2, context); if (!parserOrPath) { throw new Error("parserPath or languageOptions.parser is required!"); } parserOptions = __spreadValues$d({}, parserOptions); parserOptions.ecmaFeatures = __spreadValues$d({}, parserOptions.ecmaFeatures); parserOptions.comment = true; parserOptions.attachComment = true; parserOptions.tokens = true; parserOptions.loc = true; parserOptions.range = true; parserOptions.filePath = path2; parserOptions = withoutProjectParserOptions(parserOptions); (_c = parserOptions.ecmaVersion) != null ? _c : parserOptions.ecmaVersion = (_b = context.languageOptions) == null ? void 0 : _b.ecmaVersion; (_e = parserOptions.sourceType) != null ? _e : parserOptions.sourceType = (_d = context.languageOptions) == null ? void 0 : _d.sourceType; const parser = typeof parserOrPath === "string" ? moduleRequire(parserOrPath) : parserOrPath; content = transformHashbang(stripUnicodeBOM(String(content))); if ("parseForESLint" in parser && typeof parser.parseForESLint === "function") { let ast; try { const parserRaw = parser.parseForESLint(content, parserOptions); ast = parserRaw.ast; return makeParseReturn( ast, keysFromParser(parserOrPath, parser, parserRaw) ); } catch (error_) { const error = error_; console.warn(`Error while parsing ${parserOptions.filePath}`); console.warn( `Line ${error.lineNumber}, column ${error.column}: ${error.message}` ); } if (!ast || typeof ast !== "object") { console.warn( // Can only be invalid for custom parser per imports/parser `\`parseForESLint\` from parser \`${typeof parserOrPath === "string" ? parserOrPath : "context.languageOptions.parser"}\` is invalid and will just be ignored`, { content, parserMeta: parser.meta } ); } else { return makeParseReturn(ast, keysFromParser(parserOrPath, parser)); } } if ("parse" in parser) { const ast = parser.parse(content, parserOptions); return makeParseReturn(ast, keysFromParser(parserOrPath, parser)); } throw new Error("Parser must expose a `parse` or `parseForESLint` method"); } function getParser(path2, context) { var _a; const parserPath = getParserPath(path2, context); if (parserPath) { return parserPath; } const parser = "languageOptions" in context && ((_a = context.languageOptions) == null ? void 0 : _a.parser); if (parser && typeof parser !== "string" && ("parse" in parser && typeof parse === "function" || "parseForESLint" in parser && typeof parser.parseForESLint === "function")) { return parser; } return null; } function getParserPath(filepath, context) { const parsers = context.settings["import-x/parsers"]; if (parsers != null) { const extension = path.extname(filepath); for (const parserPath in parsers) { if (parsers[parserPath].includes(extension)) { log$4("using alt parser:", parserPath); return parserPath; } } } return context.parserPath; } function findUp(filename, cwd) { let dir = path.resolve(cwd || ""); const root = path.parse(dir).root; const filenames = [filename].flat(); while (true) { const file = filenames.find((el) => fs.existsSync(path.resolve(dir, el))); if (file) { return path.resolve(dir, file); } if (dir === root) { return null; } dir = path.dirname(dir); } } function pkgUp(opts) { return findUp("package.json", opts && opts.cwd); } function pkgDir(cwd) { const fp = pkgUp({ cwd }); return fp ? path.dirname(fp) : null; } function resolveWithLegacyResolver(resolver, config, modulePath, sourceFile) { if (resolver.interfaceVersion === 2) { return resolver.resolve(modulePath, sourceFile, config); } try { const resolved = resolver.resolveImport(modulePath, sourceFile, config); if (resolved === void 0) { return { found: false }; } return { found: true, path: resolved }; } catch (e) { return { found: false }; } } function normalizeConfigResolvers(resolvers, sourceFile) { const resolverArray = Array.isArray(resolvers) ? resolvers : [resolvers]; const map = /* @__PURE__ */ new Map(); for (const nameOrRecordOrObject of resolverArray) { if (typeof nameOrRecordOrObject === "string") { const name = nameOrRecordOrObject; map.set(name, { name, enable: true, options: void 0, resolver: requireResolver(name, sourceFile) }); } else if (typeof nameOrRecordOrObject === "object") { if (nameOrRecordOrObject.name && nameOrRecordOrObject.resolver) { const object = nameOrRecordOrObject; const { name, enable = true, options, resolver } = object; map.set(name, { name, enable, options, resolver }); } else { const record = nameOrRecordOrObject; for (const [name, enableOrOptions] of Object.entries(record)) { if (typeof enableOrOptions === "boolean") { map.set(name, { name, enable: enableOrOptions, options: void 0, resolver: requireResolver(name, sourceFile) }); } else { map.set(name, { name, enable: true, options: enableOrOptions, resolver: requireResolver(name, sourceFile) }); } } } } else { const err = new Error("invalid resolver config"); err.name = IMPORT_RESOLVE_ERROR_NAME; throw err; } } return [...map.values()]; } function requireResolver(name, sourceFile) { const resolver = tryRequire(`eslint-import-resolver-${name}`, sourceFile) || tryRequire(name, sourceFile) || tryRequire(path.resolve(getBaseDir(sourceFile), name)); if (!resolver) { const err = new Error(`unable to load resolver "${name}".`); err.name = IMPORT_RESOLVE_ERROR_NAME; throw err; } if (!isLegacyResolverValid(resolver)) { const err = new Error(`${name} with invalid interface loaded as resolver`); err.name = IMPORT_RESOLVE_ERROR_NAME; throw err; } return resolver; } function isLegacyResolverValid(resolver) { if ("interfaceVersion" in resolver && resolver.interfaceVersion === 2) { return "resolve" in resolver && !!resolver.resolve && typeof resolver.resolve === "function"; } return "resolveImport" in resolver && !!resolver.resolveImport && typeof resolver.resolveImport === "function"; } function tryRequire(target, sourceFile) { let resolved; try { if (sourceFile == null) { resolved = cjsRequire.resolve(target); } else { try { resolved = Module.createRequire(path.resolve(sourceFile)).resolve(target); } catch (e) { resolved = cjsRequire.resolve(target); } } } catch (e) { return void 0; } return cjsRequire(resolved); } function getBaseDir(sourceFile) { return pkgDir(sourceFile) || process.cwd(); } var __defProp$c = Object.defineProperty; var __getOwnPropSymbols$c = Object.getOwnPropertySymbols; var __hasOwnProp$c = Object.prototype.hasOwnProperty; var __propIsEnum$c = Object.prototype.propertyIsEnumerable; var __defNormalProp$c = (obj, key, value) => key in obj ? __defProp$c(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$c = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$c.call(b, prop)) __defNormalProp$c(a, prop, b[prop]); if (__getOwnPropSymbols$c) for (var prop of __getOwnPropSymbols$c(b)) { if (__propIsEnum$c.call(b, prop)) __defNormalProp$c(a, prop, b[prop]); } return a; }; const log$3 = debug("eslint-plugin-import-x:utils:ModuleCache"); class ModuleCache { constructor(map = /* @__PURE__ */ new Map()) { this.map = map; } set(cacheKey, result) { this.map.set(cacheKey, { result, lastSeen: process.hrtime() }); log$3("setting entry for", cacheKey); return result; } get(cacheKey, settings) { if (this.map.has(cacheKey)) { const f = this.map.get(cacheKey); if (process.hrtime(f.lastSeen)[0] < settings.lifetime) { return f.result; } } else { log$3("cache miss for", cacheKey); } } static getSettings(settings) { const cacheSettings = __spreadValues$c({ lifetime: 30 }, settings["import-x/cache"]); if (typeof cacheSettings.lifetime === "string" && ["\u221E", "Infinity"].includes(cacheSettings.lifetime)) { cacheSettings.lifetime = Number.POSITIVE_INFINITY; } return cacheSettings; } } const import_meta = {}; const importMetaUrl = import_meta.url; const _filename = importMetaUrl ? node_url.fileURLToPath(importMetaUrl) : ( /* istanbul ignore next */ __filename ); const _dirname = path.dirname(_filename); const CASE_SENSITIVE_FS = !fs.existsSync( path.resolve( _dirname, path.basename(_filename).replace(/^resolve\./, "reSOLVE.") ) ); const IMPORT_RESOLVE_ERROR_NAME = "EslintPluginImportResolveError"; const fileExistsCache = new ModuleCache(); function fileExistsWithCaseSync(filepath, cacheSettings, strict) { if (CASE_SENSITIVE_FS) { return true; } if (filepath === null) { return true; } if (filepath.toLowerCase() === process.cwd().toLowerCase() && !strict) { return true; } const parsedPath = path.parse(filepath); const dir = parsedPath.dir; let result = fileExistsCache.get(filepath, cacheSettings); if (result != null) { return result; } if (dir === "" || parsedPath.root === filepath) { result = true; } else { const filenames = fs.readdirSync(dir); result = filenames.includes(parsedPath.base) ? fileExistsWithCaseSync(dir, cacheSettings, strict) : false; } fileExistsCache.set(filepath, result); return result; } let prevSettings = null; let memoizedHash; function isNamedResolver(resolver) { return !!(typeof resolver === "object" && resolver && "name" in resolver && typeof resolver.name === "string" && resolver.name); } function isValidNewResolver(resolver) { if (typeof resolver !== "object" || resolver == null) { return false; } if (!("resolve" in resolver) || !("interfaceVersion" in resolver)) { return false; } if (typeof resolver.interfaceVersion !== "number" || resolver.interfaceVersion !== 3) { return false; } if (typeof resolver.resolve !== "function") { return false; } return true; } function fullResolve(modulePath, sourceFile, settings) { const coreSet = new Set(settings["import-x/core-modules"]); if (coreSet.has(modulePath)) { return { found: true, path: null }; } const sourceDir = path.dirname(sourceFile); if (prevSettings !== settings) { memoizedHash = stableHash.stableHash(settings); prevSettings = settings; } const cacheKey = sourceDir + memoizedHash + modulePath; const cacheSettings = ModuleCache.getSettings(settings); const cachedPath = fileExistsCache.get(cacheKey, cacheSettings); if (cachedPath !== void 0) { return { found: true, path: cachedPath }; } if (Object.prototype.hasOwnProperty.call(settings, "import-x/resolver-next") && settings["import-x/resolver-next"]) { const configResolvers = settings["import-x/resolver-next"]; for (let i = 0, len = configResolvers.length; i < len; i++) { const resolver = configResolvers[i]; const resolverName = isNamedResolver(resolver) ? resolver.name : `settings['import-x/resolver-next'][${i}]`; if (!isValidNewResolver(resolver)) { const err = new TypeError( `${resolverName} is not a valid import resolver for eslint-plugin-import-x!` ); err.name = IMPORT_RESOLVE_ERROR_NAME; throw err; } const resolved = resolver.resolve(modulePath, sourceFile); if (!resolved.found) { continue; } fileExistsCache.set(cacheKey, resolved.path); return resolved; } } else { const configResolvers = settings["import-x/resolver-legacy"] || settings["import-x/resolver"] || { node: settings["import-x/resolve"] }; for (const { enable, options, resolver } of normalizeConfigResolvers( configResolvers, sourceFile )) { if (!enable) { continue; } const resolved = resolveWithLegacyResolver( resolver, options, modulePath, sourceFile ); if (!resolved.found) { continue; } fileExistsCache.set(cacheKey, resolved.path); return resolved; } } return { found: false }; } function relative(modulePath, sourceFile, settings) { return fullResolve(modulePath, sourceFile, settings).path; } const erroredContexts = /* @__PURE__ */ new Set(); function resolve(p, context) { try { return relative(p, context.physicalFilename, context.settings); } catch (error_) { const error = error_; if (!erroredContexts.has(context)) { let errMessage = error.message; if (error.name !== IMPORT_RESOLVE_ERROR_NAME && error.stack) { errMessage = error.stack.replace(/^Error: /, ""); } context.report({ // @ts-expect-error - report without messageId message: `Resolve error: ${errMessage}`, loc: { line: 1, column: 0 } }); erroredContexts.add(context); } } } function importXResolverCompat(resolver, resolverOptions = {}) { if (isValidNewResolver(resolver)) { return resolver; } return { // deliberately not providing the name, because we can't get the name from legacy resolvers // By omitting the name, the log will use identifiable name like `settings['import-x/resolver-next'][0]` // name: 'import-x-resolver-compat', interfaceVersion: 3, resolve: (modulePath, sourceFile) => { const resolved = resolveWithLegacyResolver( resolver, resolverOptions, modulePath, sourceFile ); return resolved; } }; } const pattern = /(^|;)\s*(export|import)((\s+\w)|(\s*[*={]))|import\(/m; function isMaybeUnambiguousModule(content) { return pattern.test(content); } const unambiguousNodeType = /^(?:(?:Exp|Imp)ort.*Declaration|TSExportAssignment)$/; function isUnambiguousModule(ast) { return ast.body && ast.body.some((node) => unambiguousNodeType.test(node.type)); } function visit(node, keys, visitorSpec) { if (!node || !keys) { return; } const type = node.type; const visitor = visitorSpec[type]; if (typeof visitor === "function") { visitor(node); } const childFields = keys[type]; if (!childFields) { return; } for (const fieldName of childFields) { for (const item of [node[fieldName]].flat()) { if (!item || typeof item !== "object" || !("type" in item)) { continue; } visit(item, keys, visitorSpec); } } const exit = visitorSpec[`${type}:Exit`]; if (typeof exit === "function") { exit(node); } } var __defProp$b = Object.defineProperty; var __defProps$5 = Object.defineProperties; var __getOwnPropDescs$5 = Object.getOwnPropertyDescriptors; var __getOwnPropSymbols$b = Object.getOwnPropertySymbols; var __hasOwnProp$b = Object.prototype.hasOwnProperty; var __propIsEnum$b = Object.prototype.propertyIsEnumerable; var __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __spreadValues$b = (a, b) => { for (var prop in b || (b = {})) if (__hasOwnProp$b.call(b, prop)) __defNormalProp$b(a, prop, b[prop]); if (__getOwnPropSymbols$b) for (var prop of __getOwnPropSymbols$b(b)) { if (__propIsEnum$b.call(b, prop)) __defNormalProp$b(a, prop, b[prop]); } return a; }; var __spreadProps$5 = (a, b) => __defProps$5(a, __getOwnPropDescs$5(b)); var __publicField = (obj, key, value) => __defNormalProp$b(obj, typeof key !== "symbol" ? key + "" : key, value); const log$2 = debug("eslint-plugin-import-x:ExportMap"); const exportCache = /* @__PURE__ */ new Map(); const tsconfigCache = /* @__PURE__ */ new Map(); const declTypes = /* @__PURE__ */ new Set([ "VariableDeclaration", "ClassDeclaration", "TSDeclareFunction", "TSEnumDeclaration", "TSTypeAliasDeclaration", "TSInterfaceDeclaration", "TSAbstractClassDeclaration", "TSModuleDeclaration" ]); const fixup = /* @__PURE__ */ new Set(["deprecated", "module"]); let parseComment_; const parseComment = (comment) => { parseComment_ != null ? parseComment_ : parseComment_ = cjsRequire("comment-parser").parse; const restored = `/**${comment.split(/\r?\n/).reduce((acc, line) => { line = line.trim(); return line && line !== "*" ? acc + "\n " + line : acc; }, "")} */`; const [doc] = parseComment_(restored); return __spreadProps$5(__spreadValues$b({}, doc), { tags: doc.tags.map( (t) => t.name && fixup.has(t.tag) ? __spreadProps$5(__spreadValues$b({}, t), { description: `${t.name} ${t.description}` }) : t ) }); }; class ExportMap { constructor(path2) { this.path = path2; __publicField(this, "namespace", /* @__PURE__ */ new Map()); // todo: restructure to key on path, value is resolver + map of names __publicField(this, "reexports", /* @__PURE__ */ new Map()); /** Star-exports */ __publicField(this, "dependencies", /* @__PURE__ */ new Set()); /** Dependencies of this module that are not explicitly re-exported */ __publicField(this, "imports", /* @__PURE__ */ new Map()); __publicField(this, "exports", /* @__PURE__ */ new Map()); __publicField(this, "errors", []); __publicField(this, "parseGoal", "ambiguous"); } static for(context) { const filepath = context.path; const cacheKey = context.cacheKey; let exportMap = exportCache.get(cacheKey); const stats = lazy(() => fs.statSync(filepath)); if (exportCache.has(cacheKey)) { const exportMap2 = exportCache.get(cacheKey); if (exportMap2 === null) { return null; } if (exportMap2 != null && exportMap2.mtime - stats().mtime.valueOf() === 0) { return exportMap2; } } if (!hasValidExtension(filepath, context)) { exportCache.set(cacheKey, null); return null; } if (ignore(filepath, context, true)) { log$2("ignored path due to ignore settings:", filepath); exportCache.set(cacheKey, null); return null; } const content = fs.readFileSync(filepath, { encoding: "utf8" }); if (!isMaybeUnambiguousModule(content)) { log$2("ignored path due to unambiguous regex:", filepath); exportCache.set(cacheKey, null); return null; } log$2("cache miss", cacheKey, "for path", filepath); exportMap = ExportMap.parse(filepath, content, context); if (exportMap === null) { log$2("ignored path due to ambiguous parse:", filepath); exportCache.set(cacheKey, null); return null; } exportMap.mtime = stats().mtime.valueOf(); if (exportMap.visitorKeys) { exportCache.set(cacheKey, exportMap); } return exportMap; } static get(source, context) { const path2 = resolve(source, context); if (path2 == null) { return null; } return ExportMap.for(childContext(path2, context)); } static parse(filepath, content, context) { var _a, _b; const m = new ExportMap(filepath); const isEsModuleInteropTrue = lazy(isEsModuleInterop); let ast; let visitorKeys; try { ; ({ ast, visitorKeys } = parse(filepath, content, context)); } catch (error) { m.errors.push(error); return m; } m.visitorKeys = visitorKeys; let hasDynamicImports = false; function processDynamicImport(source2) { hasDynamicImports = true; if (source2.type !== "Literal") { return null; } const p = remotePath(source2.value); if (p == null) { return null; } const getter = thunkFor(p, context); m.imports.set(p, { getter, declarations: /* @__PURE__ */ new Set([ { source: { // capturing actual node reference holds full AST in memory! value: source2.value, loc: source2.loc }, importedSpecifiers: /* @__PURE__ */ new Set(["ImportNamespaceSpecifier"]), dynamic: true } ]) }); } visit(ast, visitorKeys, { ImportExpression(node) { processDynamicImport(node.source); }, CallExpression(_node) { const node = _node; if (node.callee.type === "Import") { processDynamicImport(node.arguments[0]); } } }); const unambiguouslyESM = lazy(() => isUnambiguousModule(ast)); if (!hasDynamicImports && !unambiguouslyESM()) { return null; } const docStyles = context.settings && context.settings["import-x/docstyle"] || ["jsdoc"]; const docStyleParsers = {}; for (const style of docStyles) { docStyleParsers[style] = availableDocStyleParsers[style]; } const namespaces = /* @__PURE__ */ new Map(); function remotePath(value) { return relative(value, filepath, context.settings); } function resolveImport(value) { const rp = remotePath(value); if (rp == null) { return null; } return ExportMap.for(childContext(rp, context)); } function getNamespace(namespace) { if (!namespaces.has(namespace)) { return; } return function() { return resolveImport(namespaces.get(namespace)); }; } function addNamespace(object, identifier) { const nsfn = getNamespace(getValue(identifier)); if (nsfn) { Object.defineProperty(object, "namespace", { get: nsfn }); } return object; } function processSpecifier(s, n, m2) { const nsource = "source" in n && n.source && n.source.value; const exportMeta = {}; let local; switch (s.type) { case "ExportDefaultSpecifier": { if (!nsource) { return; } local = "default"; break; } case "ExportNamespaceSpecifier": { m2.exports.set(s.exported.name, n); m2.namespace.set( s.exported.name, Object.defineProperty(exportMeta, "namespace", { get() { return resolveImport(nsource); } }) ); return; } case "ExportAllDeclaration": { m2.exports.set(getValue(s.exported), n); m2.namespace.set( getValue(s.exported), addNamespace(exportMeta, s.exported) ); return; } case "ExportSpecifier": { if (!("source" in n && n.source)) { m2.exports.set(getValue(s.exported), n); m2.namespace.set( getValue(s.exported), addNamespace(exportMeta, s.local) ); return; } } // else falls through default: { if ("local" in s) { local = getValue(s.local); } else { throw new Error("Unknown export specifier type"); } break; } } if ("exported" in s) { m2.reexports.set(getValue(s.exported), { local, getImport: () => resolveImport(nsource) }); } } function captureDependencyWithSpecifiers(n) { const declarationIsType = "importKind" in n && (n.importKind === "type" || // @ts-expect-error - flow type n.importKind === "typeof"); let specifiersOnlyImportingTypes = n.specifiers.length > 0; const importedSpecifiers = /* @__PURE__ */ new Set(); for (const specifier of n.specifiers) { if (specifier.type === "ImportSpecifier") { importedSpecifiers.add(getValue(specifier.imported)); } else if (supportedImportTypes.has(specifier.type)) { importedSpecifiers.add(specifier.type); } specifiersOnlyImportingTypes = specifiersOnlyImportingTypes && "importKind" in specifier && (specifier.importKind === "type" || // @ts-expect-error - flow type specifier.importKind === "typeof"); } captureDependency( n, declarationIsType || specifiersOnlyImportingTypes, importedSpecifiers ); } function captureDependency({ source: source2 }, isOnlyImportingTypes, importedSpecifiers = /* @__PURE__ */ new Set()) { if (source2 == null) { return null; } const p = remotePath(source2.value); if (p == null) { return null; } const declarationMetadata = { // capturing actual node reference holds full AST in memory! source: { value: source2.value, loc: source2.loc }, isOnlyImportingTypes, importedSpecifiers }; const existing = m.imports.get(p); if (existing != null) { existing.declarations.add(declarationMetadata); return existing.getter; } const getter = thunkFor(p, context); m.imports.set(p, { getter, declarations: /* @__PURE__ */ new Set([declarationMetadata]) }); return getter; } const source = new eslint.SourceCode({ text: content, ast }); function isEsModuleInterop() { var _a2, _b2; const parserOptions = context.parserOptions || {}; let tsconfigRootDir = parserOptions.tsconfigRootDir; const project = parserOptions.project; const cacheKey = stableHash.stableHash({ tsconfigRootDir, project }); let tsConfig; if (tsconfigCache.has(cacheKey)) { tsConfig = tsconfigCache.get(cacheKey); } else { tsconfigRootDir = tsconfigRootDir || process.cwd(); let tsconfigResult; if (project) { const projects = Array.isArray(project) ? project : [project]; for (const project2 of projects) { tsconfigResult = getTsconfig.getTsconfig( project2 === true ? context.filename : path.resolve(tsconfigRootDir, project2) ); if (tsconfigResult) { break; } } } else { tsconfigResult = getTsconfig.getTsconfig(tsconfigRootDir); } tsConfig = tsconfigResult == null ? void 0 : tsconfigResult.config; tsconfigCache.set(cacheKey, tsConfig); } return (_b2 = (_a2 = tsConfig == null ? void 0 : tsConfig.compilerOptions) == null ? void 0 : _a2.esModuleInterop) != null ? _b2 : false; } for (const n of ast.body) { if (n.type === "ExportDefaultDeclaration") { const exportMeta = captureDoc(source, docStyleParsers, n); if (n.declaration.type === "Identifier") { addNamespace(exportMeta, n.declaration); } m.exports.set("default", n); m.namespace.set("default", exportMeta); continue; } if (n.type === "ExportAllDeclaration") { if (n.exported) { namespaces.set(n.exported.name, n.source.value); processSpecifier(n, n.exported, m); } else { const getter = captureDependency(n, n.exportKind === "type"); if (getter) { m.dependencies.add(getter); } } continue; } if (n.type === "ImportDeclaration") { captureDependencyWithSpecifiers(n); const ns = n.specifiers.find((s) => s.type === "ImportNamespaceSpecifier"); if (ns) { namespaces.set(ns.local.name, n.source.value); } continue; } if (n.type === "ExportNamedDeclaration") { captureDependencyWithSpecifiers(n); if (n.declaration != null) { switch (n.declaration.type) { case "FunctionDeclaration": case "ClassDeclaration": /* eslint-disable no-fallthrough */ // @ts-expect-error - flowtype with @babel/eslint-parser case "TypeAlias": // @ts-expect-error - legacy parser type case "InterfaceDeclaration": // @ts-expect-error - legacy parser type case "DeclareFunction": case "TSDeclareFunction": case "TSEnumDeclaration": case "TSTypeAliasDeclaration": case "TSInterfaceDeclaration": // @ts-expect-error - legacy parser type case "TSAbstractClassDeclaration": case "TSModuleDeclaration": { m.exports.set(n.declaration.id.name, n); m.namespace.set( n.declaration.id.name, captureDoc(source, docStyleParsers, n) ); break; } /* eslint-enable no-fallthrough */ case "VariableDeclaration": { for (const d of n.declaration.declarations) { recursivePatternCapture(d.id, (id) => { m.exports.set(id.name, n); m.namespace.set( id.name, captureDoc(source, docStyleParsers, d, n) ); }); } break; } } } for (const s of n.specifiers) { processSpecifier(s, n, m); } } const exports = ["TSExportAssignment"]; if (isEsModuleInteropTrue()) { exports.push("TSNamespaceExportDeclaration"); } if (exports.includes(n.type)) { const exportedName = n.type === "TSNamespaceExportDeclaration" ? (n.id || // @ts-expect-error - legacy parser type n.name).name : "expression" in n && n.expression && ("name" in n.expression && n.expression.name || "id" in n.expression && n.expression.id && n.expression.id.name) || null; const getRoot = (node) => { if (node.left.type === "TSQualifiedName") { return getRoot(node.left); } return node.left; }; const exportedDecls = ast.body.filter((node) => { return declTypes.has(node.type) && ("id" in node && node.id && ("name" in node.id ? node.id.name === exportedName : "left" in node.id && getRoot(node.id).name === exportedName) || "declarations" in node && node.declarations.find( (d) => "name" in d.id && d.id.name === exportedName )); }); if (exportedDecls.length === 0) { m.exports.set("default", n); m.namespace.set("default", captureDoc(source, docStyleParsers, n)); continue; } if (isEsModuleInteropTrue() && // esModuleInterop is on in tsconfig !m.namespace.has("default")) { m.exports.set("default", n); m.namespace.set("default", {}); } for (const decl of exportedDecls) { if (decl.type === "TSModuleDeclaration") { const type = (_a = decl.body) == null ? void 0 : _a.type; if (type === "TSModuleDeclaration") { m.exports.set(decl.body.id.name, n); m.namespace.set( // @ts-expect-error - legacy parser type decl.body.id.name, captureDoc(source, docStyleParsers, decl.body) ); continue; } else if (type === "TSModuleBlock" && decl.kind === "namespace") { const metadata = captureDoc(source, docStyleParsers, decl.body); if ("name" in decl.id) { m.namespace.set(decl.id.name, metadata); } else { m.namespace.set(decl.id.right.name, metadata); } } if ((_b = decl.body) == null ? void 0 : _b.body) { for (const moduleBlockNode of decl.body.body) { const namespaceDecl = moduleBlockNode.type === "ExportNamedDeclaration" ? moduleBlockNode.declaration : moduleBlockNode; if (!namespaceDecl) ; else if (namespaceDecl.type === "VariableDeclaration") { for (const d of namespaceDecl.declarations) recursivePatternCapture(d.id, (id) => { m.exports.set(id.name, n); m.namespace.set( id.name, captureDoc( source, docStyleParsers, decl, namespaceDecl, moduleBlockNode ) ); }); } else if ("id" in namespaceDecl) { m.exports.set( namespaceDecl.id.name, n ); m.namespace.set( namespaceDecl.id.name, captureDoc(source, docStyleParsers, moduleBlockNode) ); } } } } else { m.exports.set("default", n); m.namespace.set( "default", captureDoc(source, docStyleParsers, decl) ); } } } } defineLazyProperty(m, "doc", () => { var _a2; if (!((_a2 = ast.comments) == null ? void 0 : _a2.length)) { return; } for (const c of ast.comments) { if (c.type !== "Block") { continue; } try { const doc = parseComment(c.value); if (doc.tags.some((t) => t.tag === "module")) { return doc; } } catch (e) { } } }); if (isEsModuleInteropTrue() && // esModuleInterop is on in tsconfig m.namespace.size > 0 && // anything is exported !m.namespace.has("default")) { m.exports.set("default", ast.body[0]); m.namespace.set("default", {}); } const prevParseGoal = m.parseGoal; defineLazyProperty(m, "parseGoal", () => { if (prevParseGoal !== "Module" && unambiguouslyESM()) { return "Module"; } return prevParseGoal; }); return m; } get hasDefault() { return this.get("default") != null; } // stronger than this.has get size() { let size = this.namespace.size + this.reexports.size; for (const dep of this.dependencies) { const d = dep(); if (d == null) { continue; } size += d.size; } return size; } /** * Note that this does not check explicitly re-exported names for existence in * the base namespace, but it will expand all `export * from '...'` exports if * not found in the explicit namespace. * * @returns True if `name` is exported by this module. */ has(name) { if (this.namespace.has(name)) { return true; } if (this.reexports.has(name)) { return true; } if (name !== "default") { for (const dep of this.dependencies) { const innerMap = dep(); if (!innerMap) { continue; } if (innerMap.has(name)) { return true; } } } return false; } /** Ensure that imported name fully resolves. */ hasDeep(name) { if (this.namespace.has(name)) { return { found: true, path: [this] }; } if (this.reexports.has(name)) { const reexports = this.reexports.get(name); const imported = reexports.getImport(); if (imported == null) { return { found: true, path: [this] }; } if (imported.path === this.path && reexports.local === name) { return { found: false, path: [this] }; } const deep = imported.hasDeep(reexports.local); deep.path.unshift(this); return deep; } if (name !== "default") { for (const dep of this.dependencies) { const innerMap = dep(); if (innerMap == null) { return { found: true, path: [