eslint-plugin-import-x
Version:
Import with sanity.
1,585 lines (1,547 loc) • 300 kB
JavaScript
'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 doctrine = require('doctrine');
var eslint = require('eslint');
var getTsconfig = require('get-tsconfig');
var stableHash = require('stable-hash');
var core = require('@pkgr/core');
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 doctrine__namespace = /*#__PURE__*/_interopNamespaceDefault(doctrine);
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 cjsRequire = typeof require === "undefined" ? Module.createRequire(import_meta$1.url) : (
/* istanbul ignore next */
require
);
const { name, version } = cjsRequire(
"../package.json"
);
const meta = { name, version };
var __defProp$e = Object.defineProperty;
var __getOwnPropSymbols$d = Object.getOwnPropertySymbols;
var __hasOwnProp$d = Object.prototype.hasOwnProperty;
var __propIsEnum$d = 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$d = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$d.call(b, prop))
__defNormalProp$e(a, prop, b[prop]);
if (__getOwnPropSymbols$d)
for (var prop of __getOwnPropSymbols$d(b)) {
if (__propIsEnum$d.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$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 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$d({
extensions,
conditionNames,
mainFields
}, restOptions));
return {
interfaceVersion: 3,
name: "eslint-plugin-import-x built-in node resolver",
resolve(modulePath, sourceFile) {
if (Module.isBuiltin(modulePath)) {
return { found: true, path: null };
}
if (process.versions.pnp && modulePath === "pnpapi") {
return {
found: true,
path: Module.findPnpApi(sourceFile).resolveToUnqualified(modulePath, sourceFile, {
considerBuiltins: false
})
};
}
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 = core.cjsRequire.resolve("eslint");
const eslintModule = createModule(eslintPath);
return core.cjsRequire(
// @ts-expect-error _resolveFilename is undocumented
Module._resolveFilename(p, eslintModule)
);
} catch (e) {
}
try {
return core.cjsRequire.main.require(p);
} catch (e) {
}
return core.cjsRequire(p);
}
var __defProp$d = Object.defineProperty;
var __getOwnPropSymbols$c = Object.getOwnPropertySymbols;
var __hasOwnProp$c = Object.prototype.hasOwnProperty;
var __propIsEnum$c = 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$c = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$c.call(b, prop))
__defNormalProp$d(a, prop, b[prop]);
if (__getOwnPropSymbols$c)
for (var prop of __getOwnPropSymbols$c(b)) {
if (__propIsEnum$c.call(b, prop))
__defNormalProp$d(a, prop, b[prop]);
}
return a;
};
var __objRest = (source, exclude) => {
var target = {};
for (var prop in source)
if (__hasOwnProp$c.call(source, prop) && exclude.indexOf(prop) < 0)
target[prop] = source[prop];
if (source != null && __getOwnPropSymbols$c)
for (var prop of __getOwnPropSymbols$c(source)) {
if (exclude.indexOf(prop) < 0 && __propIsEnum$c.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$c({}, parserOptions);
parserOptions.ecmaFeatures = __spreadValues$c({}, 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 = core.cjsRequire.resolve(target);
} else {
try {
resolved = Module.createRequire(path.resolve(sourceFile)).resolve(target);
} catch (e) {
resolved = core.cjsRequire.resolve(target);
}
}
} catch (e) {
return void 0;
}
return core.cjsRequire(resolved);
}
function getBaseDir(sourceFile) {
return pkgDir(sourceFile) || process.cwd();
}
var __defProp$c = Object.defineProperty;
var __getOwnPropSymbols$b = Object.getOwnPropertySymbols;
var __hasOwnProp$b = Object.prototype.hasOwnProperty;
var __propIsEnum$b = 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$b = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$b.call(b, prop))
__defNormalProp$c(a, prop, b[prop]);
if (__getOwnPropSymbols$b)
for (var prop of __getOwnPropSymbols$b(b)) {
if (__propIsEnum$b.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$b({
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 _filename = typeof __filename === "undefined" ? node_url.fileURLToPath(import_meta.url) : (
/* 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 __defNormalProp$b = (obj, key, value) => key in obj ? __defProp$b(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
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"
]);
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", () => {
if (ast.comments) {
for (let i = 0, len = ast.comments.length; i < len; i++) {
const c = ast.comments[i];
if (c.type !== "Block") {
continue;
}
try {
const doc = doctrine__namespace.parse(c.value, { unwrap: true });
if (doc.tags.some((t) => t.title === "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.
* @return 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: [this] };
}
if (!innerMap) {
continue;
}
if (innerMap.path === this.path) {
continue;
}
const innerValue = innerMap.hasDeep(name);
if (innerValue.found) {
innerValue.path.unshift(this);
return innerValue;
}
}
}
return { found: false, path: [this] };
}
get(name) {
if (this.namespace.has(name)) {
return this.namespace.get(name);
}
if (this.reexports.has(name)) {
const reexports = this.reexports.get(name);
const imported = reexports.getImport();
if (imported == null) {
return null;
}
if (imported.path === this.path && reexports.local === name) {
return void 0;
}
return imported.get(reexports.local);
}
if (name !== "default") {
for (