eslint-plugin-import-x
Version:
Import with sanity.
9,223 lines • 301 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 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: [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 (const dep of this.dependencies) {
const innerMap = dep();
if (!innerMap) {
continue;
}
if (innerMap.path === this.path) {
continue;
}
const innerValue = innerMap.get(name);
if (innerValue !== void 0) {
return innerValue;
}
}
}
}
// FIXME: `forEach` will be transformed into `.entries()`, WTF?!
$forEach(callback, thisArg) {
for (const [n, v] of this.namespace.entries()) {
callback.call(thisArg, v, n, this);
}
for (const [name, reexports] of this.reexports.entries()) {
const reexported = reexports.getImport();
callback.call(thisArg, reexported == null ? void 0 : reexported.get(reexports.local), name, this);
}
this.dependencies.forEach((dep) => {
const d = dep();
if (d == null) {
return;
}
d.$forEach((v, n) => {
if (n !== "default") {
callback.call(thisArg, v, n, this);
}
});
});
}
// todo: keys, values, entries?
reportErrors(context, declaration) {
if (!declaration.source) {
throw new Error("declaration.source is null");
}
const msg = this.errors.map((err) => `${err.message} (${err.lineNumber}:${err.column})`).join(", ");
context.report({
node: declaration.source,
// @ts-expect-error - report without messageId
message: `Parse errors in imported module '${declaration.source.value}': ${msg}`
});
}
}
function captureDoc(source, docStyleParsers, ...nodes) {
const metadata = {};
defineLazyProperty(metadata, "doc", () => {
for (let i = 0, len = nodes.length; i < len; i++) {
const n = nodes[i];
if (!n) {
continue;
}
try {
let leadingComments;
if ("leadingComments" in n && Array.isArray(n.leadingComments)) {
leadingComments = n.leadingComments;
} else if (n.range) {
leadingComments = source.getCommentsBefore(n);
}
if (!leadingComments || leadingComments.length === 0) {
continue;
}
for (const parser of Object.values(docStyleParsers)) {
const doc = parser(leadingComments);
if (doc) {
return doc;
}
}
return;
} catch (e) {
continue;
}
}
});
return metadata;
}
const availableDocStyleParsers = {
jsdoc: captureJsDoc,
tomdoc: captureTomDoc
};
function captureJsDoc(comments) {
for (let i = comments.length - 1; i >= 0; i--) {
const comment = comments[i];
if (comment.type !== "Block") {
continue;
}
try {
return parseComment(comment.value);
} catch (e) {
}
}
}
function captureTomDoc(comments) {
const lines = [];
for (const comment of comments) {
if (/^\s*$/.test(comment.value)) {
break;
}
lines.push(comment.value.trim());
}
const statusMatch = lines.join(" ").match(/^(Public|Internal|Deprecated):\s*(.+)/);
if (statusMatch) {
return {
description: statusMatch[2],
tags: [
{
tag: statusMatch[1].toLowerCase(),
description: statusMatch[2]
}
]
};
}
}
const supportedImportTypes = /* @__PURE__ */ new Set([
"ImportDefaultSpecifier",
"ImportNamespaceSpecifier"
]);
function thunkFor(p, context) {
return () => ExportMap.for(childContext(p, context));
}
function recursivePatternCapture(pattern, callback) {
switch (pattern.type) {
case "Identifier": {
callback(pattern);
break;
}
case "ObjectPattern": {
for (const p of pattern.properties) {
if (
// @ts-expect-error - legacy experimental
p.type === "ExperimentalRestProperty" || p.type === "RestElement"
) {
callback(p.argument);
continue;
}
recursivePatternCapture(p.value, callback);
}
break;
}
case "ArrayPattern": {
for (const element of pattern.elements) {
if (element == null) {
continue;
}
if (
// @ts-expect-error - legacy experimental
element.type === "ExperimentalRestProperty" || element.type === "RestElement"
) {
callback(element.argument);
continue;
}
recursivePatternCapture(element, callback);
}
break;
}
case "AssignmentPattern": {
callback(pattern.left);
break;
}
}
}
function childContext(path2, context) {
const { settings, parserOptions, parserPath, languageOptions } = context;
return {
cacheKey: makeContextCacheKey(context) + path2,
settings,
parserOptions,
parserPath,
languageOptions,
path: path2,
filename: "physicalFilename" in context ? context.physicalFilename : context.filename
};
}
function makeContextCacheKey(context) {
var _a, _b, _c;
const { settings, parserPath, parserOptions, languageOptions } = context;
let hash = stableHash.stableHash(settings) + stableHash.stableHash((_a = languageOptions == null ? void 0 : languageOptions.parserOptions) != null ? _a : parserOptions);
if (languageOptions) {
hash += String(languageOptions.ecmaVersion) + String(languageOptions.sourceType);
}
hash += stableHash.stableHash(
(_c = parserPath != null ? parserPath : (_b = languageOptions == null ? void 0 : languageOptions.parser) == null ? void 0 : _b.meta) != null ? _c : languageOptions == null ? void 0 : languageOptions.parser
);
return hash;
}
const importDeclaration = (context, node) => {
if (node.parent && node.parent.type === utils.AST_NODE_TYPES.ImportDeclaration) {
return node.parent;
}
const ancestors = context.sourceCode.getAncestors(node);
return ancestors[ancestors.length - 1];
};
function stripBOM(str) {
return str.replace(/^\uFEFF/, "");
}
function readPkgUp(opts) {
const fp = pkgUp(opts);
if (!fp) {
return {};
}
try {
return {
pkg: JSON.parse(
stripBOM(fs.readFileSync(fp, { encoding: "utf8" }))
),
path: fp
};
} catch (e) {
return {};
}
}
function getContextPackagePath(context) {
return getFilePackagePath(context.physicalFilename);
}
function getFilePackagePath(filename) {
return path.dirname(pkgUp({ cwd: filename }));
}
function getFilePackageName(filename) {
const { pkg, path: pkgPath } = readPkgUp({ cwd: filename });
if (pkg) {
return pkg.name || getFilePackageName(path.resolve(pkgPath, "../.."));
}
return null;
}
function baseModule(name) {
if (isScoped(name)) {
const [scope, pkg2] = name.split("/");
return `${scope}/${pkg2}`;
}
const [pkg] = name.split("/");
return pkg;
}
function isInternalRegexMatch(name, settings) {
const internalScope = settings == null ? void 0 : settings["import-x/internal-regex"];
return internalScope && new RegExp(internalScope).test(name);
}
function isAbsolute(name) {
return typeof name === "string" && path.isAbsolute(name);
}
function isBuiltIn(name, settings, modulePath) {
if (modulePath || !name) {
return false;
}
const base = baseModule(name);
const extras = settings && settings["import-x/core-modules"] || [];
return Module.isBuiltin(base) || extras.includes(base);
}
function isExternalModule(name, modulePath, context) {
return (isModule(name) || isScoped(name)) && typeTest(name, context, modulePath) === "external";
}
const moduleRegExp = /^\w/;
function isModule(name) {
return !!name && moduleRegExp.test(name);
}
const scopedRegExp = /^@[^/]+\/?[^/]+/;
function isScoped(name) {
return !!name && scopedRegExp.test(name);
}
function isRelativeToParent(name) {
return /^\.\.$|^\.\.[/\\]/.test(name);
}
const indexFiles = /* @__PURE__ */ new Set([".", "./", "./index", "./index.js"]);
function isIndex(name) {
return indexFiles.has(name);
}
function isRelativeToSibling(name) {
return /^\.[/\\]/.test(name);
}
function isExternalPath(filepath, context) {
if (!filepath) {
return false;
}
const { settings } = context;
const packagePath = getContextPackagePath(context);
if (path.relative(packagePath, filepath).startsWith("..")) {
return true;
}
const folders = (settings == null ? void 0 : settings["import-x/external-module-folders"]) || [
"node_modules"
];
return folders.some((folder) => {
const folderPath = path.resolve(packagePath, folder);
const relativePath = path.relative(folderPath, filepath);
return !relativePath.startsWith("..");
});
}
function isInternalPath(filepath, context) {
if (!filepath) {
return false;
}
const packagePath = getContextPackagePath(context);
return !path.relative(packagePath, filepath).startsWith("../");
}
function isExternalLookingName(name) {
return isModule(name) || isScoped(name);
}
function typeTest(name, context, path2) {
const { settings } = context;
if (typeof name === "string") {
if (isInternalRegexMatch(name, settings)) {
return "internal";
}
if (isAbsolute(name)) {
return "absolute";
}
if (isBuiltIn(name, settings, path2)) {
return "builtin";
}
if (isRelativeToParent(name)) {
return "parent";
}
if (isIndex(name)) {
return "index";
}
if (isRelativeToSibling(name)) {
return "sibling";
}
}
if (isExternalPath(path2, context)) {
return "external";
}
if (isInternalPath(path2, context)) {
return "internal";
}
if (typeof name === "string" && isExternalLookingName(name)) {
return "external";
}
return "unknown";
}
function importType(name, context) {
return typeTest(
name,
context,
typeof name === "string" ? resolve(name, context) : null
);
}
var __defProp$a = Object.defineProperty;
var __getOwnPropSymbols$a = Object.getOwnPropertySymbols;
var __hasOwnProp$a = Object.prototype.hasOwnProperty;
var __propIsEnum$a = Object.prototype.propertyIsEnumerable;
var __defNormalProp$a = (obj, key, value) => key in obj ? __defProp$a(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$a = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$a.call(b, prop))
__defNormalProp$a(a, prop, b[prop]);
if (__getOwnPropSymbols$a)
for (var prop of __getOwnPropSymbols$a(b)) {
if (__propIsEnum$a.call(b, prop))
__defNormalProp$a(a, prop, b[prop]);
}
return a;
};
function moduleVisitor(visitor, options) {
const ignore = options == null ? void 0 : options.ignore;
const amd = !!(options == null ? void 0 : options.amd);
const commonjs = !!(options == null ? void 0 : options.commonjs);
const esmodule = !!__spreadValues$a({ esmodule: true }, options).esmodule;
const ignoreRegExps = ignore == null ? [] : ignore.map((p) => new RegExp(p));
function checkSourceValue(source, importer) {
if (source == null) {
return;
}
if (ignoreRegExps.some((re) => re.test(String(source.value)))) {
return;
}
visitor(source, importer);
}
function checkSource(node) {
checkSourceValue(node.source, node);
}
function checkImportCall(node) {
let modulePath;
if (node.type === "ImportExpression") {
modulePath = node.source;
} else if (node.type === "CallExpression") {
if (node.callee.type !== "Import") {
return;
}
if (node.arguments.length !== 1) {
return;
}
modulePath = node.arguments[0];
} else {
throw new TypeError("this should be unreachable");
}
if (modulePath.type !== "Literal") {
return;
}
if (typeof modulePath.value !== "string") {
return;
}
checkSourceValue(modulePath, node);
}
function checkCommon(call) {
if (call.callee.type !== "Identifier") {
return;
}
if (call.callee.name !== "require") {
return;
}
if (call.arguments.length !== 1) {
return;
}
const modulePath = call.arguments[0];
if (modulePath.type !== "Literal") {
return;
}
if (typeof modulePath.value !== "string") {
return;
}
checkSourceValue(modulePath, call);
}
function checkAMD(call) {
if (call.callee.type !== "Identifier") {
return;
}
if (call.callee.name !== "require" && call.callee.name !== "define") {
return;
}
if (call.arguments.length !== 2) {
return;
}
const modules = call.arguments[0];
if (modules.type !== "ArrayExpression") {
return;
}
for (const element of modules.elements) {
if (!element) {
continue;
}
if (element.type !== "Literal") {
continue;
}
if (typeof element.value !== "string") {
continue;
}
if (element.value === "require" || element.value === "exports") {
continue;
}
checkSourceValue(element, element);
}
}
const visitors = {};
if (esmodule) {
Object.assign(visitors, {
ImportDeclaration: checkSource,
ExportNamedDeclaration: checkSource,
ExportAllDeclaration: checkSource,
CallExpression: checkImportCall,
ImportExpression: checkImportCall
});
}
if (commonjs || amd) {
const currentCallExpression = visitors.CallExpression;
visitors.CallExpression = function(call) {
if (currentCallExpression) {
currentCallExpression(call);
}
if (commonjs) {
checkCommon(call);
}
if (amd) {
checkAMD(call);
}
};
}
return visitors;
}
function makeOptionsSchema(additionalProperties) {
const base = {
type: "object",
properties: {
commonjs: { type: "boolean" },
amd: { type: "boolean" },
esmodule: { type: "boolean" },
ignore: {
type: "array",
minItems: 1,
items: { type: "string" },
uniqueItems: true
}
},
additionalProperties: false
};
if (additionalProperties) {
for (const key in additionalProperties) {
base.properties[key] = additionalProperties[key];
}
}
return base;
}
makeOptionsSchema();
function sourceType(context) {
if ("sourceType" in context.parserOptions) {
return context.parserOptions.sourceType;
}
if ("languageOptions" in context && context.languageOptions) {
return context.languageOptions.sourceType;
}
}
function isStaticRequire(node) {
return node && node.callee && node.callee.type === "Identifier" && node.callee.name === "require" && node.arguments.length === 1 && node.arguments[0].type === "Literal" && typeof node.arguments[0].value === "string";
}
function isComma(token) {
return token.type === "Punctuator" && token.value === ",";
}
function removeSpecifiers(fixes, fixer, sourceCode, specifiers) {
for (const specifier of specifiers) {
const token = sourceCode.getTokenAfter(specifier);
if (token && isComma(token)) {
fixes.push(fixer.remove(token));
}
fixes.push(fixer.remove(specifier));
}
}
function getImportText(node, sourceCode, specifiers, kind) {
const sourceString = sourceCode.getText(node.source);
if (specifiers.length === 0) {
return "";
}
const names = specifiers.map((s) => {
const importedName = getValue(s.imported);
if (importedName === s.local.name) {
return importedName;
}
return `${importedName} as ${s.local.name}`;
});
return `import ${kind} {${names.join(", ")}} from ${sourceString};`;
}
var consistentTypeSpecifierStyle = createRule({
name: "consistent-type-specifier-style",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Enforce or ban the use of inline type-only markers for named imports."
},
fixable: "code",
schema: [
{
type: "string",
enum: ["prefer-top-level", "prefer-inline"],
default: "prefer-top-level"
}
],
messages: {
inline: "Prefer using inline {{kind}} specifiers instead of a top-level {{kind}}-only import.",
topLevel: "Prefer using a top-level {{kind}}-only import instead of inline {{kind}} specifiers."
}
},
defaultOptions: [],
create(context) {
const { sourceCode } = context;
if (context.options[0] === "prefer-inline") {
return {
ImportDeclaration(node) {
if (node.importKind === "value" || node.importKind == null) {
return;
}
if (
// no specifiers (import type {} from '') have no specifiers to mark as inline
node.specifiers.length === 0 || node.specifiers.length === 1 && // default imports are both "inline" and "top-level"
(node.specifiers[0].type === "ImportDefaultSpecifier" || // namespace imports are both "inline" and "top-level"
node.specifiers[0].type === "ImportNamespaceSpecifier")
) {
return;
}
context.report({
node,
messageId: "inline",
data: {
kind: node.importKind
},
fix(fixer) {
const kindToken = sourceCode.getFirstToken(node, { skip: 1 });
return [
kindToken ? fixer.remove(kindToken) : [],
node.specifiers.map(
(specifier) => fixer.insertTextBefore(specifier, `${node.importKind} `)
)
].flat();
}
});
}
};
}
return {
ImportDeclaration(node) {
if (
// already top-level is valid
node.importKind === "type" || // @ts-expect-error - flow type
node.importKind === "typeof" || // no specifiers (import {} from '') cannot have inline - so is valid
node.specifiers.length === 0 || node.specifiers.length === 1 && // default imports are both "inline" and "top-level"
(node.specifiers[0].type === "ImportDefaultSpecifier" || // namespace imports are both "inline" and "top-level"
node.specifiers[0].type === "ImportNamespaceSpecifier")
) {
return;
}
const typeSpecifiers = [];
const typeofSpecifiers = [];
const valueSpecifiers = [];
let defaultSpecifier = null;
for (const specifier of node.specifiers) {
if (specifier.type === "ImportDefaultSpecifier") {
defaultSpecifier = specifier;
continue;
}
if (!("importKind" in specifier)) {
continue;
}
if (specifier.importKind === "type") {
typeSpecifiers.push(specifier);
} else if (
// @ts-expect-error - flow type
specifier.importKind === "typeof"
) {
typeofSpecifiers.push(specifier);
} else if (specifier.importKind === "value" || specifier.importKind == null) {
valueSpecifiers.push(specifier);
}
}
const typeImport = getImportText(
node,
sourceCode,
typeSpecifiers,
"type"
);
const typeofImport = getImportText(
node,
sourceCode,
typeofSpecifiers,
"typeof"
);
const newImports = `${typeImport}
${typeofImport}`.trim();
if (typeSpecifiers.length + typeofSpecifiers.length === node.specifiers.length) {
const kind = [
typeSpecifiers.length > 0 ? "type" : [],
typeofSpecifiers.length > 0 ? "typeof" : []
].flat();
context.report({
node,
messageId: "topLevel",
data: {
kind: kind.join("/")
},
fix(fixer) {
return fixer.replaceText(node, newImports);
}
});
} else {
for (const specifier of [...typeSpecifiers, ...typeofSpecifiers]) {
context.report({
node: specifier,
messageId: "topLevel",
data: {
kind: specifier.importKind
},
fix(fixer) {
const fixes = [];
if (valueSpecifiers.length > 0) {
removeSpecifiers(fixes, fixer, sourceCode, typeSpecifiers);
removeSpecifiers(fixes, fixer, sourceCode, typeofSpecifiers);
const maybeComma = sourceCode.getTokenAfter(
valueSpecifiers[valueSpecifiers.length - 1]
);
if (isComma(maybeComma)) {
fixes.push(fixer.remove(maybeComma));
}
} else if (defaultSpecifier) {
const comma = sourceCode.getTokenAfter(
defaultSpecifier,
isComma
);
const closingBrace = sourceCode.getTokenAfter(
node.specifiers[node.specifiers.length - 1],
(token) => token.type === "Punctuator" && token.value === "}"
);
fixes.push(
fixer.removeRange([
comma.range[0],
closingBrace.range[1]
])
);
}
return [
...fixes,
// insert the new imports after the old declaration
fixer.insertTextAfter(node, `
${newImports}`)
];
}
});
}
}
}
};
}
});
var default_ = createRule({
name: "default",
meta: {
type: "problem",
docs: {
category: "Static analysis",
description: "Ensure a default export is present, given a default import."
},
schema: [],
messages: {
noDefaultExport: 'No default export found in imported module "{{module}}".'
}
},
defaultOptions: [],
create(context) {
function checkDefault(specifierType, node) {
const defaultSpecifier = node.specifiers.find((specifier) => specifier.type === specifierType);
if (!defaultSpecifier) {
return;
}
const imports = ExportMap.get(node.source.value, context);
if (imports == null) {
return;
}
if (imports.errors.length > 0) {
imports.reportErrors(context, node);
} else if (imports.get("default") === void 0) {
context.report({
node: defaultSpecifier,
messageId: "noDefaultExport",
data: {
module: node.source.value
}
});
}
}
return {
ImportDeclaration: checkDefault.bind(null, "ImportDefaultSpecifier"),
ExportNamedDeclaration: checkDefault.bind(null, "ExportDefaultSpecifier")
};
}
});
var dynamicImportChunkname = createRule({
name: "dynamic-import-chunkname",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Enforce a leading comment with the webpackChunkName for dynamic imports."
},
hasSuggestions: true,
schema: [
{
type: "object",
properties: {
importFunctions: {
type: "array",
uniqueItems: true,
items: {
type: "string"
}
},
allowEmpty: {
type: "boolean"
},
webpackChunknameFormat: {
type: "string"
}
}
}
],
messages: {
leadingComment: "dynamic imports require a leading comment with the webpack chunkname",
blockComment: "dynamic imports require a /* foo */ style comment, not a // foo comment",
paddedSpaces: "dynamic imports require a block comment padded with spaces - /* foo */",
webpackComment: 'dynamic imports require a "webpack" comment with valid syntax',
chunknameFormat: "dynamic imports require a leading comment in the form /* {{format}} */",
webpackEagerModeNoChunkName: "dynamic imports using eager mode do not need a webpackChunkName",
webpackRemoveEagerMode: "Remove webpackMode",
webpackRemoveChunkName: "Remove webpackChunkName"
}
},
defaultOptions: [],
create(context) {
const {
importFunctions = [],
allowEmpty = false,
webpackChunknameFormat = String.raw`([0-9a-zA-Z-_/.]|\[(request|index)\])+`
} = context.options[0] || {};
const paddedCommentRegex = /^ (\S[\S\s]+\S) $/;
const commentStyleRegex = /^( (((webpackChunkName|webpackFetchPriority): .+)|((webpackPrefetch|webpackPreload): (true|false|-?\d+))|(webpackIgnore: (true|false))|((webpackInclude|webpackExclude): \/.+\/)|(webpackMode: ["'](lazy|lazy-once|eager|weak)["'])|(webpackExports: (["']\w+["']|\[(["']\w+["'], *)+(["']\w+["']*)]))),?)+ $/;
const chunkSubstrFormat = `webpackChunkName: ["']${webpackChunknameFormat}["'],?`;
const chunkSubstrRegex = new RegExp(chunkSubstrFormat);
const eagerModeFormat = `webpackMode: ["']eager["'],?`;
const eagerModeRegex = new RegExp(eagerModeFormat);
function run(node, arg) {
const { sourceCode } = context;
const leadingComments = sourceCode.getCommentsBefore(arg);
if ((!leadingComments || leadingComments.length === 0) && !allowEmpty) {
context.report({
node,
messageId: "leadingComment"
});
return;
}
let isChunknamePresent = false;
let isEagerModePresent = false;
for (const comment of leadingComments) {
if (comment.type !== "Block") {
context.report({
node,
messageId: "blockComment"
});
return;
}
if (!paddedCommentRegex.test(comment.value)) {
context.report({
node,
messageId: "paddedSpaces"
});
return;
}
try {
vm.runInNewContext(`(function() {return {${comment.value}}})()`);
} catch (e) {
context.report({
node,
messageId: "webpackComment"
});
return;
}
if (!commentStyleRegex.test(comment.value)) {
context.report({
node,
messageId: "webpackComment"
});
return;
}
if (eagerModeRegex.test(comment.value)) {
isEagerModePresent = true;
}
if (chunkSubstrRegex.test(comment.value)) {
isChunknamePresent = true;
}
}
const removeCommentsAndLeadingSpaces = (fixer, comment) => {
const leftToken = sourceCode.getTokenBefore(comment);
const leftComments = sourceCode.getCommentsBefore(comment);
if (leftToken) {
if (leftComments.length > 0) {
return fixer.removeRange([
Math.max(
leftToken.range[1],
leftComments[leftComments.length - 1].range[1]
),
comment.range[1]
]);
}
return fixer.removeRange([leftToken.range[1], comment.range[1]]);
}
return fixer.remove(comment);
};
if (isChunknamePresent && isEagerModePresent) {
context.report({
node,
messageId: "webpackEagerModeNoChunkName",
suggest: [
{
messageId: "webpackRemoveChunkName",
fix(fixer) {
for (const comment of leadingComments) {
if (chunkSubstrRegex.test(comment.value)) {
const replacement = comment.value.replace(chunkSubstrRegex, "").trim().replace(/,$/, "");
return replacement === "" ? removeCommentsAndLeadingSpaces(fixer, comment) : fixer.replaceText(comment, `/* ${replacement} */`);
}
}
return null;
}
},
{
messageId: "webpackRemoveEagerMode",
fix(fixer) {
for (const comment of leadingComments) {
if (eagerModeRegex.test(comment.value)) {
const replacement = comment.value.replace(eagerModeRegex, "").trim().replace(/,$/, "");
return replacement === "" ? removeCommentsAndLeadingSpaces(fixer, comment) : fixer.replaceText(comment, `/* ${replacement} */`);
}
}
return null;
}
}
]
});
}
if (!isChunknamePresent && !allowEmpty && !isEagerModePresent) {
context.report({
node,
messageId: "chunknameFormat",
data: {
format: chunkSubstrFormat
}
});
}
}
return {
ImportExpression(node) {
run(node, node.source);
},
CallExpression(node) {
if (
// @ts-expect-error - legacy parser type
node.callee.type !== "Import" && "name" in node.callee && !importFunctions.includes(node.callee.name)
) {
return;
}
run(node, node.arguments[0]);
}
};
}
});
const rootProgram = "root";
const tsTypePrefix = "type:";
function removeTypescriptFunctionOverloads(nodes) {
var _a;
for (const node of nodes) {
const declType = node.type === utils.AST_NODE_TYPES.ExportDefaultDeclaration ? node.declaration.type : (_a = node.parent) == null ? void 0 : _a.type;
if (declType === utils.AST_NODE_TYPES.TSDeclareFunction) {
nodes.delete(node);
}
}
}
function isTypescriptNamespaceMerging(nodes) {
const types = new Set(
Array.from(nodes, (node) => `${node.parent.type}`)
);
const noNamespaceNodes = [...nodes].filter(
(node) => node.parent.type !== "TSModuleDeclaration"
);
return types.has("TSModuleDeclaration") && (types.size === 1 || // Merging with functions
types.size === 2 && (types.has("FunctionDeclaration") || types.has("TSDeclareFunction")) || types.size === 3 && types.has("FunctionDeclaration") && types.has("TSDeclareFunction") || // Merging with classes or enums
types.size === 2 && (types.has("ClassDeclaration") || types.has("TSEnumDeclaration")) && noNamespaceNodes.length === 1);
}
function shouldSkipTypescriptNamespace(node, nodes) {
const types = new Set(
Array.from(nodes, (node2) => `${node2.parent.type}`)
);
return !isTypescriptNamespaceMerging(nodes) && node.parent.type === "TSModuleDeclaration" && (types.has("TSEnumDeclaration") || types.has("ClassDeclaration") || types.has("FunctionDeclaration") || types.has("TSDeclareFunction"));
}
var export_ = createRule({
name: "export",
meta: {
type: "problem",
docs: {
category: "Helpful warnings",
description: "Forbid any invalid exports, i.e. re-export of the same name."
},
schema: [],
messages: {
noNamed: "No named exports found in module '{{module}}'.",
multiDefault: "Multiple default exports.",
multiNamed: "Multiple exports of name '{{name}}'."
}
},
defaultOptions: [],
create(context) {
const namespace = /* @__PURE__ */ new Map([[rootProgram, /* @__PURE__ */ new Map()]]);
function addNamed(name, node, parent, isType) {
if (!namespace.has(parent)) {
namespace.set(parent, /* @__PURE__ */ new Map());
}
const named = namespace.get(parent);
const key = isType ? `${tsTypePrefix}${name}` : name;
let nodes = named.get(key);
if (nodes == null) {
nodes = /* @__PURE__ */ new Set();
named.set(key, nodes);
}
nodes.add(node);
}
function getParent(node) {
var _a;
if (((_a = node.parent) == null ? void 0 : _a.type) === "TSModuleBlock") {
return node.parent.parent;
}
return rootProgram;
}
return {
ExportDefaultDeclaration(node) {
addNamed("default", node, getParent(node));
},
ExportSpecifier(node) {
addNamed(
getValue(node.exported),
node.exported,
getParent(node.parent)
);
},
ExportNamedDeclaration(node) {
if (node.declaration == null) {
return;
}
const parent = getParent(node);
const isTypeVariableDecl = "kind" in node.declaration && // @ts-expect-error - support for old TypeScript versions
node.declaration.kind === "type";
if ("id" in node.declaration && node.declaration.id != null) {
const id = node.declaration.id;
addNamed(
id.name,
id,
parent,
["TSTypeAliasDeclaration", "TSInterfaceDeclaration"].includes(
node.declaration.type
) || isTypeVariableDecl
);
}
if ("declarations" in node.declaration && node.declaration.declarations != null) {
for (const declaration of node.declaration.declarations) {
recursivePatternCapture(declaration.id, (v) => {
addNamed(
v.name,
v,
parent,
isTypeVariableDecl
);
});
}
}
},
ExportAllDeclaration(node) {
if (node.source == null) {
return;
}
if (node.exported && node.exported.name) {
return;
}
const remoteExports = ExportMap.get(node.source.value, context);
if (remoteExports == null) {
return;
}
if (remoteExports.errors.length > 0) {
remoteExports.reportErrors(context, node);
return;
}
const parent = getParent(node);
let any = false;
remoteExports.$forEach((_, name) => {
if (name !== "default") {
any = true;
addNamed(name, node, parent);
}
});
if (!any) {
context.report({
node: node.source,
messageId: "noNamed",
data: { module: node.source.value }
});
}
},
"Program:exit"() {
for (const [, named] of namespace) {
for (const [name, nodes] of named) {
if (nodes.size === 0) {
continue;
}
removeTypescriptFunctionOverloads(nodes);
if (nodes.size <= 1) {
continue;
}
if (isTypescriptNamespaceMerging(nodes)) {
continue;
}
for (const node of nodes) {
if (shouldSkipTypescriptNamespace(node, nodes)) {
continue;
}
if (name === "default") {
context.report({
node,
messageId: "multiDefault"
});
} else {
context.report({
node,
messageId: "multiNamed",
data: {
name: name.replace(tsTypePrefix, "")
}
});
}
}
}
}
}
};
}
});
const findLastIndex = (array, predicate) => {
let i = array.length - 1;
while (i >= 0) {
if (predicate(array[i])) {
return i;
}
i--;
}
return -1;
};
function isNonExportStatement({ type }) {
return type !== "ExportDefaultDeclaration" && type !== "ExportNamedDeclaration" && type !== "ExportAllDeclaration";
}
var exportsLast = createRule({
name: "exports-last",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Ensure all exports appear after other statements."
},
schema: [],
messages: {
end: "Export statements should appear at the end of the file"
}
},
defaultOptions: [],
create(context) {
return {
Program({ body }) {
const lastNonExportStatementIndex = findLastIndex(
body,
isNonExportStatement
);
if (lastNonExportStatementIndex !== -1) {
for (const node of body.slice(0, lastNonExportStatementIndex)) {
if (!isNonExportStatement(node)) {
context.report({
node,
messageId: "end"
});
}
}
}
}
};
}
});
const modifierValues = ["always", "ignorePackages", "never"];
const modifierSchema = {
type: "string",
enum: [...modifierValues]
};
const modifierByFileExtensionSchema = {
type: "object",
patternProperties: { ".*": modifierSchema }
};
const properties = {
type: "object",
properties: {
pattern: modifierByFileExtensionSchema,
ignorePackages: {
type: "boolean"
},
checkTypeImports: {
type: "boolean"
}
}
};
function buildProperties(context) {
const result = {
defaultConfig: "never",
pattern: {},
ignorePackages: false,
checkTypeImports: false
};
for (const obj of context.options) {
if (typeof obj === "string") {
result.defaultConfig = obj;
continue;
}
if (typeof obj !== "object" || !obj) {
continue;
}
if ((!("pattern" in obj) || obj.pattern === void 0) && obj.ignorePackages === void 0 && obj.checkTypeImports === void 0) {
Object.assign(result.pattern, obj);
continue;
}
if ("pattern" in obj && obj.pattern !== void 0) {
Object.assign(result.pattern, obj.pattern);
}
if (typeof obj.ignorePackages === "boolean") {
result.ignorePackages = obj.ignorePackages;
}
if (typeof obj.checkTypeImports === "boolean") {
result.checkTypeImports = obj.checkTypeImports;
}
}
if (result.defaultConfig === "ignorePackages") {
result.defaultConfig = "always";
result.ignorePackages = true;
}
return result;
}
function isExternalRootModule(file) {
if (file === "." || file === "..") {
return false;
}
const slashCount = file.split("/").length - 1;
if (slashCount === 0) {
return true;
}
if (isScoped(file) && slashCount <= 1) {
return true;
}
return false;
}
var extensions = createRule({
name: "extensions",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Ensure consistent use of file extension within the import path."
},
schema: {
anyOf: [
{
type: "array",
items: [modifierSchema],
additionalItems: false
},
{
type: "array",
items: [modifierSchema, properties],
additionalItems: false
},
{
type: "array",
items: [properties],
additionalItems: false
},
{
type: "array",
items: [modifierSchema, modifierByFileExtensionSchema],
additionalItems: false
},
{
type: "array",
items: [modifierByFileExtensionSchema],
additionalItems: false
}
]
},
messages: {
missing: 'Missing file extension for "{{importPath}}"',
missingKnown: 'Missing file extension "{{extension}}" for "{{importPath}}"',
unexpected: 'Unexpected use of file extension "{{extension}}" for "{{importPath}}"'
}
},
defaultOptions: [],
create(context) {
const props = buildProperties(context);
function getModifier(extension) {
return props.pattern[extension] || props.defaultConfig;
}
function isUseOfExtensionRequired(extension, isPackage) {
return getModifier(extension) === "always" && (!props.ignorePackages || !isPackage);
}
function isUseOfExtensionForbidden(extension) {
return getModifier(extension) === "never";
}
function isResolvableWithoutExtension(file) {
const extension = path.extname(file);
const fileWithoutExtension = file.slice(0, -extension.length);
const resolvedFileWithoutExtension = resolve(
fileWithoutExtension,
context
);
return resolvedFileWithoutExtension === resolve(file, context);
}
return moduleVisitor(
(source, node) => {
if (!source || !source.value) {
return;
}
const importPathWithQueryString = source.value;
if (isBuiltIn(importPathWithQueryString, context.settings)) {
return;
}
const importPath = importPathWithQueryString.replace(/\?(.*)$/, "");
if (isExternalRootModule(importPath)) {
return;
}
const resolvedPath = resolve(importPath, context);
const extension = path.extname(resolvedPath || importPath).slice(1);
const isPackage = isExternalModule(
importPath,
resolve(importPath, context),
context
) || isScoped(importPath);
if (!extension || !importPath.endsWith(`.${extension}`)) {
if (!props.checkTypeImports && ("importKind" in node && node.importKind === "type" || "exportKind" in node && node.exportKind === "type")) {
return;
}
const extensionRequired = isUseOfExtensionRequired(
extension,
isPackage
);
const extensionForbidden = isUseOfExtensionForbidden(extension);
if (extensionRequired && !extensionForbidden) {
context.report({
node: source,
messageId: extension ? "missingKnown" : "missing",
data: {
extension,
importPath: importPathWithQueryString
}
});
}
} else if (extension && isUseOfExtensionForbidden(extension) && isResolvableWithoutExtension(importPath)) {
context.report({
node: source,
messageId: "unexpected",
data: {
extension,
importPath: importPathWithQueryString
}
});
}
},
{ commonjs: true }
);
}
});
function getImportValue(node) {
return node.type === "ImportDeclaration" ? node.source.value : "moduleReference" in node && "expression" in node.moduleReference && "value" in node.moduleReference.expression && node.moduleReference.expression.value;
}
function isPossibleDirective(node) {
return node.type === "ExpressionStatement" && node.expression.type === "Literal" && typeof node.expression.value === "string";
}
var first = createRule({
name: "first",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Ensure all imports appear before other statements."
},
fixable: "code",
schema: [
{
type: "string",
enum: ["absolute-first", "disable-absolute-first"]
}
],
messages: {
absolute: "Absolute imports should come before relative imports.",
order: "Import in body of module; reorder to top."
}
},
defaultOptions: [],
create(context) {
return {
Program(n) {
const body = n.body;
if (!(body == null ? void 0 : body.length)) {
return;
}
const absoluteFirst = context.options[0] === "absolute-first";
const { sourceCode } = context;
const originSourceCode = sourceCode.getText();
let nonImportCount = 0;
let anyExpressions = false;
let anyRelative = false;
let lastLegalImp = null;
const errorInfos = [];
let shouldSort = true;
let lastSortNodesIndex = 0;
for (const [index, node] of body.entries()) {
if (!anyExpressions && isPossibleDirective(node)) {
continue;
}
anyExpressions = true;
if (node.type === "ImportDeclaration" || node.type === "TSImportEqualsDeclaration") {
if (absoluteFirst) {
const importValue = getImportValue(node);
if (typeof importValue === "string" && /^\./.test(importValue)) {
anyRelative = true;
} else if (anyRelative) {
context.report({
node: node.type === "ImportDeclaration" ? node.source : node.moduleReference,
messageId: "absolute"
});
}
}
if (nonImportCount > 0) {
for (const variable of sourceCode.getDeclaredVariables(node)) {
if (!shouldSort) {
break;
}
for (const reference of variable.references) {
if (reference.identifier.range[0] < node.range[1]) {
shouldSort = false;
break;
}
}
}
if (shouldSort) {
lastSortNodesIndex = errorInfos.length;
}
errorInfos.push({
node,
range: [body[index - 1].range[1], node.range[1]]
});
} else {
lastLegalImp = node;
}
} else {
nonImportCount++;
}
}
if (errorInfos.length === 0) {
return;
}
for (const [index, { node }] of errorInfos.entries()) {
let fix;
if (index < lastSortNodesIndex) {
fix = (fixer) => fixer.insertTextAfter(node, "");
} else if (index === lastSortNodesIndex) {
const sortNodes = errorInfos.slice(0, lastSortNodesIndex + 1);
fix = (fixer) => {
const removeFixers = sortNodes.map(
({ range: range2 }) => fixer.removeRange(range2)
);
const range = [
0,
removeFixers[removeFixers.length - 1].range[1]
];
let insertSourceCode = sortNodes.map(({ range: range2 }) => {
const nodeSourceCode = originSourceCode.slice(...range2);
if (/\S/.test(nodeSourceCode[0])) {
return `
${nodeSourceCode}`;
}
return nodeSourceCode;
}).join("");
let replaceSourceCode = "";
if (!lastLegalImp) {
insertSourceCode = insertSourceCode.trim() + insertSourceCode.match(/^(\s+)/)[0];
}
const insertFixer = lastLegalImp ? fixer.insertTextAfter(lastLegalImp, insertSourceCode) : fixer.insertTextBefore(body[0], insertSourceCode);
const fixers = [insertFixer, ...removeFixers];
for (const [i, computedFixer] of fixers.entries()) {
replaceSourceCode += originSourceCode.slice(
fixers[i - 1] ? fixers[i - 1].range[1] : 0,
computedFixer.range[0]
) + computedFixer.text;
}
return fixer.replaceTextRange(range, replaceSourceCode);
};
}
context.report({
node,
messageId: "order",
fix
});
}
}
};
}
});
function accessorChain(node) {
const chain = [];
let exp = node;
do {
if ("name" in exp.property) {
chain.unshift(exp.property.name);
} else if ("value" in exp.property) {
chain.unshift(exp.property.value);
}
if (exp.object.type === "Identifier") {
chain.unshift(exp.object.name);
break;
}
exp = exp.object;
} while (exp.type === "MemberExpression");
return chain;
}
var groupExports = createRule({
name: "group-exports",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Prefer named exports to be grouped together in a single export declaration."
},
schema: [],
messages: {
ExportNamedDeclaration: "Multiple named export declarations; consolidate all named exports into a single export declaration",
AssignmentExpression: "Multiple CommonJS exports; consolidate all exports into a single assignment to `module.exports`"
}
},
defaultOptions: [],
create(context) {
const nodes = {
modules: {
set: /* @__PURE__ */ new Set(),
sources: {}
},
types: {
set: /* @__PURE__ */ new Set(),
sources: {}
},
commonjs: {
set: /* @__PURE__ */ new Set()
}
};
return {
ExportNamedDeclaration(node) {
const target = node.exportKind === "type" ? nodes.types : nodes.modules;
if (!node.source) {
target.set.add(node);
} else if (Array.isArray(target.sources[node.source.value])) {
target.sources[node.source.value].push(node);
} else {
target.sources[node.source.value] = [node];
}
},
AssignmentExpression(node) {
if (node.left.type !== "MemberExpression") {
return;
}
const chain = accessorChain(node.left);
if (chain[0] === "module" && chain[1] === "exports" && chain.length <= 3) {
nodes.commonjs.set.add(node);
return;
}
if (chain[0] === "exports" && chain.length === 2) {
nodes.commonjs.set.add(node);
return;
}
},
"Program:exit"() {
if (nodes.modules.set.size > 1) {
for (const node of nodes.modules.set) {
context.report({
node,
messageId: node.type
});
}
}
for (const node of Object.values(nodes.modules.sources).filter(
(nodesWithSource) => Array.isArray(nodesWithSource) && nodesWithSource.length > 1
).flat()) {
context.report({
node,
messageId: node.type
});
}
if (nodes.types.set.size > 1) {
for (const node of nodes.types.set) {
context.report({
node,
messageId: node.type
});
}
}
for (const node of Object.values(nodes.types.sources).filter(
(nodesWithSource) => Array.isArray(nodesWithSource) && nodesWithSource.length > 1
).flat()) {
context.report({
node,
messageId: node.type
});
}
if (nodes.commonjs.set.size > 1) {
for (const node of nodes.commonjs.set) {
context.report({
node,
messageId: node.type
});
}
}
}
};
}
});
var __defProp$9 = Object.defineProperty;
var __defProps$4 = Object.defineProperties;
var __getOwnPropDescs$4 = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$9 = Object.getOwnPropertySymbols;
var __hasOwnProp$9 = Object.prototype.hasOwnProperty;
var __propIsEnum$9 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$9 = (obj, key, value) => key in obj ? __defProp$9(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$9 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$9.call(b, prop))
__defNormalProp$9(a, prop, b[prop]);
if (__getOwnPropSymbols$9)
for (var prop of __getOwnPropSymbols$9(b)) {
if (__propIsEnum$9.call(b, prop))
__defNormalProp$9(a, prop, b[prop]);
}
return a;
};
var __spreadProps$4 = (a, b) => __defProps$4(a, __getOwnPropDescs$4(b));
var importsFirst = createRule(__spreadProps$4(__spreadValues$9({}, first), {
name: "imports-first",
meta: __spreadProps$4(__spreadValues$9({}, first.meta), {
deprecated: true,
docs: {
category: "Style guide",
description: "Replaced by `import-x/first`."
}
})
}));
var __defProp$8 = Object.defineProperty;
var __getOwnPropSymbols$8 = Object.getOwnPropertySymbols;
var __hasOwnProp$8 = Object.prototype.hasOwnProperty;
var __propIsEnum$8 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$8 = (obj, key, value) => key in obj ? __defProp$8(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$8 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$8.call(b, prop))
__defNormalProp$8(a, prop, b[prop]);
if (__getOwnPropSymbols$8)
for (var prop of __getOwnPropSymbols$8(b)) {
if (__propIsEnum$8.call(b, prop))
__defNormalProp$8(a, prop, b[prop]);
}
return a;
};
var maxDependencies = createRule({
name: "max-dependencies",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Enforce the maximum number of dependencies a module can have."
},
schema: [
{
type: "object",
properties: {
max: { type: "number" },
ignoreTypeImports: { type: "boolean" }
},
additionalProperties: false
}
],
messages: {
max: "Maximum number of dependencies ({{max}}) exceeded."
}
},
defaultOptions: [],
create(context) {
const { ignoreTypeImports } = context.options[0] || {};
const dependencies = /* @__PURE__ */ new Set();
let lastNode;
return __spreadValues$8({
"Program:exit"() {
const { max = 10 } = context.options[0] || {};
if (dependencies.size <= max) {
return;
}
context.report({
node: lastNode,
messageId: "max",
data: {
max
}
});
}
}, moduleVisitor(
(source, node) => {
if ("importKind" in node && node.importKind !== "type" || !ignoreTypeImports) {
dependencies.add(source.value);
}
lastNode = source;
},
{ commonjs: true }
));
}
});
var named = createRule({
name: "named",
meta: {
type: "problem",
docs: {
category: "Static analysis",
description: "Ensure named imports correspond to a named export in the remote file."
},
schema: [
{
type: "object",
properties: {
commonjs: {
type: "boolean"
}
},
additionalProperties: false
}
],
messages: {
notFound: "{{name}} not found in '{{path}}'",
notFoundDeep: "{{name}} not found via {{deepPath}}"
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
function checkSpecifiers(key, type, node) {
if (node.source == null || "importKind" in node && (node.importKind === "type" || // @ts-expect-error - flow type
node.importKind === "typeof") || "exportKind" in node && node.exportKind === "type") {
return;
}
if (!node.specifiers.some((im) => im.type === type)) {
return;
}
const imports = ExportMap.get(node.source.value, context);
if (imports == null || imports.parseGoal === "ambiguous") {
return;
}
if (imports.errors.length > 0) {
imports.reportErrors(context, node);
return;
}
for (const im of node.specifiers) {
if (im.type !== type || // ignore type imports
"importKind" in im && (im.importKind === "type" || // @ts-expect-error - flow type
im.importKind === "typeof")) {
continue;
}
const imNode = im[key];
const name = imNode.name || // @ts-expect-error - old version ast
imNode.value;
const deepLookup = imports.hasDeep(name);
if (!deepLookup.found) {
if (deepLookup.path.length > 1) {
const deepPath = deepLookup.path.map(
(i) => path.relative(path.dirname(context.physicalFilename), i.path)
).join(" -> ");
context.report({
node: imNode,
messageId: "notFoundDeep",
data: {
name,
deepPath
}
});
} else {
context.report({
node: imNode,
messageId: "notFound",
data: {
name,
path: node.source.value
}
});
}
}
}
}
return {
ImportDeclaration: checkSpecifiers.bind(
null,
"imported",
"ImportSpecifier"
),
ExportNamedDeclaration: checkSpecifiers.bind(
null,
"local",
"ExportSpecifier"
),
VariableDeclarator(node) {
if (!options.commonjs || node.type !== "VariableDeclarator" || // return if it's not an object destructure or it's an empty object destructure
!node.id || node.id.type !== "ObjectPattern" || node.id.properties.length === 0 || // return if there is no call expression on the right side
!node.init || node.init.type !== "CallExpression") {
return;
}
const call = node.init;
const source = call.arguments[0];
const variableImports = node.id.properties;
const variableExports = ExportMap.get(source.value, context);
if (
// return if it's not a commonjs require statement
call.callee.type !== "Identifier" || call.callee.name !== "require" || call.arguments.length !== 1 || // return if it's not a string source
source.type !== "Literal" || variableExports == null || variableExports.parseGoal === "ambiguous"
) {
return;
}
if (variableExports.errors.length > 0) {
variableExports.reportErrors(
context,
// @ts-expect-error - FIXME: no idea yet
node
);
return;
}
for (const im of variableImports) {
if (im.type !== "Property" || !im.key || im.key.type !== "Identifier") {
continue;
}
const deepLookup = variableExports.hasDeep(im.key.name);
if (!deepLookup.found) {
if (deepLookup.path.length > 1) {
const deepPath = deepLookup.path.map((i) => path.relative(path.dirname(context.filename), i.path)).join(" -> ");
context.report({
node: im.key,
messageId: "notFoundDeep",
data: {
name: im.key.name,
deepPath
}
});
} else {
context.report({
node: im.key,
messageId: "notFound",
data: {
name: im.key.name,
path: source.value
}
});
}
}
}
}
};
}
});
function processBodyStatement(context, namespaces, declaration) {
if (declaration.type !== "ImportDeclaration") {
return;
}
if (declaration.specifiers.length === 0) {
return;
}
const imports = ExportMap.get(declaration.source.value, context);
if (imports == null) {
return;
}
if (imports.errors.length > 0) {
imports.reportErrors(context, declaration);
return;
}
for (const specifier of declaration.specifiers) {
switch (specifier.type) {
case "ImportNamespaceSpecifier": {
if (imports.size === 0) {
context.report({
node: specifier,
messageId: "noNamesFound",
data: {
module: declaration.source.value
}
});
}
namespaces.set(specifier.local.name, imports);
break;
}
case "ImportDefaultSpecifier":
case "ImportSpecifier": {
const meta = imports.get(
"imported" in specifier ? getValue(specifier.imported) : (
// default to 'default' for default
"default"
)
);
if (!meta || !meta.namespace) {
break;
}
namespaces.set(specifier.local.name, meta.namespace);
break;
}
}
}
}
function makeMessage(last, namepath, node = last) {
const messageId = namepath.length > 1 ? "notFoundInNamespaceDeep" : "notFoundInNamespace";
return {
node,
messageId,
data: {
name: last.name,
namepath: namepath.join(".")
}
};
}
var namespace = createRule({
name: "namespace",
meta: {
type: "problem",
docs: {
category: "Static analysis",
description: "Ensure imported namespaces contain dereferenced properties as they are dereferenced."
},
schema: [
{
type: "object",
properties: {
allowComputed: {
description: "If `false`, will report computed (and thus, un-lintable) references to namespace members.",
type: "boolean",
default: false
}
},
additionalProperties: false
}
],
messages: {
noNamesFound: "No exported names found in module '{{module}}'.",
computedReference: "Unable to validate computed reference to imported namespace '{{namespace}}'.",
namespaceMember: "Assignment to member of namespace '{{namespace}}'.",
topLevelNames: "Only destructure top-level names.",
notFoundInNamespace: "'{{name}}' not found in imported namespace '{{namepath}}'.",
notFoundInNamespaceDeep: "'{{name}}' not found in deeply imported namespace '{{namepath}}'."
}
},
defaultOptions: [
{
allowComputed: false
}
],
create(context) {
const { allowComputed } = context.options[0] || {};
const namespaces = /* @__PURE__ */ new Map();
return {
// pick up all imports at body entry time, to properly respect hoisting
Program({ body }) {
for (const x of body) {
processBodyStatement(context, namespaces, x);
}
},
// same as above, but does not add names to local map
ExportNamespaceSpecifier(namespace) {
const declaration = importDeclaration(
context,
namespace
);
const imports = ExportMap.get(declaration.source.value, context);
if (imports == null) {
return null;
}
if (imports.errors.length > 0) {
imports.reportErrors(context, declaration);
return;
}
if (imports.size === 0) {
context.report({
node: namespace,
messageId: "noNamesFound",
data: {
module: declaration.source.value
}
});
}
},
// todo: check for possible redefinition
MemberExpression(dereference) {
if (dereference.object.type !== "Identifier") {
return;
}
if (!namespaces.has(dereference.object.name)) {
return;
}
if (declaredScope(context, dereference, dereference.object.name) !== "module") {
return;
}
const parent = dereference.parent;
if ((parent == null ? void 0 : parent.type) === "AssignmentExpression" && parent.left === dereference) {
context.report({
node: parent,
messageId: "namespaceMember",
data: {
namespace: dereference.object.name
}
});
}
let namespace = namespaces.get(dereference.object.name);
const namepath = [dereference.object.name];
let deref = dereference;
while (namespace instanceof ExportMap && (deref == null ? void 0 : deref.type) === "MemberExpression") {
if (deref.computed) {
if (!allowComputed) {
context.report({
node: deref.property,
messageId: "computedReference",
data: {
namespace: "name" in deref.object && deref.object.name
}
});
}
return;
}
if (!namespace.has(deref.property.name)) {
context.report(makeMessage(deref.property, namepath));
break;
}
const exported = namespace.get(deref.property.name);
if (exported == null) {
return;
}
namepath.push(deref.property.name);
namespace = exported.namespace;
deref = deref.parent;
}
},
VariableDeclarator(node) {
const { id, init } = node;
if (init == null) {
return;
}
if (init.type !== "Identifier") {
return;
}
if (!namespaces.has(init.name)) {
return;
}
if (declaredScope(context, node, init.name) !== "module") {
return;
}
const initName = init.name;
function testKey(pattern, namespace, path = [initName]) {
if (!(namespace instanceof ExportMap)) {
return;
}
if (pattern.type !== "ObjectPattern") {
return;
}
for (const property of pattern.properties) {
if (
// @ts-expect-error - experimental type
property.type === "ExperimentalRestProperty" || property.type === "RestElement" || !property.key
) {
continue;
}
if (property.key.type !== "Identifier") {
context.report({
node: property,
messageId: "topLevelNames"
});
continue;
}
if (!namespace.has(property.key.name)) {
context.report(makeMessage(property.key, path, property));
continue;
}
path.push(property.key.name);
const dependencyExportMap = namespace.get(property.key.name);
if (dependencyExportMap != null) {
testKey(property.value, dependencyExportMap.namespace, path);
}
path.pop();
}
}
testKey(id, namespaces.get(init.name));
},
JSXMemberExpression({ object, property }) {
if (!("name" in object) || typeof object.name !== "string" || !namespaces.has(object.name)) {
return;
}
const namespace = namespaces.get(object.name);
if (!namespace.has(property.name)) {
context.report(makeMessage(property, [object.name]));
}
}
};
}
});
var __defProp$7 = Object.defineProperty;
var __getOwnPropSymbols$7 = Object.getOwnPropertySymbols;
var __hasOwnProp$7 = Object.prototype.hasOwnProperty;
var __propIsEnum$7 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$7 = (obj, key, value) => key in obj ? __defProp$7(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$7 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$7.call(b, prop))
__defNormalProp$7(a, prop, b[prop]);
if (__getOwnPropSymbols$7)
for (var prop of __getOwnPropSymbols$7(b)) {
if (__propIsEnum$7.call(b, prop))
__defNormalProp$7(a, prop, b[prop]);
}
return a;
};
const log$1 = debug("eslint-plugin-import-x:rules:newline-after-import");
function containsNodeOrEqual(outerNode, innerNode) {
return outerNode.range[0] <= innerNode.range[0] && outerNode.range[1] >= innerNode.range[1];
}
function getScopeBody(scope) {
if (scope.block.type === "SwitchStatement") {
log$1("SwitchStatement scopes not supported");
return [];
}
const body = "body" in scope.block ? scope.block.body : null;
if (body && "type" in body && body.type === "BlockStatement") {
return body.body;
}
return Array.isArray(body) ? body : [];
}
function findNodeIndexInScopeBody(body, nodeToFind) {
return body.findIndex((node) => containsNodeOrEqual(node, nodeToFind));
}
function getLineDifference(node, nextNode) {
return nextNode.loc.start.line - node.loc.end.line;
}
function isClassWithDecorator(node) {
var _a;
return node.type === "ClassDeclaration" && !!((_a = node.decorators) == null ? void 0 : _a.length);
}
function isExportDefaultClass(node) {
return node.type === "ExportDefaultDeclaration" && node.declaration.type === "ClassDeclaration";
}
function isExportNameClass(node) {
var _a;
return node.type === "ExportNamedDeclaration" && ((_a = node.declaration) == null ? void 0 : _a.type) === "ClassDeclaration";
}
var newlineAfterImport = createRule({
name: "newline-after-import",
meta: {
type: "layout",
docs: {
category: "Style guide",
description: "Enforce a newline after import statements."
},
fixable: "whitespace",
schema: [
{
type: "object",
properties: {
count: {
type: "integer",
minimum: 1
},
exactCount: { type: "boolean" },
considerComments: { type: "boolean" }
},
additionalProperties: false
}
],
messages: {
newline: "Expected {{count}} empty line{{lineSuffix}} after {{type}} statement not followed by another {{type}}."
}
},
defaultOptions: [],
create(context) {
let level = 0;
const requireCalls = [];
const options = __spreadValues$7({
count: 1,
exactCount: false,
considerComments: false
}, context.options[0]);
function checkForNewLine(node, nextNode, type) {
if (isExportDefaultClass(nextNode) || isExportNameClass(nextNode)) {
const classNode = nextNode.declaration;
if (isClassWithDecorator(classNode)) {
nextNode = classNode.decorators[0];
}
} else if (isClassWithDecorator(nextNode)) {
nextNode = nextNode.decorators[0];
}
const lineDifference = getLineDifference(node, nextNode);
const EXPECTED_LINE_DIFFERENCE = options.count + 1;
if (lineDifference < EXPECTED_LINE_DIFFERENCE || options.exactCount && lineDifference !== EXPECTED_LINE_DIFFERENCE) {
let column = node.loc.start.column;
if (node.loc.start.line !== node.loc.end.line) {
column = 0;
}
context.report({
loc: {
line: node.loc.end.line,
column
},
messageId: "newline",
data: {
count: options.count,
lineSuffix: options.count > 1 ? "s" : "",
type
},
fix: options.exactCount && EXPECTED_LINE_DIFFERENCE < lineDifference ? void 0 : (fixer) => fixer.insertTextAfter(
node,
"\n".repeat(EXPECTED_LINE_DIFFERENCE - lineDifference)
)
});
}
}
function commentAfterImport(node, nextComment, type) {
const lineDifference = getLineDifference(node, nextComment);
const EXPECTED_LINE_DIFFERENCE = options.count + 1;
if (lineDifference < EXPECTED_LINE_DIFFERENCE) {
let column = node.loc.start.column;
if (node.loc.start.line !== node.loc.end.line) {
column = 0;
}
context.report({
loc: {
line: node.loc.end.line,
column
},
messageId: "newline",
data: {
count: options.count,
lineSuffix: options.count > 1 ? "s" : "",
type
},
fix: options.exactCount && EXPECTED_LINE_DIFFERENCE < lineDifference ? void 0 : (fixer) => fixer.insertTextAfter(
node,
"\n".repeat(EXPECTED_LINE_DIFFERENCE - lineDifference)
)
});
}
}
function incrementLevel() {
level++;
}
function decrementLevel() {
level--;
}
function checkImport(node) {
const { parent } = node;
if (!parent || !("body" in parent) || !parent.body) {
return;
}
const root = parent;
const nodePosition = root.body.indexOf(node);
const nextNode = root.body[nodePosition + 1];
const endLine = node.loc.end.line;
let nextComment;
if (root.comments !== void 0 && options.considerComments) {
nextComment = root.comments.find(
(o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + options.count + 1
);
}
if (node.type === "TSImportEqualsDeclaration" && // @ts-expect-error - legacy parser type
node.isExport) {
return;
}
if (nextComment) {
commentAfterImport(node, nextComment, "import");
} else if (nextNode && nextNode.type !== "ImportDeclaration" && (nextNode.type !== "TSImportEqualsDeclaration" || // @ts-expect-error - legacy parser type
nextNode.isExport)) {
checkForNewLine(node, nextNode, "import");
}
}
return {
ImportDeclaration: checkImport,
TSImportEqualsDeclaration: checkImport,
CallExpression(node) {
if (isStaticRequire(node) && level === 0) {
requireCalls.push(node);
}
},
"Program:exit"(node) {
log$1("exit processing for", context.physicalFilename);
const scopeBody = getScopeBody(context.sourceCode.getScope(node));
log$1("got scope:", scopeBody);
for (const [index, node2] of requireCalls.entries()) {
const nodePosition = findNodeIndexInScopeBody(scopeBody, node2);
log$1("node position in scope:", nodePosition);
const statementWithRequireCall = scopeBody[nodePosition];
const nextStatement = scopeBody[nodePosition + 1];
const nextRequireCall = requireCalls[index + 1];
if (nextRequireCall && containsNodeOrEqual(statementWithRequireCall, nextRequireCall)) {
continue;
}
if (nextStatement && (!nextRequireCall || !containsNodeOrEqual(nextStatement, nextRequireCall))) {
let nextComment;
if ("comments" in statementWithRequireCall.parent && statementWithRequireCall.parent.comments !== void 0 && options.considerComments) {
const endLine = node2.loc.end.line;
nextComment = statementWithRequireCall.parent.comments.find(
(o) => o.loc.start.line >= endLine && o.loc.start.line <= endLine + options.count + 1
);
}
if (nextComment && nextComment !== void 0) {
commentAfterImport(
statementWithRequireCall,
nextComment,
"require"
);
} else {
checkForNewLine(
statementWithRequireCall,
nextStatement,
"require"
);
}
}
}
},
FunctionDeclaration: incrementLevel,
FunctionExpression: incrementLevel,
ArrowFunctionExpression: incrementLevel,
BlockStatement: incrementLevel,
ObjectExpression: incrementLevel,
Decorator: incrementLevel,
"FunctionDeclaration:exit": decrementLevel,
"FunctionExpression:exit": decrementLevel,
"ArrowFunctionExpression:exit": decrementLevel,
"BlockStatement:exit": decrementLevel,
"ObjectExpression:exit": decrementLevel,
"Decorator:exit": decrementLevel
};
}
});
var __defProp$6 = Object.defineProperty;
var __getOwnPropSymbols$6 = Object.getOwnPropertySymbols;
var __hasOwnProp$6 = Object.prototype.hasOwnProperty;
var __propIsEnum$6 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$6 = (obj, key, value) => key in obj ? __defProp$6(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$6 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$6.call(b, prop))
__defNormalProp$6(a, prop, b[prop]);
if (__getOwnPropSymbols$6)
for (var prop of __getOwnPropSymbols$6(b)) {
if (__propIsEnum$6.call(b, prop))
__defNormalProp$6(a, prop, b[prop]);
}
return a;
};
var noAbsolutePath = createRule({
name: "no-absolute-path",
meta: {
type: "suggestion",
docs: {
category: "Static analysis",
description: "Forbid import of modules using absolute paths."
},
fixable: "code",
schema: [makeOptionsSchema()],
messages: {
absolute: "Do not import modules using an absolute path"
}
},
defaultOptions: [],
create(context) {
const options = __spreadValues$6({ esmodule: true, commonjs: true }, context.options[0]);
return moduleVisitor((source) => {
if (!isAbsolute(source.value)) {
return;
}
context.report({
node: source,
messageId: "absolute",
fix(fixer) {
let relativePath = path.posix.relative(
path.dirname(context.physicalFilename),
source.value
);
if (!relativePath.startsWith(".")) {
relativePath = `./${relativePath}`;
}
return fixer.replaceText(source, JSON.stringify(relativePath));
}
});
}, options);
}
});
var noAmd = createRule({
name: "no-amd",
meta: {
type: "suggestion",
docs: {
category: "Module systems",
description: "Forbid AMD `require` and `define` calls."
},
schema: [],
messages: {
amd: "Expected imports instead of AMD {{type}}()."
}
},
defaultOptions: [],
create(context) {
return {
CallExpression(node) {
if (context.sourceCode.getScope(node).type !== "module") {
return;
}
if (node.callee.type !== "Identifier") {
return;
}
if (node.callee.name !== "require" && node.callee.name !== "define") {
return;
}
if (node.arguments.length !== 2) {
return;
}
const modules = node.arguments[0];
if (modules.type !== "ArrayExpression") {
return;
}
context.report({
node,
messageId: "amd",
data: {
type: node.callee.name
}
});
}
};
}
});
var __defProp$5 = Object.defineProperty;
var __getOwnPropSymbols$5 = Object.getOwnPropertySymbols;
var __hasOwnProp$5 = Object.prototype.hasOwnProperty;
var __propIsEnum$5 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$5 = (obj, key, value) => key in obj ? __defProp$5(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$5 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$5.call(b, prop))
__defNormalProp$5(a, prop, b[prop]);
if (__getOwnPropSymbols$5)
for (var prop of __getOwnPropSymbols$5(b)) {
if (__propIsEnum$5.call(b, prop))
__defNormalProp$5(a, prop, b[prop]);
}
return a;
};
const { hasOwnProperty } = Object.prototype;
const hasOwn = (object, key) => hasOwnProperty.call(object, key);
const defs = {
ArrayExpression: {
option: "allowArray",
description: "If `false`, will report default export of an array",
messageId: "assign",
data: {
type: "array"
}
},
ArrowFunctionExpression: {
option: "allowArrowFunction",
description: "If `false`, will report default export of an arrow function",
messageId: "assign",
data: {
type: "arrow function"
}
},
CallExpression: {
option: "allowCallExpression",
description: "If `false`, will report default export of a function call",
messageId: "assign",
data: {
type: "call result"
},
default: true
},
ClassDeclaration: {
option: "allowAnonymousClass",
description: "If `false`, will report default export of an anonymous class",
messageId: "anonymous",
data: {
type: "class"
},
forbid: (node) => !("id" in node.declaration) || !node.declaration.id
},
FunctionDeclaration: {
option: "allowAnonymousFunction",
description: "If `false`, will report default export of an anonymous function",
messageId: "anonymous",
data: {
type: "function"
},
forbid: (node) => !("id" in node.declaration) || !node.declaration.id
},
Literal: {
option: "allowLiteral",
description: "If `false`, will report default export of a literal",
messageId: "assign",
data: {
type: "literal"
}
},
ObjectExpression: {
option: "allowObject",
description: "If `false`, will report default export of an object expression",
messageId: "assign",
data: {
type: "object"
}
},
TemplateLiteral: {
option: "allowLiteral",
description: "If `false`, will report default export of a literal",
messageId: "assign",
data: {
type: "literal"
}
},
NewExpression: {
option: "allowNew",
description: "If `false`, will report default export of a class instantiation",
messageId: "assign",
data: {
type: "instance"
}
}
};
const schemaProperties = Object.fromEntries(
Object.values(defs).map((def) => [
def.option,
{
description: def.description,
type: "boolean"
}
])
);
const defaults = Object.fromEntries(
Object.values(defs).map((def) => [
def.option,
hasOwn(def, "default") ? def.default : false
])
);
var noAnonymousDefaultExport = createRule({
name: "no-anonymous-default-export",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Forbid anonymous values as default exports."
},
schema: [
{
type: "object",
properties: schemaProperties,
additionalProperties: false
}
],
messages: {
assign: "Assign {{type}} to a variable before exporting as module default",
anonymous: "Unexpected default export of anonymous {{type}}"
}
},
defaultOptions: [],
create(context) {
const options = __spreadValues$5(__spreadValues$5({}, defaults), context.options[0]);
return {
ExportDefaultDeclaration(node) {
const type = node.declaration.type;
if (!(type in defs)) {
return;
}
const def = defs[type];
if (!options[def.option] && (!("forbid" in def) || def.forbid(node))) {
context.report({
node,
messageId: def.messageId,
data: def.data
});
}
}
};
}
});
function normalizeLegacyOptions(options) {
if (options.includes("allow-primitive-modules")) {
return { allowPrimitiveModules: true };
}
return options[0] || {};
}
function allowPrimitive(node, options) {
if (!options.allowPrimitiveModules) {
return false;
}
if (node.parent.type !== "AssignmentExpression") {
return false;
}
return node.parent.right.type !== "ObjectExpression";
}
function validateScope(scope) {
return scope.variableScope.type === "module";
}
function isConditional(node) {
if (node.type === "IfStatement" || node.type === "TryStatement" || node.type === "LogicalExpression" || node.type === "ConditionalExpression") {
return true;
}
if (node.parent) {
return isConditional(node.parent);
}
return false;
}
function isLiteralString(node) {
return node.type === "Literal" && typeof node.value === "string" || node.type === "TemplateLiteral" && node.expressions.length === 0;
}
var noCommonjs = createRule({
name: "no-commonjs",
meta: {
type: "suggestion",
docs: {
category: "Module systems",
description: "Forbid CommonJS `require` calls and `module.exports` or `exports.*`."
},
schema: {
anyOf: [
{
type: "array",
items: [
{
type: "string",
enum: ["allow-primitive-modules"]
}
],
additionalItems: false
},
{
type: "array",
items: [
{
type: "object",
properties: {
allowPrimitiveModules: { type: "boolean" },
allowRequire: { type: "boolean" },
allowConditionalRequire: { type: "boolean" }
},
additionalProperties: false
}
],
additionalItems: false
}
]
},
messages: {
export: 'Expected "export" or "export default"',
import: 'Expected "import" instead of "require()"'
}
},
defaultOptions: [],
create(context) {
const options = normalizeLegacyOptions(context.options);
return {
MemberExpression(node) {
if ("name" in node.object && node.object.name === "module" && "name" in node.property && node.property.name === "exports") {
if (allowPrimitive(node, options)) {
return;
}
context.report({ node, messageId: "export" });
}
if ("name" in node.object && node.object.name === "exports") {
const isInScope = context.sourceCode.getScope(node).variables.some((variable) => variable.name === "exports");
if (!isInScope) {
context.report({ node, messageId: "export" });
}
}
},
CallExpression(call) {
if (!validateScope(context.sourceCode.getScope(call))) {
return;
}
if (call.callee.type !== "Identifier") {
return;
}
if (call.callee.name !== "require") {
return;
}
if (call.arguments.length !== 1) {
return;
}
if (!isLiteralString(call.arguments[0])) {
return;
}
if (options.allowRequire) {
return;
}
if (options.allowConditionalRequire !== false && isConditional(call.parent)) {
return;
}
context.report({
node: call.callee,
messageId: "import"
});
}
};
}
});
var __defProp$4 = Object.defineProperty;
var __defProps$3 = Object.defineProperties;
var __getOwnPropDescs$3 = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$4 = Object.getOwnPropertySymbols;
var __hasOwnProp$4 = Object.prototype.hasOwnProperty;
var __propIsEnum$4 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$4 = (obj, key, value) => key in obj ? __defProp$4(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$4 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$4.call(b, prop))
__defNormalProp$4(a, prop, b[prop]);
if (__getOwnPropSymbols$4)
for (var prop of __getOwnPropSymbols$4(b)) {
if (__propIsEnum$4.call(b, prop))
__defNormalProp$4(a, prop, b[prop]);
}
return a;
};
var __spreadProps$3 = (a, b) => __defProps$3(a, __getOwnPropDescs$3(b));
const traversed = /* @__PURE__ */ new Set();
var noCycle = createRule({
name: "no-cycle",
meta: {
type: "suggestion",
docs: {
category: "Static analysis",
description: "Forbid a module from importing a module with a dependency path back to itself."
},
schema: [
makeOptionsSchema({
maxDepth: {
anyOf: [
{
description: "maximum dependency depth to traverse",
type: "integer",
minimum: 1
},
{
enum: ["\u221E"],
type: "string"
}
]
},
ignoreExternal: {
description: "ignore external modules",
type: "boolean",
default: false
},
allowUnsafeDynamicCyclicDependency: {
description: "Allow cyclic dependency if there is at least one dynamic import in the chain",
type: "boolean",
default: false
}
})
],
messages: {
cycle: "Dependency cycle detected",
cycleSource: 'Dependency cycle via "{{source}}"'
}
},
defaultOptions: [],
create(context) {
const filename = context.physicalFilename;
if (filename === "<text>") {
return {};
}
const options = context.options[0] || {};
const maxDepth = typeof options.maxDepth === "number" ? options.maxDepth : Number.POSITIVE_INFINITY;
const ignoreModule = options.ignoreExternal ? (name) => isExternalModule(name, resolve(name, context), context) : () => false;
return __spreadProps$3(__spreadValues$4({}, moduleVisitor(function checkSourceValue(sourceNode, importer) {
if (ignoreModule(sourceNode.value)) {
return;
}
if (options.allowUnsafeDynamicCyclicDependency && // Ignore `import()`
(importer.type === "ImportExpression" || // `require()` calls are always checked (if possible)
importer.type === "CallExpression" && "name" in importer.callee && importer.callee.name !== "require")) {
return;
}
if (importer.type === "ImportDeclaration" && // import type { Foo } (TS and Flow)
(importer.importKind === "type" || // import { type Foo } (Flow)
importer.specifiers.every(
(s) => "importKind" in s && s.importKind === "type"
))) {
return;
}
const imported = ExportMap.get(sourceNode.value, context);
if (imported == null) {
return;
}
if (imported.path === filename) {
return;
}
const untraversed = [{ mget: () => imported, route: [] }];
function detectCycle({ mget, route }) {
const m = mget();
if (m == null) {
return;
}
if (traversed.has(m.path)) {
return;
}
traversed.add(m.path);
for (const [path, { getter, declarations }] of m.imports) {
if (traversed.has(path)) {
continue;
}
const toTraverse = [...declarations].filter(
({ source, isOnlyImportingTypes }) => !ignoreModule(source.value) && // Ignore only type imports
!isOnlyImportingTypes
);
if (options.allowUnsafeDynamicCyclicDependency && toTraverse.some((d) => d.dynamic)) {
return;
}
if (path === filename && toTraverse.length > 0) {
return true;
}
if (route.length + 1 < maxDepth) {
for (const { source } of toTraverse) {
untraversed.push({ mget: getter, route: [...route, source] });
}
}
}
}
while (untraversed.length > 0) {
const next = untraversed.shift();
if (detectCycle(next)) {
if (next.route.length > 0) {
context.report({
node: importer,
messageId: "cycleSource",
data: {
source: routeString(next.route)
}
});
} else {
context.report({
node: importer,
messageId: "cycle"
});
}
return;
}
}
}, context.options[0])), {
"Program:exit"() {
traversed.clear();
}
});
}
});
function routeString(route) {
return route.map((s) => `${s.value}:${s.loc.start.line}`).join("=>");
}
var noDefaultExport = createRule({
name: "no-default-export",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Forbid default exports."
},
schema: [],
messages: {
preferNamed: "Prefer named exports.",
noAliasDefault: "Do not alias `{{local}}` as `default`. Just export `{{local}}` itself instead."
}
},
defaultOptions: [],
create(context) {
if (sourceType(context) !== "module") {
return {};
}
const { sourceCode } = context;
return {
ExportDefaultDeclaration(node) {
const { loc } = sourceCode.getFirstTokens(node)[1] || {};
context.report({
node,
messageId: "preferNamed",
loc
});
},
ExportNamedDeclaration(node) {
for (const specifier of node.specifiers.filter(
(specifier2) => getValue(specifier2.exported) === "default"
)) {
const { loc } = sourceCode.getFirstTokens(node)[1] || {};
if (specifier.type === "ExportDefaultSpecifier") {
context.report({
node,
messageId: "preferNamed",
loc
});
} else if (specifier.type === "ExportSpecifier") {
context.report({
node,
messageId: "noAliasDefault",
data: {
local: getValue(specifier.local)
},
loc
});
}
}
}
};
}
});
var __defProp$3 = Object.defineProperty;
var __getOwnPropSymbols$3 = Object.getOwnPropertySymbols;
var __hasOwnProp$3 = Object.prototype.hasOwnProperty;
var __propIsEnum$3 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$3 = (obj, key, value) => key in obj ? __defProp$3(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$3 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$3.call(b, prop))
__defNormalProp$3(a, prop, b[prop]);
if (__getOwnPropSymbols$3)
for (var prop of __getOwnPropSymbols$3(b)) {
if (__propIsEnum$3.call(b, prop))
__defNormalProp$3(a, prop, b[prop]);
}
return a;
};
function message(deprecation) {
if (deprecation.description) {
return {
messageId: "deprecatedDesc",
data: { description: deprecation.description }
};
}
return { messageId: "deprecated" };
}
function getDeprecation(metadata) {
if (!metadata || !metadata.doc) {
return;
}
return metadata.doc.tags.find((t) => t.tag === "deprecated");
}
var noDeprecated = createRule({
name: "no-deprecated",
meta: {
type: "suggestion",
docs: {
category: "Helpful warnings",
description: "Forbid imported names marked with `@deprecated` documentation tag."
},
schema: [],
messages: {
deprecatedDesc: "Deprecated: {{description}}",
deprecated: "Deprecated: consider to find an alternative."
}
},
defaultOptions: [],
create(context) {
const deprecated = /* @__PURE__ */ new Map();
const namespaces = /* @__PURE__ */ new Map();
return {
Program({ body }) {
var _a;
for (const node of body) {
if (node.type !== "ImportDeclaration") {
continue;
}
if (node.source == null) {
continue;
}
const imports = ExportMap.get(node.source.value, context);
if (imports == null) {
continue;
}
const moduleDeprecation = (_a = imports.doc) == null ? void 0 : _a.tags.find(
(t) => t.tag === "deprecated"
);
if (moduleDeprecation) {
context.report(__spreadValues$3({
node
}, message(moduleDeprecation)));
}
if (imports.errors.length > 0) {
imports.reportErrors(context, node);
continue;
}
for (const im of node.specifiers) {
let imported;
let local;
switch (im.type) {
case "ImportNamespaceSpecifier": {
if (imports.size === 0) {
continue;
}
namespaces.set(im.local.name, imports);
continue;
}
case "ImportDefaultSpecifier": {
imported = "default";
local = im.local.name;
break;
}
case "ImportSpecifier": {
imported = getValue(im.imported);
local = im.local.name;
break;
}
default: {
continue;
}
}
const exported = imports.get(imported);
if (exported == null) {
continue;
}
if (exported.namespace) {
namespaces.set(local, exported.namespace);
}
const deprecation = getDeprecation(imports.get(imported));
if (!deprecation) {
continue;
}
context.report(__spreadValues$3({
node: im
}, message(deprecation)));
deprecated.set(local, deprecation);
}
}
},
Identifier(node) {
if (!node.parent || node.parent.type === "MemberExpression" && node.parent.property === node) {
return;
}
if (node.parent.type.slice(0, 6) === "Import") {
return;
}
if (!deprecated.has(node.name)) {
return;
}
if (declaredScope(context, node, node.name) !== "module") {
return;
}
context.report(__spreadValues$3({
node
}, message(deprecated.get(node.name))));
},
MemberExpression(dereference) {
if (dereference.object.type !== "Identifier") {
return;
}
if (!namespaces.has(dereference.object.name)) {
return;
}
if (declaredScope(context, dereference, dereference.object.name) !== "module") {
return;
}
let namespace = namespaces.get(dereference.object.name);
const namepath = [dereference.object.name];
let node = dereference;
while (namespace instanceof ExportMap && (node == null ? void 0 : node.type) === "MemberExpression") {
if (node.computed) {
return;
}
const metadata = namespace.get(node.property.name);
if (!metadata) {
break;
}
const deprecation = getDeprecation(metadata);
if (deprecation) {
context.report(__spreadValues$3({
node: node.property
}, message(deprecation)));
}
namepath.push(node.property.name);
namespace = metadata.namespace;
node = node.parent;
}
}
};
}
});
const isTypeScriptVersionSupportPreferInline = lazy(() => {
let typescriptPkg;
try {
typescriptPkg = cjsRequire("typescript/package.json");
} catch (e) {
}
return !typescriptPkg || !semver__namespace.satisfies(typescriptPkg.version, ">= 4.5");
});
function checkImports(imported, context) {
imported.forEach((nodes, module) => {
if (nodes.length <= 1) {
return;
}
for (let i = 0, len = nodes.length; i < len; i++) {
const node = nodes[i];
context.report({
node: node.source,
messageId: "duplicate",
data: {
module
},
// Attach the autofix (if any) to the first import only
fix: i === 0 ? getFix(nodes, context.sourceCode, context) : null
});
}
});
}
function getFix(nodes, sourceCode, context) {
const first = nodes[0];
if (hasProblematicComments(first, sourceCode) || hasNamespace(first)) {
return null;
}
const defaultImportNames = new Set(
nodes.flatMap((x) => getDefaultImportName(x) || [])
);
if (defaultImportNames.size > 1) {
return null;
}
const rest = nodes.slice(1);
const restWithoutCommentsAndNamespaces = rest.filter(
(node) => !hasProblematicComments(node, sourceCode) && !hasNamespace(node)
);
const restWithoutCommentsAndNamespacesHasSpecifiers = restWithoutCommentsAndNamespaces.map(hasSpecifiers);
const specifiers = restWithoutCommentsAndNamespaces.reduce((acc, node, nodeIndex) => {
const tokens = sourceCode.getTokens(node);
const openBrace = tokens.find((token) => isPunctuator(token, "{"));
const closeBrace = tokens.find((token) => isPunctuator(token, "}"));
if (openBrace == null || closeBrace == null) {
return acc;
}
acc.push({
importNode: node,
identifiers: sourceCode.text.slice(openBrace.range[1], closeBrace.range[0]).split(","),
// Split the text into separate identifiers (retaining any whitespace before or after)
isEmpty: !restWithoutCommentsAndNamespacesHasSpecifiers[nodeIndex]
});
return acc;
}, []);
const unnecessaryImports = restWithoutCommentsAndNamespaces.filter(
(node, nodeIndex) => !restWithoutCommentsAndNamespacesHasSpecifiers[nodeIndex] && !specifiers.some((specifier) => specifier.importNode === node)
);
const shouldAddSpecifiers = specifiers.length > 0;
const shouldRemoveUnnecessary = unnecessaryImports.length > 0;
const shouldAddDefault = lazy(
() => getDefaultImportName(first) == null && defaultImportNames.size === 1
);
if (!shouldAddSpecifiers && !shouldRemoveUnnecessary && !shouldAddDefault()) {
return null;
}
const preferInline = context.options[0] && context.options[0]["prefer-inline"];
return (fixer) => {
const tokens = sourceCode.getTokens(first);
const openBrace = tokens.find((token) => isPunctuator(token, "{"));
const closeBrace = tokens.find((token) => isPunctuator(token, "}"));
const firstToken = sourceCode.getFirstToken(first);
const [defaultImportName] = defaultImportNames;
const firstHasTrailingComma = closeBrace != null && isPunctuator(sourceCode.getTokenBefore(closeBrace), ",");
const firstIsEmpty = !hasSpecifiers(first);
const firstExistingIdentifiers = firstIsEmpty ? /* @__PURE__ */ new Set() : new Set(
sourceCode.text.slice(openBrace.range[1], closeBrace.range[0]).split(",").map((x) => x.split(" as ")[0].trim())
);
const [specifiersText] = specifiers.reduce(
([result, needsComma, existingIdentifiers], specifier) => {
const isTypeSpecifier = "importNode" in specifier && specifier.importNode.importKind === "type";
if (preferInline && isTypeScriptVersionSupportPreferInline()) {
throw new Error(
"Your version of TypeScript does not support inline type imports."
);
}
const [specifierText, updatedExistingIdentifiers] = specifier.identifiers.reduce(
([text, set], cur) => {
const trimmed = cur.trim();
if (trimmed.length === 0 || existingIdentifiers.has(trimmed)) {
return [text, set];
}
const curWithType = preferInline && isTypeSpecifier ? cur.replace(/^(\s*)/, "$1type ") : cur;
return [
text.length > 0 ? `${text},${curWithType}` : curWithType,
set.add(trimmed)
];
},
["", existingIdentifiers]
);
return [
needsComma && !specifier.isEmpty && specifierText.length > 0 ? `${result},${specifierText}` : `${result}${specifierText}`,
specifier.isEmpty ? needsComma : true,
updatedExistingIdentifiers
];
},
["", !firstHasTrailingComma && !firstIsEmpty, firstExistingIdentifiers]
);
const fixes = [];
if (shouldAddSpecifiers && preferInline && first.importKind === "type") {
const typeIdentifierToken = tokens.find(
(token) => token.type === "Identifier" && token.value === "type"
);
if (typeIdentifierToken) {
fixes.push(
fixer.removeRange([
typeIdentifierToken.range[0],
typeIdentifierToken.range[1] + 1
])
);
}
for (const identifier of tokens.filter(
(token) => firstExistingIdentifiers.has(token.value)
)) {
fixes.push(
fixer.replaceTextRange(
[identifier.range[0], identifier.range[1]],
`type ${identifier.value}`
)
);
}
}
if (openBrace == null && shouldAddSpecifiers && shouldAddDefault()) {
fixes.push(
fixer.insertTextAfter(
firstToken,
` ${defaultImportName}, {${specifiersText}} from`
)
);
} else if (openBrace == null && !shouldAddSpecifiers && shouldAddDefault()) {
fixes.push(
fixer.insertTextAfter(firstToken, ` ${defaultImportName} from`)
);
} else if (openBrace != null && closeBrace != null && shouldAddDefault()) {
fixes.push(fixer.insertTextAfter(firstToken, ` ${defaultImportName},`));
if (shouldAddSpecifiers) {
fixes.push(fixer.insertTextBefore(closeBrace, specifiersText));
}
} else if (openBrace == null && shouldAddSpecifiers && !shouldAddDefault()) {
if (first.specifiers.length === 0) {
fixes.push(
fixer.insertTextAfter(firstToken, ` {${specifiersText}} from`)
);
} else {
fixes.push(
fixer.insertTextAfter(first.specifiers[0], `, {${specifiersText}}`)
);
}
} else if (openBrace != null && closeBrace != null && !shouldAddDefault()) {
const tokenBefore = sourceCode.getTokenBefore(closeBrace);
fixes.push(fixer.insertTextAfter(tokenBefore, specifiersText));
}
for (const specifier of specifiers) {
const importNode = specifier.importNode;
fixes.push(fixer.remove(importNode));
const charAfterImportRange = [
importNode.range[1],
importNode.range[1] + 1
];
const charAfterImport = sourceCode.text.slice(
charAfterImportRange[0],
charAfterImportRange[1]
);
if (charAfterImport === "\n") {
fixes.push(fixer.removeRange(charAfterImportRange));
}
}
for (const node of unnecessaryImports) {
fixes.push(fixer.remove(node));
const charAfterImportRange = [node.range[1], node.range[1] + 1];
const charAfterImport = sourceCode.text.slice(
charAfterImportRange[0],
charAfterImportRange[1]
);
if (charAfterImport === "\n") {
fixes.push(fixer.removeRange(charAfterImportRange));
}
}
return fixes;
};
}
function isPunctuator(node, value) {
return node.type === "Punctuator" && node.value === value;
}
function getDefaultImportName(node) {
const defaultSpecifier = node.specifiers.find(
(specifier) => specifier.type === "ImportDefaultSpecifier"
);
return defaultSpecifier == null ? void 0 : defaultSpecifier.local.name;
}
function hasNamespace(node) {
return node.specifiers.some(
(specifier) => specifier.type === "ImportNamespaceSpecifier"
);
}
function hasSpecifiers(node) {
return node.specifiers.some((specifier) => specifier.type === "ImportSpecifier");
}
function hasProblematicComments(node, sourceCode) {
return hasCommentBefore(node, sourceCode) || hasCommentAfter(node, sourceCode) || hasCommentInsideNonSpecifiers(node, sourceCode);
}
function hasCommentBefore(node, sourceCode) {
return sourceCode.getCommentsBefore(node).some((comment) => comment.loc.end.line >= node.loc.start.line - 1);
}
function hasCommentAfter(node, sourceCode) {
return sourceCode.getCommentsAfter(node).some((comment) => comment.loc.start.line === node.loc.end.line);
}
function hasCommentInsideNonSpecifiers(node, sourceCode) {
const tokens = sourceCode.getTokens(node);
const openBraceIndex = tokens.findIndex((token) => isPunctuator(token, "{"));
const closeBraceIndex = tokens.findIndex((token) => isPunctuator(token, "}"));
const someTokens = openBraceIndex !== -1 && closeBraceIndex !== -1 ? [
...tokens.slice(1, openBraceIndex + 1),
...tokens.slice(closeBraceIndex + 1)
] : tokens.slice(1);
return someTokens.some(
(token) => sourceCode.getCommentsBefore(token).length > 0
);
}
var noDuplicates = createRule({
name: "no-duplicates",
meta: {
type: "problem",
docs: {
category: "Style guide",
description: "Forbid repeated import of the same module in multiple places."
},
fixable: "code",
schema: [
{
type: "object",
properties: {
considerQueryString: {
type: "boolean"
},
"prefer-inline": {
type: "boolean"
}
},
additionalProperties: false
}
],
messages: {
duplicate: "'{{module}}' imported multiple times."
}
},
defaultOptions: [],
create(context) {
var _a, _b;
const preferInline = (_a = context.options[0]) == null ? void 0 : _a["prefer-inline"];
const considerQueryStringOption = (_b = context.options[0]) == null ? void 0 : _b.considerQueryString;
const defaultResolver = (sourcePath) => resolve(sourcePath, context) || sourcePath;
const resolver = considerQueryStringOption ? (sourcePath) => {
const parts = sourcePath.match(/^([^?]*)\?(.*)$/);
if (!parts) {
return defaultResolver(sourcePath);
}
return `${defaultResolver(parts[1])}?${parts[2]}`;
} : defaultResolver;
const moduleMaps = /* @__PURE__ */ new Map();
function getImportMap(n) {
const parent = n.parent;
let map;
if (moduleMaps.has(parent)) {
map = moduleMaps.get(parent);
} else {
map = {
imported: /* @__PURE__ */ new Map(),
nsImported: /* @__PURE__ */ new Map(),
defaultTypesImported: /* @__PURE__ */ new Map(),
namespaceTypesImported: /* @__PURE__ */ new Map(),
namedTypesImported: /* @__PURE__ */ new Map()
};
moduleMaps.set(parent, map);
}
if (n.importKind === "type") {
if (n.specifiers.length > 0 && n.specifiers[0].type === "ImportDefaultSpecifier") {
return map.defaultTypesImported;
}
if (n.specifiers.length > 0 && n.specifiers[0].type === "ImportNamespaceSpecifier") {
return map.namespaceTypesImported;
}
if (!preferInline) {
return map.namedTypesImported;
}
}
if (!preferInline && n.specifiers.some(
(spec) => "importKind" in spec && spec.importKind === "type"
)) {
return map.namedTypesImported;
}
return hasNamespace(n) ? map.nsImported : map.imported;
}
return {
ImportDeclaration(n) {
const resolvedPath = resolver(n.source.value);
const importMap = getImportMap(n);
if (importMap.has(resolvedPath)) {
importMap.get(resolvedPath).push(n);
} else {
importMap.set(resolvedPath, [n]);
}
},
"Program:exit"() {
for (const map of moduleMaps.values()) {
checkImports(map.imported, context);
checkImports(map.nsImported, context);
checkImports(map.defaultTypesImported, context);
checkImports(map.namedTypesImported, context);
}
}
};
}
});
function isRequire(node) {
var _a;
return ((_a = node.callee) == null ? void 0 : _a.type) === "Identifier" && node.callee.name === "require" && node.arguments.length > 0;
}
function isDynamicImport(node) {
return (node == null ? void 0 : node.callee) && // @ts-expect-error - legacy parser type
node.callee.type === "Import";
}
function isStaticValue(node) {
return node.type === "Literal" || node.type === "TemplateLiteral" && node.expressions.length === 0;
}
var noDynamicRequire = createRule({
name: "no-dynamic-require",
meta: {
type: "suggestion",
docs: {
category: "Static analysis",
description: "Forbid `require()` calls with expressions."
},
schema: [
{
type: "object",
properties: {
esmodule: {
type: "boolean"
}
},
additionalProperties: false
}
],
messages: {
import: "Calls to import() should use string literals",
require: "Calls to require() should use string literals"
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
return {
CallExpression(node) {
if (!node.arguments[0] || isStaticValue(node.arguments[0])) {
return;
}
if (isRequire(node)) {
return context.report({
node,
messageId: "require"
});
}
if (options.esmodule && isDynamicImport(node)) {
return context.report({
node,
messageId: "import"
});
}
},
ImportExpression(node) {
if (!options.esmodule || isStaticValue(node.source)) {
return;
}
return context.report({
node,
messageId: "import"
});
}
};
}
});
function getEmptyBlockRange(tokens, index) {
const token = tokens[index];
const nextToken = tokens[index + 1];
const prevToken = tokens[index - 1];
let start = token.range[0];
const end = nextToken.range[1];
if (prevToken.value === "," || prevToken.value === "type" || prevToken.value === "typeof") {
start = prevToken.range[0];
}
return [start, end];
}
var noEmptyNamedBlocks = createRule({
name: "no-empty-named-blocks",
meta: {
type: "suggestion",
docs: {
category: "Helpful warnings",
description: "Forbid empty named import blocks."
},
fixable: "code",
hasSuggestions: true,
schema: [],
messages: {
emptyNamed: "Unexpected empty named import block",
unused: "Remove unused import",
emptyImport: "Remove empty import block"
}
},
defaultOptions: [],
create(context) {
const importsWithoutNameds = [];
return {
ImportDeclaration(node) {
if (!node.specifiers.some((x) => x.type === "ImportSpecifier")) {
importsWithoutNameds.push(node);
}
},
"Program:exit"(program) {
const importsTokens = importsWithoutNameds.map(
(node) => [
node,
program.tokens.filter(
(x) => x.range[0] >= node.range[0] && x.range[1] <= node.range[1]
)
]
);
const pTokens = program.tokens || [];
for (const [node, tokens] of importsTokens) {
for (const token of tokens) {
const idx = pTokens.indexOf(token);
const nextToken = pTokens[idx + 1];
if (nextToken && token.value === "{" && nextToken.value === "}") {
const hasOtherIdentifiers = tokens.some(
(token2) => token2.type === "Identifier" && token2.value !== "from" && token2.value !== "type" && token2.value !== "typeof"
);
if (hasOtherIdentifiers) {
context.report({
node,
messageId: "emptyNamed",
fix(fixer) {
return fixer.removeRange(getEmptyBlockRange(pTokens, idx));
}
});
} else {
context.report({
node,
messageId: "emptyNamed",
suggest: [
{
messageId: "unused",
fix(fixer) {
return fixer.remove(node);
}
},
{
messageId: "emptyImport",
fix(fixer) {
const { sourceCode } = context;
const fromToken = pTokens.find((t) => t.value === "from");
const importToken = pTokens.find(
(t) => t.value === "import"
);
const hasSpaceAfterFrom = sourceCode.isSpaceBetween(
fromToken,
sourceCode.getTokenAfter(fromToken)
);
const hasSpaceAfterImport = sourceCode.isSpaceBetween(
importToken,
sourceCode.getTokenAfter(fromToken)
);
const [start] = getEmptyBlockRange(pTokens, idx);
const [, end] = fromToken.range;
const range = [
start,
hasSpaceAfterFrom ? end + 1 : end
];
return fixer.replaceTextRange(
range,
hasSpaceAfterImport ? "" : " "
);
}
}
]
});
}
}
}
}
}
};
}
});
var __defProp$2 = Object.defineProperty;
var __defProps$2 = Object.defineProperties;
var __getOwnPropDescs$2 = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$2 = Object.getOwnPropertySymbols;
var __hasOwnProp$2 = Object.prototype.hasOwnProperty;
var __propIsEnum$2 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$2 = (obj, key, value) => key in obj ? __defProp$2(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$2 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$2.call(b, prop))
__defNormalProp$2(a, prop, b[prop]);
if (__getOwnPropSymbols$2)
for (var prop of __getOwnPropSymbols$2(b)) {
if (__propIsEnum$2.call(b, prop))
__defNormalProp$2(a, prop, b[prop]);
}
return a;
};
var __spreadProps$2 = (a, b) => __defProps$2(a, __getOwnPropDescs$2(b));
const depFieldCache = /* @__PURE__ */ new Map();
function hasKeys(obj = {}) {
return Object.keys(obj).length > 0;
}
function arrayOrKeys(arrayOrObject) {
return Array.isArray(arrayOrObject) ? arrayOrObject : Object.keys(arrayOrObject);
}
function readJSON(jsonPath, throwException) {
try {
return JSON.parse(fs.readFileSync(jsonPath, "utf8"));
} catch (error) {
if (throwException) {
throw error;
}
}
}
function extractDepFields(pkg) {
return {
dependencies: pkg.dependencies || {},
devDependencies: pkg.devDependencies || {},
optionalDependencies: pkg.optionalDependencies || {},
peerDependencies: pkg.peerDependencies || {},
// BundledDeps should be in the form of an array, but object notation is also supported by
// `npm`, so we convert it to an array if it is an object
bundledDependencies: arrayOrKeys(
pkg.bundleDependencies || pkg.bundledDependencies || []
)
};
}
function getPackageDepFields(packageJsonPath, throwAtRead) {
if (!depFieldCache.has(packageJsonPath)) {
const packageJson = readJSON(packageJsonPath, throwAtRead);
if (packageJson) {
const depFields = extractDepFields(packageJson);
depFieldCache.set(packageJsonPath, depFields);
}
}
return depFieldCache.get(packageJsonPath);
}
function getDependencies(context, packageDir) {
let paths = [];
try {
let packageContent = {
dependencies: {},
devDependencies: {},
optionalDependencies: {},
peerDependencies: {},
bundledDependencies: []
};
if (packageDir && packageDir.length > 0) {
paths = Array.isArray(packageDir) ? packageDir.map((dir) => path.resolve(dir)) : [path.resolve(packageDir)];
}
if (paths.length > 0) {
for (const dir of paths) {
const packageJsonPath = path.resolve(dir, "package.json");
const packageContent_ = getPackageDepFields(
packageJsonPath,
paths.length === 1
);
if (packageContent_) {
for (const depsKey of Object.keys(packageContent)) {
const key = depsKey;
Object.assign(packageContent[key], packageContent_[key]);
}
}
}
} else {
const packageJsonPath = pkgUp({
cwd: context.physicalFilename
});
const packageContent_ = getPackageDepFields(packageJsonPath, false);
if (packageContent_) {
packageContent = packageContent_;
}
}
if (![
packageContent.dependencies,
packageContent.devDependencies,
packageContent.optionalDependencies,
packageContent.peerDependencies,
packageContent.bundledDependencies
].some(hasKeys)) {
return;
}
return packageContent;
} catch (error_) {
const error = error_;
if (paths.length > 0 && error.code === "ENOENT") {
context.report({
messageId: "pkgNotFound",
loc: { line: 0, column: 0 }
});
}
if (error.name === "JSONError" || error instanceof SyntaxError) {
context.report({
messageId: "pkgUnparsable",
data: { error: error.message },
loc: { line: 0, column: 0 }
});
}
}
}
function getModuleOriginalName(name) {
const [first, second] = name.split("/");
return first.startsWith("@") ? `${first}/${second}` : first;
}
function checkDependencyDeclaration(deps, packageName, declarationStatus) {
const newDeclarationStatus = declarationStatus || {
isInDeps: false,
isInDevDeps: false,
isInOptDeps: false,
isInPeerDeps: false,
isInBundledDeps: false
};
const packageHierarchy = [];
const packageNameParts = packageName ? packageName.split("/") : [];
for (const [index, namePart] of packageNameParts.entries()) {
if (!namePart.startsWith("@")) {
const ancestor = packageNameParts.slice(0, index + 1).join("/");
packageHierarchy.push(ancestor);
}
}
return packageHierarchy.reduce(
(result, ancestorName) => ({
isInDeps: result.isInDeps || deps.dependencies[ancestorName] !== void 0,
isInDevDeps: result.isInDevDeps || deps.devDependencies[ancestorName] !== void 0,
isInOptDeps: result.isInOptDeps || deps.optionalDependencies[ancestorName] !== void 0,
isInPeerDeps: result.isInPeerDeps || deps.peerDependencies[ancestorName] !== void 0,
isInBundledDeps: result.isInBundledDeps || deps.bundledDependencies.includes(ancestorName)
}),
newDeclarationStatus
);
}
function reportIfMissing(context, deps, depsOptions, node, name, whitelist) {
if (!depsOptions.verifyTypeImports && ("importKind" in node && (node.importKind === "type" || // @ts-expect-error - flow type
node.importKind === "typeof") || "exportKind" in node && node.exportKind === "type" || "specifiers" in node && Array.isArray(node.specifiers) && node.specifiers.length > 0 && node.specifiers.every(
(specifier) => "importKind" in specifier && (specifier.importKind === "type" || // @ts-expect-error - flow type
specifier.importKind === "typeof")
))) {
return;
}
const typeOfImport = importType(name, context);
if (typeOfImport !== "external" && (typeOfImport !== "internal" || !depsOptions.verifyInternalDeps)) {
return;
}
const resolved = resolve(name, context);
if (!resolved) {
return;
}
const importPackageName = getModuleOriginalName(name);
let declarationStatus = checkDependencyDeclaration(deps, importPackageName);
if (declarationStatus.isInDeps || depsOptions.allowDevDeps && declarationStatus.isInDevDeps || depsOptions.allowPeerDeps && declarationStatus.isInPeerDeps || depsOptions.allowOptDeps && declarationStatus.isInOptDeps || depsOptions.allowBundledDeps && declarationStatus.isInBundledDeps) {
return;
}
const realPackageName = getFilePackageName(resolved);
if (realPackageName && realPackageName !== importPackageName) {
declarationStatus = checkDependencyDeclaration(
deps,
realPackageName,
declarationStatus
);
if (declarationStatus.isInDeps || depsOptions.allowDevDeps && declarationStatus.isInDevDeps || depsOptions.allowPeerDeps && declarationStatus.isInPeerDeps || depsOptions.allowOptDeps && declarationStatus.isInOptDeps || depsOptions.allowBundledDeps && declarationStatus.isInBundledDeps) {
return;
}
}
const packageName = realPackageName || importPackageName;
if (whitelist == null ? void 0 : whitelist.has(packageName)) {
return;
}
if (declarationStatus.isInDevDeps && !depsOptions.allowDevDeps) {
context.report({
node,
messageId: "devDep",
data: {
packageName
}
});
return;
}
if (declarationStatus.isInOptDeps && !depsOptions.allowOptDeps) {
context.report({
node,
messageId: "optDep",
data: {
packageName
}
});
return;
}
context.report({
node,
messageId: "missing",
data: {
packageName
}
});
}
function testConfig(config, filename) {
if (typeof config === "boolean" || config === void 0) {
return config;
}
return config.some(
(c) => minimatch.minimatch(filename, c) || minimatch.minimatch(filename, path.resolve(c), { windowsPathsNoEscape: true })
);
}
var noExtraneousDependencies = createRule({
name: "no-extraneous-dependencies",
meta: {
type: "problem",
docs: {
category: "Helpful warnings",
description: "Forbid the use of extraneous packages."
},
schema: [
{
type: "object",
properties: {
devDependencies: { type: ["boolean", "array"] },
optionalDependencies: { type: ["boolean", "array"] },
peerDependencies: { type: ["boolean", "array"] },
bundledDependencies: { type: ["boolean", "array"] },
packageDir: { type: ["string", "array"] },
includeInternal: { type: ["boolean"] },
includeTypes: { type: ["boolean"] },
whitelist: { type: ["array"] }
},
additionalProperties: false
}
],
messages: {
pkgNotFound: "The package.json file could not be found.",
pkgUnparsable: "The package.json file could not be parsed: {{error}}",
devDep: "'{{packageName}}' should be listed in the project's dependencies, not devDependencies.",
optDep: "'{{packageName}}' should be listed in the project's dependencies, not optionalDependencies.",
missing: "'{{packageName}}' should be listed in the project's dependencies. Run 'npm i -S {{packageName}}' to add it"
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
const filename = context.physicalFilename;
const deps = getDependencies(context, options.packageDir) || extractDepFields({});
const depsOptions = {
allowDevDeps: testConfig(options.devDependencies, filename) !== false,
allowOptDeps: testConfig(options.optionalDependencies, filename) !== false,
allowPeerDeps: testConfig(options.peerDependencies, filename) !== false,
allowBundledDeps: testConfig(options.bundledDependencies, filename) !== false,
verifyInternalDeps: !!options.includeInternal,
verifyTypeImports: !!options.includeTypes
};
return __spreadProps$2(__spreadValues$2({}, moduleVisitor(
(source, node) => {
reportIfMissing(
context,
deps,
depsOptions,
node,
source.value,
options.whitelist ? new Set(options.whitelist) : void 0
);
},
{ commonjs: true }
)), {
"Program:exit"() {
depFieldCache.clear();
}
});
}
});
function getEntryPoint(context) {
const pkgPath = pkgUp({
cwd: context.physicalFilename
});
try {
return cjsRequire.resolve(path.dirname(pkgPath));
} catch (e) {
return null;
}
}
function findScope(context, identifier) {
const { scopeManager } = context.sourceCode;
return scopeManager == null ? void 0 : scopeManager.scopes.slice().reverse().find(
(scope) => scope.variables.some(
(variable) => variable.identifiers.some((node) => node.name === identifier)
)
);
}
function findDefinition(objectScope, identifier) {
const variable = objectScope.variables.find(
(variable2) => variable2.name === identifier
);
return variable.defs.find(
(def) => "name" in def.name && def.name.name === identifier
);
}
var noImportModuleExports = createRule({
name: "no-import-module-exports",
meta: {
type: "problem",
docs: {
category: "Module systems",
description: "Forbid import statements with CommonJS module.exports.",
recommended: true
},
fixable: "code",
schema: [
{
type: "object",
properties: {
exceptions: { type: "array" }
},
additionalProperties: false
}
],
messages: {
notAllowed: "Cannot use import declarations in modules that export using CommonJS (module.exports = 'foo' or exports.bar = 'hi')"
}
},
defaultOptions: [],
create(context) {
const importDeclarations = [];
const entryPoint = getEntryPoint(context);
const options = context.options[0] || {};
let alreadyReported = false;
return {
ImportDeclaration(node) {
importDeclarations.push(node);
},
MemberExpression(node) {
var _a;
if (alreadyReported) {
return;
}
const filename = context.physicalFilename;
const isEntryPoint = entryPoint === filename;
const isIdentifier = node.object.type === "Identifier";
if (!("name" in node.object)) {
return;
}
const hasKeywords = /^(module|exports)$/.test(node.object.name);
const objectScope = hasKeywords ? findScope(context, node.object.name) : void 0;
const variableDefinition = objectScope && findDefinition(objectScope, node.object.name);
const isImportBinding = (variableDefinition == null ? void 0 : variableDefinition.type) === "ImportBinding";
const hasCJSExportReference = hasKeywords && (!objectScope || objectScope.type === "module");
if (isIdentifier && hasCJSExportReference && !isEntryPoint && !((_a = options.exceptions) == null ? void 0 : _a.some((glob) => minimatch.minimatch(filename, glob))) && !isImportBinding) {
for (const importDeclaration of importDeclarations) {
context.report({
node: importDeclaration,
messageId: "notAllowed"
});
}
alreadyReported = true;
}
}
};
}
});
function normalizeSep(somePath) {
return somePath.split("\\").join("/");
}
function toSteps(somePath) {
return normalizeSep(somePath).split("/").filter((step) => step && step !== ".").reduce((acc, step) => {
if (step === "..") {
return acc.slice(0, -1);
}
return [...acc, step];
}, []);
}
const potentialViolationTypes$1 = /* @__PURE__ */ new Set([
"parent",
"index",
"sibling",
"external",
"internal"
]);
var noInternalModules = createRule({
name: "no-internal-modules",
meta: {
type: "suggestion",
docs: {
category: "Static analysis",
description: "Forbid importing the submodules of other modules."
},
schema: [
{
anyOf: [
{
type: "object",
properties: {
allow: {
type: "array",
items: {
type: "string"
}
}
},
additionalProperties: false
},
{
type: "object",
properties: {
forbid: {
type: "array",
items: {
type: "string"
}
}
},
additionalProperties: false
}
]
}
],
messages: {
noAllowed: `Reaching to "{{importPath}}" is not allowed.`
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
const allowRegexps = (options.allow || []).map((p) => minimatch.makeRe(p)).filter(Boolean);
const forbidRegexps = (options.forbid || []).map((p) => minimatch.makeRe(p)).filter(Boolean);
function reachingAllowed(importPath) {
return allowRegexps.some((re) => re.test(importPath));
}
function reachingForbidden(importPath) {
return forbidRegexps.some((re) => re.test(importPath));
}
function isAllowViolation(importPath) {
const steps = toSteps(importPath);
const nonScopeSteps = steps.filter((step) => step.indexOf("@") !== 0);
if (nonScopeSteps.length <= 1) {
return false;
}
const justSteps = steps.join("/");
if (reachingAllowed(justSteps) || reachingAllowed(`/${justSteps}`)) {
return false;
}
const resolved = resolve(importPath, context);
if (!resolved || reachingAllowed(normalizeSep(resolved))) {
return false;
}
return true;
}
function isForbidViolation(importPath) {
const steps = toSteps(importPath);
const justSteps = steps.join("/");
if (reachingForbidden(justSteps) || reachingForbidden(`/${justSteps}`)) {
return true;
}
const resolved = resolve(importPath, context);
if (resolved && reachingForbidden(normalizeSep(resolved))) {
return true;
}
return false;
}
const isReachViolation = options.forbid ? isForbidViolation : isAllowViolation;
return moduleVisitor(
(source) => {
const importPath = source.value;
if (potentialViolationTypes$1.has(importType(importPath, context)) && isReachViolation(importPath)) {
context.report({
node: source,
messageId: "noAllowed",
data: {
importPath
}
});
}
},
{ commonjs: true }
);
}
});
var noMutableExports = createRule({
name: "no-mutable-exports",
meta: {
type: "suggestion",
docs: {
category: "Helpful warnings",
description: "Forbid the use of mutable exports with `var` or `let`."
},
schema: [],
messages: {
noMutable: "Exporting mutable '{{kind}}' binding, use 'const' instead."
}
},
defaultOptions: [],
create(context) {
function checkDeclaration(node) {
if ("kind" in node && (node.kind === "var" || node.kind === "let")) {
context.report({
node,
messageId: "noMutable",
data: {
kind: node.kind
}
});
}
}
function checkDeclarationsInScope({ variables }, name) {
for (const variable of variables) {
if (variable.name === name) {
for (const def of variable.defs) {
if (def.type === "Variable" && def.parent) {
checkDeclaration(def.parent);
}
}
}
}
}
return {
ExportDefaultDeclaration(node) {
const scope = context.sourceCode.getScope(node);
if ("name" in node.declaration) {
checkDeclarationsInScope(scope, node.declaration.name);
}
},
ExportNamedDeclaration(node) {
const scope = context.sourceCode.getScope(node);
if (node.declaration) {
checkDeclaration(node.declaration);
} else if (!node.source) {
for (const specifier of node.specifiers) {
checkDeclarationsInScope(scope, specifier.local.name);
}
}
}
};
}
});
var noNamedAsDefaultMember = createRule({
name: "no-named-as-default-member",
meta: {
type: "suggestion",
docs: {
category: "Helpful warnings",
description: "Forbid use of exported name as property of default export."
},
schema: [],
messages: {
member: "Caution: `{{objectName}}` also has a named export `{{propName}}`. Check if you meant to write `import {{{propName}}} from '{{sourcePath}}'` instead."
}
},
defaultOptions: [],
create(context) {
const fileImports = /* @__PURE__ */ new Map();
const allPropertyLookups = /* @__PURE__ */ new Map();
function storePropertyLookup(objectName, propName, node) {
const lookups = allPropertyLookups.get(objectName) || [];
lookups.push({ node, propName });
allPropertyLookups.set(objectName, lookups);
}
return {
ImportDefaultSpecifier(node) {
const declaration = importDeclaration(context, node);
const exportMap = ExportMap.get(declaration.source.value, context);
if (exportMap == null) {
return;
}
if (exportMap.errors.length > 0) {
exportMap.reportErrors(context, declaration);
return;
}
fileImports.set(node.local.name, {
exportMap,
sourcePath: declaration.source.value
});
},
MemberExpression(node) {
if ("name" in node.object && "name" in node.property) {
storePropertyLookup(node.object.name, node.property.name, node);
}
},
VariableDeclarator(node) {
var _a;
const isDestructure = node.id.type === "ObjectPattern" && ((_a = node.init) == null ? void 0 : _a.type) === "Identifier";
if (!isDestructure || !node.init || !("name" in node.init) || !("properties" in node.id)) {
return;
}
const objectName = node.init.name;
for (const prop of node.id.properties) {
if (!("key" in prop) || !("name" in prop.key)) {
continue;
}
storePropertyLookup(objectName, prop.key.name, prop.key);
}
},
"Program:exit"() {
for (const [objectName, lookups] of allPropertyLookups.entries()) {
const fileImport = fileImports.get(objectName);
if (fileImport == null) {
continue;
}
for (const { propName, node } of lookups) {
if (propName === "default") {
continue;
}
if (!fileImport.exportMap.namespace.has(propName)) {
continue;
}
context.report({
node,
messageId: "member",
data: {
objectName,
propName,
sourcePath: fileImport.sourcePath
}
});
}
}
}
};
}
});
var noNamedAsDefault = createRule({
name: "no-named-as-default",
meta: {
type: "problem",
docs: {
category: "Helpful warnings",
description: "Forbid use of exported name as identifier of default export."
},
schema: [],
messages: {
default: "Using exported name '{{name}}' as identifier for default export."
}
},
defaultOptions: [],
create(context) {
function createCheckDefault(nameKey) {
return function checkDefault(defaultSpecifier) {
const nameValue = defaultSpecifier[nameKey].name;
if (nameValue === "default") {
return;
}
const declaration = importDeclaration(context, defaultSpecifier);
const exportMapOfImported = ExportMap.get(
declaration.source.value,
context
);
if (exportMapOfImported == null) {
return;
}
if (exportMapOfImported.errors.length > 0) {
exportMapOfImported.reportErrors(context, declaration);
return;
}
if (!exportMapOfImported.hasDefault) {
return;
}
if (!exportMapOfImported.has(nameValue)) {
return;
}
if (exportMapOfImported.exports.has("default") && exportMapOfImported.exports.has(nameValue)) {
context.report({
node: defaultSpecifier,
messageId: "default",
data: {
name: nameValue
}
});
}
};
}
return {
ImportDefaultSpecifier: createCheckDefault("local"),
ExportDefaultSpecifier: createCheckDefault("exported")
};
}
});
var noNamedDefault = createRule({
name: "no-named-default",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Forbid named default exports."
},
schema: [],
messages: {
default: `Use default import syntax to import '{{importName}}'.`
}
},
defaultOptions: [],
create(context) {
return {
ImportDeclaration(node) {
for (const im of node.specifiers) {
if ("importKind" in im && (im.importKind === "type" || // @ts-expect-error - flow type
im.importKind === "typeof")) {
continue;
}
if (im.type === "ImportSpecifier" && getValue(im.imported) === "default") {
context.report({
node: im.local,
messageId: "default",
data: {
importName: im.local.name
}
});
}
}
}
};
}
});
var noNamedExport = createRule({
name: "no-named-export",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Forbid named exports."
},
schema: [],
messages: {
noAllowed: "Named exports are not allowed."
}
},
defaultOptions: [],
create(context) {
if (sourceType(context) !== "module") {
return {};
}
return {
ExportAllDeclaration(node) {
context.report({ node, messageId: "noAllowed" });
},
ExportNamedDeclaration(node) {
if (node.specifiers.length === 0) {
return context.report({ node, messageId: "noAllowed" });
}
const someNamed = node.specifiers.some(
(specifier) => getValue(specifier.exported) !== "default"
);
if (someNamed) {
context.report({ node, messageId: "noAllowed" });
}
}
};
}
});
var noNamespace = createRule({
name: "no-namespace",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: 'Forbid namespace (a.k.a. "wildcard" `*`) imports.'
},
fixable: "code",
schema: [
{
type: "object",
properties: {
ignore: {
type: "array",
items: {
type: "string"
},
uniqueItems: true
}
}
}
],
messages: {
noNamespace: "Unexpected namespace import."
}
},
defaultOptions: [],
create(context) {
const firstOption = context.options[0] || {};
const ignoreGlobs = firstOption.ignore;
return {
ImportNamespaceSpecifier(node) {
if (ignoreGlobs == null ? void 0 : ignoreGlobs.find(
(glob) => minimatch.minimatch(node.parent.source.value, glob, { matchBase: true })
)) {
return;
}
const scopeVariables = context.sourceCode.getScope(node).variables;
const namespaceVariable = scopeVariables.find(
(variable) => variable.defs[0].node === node
);
const namespaceReferences = namespaceVariable.references;
const namespaceIdentifiers = namespaceReferences.map(
(reference) => reference.identifier
);
const canFix = namespaceIdentifiers.length > 0 && !usesNamespaceAsObject(namespaceIdentifiers);
context.report({
node,
messageId: `noNamespace`,
fix: canFix ? (fixer) => {
const scopeManager = context.sourceCode.scopeManager;
const fixes = [];
const importNameConflicts = {};
for (const identifier of namespaceIdentifiers) {
const parent = identifier.parent;
if (parent && parent.type === "MemberExpression") {
const importName = getMemberPropertyName(parent);
const localConflicts = getVariableNamesInScope(
scopeManager,
parent
);
if (importNameConflicts[importName]) {
for (const c of localConflicts)
importNameConflicts[importName].add(c);
} else {
importNameConflicts[importName] = localConflicts;
}
}
}
const importNames = Object.keys(importNameConflicts);
const importLocalNames = generateLocalNames(
importNames,
importNameConflicts,
namespaceVariable.name
);
const namedImportSpecifiers = importNames.map(
(importName) => importName === importLocalNames[importName] ? importName : `${importName} as ${importLocalNames[importName]}`
);
fixes.push(
fixer.replaceText(
node,
`{ ${namedImportSpecifiers.join(", ")} }`
)
);
for (const identifier of namespaceIdentifiers) {
const parent = identifier.parent;
if (parent && parent.type === "MemberExpression") {
const importName = getMemberPropertyName(parent);
fixes.push(
fixer.replaceText(parent, importLocalNames[importName])
);
}
}
return fixes;
} : null
});
}
};
}
});
function usesNamespaceAsObject(namespaceIdentifiers) {
return !namespaceIdentifiers.every((identifier) => {
const parent = identifier.parent;
return parent && parent.type === "MemberExpression" && (parent.property.type === "Identifier" || parent.property.type === "Literal");
});
}
function getMemberPropertyName(memberExpression) {
return memberExpression.property.type === "Identifier" ? memberExpression.property.name : memberExpression.property.value;
}
function getVariableNamesInScope(scopeManager, node) {
let currentNode = node;
let scope = scopeManager.acquire(currentNode);
while (scope == null) {
currentNode = currentNode.parent;
scope = scopeManager.acquire(currentNode, true);
}
return new Set(
[...scope.variables, ...scope.upper.variables].map(
(variable) => variable.name
)
);
}
function generateLocalNames(names, nameConflicts, namespaceName) {
const localNames = {};
for (const name of names) {
let localName;
if (!nameConflicts[name].has(name)) {
localName = name;
} else if (nameConflicts[name].has(`${namespaceName}_${name}`)) {
for (let i = 1; i < Number.POSITIVE_INFINITY; i++) {
if (!nameConflicts[name].has(`${namespaceName}_${name}_${i}`)) {
localName = `${namespaceName}_${name}_${i}`;
break;
}
}
} else {
localName = `${namespaceName}_${name}`;
}
localNames[name] = localName;
}
return localNames;
}
var noNodejsModules = createRule({
name: "no-nodejs-modules",
meta: {
type: "suggestion",
docs: {
category: "Module systems",
description: "Forbid Node.js builtin modules."
},
schema: [
{
type: "object",
properties: {
allow: {
type: "array",
uniqueItems: true,
items: {
type: "string"
}
}
},
additionalProperties: false
}
],
messages: {
builtin: 'Do not import Node.js builtin module "{{moduleName}}"'
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
const allowed = options.allow || [];
return moduleVisitor(
(source, node) => {
const moduleName = source.value;
if (!allowed.includes(moduleName) && importType(moduleName, context) === "builtin") {
context.report({
node,
messageId: "builtin",
data: {
moduleName
}
});
}
},
{ commonjs: true }
);
}
});
function toPosixPath(filePath) {
return filePath.replaceAll("\\", "/");
}
function findNamedPackage(filePath) {
const found = readPkgUp({ cwd: filePath });
if (found.pkg && !found.pkg.name) {
return findNamedPackage(path.resolve(found.path, "../.."));
}
return found;
}
const potentialViolationTypes = /* @__PURE__ */ new Set(["parent", "index", "sibling"]);
function checkImportForRelativePackage(context, importPath, node) {
if (!potentialViolationTypes.has(importType(importPath, context))) {
return;
}
const resolvedImport = resolve(importPath, context);
const resolvedContext = context.physicalFilename;
if (!resolvedImport || !resolvedContext) {
return;
}
const importPkg = findNamedPackage(resolvedImport);
const contextPkg = findNamedPackage(resolvedContext);
if (importPkg.pkg && contextPkg.pkg && importPkg.pkg.name !== contextPkg.pkg.name) {
const importBaseName = path.basename(importPath);
const importRoot = path.dirname(importPkg.path);
const properPath = path.relative(importRoot, resolvedImport);
const properImport = path.join(
importPkg.pkg.name,
path.dirname(properPath),
importBaseName === path.basename(importRoot) ? "" : importBaseName
);
context.report({
node,
messageId: "noAllowed",
data: {
properImport,
importPath
},
fix: (fixer) => fixer.replaceText(node, JSON.stringify(toPosixPath(properImport)))
});
}
}
var noRelativePackages = createRule({
name: "no-relative-packages",
meta: {
type: "suggestion",
docs: {
category: "Static analysis",
description: "Forbid importing packages through relative paths."
},
fixable: "code",
schema: [makeOptionsSchema()],
messages: {
noAllowed: "Relative import from another package is not allowed. Use `{{properImport}}` instead of `{{importPath}}`"
}
},
defaultOptions: [],
create(context) {
return moduleVisitor(
(source) => checkImportForRelativePackage(context, source.value, source),
context.options[0]
);
}
});
var noRelativeParentImports = createRule({
name: "no-relative-parent-imports",
meta: {
type: "suggestion",
docs: {
category: "Static analysis",
description: "Forbid importing modules from parent directories."
},
schema: [makeOptionsSchema()],
messages: {
noAllowed: "Relative imports from parent directories are not allowed. Please either pass what you're importing through at runtime (dependency injection), move `{{filename}}` to same directory as `{{depPath}}` or consider making `{{depPath}}` a package."
}
},
defaultOptions: [],
create(context) {
const filename = context.physicalFilename;
if (filename === "<text>") {
return {};
}
return moduleVisitor((sourceNode) => {
const depPath = sourceNode.value;
if (importType(depPath, context) === "external") {
return;
}
const absDepPath = resolve(depPath, context);
if (!absDepPath) {
return;
}
const relDepPath = path.relative(path.dirname(filename), absDepPath);
if (importType(relDepPath, context) === "parent") {
context.report({
node: sourceNode,
messageId: "noAllowed",
data: {
filename: path.basename(filename),
depPath
}
});
}
}, context.options[0]);
}
});
var noRenameDefault = createRule({
name: "no-rename-default",
meta: {
type: "suggestion",
docs: {
category: "Helpful warnings",
description: "Forbid importing a default export by a different name."
},
schema: [
{
type: "object",
properties: {
commonjs: {
default: false,
type: "boolean"
},
preventRenamingBindings: {
default: true,
type: "boolean"
}
},
additionalProperties: false
}
],
messages: {
renameDefault: "Caution: `{{importBasename}}` has a default export `{{defaultExportName}}`. This {{requiresOrImports}} `{{defaultExportName}}` as `{{importName}}`. Check if you meant to write `{{suggestion}}` instead."
}
},
defaultOptions: [],
create(context) {
const { commonjs = false, preventRenamingBindings = true } = context.options[0] || {};
function getDefaultExportName(targetNode) {
var _a;
if (targetNode == null) {
return;
}
switch (targetNode.type) {
case "AssignmentExpression": {
if (!preventRenamingBindings) {
return;
}
if (targetNode.left.type !== "Identifier") {
return;
}
return targetNode.left.name;
}
case "CallExpression": {
const [argumentNode] = targetNode.arguments;
return getDefaultExportName(argumentNode);
}
case "ClassDeclaration": {
if (targetNode.id && typeof targetNode.id.name === "string") {
return targetNode.id.name;
}
return;
}
case "ExportSpecifier": {
return getValue(targetNode.local);
}
case "FunctionDeclaration": {
return (_a = targetNode.id) == null ? void 0 : _a.name;
}
case "Identifier": {
if (!preventRenamingBindings) {
return;
}
return targetNode.name;
}
}
}
function getExportMap(source) {
if (!source) {
return;
}
const exportMap = ExportMap.get(source.value, context);
if (exportMap == null) {
return;
}
if (exportMap.errors.length > 0) {
exportMap.reportErrors(context, { source });
return;
}
return exportMap;
}
function handleImport(node) {
var _a;
const exportMap = getExportMap(node.parent.source);
if (exportMap == null) {
return;
}
const defaultExportNode = getDefaultExportNode(exportMap);
if (defaultExportNode == null) {
return;
}
const defaultExportName = getDefaultExportName(defaultExportNode);
if (defaultExportName === void 0) {
return;
}
const importTarget = (_a = node.parent.source) == null ? void 0 : _a.value;
const importBasename = path.basename(exportMap.path);
if (node.type === "ImportDefaultSpecifier") {
const importName = node.local.name;
if (importName === defaultExportName) {
return;
}
context.report({
node,
messageId: "renameDefault",
data: {
importBasename,
defaultExportName,
importName,
requiresOrImports: "imports",
suggestion: `import ${defaultExportName} from '${importTarget}'`
}
});
return;
}
if (node.type !== "ImportSpecifier") {
return;
}
if (getValue(node.imported) !== "default") {
return;
}
const actualImportedName = node.local.name;
if (actualImportedName === defaultExportName) {
return;
}
context.report({
node,
messageId: "renameDefault",
data: {
importBasename,
defaultExportName,
importName: actualImportedName,
requiresOrImports: "imports",
suggestion: `import { default as ${defaultExportName} } from '${importTarget}'`
}
});
}
function handleRequire(node) {
var _a;
if (!commonjs || node.type !== "VariableDeclarator" || !node.id || !(node.id.type === "Identifier" || node.id.type === "ObjectPattern") || !node.init || node.init.type !== "CallExpression") {
return;
}
let defaultDestructure;
if (node.id.type === "ObjectPattern") {
defaultDestructure = findDefaultDestructure(node.id.properties);
if (defaultDestructure === void 0) {
return;
}
}
const call = node.init;
const [source] = call.arguments;
if (call.callee.type !== "Identifier" || call.callee.name !== "require" || call.arguments.length !== 1 || source.type !== "Literal" || typeof source.value !== "string") {
return;
}
const exportMap = getExportMap(source);
if (exportMap == null) {
return;
}
const defaultExportNode = getDefaultExportNode(exportMap);
if (defaultExportNode == null) {
return;
}
const defaultExportName = getDefaultExportName(defaultExportNode);
const requireTarget = source.value;
const requireBasename = path.basename(exportMap.path);
let requireName;
if (node.id.type === "Identifier") {
requireName = node.id.name;
} else if (((_a = defaultDestructure == null ? void 0 : defaultDestructure.value) == null ? void 0 : _a.type) === "Identifier") {
requireName = defaultDestructure.value.name;
} else {
requireName = "";
}
if (defaultExportName === void 0) {
return;
}
if (requireName === defaultExportName) {
return;
}
if (node.id.type === "Identifier") {
context.report({
node,
messageId: "renameDefault",
data: {
importBasename: requireBasename,
defaultExportName,
importName: requireName,
requiresOrImports: "requires",
suggestion: `const ${defaultExportName} = require('${requireTarget}')`
}
});
return;
}
context.report({
node,
messageId: "renameDefault",
data: {
importBasename: requireBasename,
defaultExportName,
importName: requireName,
requiresOrImports: "requires",
suggestion: `const { default: ${defaultExportName} } = require('${requireTarget}')`
}
});
}
return {
ImportDefaultSpecifier: handleImport,
ImportSpecifier: handleImport,
VariableDeclarator: handleRequire
};
}
});
function findDefaultDestructure(properties) {
const found = properties.find((property) => {
if ("key" in property && "name" in property.key && property.key.name === "default") {
return property;
}
});
return found;
}
function getDefaultExportNode(exportMap) {
const defaultExportNode = exportMap.exports.get("default");
if (defaultExportNode == null) {
return;
}
switch (defaultExportNode.type) {
case "ExportDefaultDeclaration": {
return defaultExportNode.declaration;
}
case "ExportNamedDeclaration": {
return defaultExportNode.specifiers.find(
(specifier) => getValue(specifier.exported) === "default"
);
}
default: {
return;
}
}
}
const containsPath = (filepath, target) => {
const relative = path.relative(target, filepath);
return relative === "" || !relative.startsWith("..");
};
function isMatchingTargetPath(filename, targetPath) {
if (isGlob(targetPath)) {
const mm = new minimatch.Minimatch(targetPath, { windowsPathsNoEscape: true });
return mm.match(filename);
}
return containsPath(filename, targetPath);
}
function areBothGlobPatternAndAbsolutePath(areGlobPatterns) {
return areGlobPatterns.some(Boolean) && areGlobPatterns.some((isGlob2) => !isGlob2);
}
var noRestrictedPaths = createRule({
name: "no-restricted-paths",
meta: {
type: "problem",
docs: {
category: "Static analysis",
description: "Enforce which files can be imported in a given folder."
},
schema: [
{
type: "object",
properties: {
zones: {
type: "array",
minItems: 1,
items: {
type: "object",
properties: {
target: {
anyOf: [
{ type: "string" },
{
type: "array",
items: { type: "string" },
uniqueItems: true,
minItems: 1
}
]
},
from: {
anyOf: [
{ type: "string" },
{
type: "array",
items: { type: "string" },
uniqueItems: true,
minItems: 1
}
]
},
except: {
type: "array",
items: {
type: "string"
},
uniqueItems: true
},
message: { type: "string" }
},
additionalProperties: false
}
},
basePath: { type: "string" }
},
additionalProperties: false
}
],
messages: {
path: "Restricted path exceptions must be descendants of the configured `from` path for that zone.",
mixedGlob: "Restricted path `from` must contain either only glob patterns or none",
glob: "Restricted path exceptions must be glob patterns when `from` contains glob patterns",
zone: 'Unexpected path "{{importPath}}" imported in restricted zone.{{extra}}'
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
const restrictedPaths = options.zones || [];
const basePath = options.basePath || process.cwd();
const filename = context.physicalFilename;
const matchingZones = restrictedPaths.filter(
(zone) => [zone.target].flat().map((target) => path.resolve(basePath, target)).some((targetPath) => isMatchingTargetPath(filename, targetPath))
);
function isValidExceptionPath(absoluteFromPath, absoluteExceptionPath) {
const relativeExceptionPath = path.relative(
absoluteFromPath,
absoluteExceptionPath
);
return importType(relativeExceptionPath, context) !== "parent";
}
function reportInvalidExceptionPath(node) {
context.report({
node,
messageId: "path"
});
}
function reportInvalidExceptionMixedGlobAndNonGlob(node) {
context.report({
node,
messageId: "mixedGlob"
});
}
function reportInvalidExceptionGlob(node) {
context.report({
node,
messageId: "glob"
});
}
function computeMixedGlobAndAbsolutePathValidator() {
return {
isPathRestricted: () => true,
hasValidExceptions: false,
reportInvalidException: reportInvalidExceptionMixedGlobAndNonGlob
};
}
function computeGlobPatternPathValidator(absoluteFrom, zoneExcept) {
let isPathException;
const mm = new minimatch.Minimatch(absoluteFrom, { windowsPathsNoEscape: true });
const isPathRestricted = (absoluteImportPath) => mm.match(absoluteImportPath);
const hasValidExceptions = zoneExcept.every((it) => isGlob(it));
if (hasValidExceptions) {
const exceptionsMm = zoneExcept.map(
(except) => new minimatch.Minimatch(except, { windowsPathsNoEscape: true })
);
isPathException = (absoluteImportPath) => exceptionsMm.some((mm2) => mm2.match(absoluteImportPath));
}
const reportInvalidException = reportInvalidExceptionGlob;
return {
isPathRestricted,
hasValidExceptions,
isPathException,
reportInvalidException
};
}
function computeAbsolutePathValidator(absoluteFrom, zoneExcept) {
let isPathException;
const isPathRestricted = (absoluteImportPath) => containsPath(absoluteImportPath, absoluteFrom);
const absoluteExceptionPaths = zoneExcept.map(
(exceptionPath) => path.resolve(absoluteFrom, exceptionPath)
);
const hasValidExceptions = absoluteExceptionPaths.every(
(absoluteExceptionPath) => isValidExceptionPath(absoluteFrom, absoluteExceptionPath)
);
if (hasValidExceptions) {
isPathException = (absoluteImportPath) => absoluteExceptionPaths.some(
(absoluteExceptionPath) => containsPath(absoluteImportPath, absoluteExceptionPath)
);
}
const reportInvalidException = reportInvalidExceptionPath;
return {
isPathRestricted,
hasValidExceptions,
isPathException,
reportInvalidException
};
}
function reportInvalidExceptions(validators2, node) {
for (const validator of validators2) validator.reportInvalidException(node);
}
function reportImportsInRestrictedZone(validators2, node, importPath, customMessage) {
for (const _ of validators2) {
context.report({
node,
messageId: "zone",
data: {
importPath,
extra: customMessage ? ` ${customMessage}` : ""
}
});
}
}
const makePathValidators = (zoneFrom, zoneExcept = []) => {
const allZoneFrom = [zoneFrom].flat();
const areGlobPatterns = allZoneFrom.map((it) => isGlob(it));
if (areBothGlobPatternAndAbsolutePath(areGlobPatterns)) {
return [computeMixedGlobAndAbsolutePathValidator()];
}
const isGlobPattern = areGlobPatterns.every(Boolean);
return allZoneFrom.map((singleZoneFrom) => {
const absoluteFrom = path.resolve(basePath, singleZoneFrom);
if (isGlobPattern) {
return computeGlobPatternPathValidator(absoluteFrom, zoneExcept);
}
return computeAbsolutePathValidator(absoluteFrom, zoneExcept);
});
};
const validators = [];
return moduleVisitor(
(source) => {
const importPath = source.value;
const absoluteImportPath = resolve(importPath, context);
if (!absoluteImportPath) {
return;
}
for (const [index, zone] of matchingZones.entries()) {
if (!validators[index]) {
validators[index] = makePathValidators(zone.from, zone.except);
}
const applicableValidatorsForImportPath = validators[index].filter(
(validator) => validator.isPathRestricted(absoluteImportPath)
);
const validatorsWithInvalidExceptions = applicableValidatorsForImportPath.filter(
(validator) => !validator.hasValidExceptions
);
reportInvalidExceptions(validatorsWithInvalidExceptions, source);
const applicableValidatorsForImportPathExcludingExceptions = applicableValidatorsForImportPath.filter(
(validator) => validator.hasValidExceptions && !validator.isPathException(absoluteImportPath)
);
reportImportsInRestrictedZone(
applicableValidatorsForImportPathExcludingExceptions,
source,
importPath,
zone.message
);
}
},
{ commonjs: true }
);
}
});
function isImportingSelf(context, node, requireName) {
const filename = context.physicalFilename;
if (filename !== "<text>" && filename === resolve(requireName, context)) {
context.report({
node,
messageId: "self"
});
}
}
var noSelfImport = createRule({
name: "no-self-import",
meta: {
type: "problem",
docs: {
category: "Static analysis",
description: "Forbid a module from importing itself.",
recommended: true
},
schema: [],
messages: {
self: "Module imports itself."
}
},
defaultOptions: [],
create(context) {
return moduleVisitor(
(source, node) => {
isImportingSelf(context, node, source.value);
},
{ commonjs: true }
);
}
});
function testIsAllow(globs, filename, source) {
if (!Array.isArray(globs)) {
return false;
}
const filePath = (
// a node module
source[0] !== "." && source[0] !== "/" ? source : path.resolve(filename, "..", source)
);
return globs.some(
(glob) => minimatch.minimatch(filePath, glob) || minimatch.minimatch(filePath, path.resolve(glob), { windowsPathsNoEscape: true })
);
}
var noUnassignedImport = createRule({
name: "no-unassigned-import",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Forbid unassigned imports."
},
schema: [
{
type: "object",
properties: {
devDependencies: { type: ["boolean", "array"] },
optionalDependencies: { type: ["boolean", "array"] },
peerDependencies: { type: ["boolean", "array"] },
allow: {
type: "array",
items: {
type: "string"
}
}
},
additionalProperties: false
}
],
messages: {
unassigned: "Imported module should be assigned"
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
const filename = context.physicalFilename;
const isAllow = (source) => testIsAllow(options.allow, filename, source);
return {
ImportDeclaration(node) {
if (node.specifiers.length === 0 && !isAllow(node.source.value)) {
context.report({
node,
messageId: "unassigned"
});
}
},
ExpressionStatement(node) {
if (node.expression.type === "CallExpression" && isStaticRequire(node.expression) && "value" in node.expression.arguments[0] && typeof node.expression.arguments[0].value === "string" && !isAllow(node.expression.arguments[0].value)) {
context.report({
node: node.expression,
messageId: "unassigned"
});
}
}
};
}
});
var noUnresolved = createRule({
name: "no-unresolved",
meta: {
type: "problem",
docs: {
category: "Static analysis",
description: "Ensure imports point to a file/module that can be resolved."
},
schema: [
makeOptionsSchema({
caseSensitive: { type: "boolean", default: true },
caseSensitiveStrict: { type: "boolean" }
})
],
messages: {
unresolved: "Unable to resolve path to module '{{module}}'.",
casingMismatch: "Casing of {{module}} does not match the underlying filesystem."
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
return moduleVisitor(function checkSourceValue(source, node) {
if ("importKind" in node && node.importKind === "type" || "exportKind" in node && node.exportKind === "type") {
return;
}
const caseSensitive = !CASE_SENSITIVE_FS && options.caseSensitive !== false;
const caseSensitiveStrict = !CASE_SENSITIVE_FS && options.caseSensitiveStrict;
const resolvedPath = resolve(source.value, context);
if (resolvedPath === void 0) {
context.report({
node: source,
messageId: "unresolved",
data: {
module: source.value
}
});
} else if (caseSensitive || caseSensitiveStrict) {
const cacheSettings = ModuleCache.getSettings(context.settings);
if (!fileExistsWithCaseSync(
resolvedPath,
cacheSettings,
caseSensitiveStrict
)) {
context.report({
node: source,
messageId: "casingMismatch",
data: {
module: source.value
}
});
}
}
}, options);
}
});
const { FileEnumerator } = eslintUnsupportedApi;
function listFilesToProcess(src, extensions) {
const enumerator = new FileEnumerator({
extensions
});
return Array.from(enumerator.iterateFiles(src), ({ filePath, ignored }) => ({
ignored,
filename: filePath
}));
}
const DEFAULT = "default";
const { AST_NODE_TYPES } = utils.TSESTree;
function forEachDeclarationIdentifier(declaration, cb) {
if (declaration) {
const isTypeDeclaration = declaration.type === AST_NODE_TYPES.TSInterfaceDeclaration || declaration.type === AST_NODE_TYPES.TSTypeAliasDeclaration || declaration.type === AST_NODE_TYPES.TSEnumDeclaration;
if (declaration.type === AST_NODE_TYPES.FunctionDeclaration || declaration.type === AST_NODE_TYPES.ClassDeclaration || isTypeDeclaration) {
cb(declaration.id.name, isTypeDeclaration);
} else if (declaration.type === AST_NODE_TYPES.VariableDeclaration) {
for (const { id } of declaration.declarations) {
if (id.type === AST_NODE_TYPES.ObjectPattern) {
recursivePatternCapture(id, (pattern) => {
if (pattern.type === AST_NODE_TYPES.Identifier) {
cb(pattern.name, false);
}
});
} else if (id.type === AST_NODE_TYPES.ArrayPattern) {
for (const el of id.elements) {
if ((el == null ? void 0 : el.type) === AST_NODE_TYPES.Identifier) {
cb(el.name, false);
}
}
} else {
cb(id.name, false);
}
}
}
}
}
const importList = /* @__PURE__ */ new Map();
const exportList = /* @__PURE__ */ new Map();
const visitorKeyMap = /* @__PURE__ */ new Map();
const ignoredFiles = /* @__PURE__ */ new Set();
const filesOutsideSrc = /* @__PURE__ */ new Set();
const isNodeModule = (path2) => /([/\\])(node_modules)\1/.test(path2);
const resolveFiles = (src, ignoreExports, context) => {
const extensions = [...getFileExtensions(context.settings)];
const srcFileList = listFilesToProcess(src, extensions);
const ignoredFilesList = listFilesToProcess(ignoreExports, extensions);
for (const { filename } of ignoredFilesList) ignoredFiles.add(filename);
return new Set(
srcFileList.flatMap(
({ filename }) => isNodeModule(filename) ? [] : filename
)
);
};
const prepareImportsAndExports = (srcFiles2, context) => {
const exportAll = /* @__PURE__ */ new Map();
for (const file of srcFiles2) {
const exports = /* @__PURE__ */ new Map();
const imports = /* @__PURE__ */ new Map();
const currentExports = ExportMap.get(file, context);
if (currentExports) {
const {
dependencies,
reexports,
imports: localImportList,
namespace,
visitorKeys
} = currentExports;
visitorKeyMap.set(file, visitorKeys);
const currentExportAll = /* @__PURE__ */ new Set();
for (const getDependency of dependencies) {
const dependency = getDependency();
if (dependency === null) {
continue;
}
currentExportAll.add(dependency.path);
}
exportAll.set(file, currentExportAll);
for (const [key, value] of reexports.entries()) {
if (key === DEFAULT) {
exports.set(AST_NODE_TYPES.ImportDefaultSpecifier, {
whereUsed: /* @__PURE__ */ new Set()
});
} else {
exports.set(key, { whereUsed: /* @__PURE__ */ new Set() });
}
const reexport = value.getImport();
if (!reexport) {
continue;
}
let localImport = imports.get(reexport.path);
const currentValue = value.local === DEFAULT ? AST_NODE_TYPES.ImportDefaultSpecifier : value.local;
localImport = localImport === void 0 ? /* @__PURE__ */ new Set([currentValue]) : /* @__PURE__ */ new Set([...localImport, currentValue]);
imports.set(reexport.path, localImport);
}
for (const [key, value] of localImportList.entries()) {
if (isNodeModule(key)) {
continue;
}
const localImport = imports.get(key) || /* @__PURE__ */ new Set();
for (const { importedSpecifiers } of value.declarations) {
for (const specifier of importedSpecifiers) {
localImport.add(specifier);
}
}
imports.set(key, localImport);
}
importList.set(file, imports);
if (ignoredFiles.has(file)) {
continue;
}
for (const [key, _value] of namespace.entries()) {
if (key === DEFAULT) {
exports.set(AST_NODE_TYPES.ImportDefaultSpecifier, {
whereUsed: /* @__PURE__ */ new Set()
});
} else {
exports.set(key, { whereUsed: /* @__PURE__ */ new Set() });
}
}
}
exports.set(AST_NODE_TYPES.ExportAllDeclaration, {
whereUsed: /* @__PURE__ */ new Set()
});
exports.set(AST_NODE_TYPES.ImportNamespaceSpecifier, {
whereUsed: /* @__PURE__ */ new Set()
});
exportList.set(file, exports);
}
for (const [key, value] of exportAll.entries()) {
for (const val of value) {
const currentExports = exportList.get(val);
if (currentExports) {
const currentExport = currentExports.get(
AST_NODE_TYPES.ExportAllDeclaration
);
currentExport.whereUsed.add(key);
}
}
}
};
const determineUsage = () => {
for (const [listKey, listValue] of importList.entries()) {
for (const [key, value] of listValue.entries()) {
const exports = exportList.get(key);
if (exports !== void 0) {
for (const currentImport of value) {
let specifier;
if (currentImport === AST_NODE_TYPES.ImportNamespaceSpecifier) {
specifier = AST_NODE_TYPES.ImportNamespaceSpecifier;
} else if (currentImport === AST_NODE_TYPES.ImportDefaultSpecifier) {
specifier = AST_NODE_TYPES.ImportDefaultSpecifier;
} else {
specifier = currentImport;
}
if (specifier !== void 0) {
const exportStatement = exports.get(specifier);
if (exportStatement !== void 0) {
const { whereUsed } = exportStatement;
whereUsed.add(listKey);
exports.set(specifier, { whereUsed });
}
}
}
}
}
}
};
let srcFiles;
let lastPrepareKey;
const doPreparation = (src, ignoreExports, context) => {
const prepareKey = JSON.stringify({
src: src.sort(),
ignoreExports: (ignoreExports || []).sort(),
extensions: [...getFileExtensions(context.settings)].sort()
});
if (prepareKey === lastPrepareKey) {
return;
}
importList.clear();
exportList.clear();
ignoredFiles.clear();
filesOutsideSrc.clear();
srcFiles = resolveFiles(src, ignoreExports, context);
prepareImportsAndExports(srcFiles, context);
determineUsage();
lastPrepareKey = prepareKey;
};
const newNamespaceImportExists = (specifiers) => specifiers.some(
({ type }) => type === AST_NODE_TYPES.ImportNamespaceSpecifier
);
const newDefaultImportExists = (specifiers) => specifiers.some(({ type }) => type === AST_NODE_TYPES.ImportDefaultSpecifier);
const fileIsInPkg = (file) => {
const { pkg, path: pkgPath } = readPkgUp({ cwd: file });
const basePath = path.dirname(pkgPath);
const checkPkgFieldString = (pkgField) => {
if (path.join(basePath, pkgField) === file) {
return true;
}
};
const checkPkgFieldObject = (pkgField) => {
const pkgFieldFiles = Object.values(pkgField).flatMap(
(value) => typeof value === "boolean" ? [] : path.join(basePath, value)
);
if (pkgFieldFiles.includes(file)) {
return true;
}
};
const checkPkgField = (pkgField) => {
if (typeof pkgField === "string") {
return checkPkgFieldString(pkgField);
}
if (typeof pkgField === "object") {
return checkPkgFieldObject(pkgField);
}
};
if (!pkg) {
return false;
}
if (pkg.private === true) {
return false;
}
if (pkg.bin && checkPkgField(pkg.bin)) {
return true;
}
if (pkg.browser && checkPkgField(pkg.browser)) {
return true;
}
if (pkg.main && checkPkgFieldString(pkg.main)) {
return true;
}
return false;
};
var noUnusedModules = createRule({
name: "no-unused-modules",
meta: {
type: "suggestion",
docs: {
category: "Helpful warnings",
description: "Forbid modules without exports, or exports without matching import in another module."
},
schema: [
{
type: "object",
properties: {
src: {
description: "files/paths to be analyzed (only for unused exports)",
type: "array",
uniqueItems: true,
items: {
type: "string",
minLength: 1
}
},
ignoreExports: {
description: "files/paths for which unused exports will not be reported (e.g module entry points)",
type: "array",
uniqueItems: true,
items: {
type: "string",
minLength: 1
}
},
missingExports: {
description: "report modules without any exports",
type: "boolean"
},
unusedExports: {
description: "report exports without any usage",
type: "boolean"
},
ignoreUnusedTypeExports: {
description: "ignore type exports without any usage",
type: "boolean"
}
},
anyOf: [
{
type: "object",
properties: {
unusedExports: {
type: "boolean",
enum: [true]
},
src: {
type: "array",
minItems: 1
}
},
required: ["unusedExports"]
},
{
type: "object",
properties: {
missingExports: {
type: "boolean",
enum: [true]
}
},
required: ["missingExports"]
}
]
}
],
messages: {
notFound: "No exports found",
unused: "exported declaration '{{value}}' not used within other modules"
}
},
defaultOptions: [],
create(context) {
const {
src = [process.cwd()],
ignoreExports = [],
missingExports,
unusedExports,
ignoreUnusedTypeExports
} = context.options[0] || {};
if (unusedExports) {
doPreparation(src, ignoreExports, context);
}
const filename = context.physicalFilename;
const checkExportPresence = (node) => {
var _a;
if (!missingExports) {
return;
}
if (ignoreUnusedTypeExports) {
return;
}
if (ignoredFiles.has(filename)) {
return;
}
const exportCount = exportList.get(filename);
const exportAll = exportCount.get(AST_NODE_TYPES.ExportAllDeclaration);
const namespaceImports = exportCount.get(
AST_NODE_TYPES.ImportNamespaceSpecifier
);
exportCount.delete(AST_NODE_TYPES.ExportAllDeclaration);
exportCount.delete(AST_NODE_TYPES.ImportNamespaceSpecifier);
if (exportCount.size === 0) {
context.report({
node: (_a = node.body[0]) != null ? _a : node,
messageId: "notFound"
});
}
exportCount.set(AST_NODE_TYPES.ExportAllDeclaration, exportAll);
exportCount.set(AST_NODE_TYPES.ImportNamespaceSpecifier, namespaceImports);
};
const checkUsage = (node, exportedValue, isTypeExport) => {
if (!unusedExports) {
return;
}
if (isTypeExport && ignoreUnusedTypeExports) {
return;
}
if (ignoredFiles.has(filename)) {
return;
}
if (fileIsInPkg(filename)) {
return;
}
if (filesOutsideSrc.has(filename)) {
return;
}
if (!srcFiles.has(filename)) {
srcFiles = resolveFiles(src, ignoreExports, context);
if (!srcFiles.has(filename)) {
filesOutsideSrc.add(filename);
return;
}
}
const exports = exportList.get(filename);
if (!exports) {
console.error(
`file \`${filename}\` has no exports. Please update to the latest, and if it still happens, report this on https://github.com/import-js/eslint-plugin-import/issues/2866!`
);
return;
}
const exportAll = exports.get(AST_NODE_TYPES.ExportAllDeclaration);
if (exportAll !== void 0 && exportedValue !== AST_NODE_TYPES.ImportDefaultSpecifier && exportAll.whereUsed.size > 0) {
return;
}
const namespaceImports = exports.get(
AST_NODE_TYPES.ImportNamespaceSpecifier
);
if (namespaceImports !== void 0 && namespaceImports.whereUsed.size > 0) {
return;
}
const exportsKey = exportedValue === DEFAULT ? AST_NODE_TYPES.ImportDefaultSpecifier : exportedValue;
const exportStatement = exports.get(exportsKey);
const value = exportsKey === AST_NODE_TYPES.ImportDefaultSpecifier ? DEFAULT : exportsKey;
if (exportStatement === void 0) {
context.report({
node,
messageId: "unused",
data: {
value
}
});
} else {
if (exportStatement.whereUsed.size === 0) {
context.report({
node,
messageId: "unused",
data: {
value
}
});
}
}
};
const updateExportUsage = (node) => {
var _a, _b;
if (ignoredFiles.has(filename)) {
return;
}
const exports = (_a = exportList.get(filename)) != null ? _a : /* @__PURE__ */ new Map();
const newExports = /* @__PURE__ */ new Map();
const newExportIdentifiers = /* @__PURE__ */ new Set();
for (const s of node.body) {
if (s.type === AST_NODE_TYPES.ExportDefaultDeclaration) {
newExportIdentifiers.add(AST_NODE_TYPES.ImportDefaultSpecifier);
}
if (s.type === AST_NODE_TYPES.ExportNamedDeclaration) {
if (s.specifiers.length > 0) {
for (const specifier of s.specifiers) {
if (specifier.exported) {
newExportIdentifiers.add(getValue(specifier.exported));
}
}
}
forEachDeclarationIdentifier(s.declaration, (name) => {
newExportIdentifiers.add(name);
});
}
}
for (const [key, value] of exports.entries()) {
if (newExportIdentifiers.has(key)) {
newExports.set(key, value);
}
}
for (const key of newExportIdentifiers) {
if (!exports.has(key)) {
newExports.set(key, { whereUsed: /* @__PURE__ */ new Set() });
}
}
const exportAll = exports.get(AST_NODE_TYPES.ExportAllDeclaration);
const namespaceImports = (_b = exports.get(
AST_NODE_TYPES.ImportNamespaceSpecifier
)) != null ? _b : { whereUsed: /* @__PURE__ */ new Set() };
newExports.set(AST_NODE_TYPES.ExportAllDeclaration, exportAll);
newExports.set(AST_NODE_TYPES.ImportNamespaceSpecifier, namespaceImports);
exportList.set(filename, newExports);
};
const updateImportUsage = (node) => {
var _a, _b;
if (!unusedExports) {
return;
}
const oldImportPaths = (_a = importList.get(filename)) != null ? _a : /* @__PURE__ */ new Map();
const oldNamespaceImports = /* @__PURE__ */ new Set();
const newNamespaceImports = /* @__PURE__ */ new Set();
const oldExportAll = /* @__PURE__ */ new Set();
const newExportAll = /* @__PURE__ */ new Set();
const oldDefaultImports = /* @__PURE__ */ new Set();
const newDefaultImports = /* @__PURE__ */ new Set();
const oldImports = /* @__PURE__ */ new Map();
const newImports = /* @__PURE__ */ new Map();
for (const [key, value] of oldImportPaths.entries()) {
if (value.has(AST_NODE_TYPES.ExportAllDeclaration)) {
oldExportAll.add(key);
}
if (value.has(AST_NODE_TYPES.ImportNamespaceSpecifier)) {
oldNamespaceImports.add(key);
}
if (value.has(AST_NODE_TYPES.ImportDefaultSpecifier)) {
oldDefaultImports.add(key);
}
for (const val of value) {
if (val !== AST_NODE_TYPES.ImportNamespaceSpecifier && val !== AST_NODE_TYPES.ImportDefaultSpecifier) {
oldImports.set(val, key);
}
}
}
function processDynamicImport(source) {
if (source.type !== "Literal" || typeof source.value !== "string") {
return null;
}
const p = resolve(source.value, context);
if (p == null) {
return null;
}
newNamespaceImports.add(p);
}
visit(node, visitorKeyMap.get(filename), {
ImportExpression(child) {
processDynamicImport(child.source);
},
CallExpression(child_) {
const child = child_;
if (child.callee.type === "Import") {
processDynamicImport(child.arguments[0]);
}
}
});
for (const astNode of node.body) {
let resolvedPath;
if (astNode.type === AST_NODE_TYPES.ExportNamedDeclaration && astNode.source) {
resolvedPath = resolve(
astNode.source.raw.replaceAll(/('|")/g, ""),
context
);
for (const specifier of astNode.specifiers) {
const name = getValue(specifier.local);
if (name === DEFAULT) {
newDefaultImports.add(resolvedPath);
} else {
newImports.set(name, resolvedPath);
}
}
}
if (astNode.type === AST_NODE_TYPES.ExportAllDeclaration) {
resolvedPath = resolve(
astNode.source.raw.replaceAll(/('|")/g, ""),
context
);
newExportAll.add(resolvedPath);
}
if (astNode.type === AST_NODE_TYPES.ImportDeclaration) {
resolvedPath = resolve(
astNode.source.raw.replaceAll(/('|")/g, ""),
context
);
if (!resolvedPath) {
continue;
}
if (isNodeModule(resolvedPath)) {
continue;
}
if (newNamespaceImportExists(astNode.specifiers)) {
newNamespaceImports.add(resolvedPath);
}
if (newDefaultImportExists(astNode.specifiers)) {
newDefaultImports.add(resolvedPath);
}
for (const specifier of astNode.specifiers.filter(
(specifier2) => specifier2.type !== AST_NODE_TYPES.ImportDefaultSpecifier && specifier2.type !== AST_NODE_TYPES.ImportNamespaceSpecifier
)) {
if ("imported" in specifier) {
newImports.set(getValue(specifier.imported), resolvedPath);
}
}
}
}
for (const value of newExportAll) {
if (!oldExportAll.has(value)) {
const imports = (_b = oldImportPaths.get(value)) != null ? _b : /* @__PURE__ */ new Set();
imports.add(AST_NODE_TYPES.ExportAllDeclaration);
oldImportPaths.set(value, imports);
let exports = exportList.get(value);
let currentExport;
if (exports === void 0) {
exports = /* @__PURE__ */ new Map();
exportList.set(value, exports);
} else {
currentExport = exports.get(AST_NODE_TYPES.ExportAllDeclaration);
}
if (currentExport === void 0) {
const whereUsed = /* @__PURE__ */ new Set();
whereUsed.add(filename);
exports.set(AST_NODE_TYPES.ExportAllDeclaration, {
whereUsed
});
} else {
currentExport.whereUsed.add(filename);
}
}
}
for (const value of oldExportAll) {
if (!newExportAll.has(value)) {
const imports = oldImportPaths.get(value);
imports.delete(AST_NODE_TYPES.ExportAllDeclaration);
const exports = exportList.get(value);
if (exports !== void 0) {
const currentExport = exports.get(
AST_NODE_TYPES.ExportAllDeclaration
);
if (currentExport !== void 0) {
currentExport.whereUsed.delete(filename);
}
}
}
}
for (const value of newDefaultImports) {
if (!oldDefaultImports.has(value)) {
let imports = oldImportPaths.get(value);
if (imports === void 0) {
imports = /* @__PURE__ */ new Set();
}
imports.add(AST_NODE_TYPES.ImportDefaultSpecifier);
oldImportPaths.set(value, imports);
let exports = exportList.get(value);
let currentExport;
if (exports === void 0) {
exports = /* @__PURE__ */ new Map();
exportList.set(value, exports);
} else {
currentExport = exports.get(AST_NODE_TYPES.ImportDefaultSpecifier);
}
if (currentExport === void 0) {
const whereUsed = /* @__PURE__ */ new Set();
whereUsed.add(filename);
exports.set(AST_NODE_TYPES.ImportDefaultSpecifier, {
whereUsed
});
} else {
currentExport.whereUsed.add(filename);
}
}
}
for (const value of oldDefaultImports) {
if (!newDefaultImports.has(value)) {
const imports = oldImportPaths.get(value);
imports.delete(AST_NODE_TYPES.ImportDefaultSpecifier);
const exports = exportList.get(value);
if (exports !== void 0) {
const currentExport = exports.get(
AST_NODE_TYPES.ImportDefaultSpecifier
);
if (currentExport !== void 0) {
currentExport.whereUsed.delete(filename);
}
}
}
}
for (const value of newNamespaceImports) {
if (!oldNamespaceImports.has(value)) {
let imports = oldImportPaths.get(value);
if (imports === void 0) {
imports = /* @__PURE__ */ new Set();
}
imports.add(AST_NODE_TYPES.ImportNamespaceSpecifier);
oldImportPaths.set(value, imports);
let exports = exportList.get(value);
let currentExport;
if (exports === void 0) {
exports = /* @__PURE__ */ new Map();
exportList.set(value, exports);
} else {
currentExport = exports.get(AST_NODE_TYPES.ImportNamespaceSpecifier);
}
if (currentExport === void 0) {
const whereUsed = /* @__PURE__ */ new Set();
whereUsed.add(filename);
exports.set(AST_NODE_TYPES.ImportNamespaceSpecifier, {
whereUsed
});
} else {
currentExport.whereUsed.add(filename);
}
}
}
for (const value of oldNamespaceImports) {
if (!newNamespaceImports.has(value)) {
const imports = oldImportPaths.get(value);
imports.delete(AST_NODE_TYPES.ImportNamespaceSpecifier);
const exports = exportList.get(value);
if (exports !== void 0) {
const currentExport = exports.get(
AST_NODE_TYPES.ImportNamespaceSpecifier
);
if (currentExport !== void 0) {
currentExport.whereUsed.delete(filename);
}
}
}
}
for (const [key, value] of newImports.entries()) {
if (!oldImports.has(key)) {
let imports = oldImportPaths.get(value);
if (imports === void 0) {
imports = /* @__PURE__ */ new Set();
}
imports.add(key);
oldImportPaths.set(value, imports);
let exports = exportList.get(value);
let currentExport;
if (exports === void 0) {
exports = /* @__PURE__ */ new Map();
exportList.set(value, exports);
} else {
currentExport = exports.get(key);
}
if (currentExport === void 0) {
const whereUsed = /* @__PURE__ */ new Set();
whereUsed.add(filename);
exports.set(key, { whereUsed });
} else {
currentExport.whereUsed.add(filename);
}
}
}
for (const [key, value] of oldImports.entries()) {
if (!newImports.has(key)) {
const imports = oldImportPaths.get(value);
imports.delete(key);
const exports = exportList.get(value);
if (exports !== void 0) {
const currentExport = exports.get(key);
if (currentExport !== void 0) {
currentExport.whereUsed.delete(filename);
}
}
}
}
};
return {
"Program:exit"(node) {
updateExportUsage(node);
updateImportUsage(node);
checkExportPresence(node);
},
ExportDefaultDeclaration(node) {
checkUsage(node, AST_NODE_TYPES.ImportDefaultSpecifier, false);
},
ExportNamedDeclaration(node) {
for (const specifier of node.specifiers) {
checkUsage(specifier, getValue(specifier.exported), false);
}
forEachDeclarationIdentifier(node.declaration, (name, isTypeExport) => {
checkUsage(node, name, isTypeExport);
});
}
};
}
});
function toRelativePath(relativePath) {
const stripped = relativePath.replaceAll(/\/$/g, "");
return /^((\.\.)|(\.))($|\/)/.test(stripped) ? stripped : `./${stripped}`;
}
function normalize(filepath) {
return toRelativePath(path.posix.normalize(filepath));
}
function countRelativeParents(pathSegments) {
return pathSegments.filter((x) => x === "..").length;
}
var noUselessPathSegments = createRule({
name: "no-useless-path-segments",
meta: {
type: "suggestion",
docs: {
category: "Static analysis",
description: "Forbid unnecessary path segments in import and require statements."
},
fixable: "code",
schema: [
{
type: "object",
properties: {
commonjs: { type: "boolean" },
noUselessIndex: { type: "boolean" }
},
additionalProperties: false
}
],
messages: {
useless: 'Useless path segments for "{{importPath}}", should be "{{proposedPath}}"'
}
},
defaultOptions: [],
create(context) {
const currentDir = path.dirname(context.physicalFilename);
const options = context.options[0] || {};
return moduleVisitor((source) => {
const { value: importPath } = source;
function reportWithProposedPath(proposedPath) {
context.report({
node: source,
messageId: "useless",
data: {
importPath,
proposedPath
},
fix: (fixer) => proposedPath ? fixer.replaceText(source, JSON.stringify(proposedPath)) : null
});
}
if (!importPath.startsWith(".")) {
return;
}
const resolvedPath = resolve(importPath, context);
const normedPath = normalize(importPath);
const resolvedNormedPath = resolve(normedPath, context);
if (normedPath !== importPath && resolvedPath === resolvedNormedPath) {
return reportWithProposedPath(normedPath);
}
const fileExtensions = getFileExtensions(context.settings);
const regexUnnecessaryIndex = new RegExp(
`.*\\/index(\\${[...fileExtensions].join("|\\")})?$`
);
if (options.noUselessIndex && regexUnnecessaryIndex.test(importPath)) {
const parentDirectory = path.dirname(importPath);
if (parentDirectory !== "." && parentDirectory !== "..") {
for (const fileExtension of fileExtensions) {
if (resolve(`${parentDirectory}${fileExtension}`, context)) {
return reportWithProposedPath(`${parentDirectory}/`);
}
}
}
return reportWithProposedPath(parentDirectory);
}
if (importPath.startsWith("./")) {
return;
}
if (resolvedPath === void 0) {
return;
}
const expected = path.relative(currentDir, resolvedPath);
const expectedSplit = expected.split(path.sep);
const importPathSplit = importPath.replace(/^\.\//, "").split("/");
const countImportPathRelativeParents = countRelativeParents(importPathSplit);
const countExpectedRelativeParents = countRelativeParents(expectedSplit);
const diff = countImportPathRelativeParents - countExpectedRelativeParents;
if (diff <= 0) {
return;
}
return reportWithProposedPath(
toRelativePath(
[
...importPathSplit.slice(0, countExpectedRelativeParents),
...importPathSplit.slice(countImportPathRelativeParents + diff)
].join("/")
)
);
}, options);
}
});
var noWebpackLoaderSyntax = createRule({
name: "no-webpack-loader-syntax",
meta: {
type: "problem",
docs: {
category: "Static analysis",
description: "Forbid webpack loader syntax in imports."
},
schema: [],
messages: {
unexpected: "Unexpected '!' in '{{name}}'. Do not use import syntax to configure webpack loaders."
}
},
defaultOptions: [],
create(context) {
return moduleVisitor(
(source, node) => {
var _a;
if ((_a = source.value) == null ? void 0 : _a.includes("!")) {
context.report({
node,
messageId: "unexpected",
data: {
name: source.value
}
});
}
},
{ commonjs: true }
);
}
});
var __defProp$1 = Object.defineProperty;
var __defProps$1 = Object.defineProperties;
var __getOwnPropDescs$1 = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols$1 = Object.getOwnPropertySymbols;
var __hasOwnProp$1 = Object.prototype.hasOwnProperty;
var __propIsEnum$1 = Object.prototype.propertyIsEnumerable;
var __defNormalProp$1 = (obj, key, value) => key in obj ? __defProp$1(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues$1 = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp$1.call(b, prop))
__defNormalProp$1(a, prop, b[prop]);
if (__getOwnPropSymbols$1)
for (var prop of __getOwnPropSymbols$1(b)) {
if (__propIsEnum$1.call(b, prop))
__defNormalProp$1(a, prop, b[prop]);
}
return a;
};
var __spreadProps$1 = (a, b) => __defProps$1(a, __getOwnPropDescs$1(b));
const log = debug("eslint-plugin-import-x:rules:order");
const groupBy = (array, grouper) => array.reduce((acc, curr, index) => {
const key = grouper(curr, index);
(acc[key] || (acc[key] = [])).push(curr);
return acc;
}, {});
const categories = {
named: "named",
import: "import",
exports: "exports"
};
const defaultGroups = [
"builtin",
"external",
"parent",
"sibling",
"index"
];
function reverse(array) {
return array.map((v) => __spreadProps$1(__spreadValues$1({}, v), { rank: -v.rank })).reverse();
}
function getTokensOrCommentsAfter(sourceCode, node, count) {
let currentNodeOrToken = node;
const result = [];
for (let i = 0; i < count; i++) {
currentNodeOrToken = sourceCode.getTokenAfter(currentNodeOrToken, {
includeComments: true
});
if (currentNodeOrToken == null) {
break;
}
result.push(currentNodeOrToken);
}
return result;
}
function getTokensOrCommentsBefore(sourceCode, node, count) {
let currentNodeOrToken = node;
const result = [];
for (let i = 0; i < count; i++) {
currentNodeOrToken = sourceCode.getTokenBefore(currentNodeOrToken, {
includeComments: true
});
if (currentNodeOrToken == null) {
break;
}
result.push(currentNodeOrToken);
}
return result.reverse();
}
function takeTokensAfterWhile(sourceCode, node, condition) {
const tokens = getTokensOrCommentsAfter(sourceCode, node, 100);
const result = [];
for (const token of tokens) {
if (condition(token)) {
result.push(token);
} else {
break;
}
}
return result;
}
function takeTokensBeforeWhile(sourceCode, node, condition) {
const tokens = getTokensOrCommentsBefore(sourceCode, node, 100);
const result = [];
for (let i = tokens.length - 1; i >= 0; i--) {
if (condition(tokens[i])) {
result.push(tokens[i]);
} else {
break;
}
}
return result.reverse();
}
function findOutOfOrder(imported) {
if (imported.length === 0) {
return [];
}
let maxSeenRankNode = imported[0];
return imported.filter(function(importedModule) {
const res = importedModule.rank < maxSeenRankNode.rank;
if (maxSeenRankNode.rank < importedModule.rank) {
maxSeenRankNode = importedModule;
}
return res;
});
}
function findRootNode(node) {
let parent = node;
while (parent.parent != null && (!("body" in parent.parent) || parent.parent.body == null)) {
parent = parent.parent;
}
return parent;
}
function findEndOfLineWithComments(sourceCode, node) {
const tokensToEndOfLine = takeTokensAfterWhile(
sourceCode,
node,
commentOnSameLineAs(node)
);
const endOfTokens = tokensToEndOfLine.length > 0 ? tokensToEndOfLine[tokensToEndOfLine.length - 1].range[1] : node.range[1];
let result = endOfTokens;
for (let i = endOfTokens; i < sourceCode.text.length; i++) {
if (sourceCode.text[i] === "\n") {
result = i + 1;
break;
}
if (sourceCode.text[i] !== " " && sourceCode.text[i] !== " " && sourceCode.text[i] !== "\r") {
break;
}
result = i + 1;
}
return result;
}
function commentOnSameLineAs(node) {
return (token) => (token.type === "Block" || token.type === "Line") && token.loc.start.line === token.loc.end.line && token.loc.end.line === node.loc.end.line;
}
function findStartOfLineWithComments(sourceCode, node) {
const tokensToEndOfLine = takeTokensBeforeWhile(
sourceCode,
node,
commentOnSameLineAs(node)
);
const startOfTokens = tokensToEndOfLine.length > 0 ? tokensToEndOfLine[0].range[0] : node.range[0];
let result = startOfTokens;
for (let i = startOfTokens - 1; i > 0; i--) {
if (sourceCode.text[i] !== " " && sourceCode.text[i] !== " ") {
break;
}
result = i;
}
return result;
}
function findSpecifierStart(sourceCode, node) {
let token;
do {
token = sourceCode.getTokenBefore(node);
} while (token.value !== "," && token.value !== "{");
return token.range[1];
}
function findSpecifierEnd(sourceCode, node) {
let token;
do {
token = sourceCode.getTokenAfter(node);
} while (token.value !== "," && token.value !== "}");
return token.range[0];
}
function isRequireExpression(expr) {
return expr != null && expr.type === "CallExpression" && expr.callee != null && "name" in expr.callee && expr.callee.name === "require" && expr.arguments != null && expr.arguments.length === 1 && expr.arguments[0].type === "Literal";
}
function isSupportedRequireModule(node) {
if (node.type !== "VariableDeclaration") {
return false;
}
if (node.declarations.length !== 1) {
return false;
}
const decl = node.declarations[0];
const isPlainRequire = decl.id && (decl.id.type === "Identifier" || decl.id.type === "ObjectPattern") && isRequireExpression(decl.init);
const isRequireWithMemberExpression = decl.id && (decl.id.type === "Identifier" || decl.id.type === "ObjectPattern") && decl.init != null && decl.init.type === "CallExpression" && decl.init.callee != null && decl.init.callee.type === "MemberExpression" && isRequireExpression(decl.init.callee.object);
return isPlainRequire || isRequireWithMemberExpression;
}
function isPlainImportModule(node) {
return node.type === "ImportDeclaration" && node.specifiers != null && node.specifiers.length > 0;
}
function isPlainImportEquals(node) {
return node.type === "TSImportEqualsDeclaration" && "expression" in node.moduleReference && !!node.moduleReference.expression;
}
function isCJSExports(context, node) {
if (node.type === "MemberExpression" && node.object.type === "Identifier" && node.property.type === "Identifier" && node.object.name === "module" && node.property.name === "exports") {
return !context.sourceCode.getScope(node).variables.some((variable) => variable.name === "module");
}
if (node.type === "Identifier" && node.name === "exports") {
return !context.sourceCode.getScope(node).variables.some((variable) => variable.name === "exports");
}
}
function getNamedCJSExports(context, node) {
if (node.type !== "MemberExpression") {
return;
}
const result = [];
let root = node;
let parent;
while (root.type === "MemberExpression") {
if (root.property.type !== "Identifier") {
return;
}
result.unshift(root.property.name);
parent = root;
root = root.object;
}
if (isCJSExports(context, root)) {
return result;
}
if (isCJSExports(context, parent)) {
return result.slice(1);
}
}
function canCrossNodeWhileReorder(node) {
return isSupportedRequireModule(node) || isPlainImportModule(node) || isPlainImportEquals(node);
}
function canReorderItems(firstNode, secondNode) {
const parent = firstNode.parent;
if (!parent || !("body" in parent) || !Array.isArray(parent.body)) {
return false;
}
const body = parent.body;
const [firstIndex, secondIndex] = [
body.indexOf(firstNode),
body.indexOf(secondNode)
].sort();
const nodesBetween = parent.body.slice(firstIndex, secondIndex + 1);
for (const nodeBetween of nodesBetween) {
if (!canCrossNodeWhileReorder(nodeBetween)) {
return false;
}
}
return true;
}
function makeImportDescription(node) {
if (node.type === "export") {
if (node.node.exportKind === "type") {
return "type export";
}
return "export";
}
if (node.node.importKind === "type") {
return "type import";
}
if (node.node.importKind === "typeof") {
return "typeof import";
}
return "import";
}
function fixOutOfOrder(context, firstNode, secondNode, order, category) {
const isNamed = category === categories.named;
const isExports = category === categories.exports;
const { sourceCode } = context;
const { firstRoot, secondRoot } = isNamed ? { firstRoot: firstNode.node, secondRoot: secondNode.node } : {
firstRoot: findRootNode(firstNode.node),
secondRoot: findRootNode(secondNode.node)
};
const { firstRootStart, firstRootEnd, secondRootStart, secondRootEnd } = isNamed ? {
firstRootStart: findSpecifierStart(sourceCode, firstRoot),
firstRootEnd: findSpecifierEnd(sourceCode, firstRoot),
secondRootStart: findSpecifierStart(sourceCode, secondRoot),
secondRootEnd: findSpecifierEnd(sourceCode, secondRoot)
} : {
firstRootStart: findStartOfLineWithComments(sourceCode, firstRoot),
firstRootEnd: findEndOfLineWithComments(sourceCode, firstRoot),
secondRootStart: findStartOfLineWithComments(sourceCode, secondRoot),
secondRootEnd: findEndOfLineWithComments(sourceCode, secondRoot)
};
if (firstNode.displayName === secondNode.displayName) {
if (firstNode.alias) {
firstNode.displayName = `${firstNode.displayName} as ${firstNode.alias}`;
}
if (secondNode.alias) {
secondNode.displayName = `${secondNode.displayName} as ${secondNode.alias}`;
}
}
const firstDesc = makeImportDescription(firstNode);
const secondDesc = makeImportDescription(secondNode);
if (firstNode.displayName === secondNode.displayName && firstDesc === secondDesc) {
log(
firstNode.displayName,
firstNode.node.loc,
secondNode.displayName,
secondNode.node.loc
);
return;
}
const firstImport = `${firstDesc} of \`${firstNode.displayName}\``;
const secondImport = `\`${secondNode.displayName}\` ${secondDesc}`;
const messageOptions = {
messageId: "order",
data: { firstImport, secondImport, order }
};
if (isNamed) {
const firstCode = sourceCode.text.slice(firstRootStart, firstRoot.range[1]);
const firstTrivia = sourceCode.text.slice(firstRoot.range[1], firstRootEnd);
const secondCode = sourceCode.text.slice(
secondRootStart,
secondRoot.range[1]
);
const secondTrivia = sourceCode.text.slice(
secondRoot.range[1],
secondRootEnd
);
if (order === "before") {
const trimmedTrivia = secondTrivia.trimEnd();
const gapCode = sourceCode.text.slice(firstRootEnd, secondRootStart - 1);
const whitespaces = secondTrivia.slice(trimmedTrivia.length);
context.report(__spreadProps$1(__spreadValues$1({
node: secondNode.node
}, messageOptions), {
fix: (fixer) => fixer.replaceTextRange(
[firstRootStart, secondRootEnd],
`${secondCode},${trimmedTrivia}${firstCode}${firstTrivia}${gapCode}${whitespaces}`
)
}));
} else if (order === "after") {
const trimmedTrivia = firstTrivia.trimEnd();
const gapCode = sourceCode.text.slice(secondRootEnd + 1, firstRootStart);
const whitespaces = firstTrivia.slice(trimmedTrivia.length);
context.report(__spreadProps$1(__spreadValues$1({
node: secondNode.node
}, messageOptions), {
fix: (fixes) => fixes.replaceTextRange(
[secondRootStart, firstRootEnd],
`${gapCode}${firstCode},${trimmedTrivia}${secondCode}${whitespaces}`
)
}));
}
} else {
const canFix = isExports || canReorderItems(firstRoot, secondRoot);
let newCode = sourceCode.text.slice(secondRootStart, secondRootEnd);
if (newCode[newCode.length - 1] !== "\n") {
newCode = `${newCode}
`;
}
if (order === "before") {
context.report(__spreadProps$1(__spreadValues$1({
node: secondNode.node
}, messageOptions), {
fix: canFix ? (fixer) => fixer.replaceTextRange(
[firstRootStart, secondRootEnd],
newCode + sourceCode.text.slice(firstRootStart, secondRootStart)
) : null
}));
} else if (order === "after") {
context.report(__spreadProps$1(__spreadValues$1({
node: secondNode.node
}, messageOptions), {
fix: canFix ? (fixer) => fixer.replaceTextRange(
[secondRootStart, firstRootEnd],
sourceCode.text.slice(secondRootEnd, firstRootEnd) + newCode
) : null
}));
}
}
}
function reportOutOfOrder(context, imported, outOfOrder, order, category) {
for (const imp of outOfOrder) {
fixOutOfOrder(
context,
imported.find((importedItem) => importedItem.rank > imp.rank),
imp,
order,
category
);
}
}
function makeOutOfOrderReport(context, imported, category) {
const outOfOrder = findOutOfOrder(imported);
if (outOfOrder.length === 0) {
return;
}
const reversedImported = reverse(imported);
const reversedOrder = findOutOfOrder(reversedImported);
if (reversedOrder.length < outOfOrder.length) {
reportOutOfOrder(
context,
reversedImported,
reversedOrder,
"after",
category
);
return;
}
reportOutOfOrder(context, imported, outOfOrder, "before", category);
}
const compareString = (a, b) => {
if (a < b) {
return -1;
}
if (a > b) {
return 1;
}
return 0;
};
const DEFAULT_IMPORT_KIND = "value";
const getNormalizedValue = (node, toLowerCase) => {
const value = String(node.value);
return toLowerCase ? value.toLowerCase() : value;
};
const RELATIVE_DOTS = /* @__PURE__ */ new Set([".", ".."]);
function getSorter(alphabetizeOptions) {
const multiplier = alphabetizeOptions.order === "asc" ? 1 : -1;
const orderImportKind = alphabetizeOptions.orderImportKind;
const multiplierImportKind = orderImportKind !== "ignore" && (alphabetizeOptions.orderImportKind === "asc" ? 1 : -1);
return function importsSorter(nodeA, nodeB) {
const importA = getNormalizedValue(
nodeA,
alphabetizeOptions.caseInsensitive
);
const importB = getNormalizedValue(
nodeB,
alphabetizeOptions.caseInsensitive
);
let result = 0;
if (!importA.includes("/") && !importB.includes("/")) {
result = compareString(importA, importB);
} else {
const A = importA.split("/");
const B = importB.split("/");
const a = A.length;
const b = B.length;
for (let i = 0; i < Math.min(a, b); i++) {
const x = A[i];
const y = B[i];
if (i === 0 && RELATIVE_DOTS.has(x) && RELATIVE_DOTS.has(y)) {
if (x !== y) {
break;
}
continue;
}
result = compareString(x, y);
if (result) {
break;
}
}
if (!result && a !== b) {
result = a < b ? -1 : 1;
}
}
result = result * multiplier;
if (!result && multiplierImportKind) {
result = multiplierImportKind * compareString(
nodeA.node.importKind || DEFAULT_IMPORT_KIND,
nodeB.node.importKind || DEFAULT_IMPORT_KIND
);
}
return result;
};
}
function mutateRanksToAlphabetize(imported, alphabetizeOptions) {
const groupedByRanks = groupBy(imported, (item) => item.rank);
const sorterFn = getSorter(alphabetizeOptions);
const groupRanks = Object.keys(groupedByRanks).sort((a, b) => +a - +b);
for (const groupRank of groupRanks) {
groupedByRanks[groupRank].sort(sorterFn);
}
let newRank = 0;
const alphabetizedRanks = groupRanks.reduce(
(acc, groupRank) => {
for (const importedItem of groupedByRanks[groupRank]) {
acc[`${importedItem.value}|${importedItem.node.importKind}`] = Number.parseInt(groupRank, 10) + newRank;
newRank += 1;
}
return acc;
},
{}
);
for (const importedItem of imported) {
importedItem.rank = alphabetizedRanks[`${importedItem.value}|${importedItem.node.importKind}`];
}
}
function computePathRank(ranks, pathGroups, path, maxPosition) {
for (const { pattern, patternOptions, group, position = 1 } of pathGroups) {
if (minimatch.minimatch(path, pattern, patternOptions || { nocomment: true })) {
return ranks[group] + position / maxPosition;
}
}
}
function computeRank(context, ranks, importEntry, excludedImportTypes, isSortingTypesGroup) {
let impType;
let rank;
const isTypeGroupInGroups = !ranks.omittedTypes.includes("type");
const isTypeOnlyImport = importEntry.node.importKind === "type";
const isExcludedFromPathRank = isTypeOnlyImport && isTypeGroupInGroups && excludedImportTypes.has("type");
if (importEntry.type === "import:object") {
impType = "object";
} else if (isTypeOnlyImport && isTypeGroupInGroups && !isSortingTypesGroup) {
impType = "type";
} else {
impType = importType(importEntry.value, context);
}
if (!excludedImportTypes.has(impType) && !isExcludedFromPathRank) {
rank = typeof importEntry.value === "string" ? computePathRank(
ranks.groups,
ranks.pathGroups,
importEntry.value,
ranks.maxPosition
) : void 0;
}
if (rank === void 0) {
rank = ranks.groups[impType];
if (rank === void 0) {
return -1;
}
}
if (isTypeOnlyImport && isSortingTypesGroup) {
rank = ranks.groups.type + rank / 10;
}
if (importEntry.type !== "import" && !importEntry.type.startsWith("import:")) {
rank += 100;
}
return rank;
}
function registerNode(context, importEntry, ranks, imported, excludedImportTypes, isSortingTypesGroup) {
var _a, _b;
const rank = computeRank(
context,
ranks,
importEntry,
excludedImportTypes,
isSortingTypesGroup
);
if (rank !== -1) {
let importNode = importEntry.node;
if (importEntry.type === "require" && ((_b = (_a = importNode.parent) == null ? void 0 : _a.parent) == null ? void 0 : _b.type) === "VariableDeclaration") {
importNode = importNode.parent.parent;
}
imported.push(__spreadProps$1(__spreadValues$1({}, importEntry), {
rank,
isMultiline: importNode.loc.end.line !== importNode.loc.start.line
}));
}
}
function getRequireBlock(node) {
var _a, _b, _c;
let n = node;
while (((_a = n.parent) == null ? void 0 : _a.type) === "MemberExpression" && n.parent.object === n || ((_b = n.parent) == null ? void 0 : _b.type) === "CallExpression" && n.parent.callee === n) {
n = n.parent;
}
if (((_c = n.parent) == null ? void 0 : _c.type) === "VariableDeclarator" && n.parent.parent.type === "VariableDeclaration" && n.parent.parent.parent.type === "Program") {
return n.parent.parent.parent;
}
}
const types = [
"builtin",
"external",
"internal",
"unknown",
"parent",
"sibling",
"index",
"object",
"type"
];
function convertGroupsToRanks(groups) {
const rankObject = groups.reduce(
(res, group, index) => {
for (const groupItem of [group].flat()) {
if (!types.includes(groupItem)) {
throw new Error(
`Incorrect configuration of the rule: Unknown type \`${JSON.stringify(groupItem)}\``
);
}
if (res[groupItem] !== void 0) {
throw new Error(
`Incorrect configuration of the rule: \`${groupItem}\` is duplicated`
);
}
res[groupItem] = index * 2;
}
return res;
},
{}
);
const omittedTypes = types.filter((type) => rankObject[type] === void 0);
const ranks = omittedTypes.reduce(function(res, type) {
res[type] = groups.length * 2;
return res;
}, rankObject);
return { groups: ranks, omittedTypes };
}
function convertPathGroupsForRanks(pathGroups) {
const after = {};
const before = {};
const transformed = pathGroups.map((pathGroup, index) => {
const { group, position: positionString } = pathGroup;
let position = 0;
if (positionString === "after") {
if (!after[group]) {
after[group] = 1;
}
position = after[group]++;
} else if (positionString === "before") {
if (!before[group]) {
before[group] = [];
}
before[group].push(index);
}
return __spreadProps$1(__spreadValues$1({}, pathGroup), { position });
});
let maxPosition = 1;
for (const group of Object.keys(before)) {
const groupLength = before[group].length;
for (const [index, groupIndex] of before[group].entries()) {
transformed[groupIndex].position = -1 * (groupLength - index);
}
maxPosition = Math.max(maxPosition, groupLength);
}
for (const key of Object.keys(after)) {
const groupNextPosition = after[key];
maxPosition = Math.max(maxPosition, groupNextPosition - 1);
}
return {
pathGroups: transformed,
maxPosition: maxPosition > 10 ? Math.pow(10, Math.ceil(Math.log10(maxPosition))) : 10
};
}
function fixNewLineAfterImport(context, previousImport) {
const prevRoot = findRootNode(previousImport.node);
const tokensToEndOfLine = takeTokensAfterWhile(
context.sourceCode,
prevRoot,
commentOnSameLineAs(prevRoot)
);
let endOfLine = prevRoot.range[1];
if (tokensToEndOfLine.length > 0) {
endOfLine = tokensToEndOfLine[tokensToEndOfLine.length - 1].range[1];
}
return (fixer) => fixer.insertTextAfterRange([prevRoot.range[0], endOfLine], "\n");
}
function removeNewLineAfterImport(context, currentImport, previousImport) {
const { sourceCode } = context;
const prevRoot = findRootNode(previousImport.node);
const currRoot = findRootNode(currentImport.node);
const rangeToRemove = [
findEndOfLineWithComments(sourceCode, prevRoot),
findStartOfLineWithComments(sourceCode, currRoot)
];
if (/^\s*$/.test(sourceCode.text.slice(rangeToRemove[0], rangeToRemove[1]))) {
return (fixer) => fixer.removeRange(rangeToRemove);
}
return;
}
function makeNewlinesBetweenReport(context, imported, newlinesBetweenImports_, newlinesBetweenTypeOnlyImports_, distinctGroup, isSortingTypesGroup, isConsolidatingSpaceBetweenImports) {
const getNumberOfEmptyLinesBetween = (currentImport, previousImport2) => {
return context.sourceCode.lines.slice(
previousImport2.node.loc.end.line,
currentImport.node.loc.start.line - 1
).filter((line) => line.trim().length === 0).length;
};
const getIsStartOfDistinctGroup = (currentImport, previousImport2) => currentImport.rank - 1 >= previousImport2.rank;
let previousImport = imported[0];
for (const currentImport of imported.slice(1)) {
const emptyLinesBetween = getNumberOfEmptyLinesBetween(
currentImport,
previousImport
);
const isStartOfDistinctGroup = getIsStartOfDistinctGroup(
currentImport,
previousImport
);
const isTypeOnlyImport = currentImport.node.importKind === "type";
const isPreviousImportTypeOnlyImport = previousImport.node.importKind === "type";
const isNormalImportNextToTypeOnlyImportAndRelevant = isTypeOnlyImport !== isPreviousImportTypeOnlyImport && isSortingTypesGroup;
const isTypeOnlyImportAndRelevant = isTypeOnlyImport && isSortingTypesGroup;
const newlinesBetweenImports = isSortingTypesGroup && isConsolidatingSpaceBetweenImports && (previousImport.isMultiline || currentImport.isMultiline) && newlinesBetweenImports_ === "never" ? "always-and-inside-groups" : newlinesBetweenImports_;
const newlinesBetweenTypeOnlyImports = isSortingTypesGroup && isConsolidatingSpaceBetweenImports && (isNormalImportNextToTypeOnlyImportAndRelevant || previousImport.isMultiline || currentImport.isMultiline) && newlinesBetweenTypeOnlyImports_ === "never" ? "always-and-inside-groups" : newlinesBetweenTypeOnlyImports_;
const isNotIgnored = isTypeOnlyImportAndRelevant && newlinesBetweenTypeOnlyImports !== "ignore" || !isTypeOnlyImportAndRelevant && newlinesBetweenImports !== "ignore";
if (isNotIgnored) {
const shouldAssertNewlineBetweenGroups = (isTypeOnlyImportAndRelevant || isNormalImportNextToTypeOnlyImportAndRelevant) && (newlinesBetweenTypeOnlyImports === "always" || newlinesBetweenTypeOnlyImports === "always-and-inside-groups") || !isTypeOnlyImportAndRelevant && !isNormalImportNextToTypeOnlyImportAndRelevant && (newlinesBetweenImports === "always" || newlinesBetweenImports === "always-and-inside-groups");
const shouldAssertNoNewlineWithinGroup = (isTypeOnlyImportAndRelevant || isNormalImportNextToTypeOnlyImportAndRelevant) && newlinesBetweenTypeOnlyImports !== "always-and-inside-groups" || !isTypeOnlyImportAndRelevant && !isNormalImportNextToTypeOnlyImportAndRelevant && newlinesBetweenImports !== "always-and-inside-groups";
const shouldAssertNoNewlineBetweenGroup = !isSortingTypesGroup || !isNormalImportNextToTypeOnlyImportAndRelevant || newlinesBetweenTypeOnlyImports === "never";
const isTheNewlineBetweenImportsInTheSameGroup = distinctGroup && currentImport.rank === previousImport.rank || !distinctGroup && !isStartOfDistinctGroup;
let alreadyReported = false;
if (shouldAssertNewlineBetweenGroups) {
if (currentImport.rank !== previousImport.rank && emptyLinesBetween === 0) {
if (distinctGroup || isStartOfDistinctGroup) {
alreadyReported = true;
context.report({
node: previousImport.node,
messageId: "oneLineBetweenGroups",
fix: fixNewLineAfterImport(context, previousImport)
});
}
} else if (emptyLinesBetween > 0 && shouldAssertNoNewlineWithinGroup && isTheNewlineBetweenImportsInTheSameGroup) {
alreadyReported = true;
context.report({
node: previousImport.node,
messageId: "noLineWithinGroup",
fix: removeNewLineAfterImport(
context,
currentImport,
previousImport
)
});
}
} else if (emptyLinesBetween > 0 && shouldAssertNoNewlineBetweenGroup) {
alreadyReported = true;
context.report({
node: previousImport.node,
messageId: "noLineBetweenGroups",
fix: removeNewLineAfterImport(context, currentImport, previousImport)
});
}
if (!alreadyReported && isConsolidatingSpaceBetweenImports) {
if (emptyLinesBetween === 0 && currentImport.isMultiline) {
context.report({
node: previousImport.node,
messageId: "oneLineBetweenTheMultiLineImport",
fix: fixNewLineAfterImport(context, previousImport)
});
} else if (emptyLinesBetween === 0 && previousImport.isMultiline) {
context.report({
node: previousImport.node,
messageId: "oneLineBetweenThisMultiLineImport",
fix: fixNewLineAfterImport(context, previousImport)
});
} else if (emptyLinesBetween > 0 && !previousImport.isMultiline && !currentImport.isMultiline && isTheNewlineBetweenImportsInTheSameGroup) {
context.report({
node: previousImport.node,
messageId: "noLineBetweenSingleLineImport",
fix: removeNewLineAfterImport(
context,
currentImport,
previousImport
)
});
}
}
}
previousImport = currentImport;
}
}
function getAlphabetizeConfig(options) {
const alphabetize = options.alphabetize || {};
const order = alphabetize.order || "ignore";
const orderImportKind = alphabetize.orderImportKind || "ignore";
const caseInsensitive = alphabetize.caseInsensitive || false;
return { order, orderImportKind, caseInsensitive };
}
const defaultDistinctGroup = true;
var order = createRule({
name: "order",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Enforce a convention in module import order."
},
fixable: "code",
schema: [
{
type: "object",
properties: {
groups: {
type: "array"
},
pathGroupsExcludedImportTypes: {
type: "array"
},
distinctGroup: {
type: "boolean",
default: defaultDistinctGroup
},
pathGroups: {
type: "array",
items: {
type: "object",
properties: {
pattern: {
type: "string"
},
patternOptions: {
type: "object"
},
group: {
type: "string",
enum: types
},
position: {
type: "string",
enum: ["after", "before"]
}
},
additionalProperties: false,
required: ["pattern", "group"]
}
},
"newlines-between": {
type: "string",
enum: ["ignore", "always", "always-and-inside-groups", "never"]
},
"newlines-between-types": {
type: "string",
enum: ["ignore", "always", "always-and-inside-groups", "never"]
},
consolidateIslands: {
type: "string",
enum: ["inside-groups", "never"]
},
sortTypesGroup: {
type: "boolean",
default: false
},
named: {
default: false,
oneOf: [
{
type: "boolean"
},
{
type: "object",
properties: {
enabled: { type: "boolean" },
import: { type: "boolean" },
export: { type: "boolean" },
require: { type: "boolean" },
cjsExports: { type: "boolean" },
types: {
type: "string",
enum: ["mixed", "types-first", "types-last"]
}
},
additionalProperties: false
}
]
},
alphabetize: {
type: "object",
properties: {
caseInsensitive: {
type: "boolean",
default: false
},
order: {
type: "string",
enum: ["ignore", "asc", "desc"],
default: "ignore"
},
orderImportKind: {
type: "string",
enum: ["ignore", "asc", "desc"],
default: "ignore"
}
},
additionalProperties: false
},
warnOnUnassignedImports: {
type: "boolean",
default: false
}
},
additionalProperties: false,
dependencies: {
"newlines-between-types": {
type: "object",
properties: {
sortTypesGroup: {
type: "boolean",
enum: [true]
}
},
required: ["sortTypesGroup"]
},
consolidateIslands: {
anyOf: [
{
type: "object",
properties: {
"newlines-between": {
type: "string",
enum: ["always-and-inside-groups"]
}
},
required: ["newlines-between"]
},
{
type: "object",
properties: {
"newlines-between-types": {
type: "string",
enum: ["always-and-inside-groups"]
}
},
required: ["newlines-between-types"]
}
]
}
}
}
],
messages: {
error: "{{error}}",
noLineWithinGroup: "There should be no empty line within import group",
noLineBetweenGroups: "There should be no empty line between import groups",
oneLineBetweenGroups: "There should be at least one empty line between import groups",
order: "{{secondImport}} should occur {{order}} {{firstImport}}",
oneLineBetweenTheMultiLineImport: "There should be at least one empty line between this import and the multi-line import that follows it",
oneLineBetweenThisMultiLineImport: "There should be at least one empty line between this multi-line import and the import that follows it",
noLineBetweenSingleLineImport: "There should be no empty lines between this single-line import and the single-line import that follows it"
}
},
defaultOptions: [],
create(context) {
const options = context.options[0] || {};
const newlinesBetweenImports = options["newlines-between"] || "ignore";
const newlinesBetweenTypeOnlyImports = options["newlines-between-types"] || newlinesBetweenImports;
const pathGroupsExcludedImportTypes = new Set(
options.pathGroupsExcludedImportTypes || ["builtin", "external", "object"]
);
const sortTypesGroup = options.sortTypesGroup;
const consolidateIslands = options.consolidateIslands || "never";
const named = __spreadValues$1({
types: "mixed"
}, typeof options.named === "object" ? __spreadProps$1(__spreadValues$1({}, options.named), {
import: "import" in options.named ? options.named.import : options.named.enabled,
export: "export" in options.named ? options.named.export : options.named.enabled,
require: "require" in options.named ? options.named.require : options.named.enabled,
cjsExports: "cjsExports" in options.named ? options.named.cjsExports : options.named.enabled
}) : {
import: options.named,
export: options.named,
require: options.named,
cjsExports: options.named
});
const namedGroups = named.types === "mixed" ? [] : named.types === "types-last" ? ["value"] : ["type"];
const alphabetize = getAlphabetizeConfig(options);
const distinctGroup = options.distinctGroup == null ? defaultDistinctGroup : !!options.distinctGroup;
let ranks;
try {
const { pathGroups, maxPosition } = convertPathGroupsForRanks(
options.pathGroups || []
);
const { groups, omittedTypes } = convertGroupsToRanks(
options.groups || defaultGroups
);
ranks = {
groups,
omittedTypes,
pathGroups,
maxPosition
};
} catch (error) {
return {
Program(node) {
context.report({
node,
messageId: "error",
data: {
error: error.message
}
});
}
};
}
const importMap = /* @__PURE__ */ new Map();
const exportMap = /* @__PURE__ */ new Map();
const isTypeGroupInGroups = !ranks.omittedTypes.includes("type");
const isSortingTypesGroup = isTypeGroupInGroups && sortTypesGroup;
function getBlockImports(node) {
let blockImports = importMap.get(node);
if (!blockImports) {
importMap.set(node, blockImports = []);
}
return blockImports;
}
function getBlockExports(node) {
let blockExports = exportMap.get(node);
if (!blockExports) {
exportMap.set(node, blockExports = []);
}
return blockExports;
}
function makeNamedOrderReport(context2, namedImports) {
if (namedImports.length > 1) {
const imports = namedImports.map((namedImport) => {
const kind = namedImport.kind || "value";
const rank = namedGroups.indexOf(kind);
return __spreadProps$1(__spreadValues$1({
displayName: namedImport.value,
rank: rank === -1 ? namedGroups.length : rank
}, namedImport), {
value: `${namedImport.value}:${namedImport.alias || ""}`
});
});
if (alphabetize.order !== "ignore") {
mutateRanksToAlphabetize(imports, alphabetize);
}
makeOutOfOrderReport(context2, imports, categories.named);
}
}
return __spreadProps$1(__spreadValues$1(__spreadValues$1(__spreadValues$1({
ImportDeclaration(node) {
if (node.specifiers.length > 0 || options.warnOnUnassignedImports) {
const name = node.source.value;
registerNode(
context,
{
node,
value: name,
displayName: name,
type: "import"
},
ranks,
getBlockImports(node.parent),
pathGroupsExcludedImportTypes,
isSortingTypesGroup
);
if (named.import) {
makeNamedOrderReport(
context,
node.specifiers.filter((specifier) => specifier.type === "ImportSpecifier").map((specifier) => __spreadValues$1({
node: specifier,
value: getValue(specifier.imported),
type: "import",
kind: specifier.importKind
}, specifier.local.range[0] !== specifier.imported.range[0] && {
alias: specifier.local.name
}))
);
}
}
},
TSImportEqualsDeclaration(node) {
if (node.isExport) {
return;
}
let displayName;
let value;
let type;
if (node.moduleReference.type === "TSExternalModuleReference") {
value = node.moduleReference.expression.value;
displayName = value;
type = "import";
} else {
value = "";
displayName = context.sourceCode.getText(node.moduleReference);
type = "import:object";
}
registerNode(
context,
{
node,
value,
displayName,
type
},
ranks,
getBlockImports(node.parent),
pathGroupsExcludedImportTypes,
isSortingTypesGroup
);
},
CallExpression(node) {
if (!isStaticRequire(node)) {
return;
}
const block = getRequireBlock(node);
const firstArg = node.arguments[0];
if (!block || !("value" in firstArg)) {
return;
}
const { value } = firstArg;
registerNode(
context,
{
node,
value,
displayName: value,
type: "require"
},
ranks,
getBlockImports(block),
pathGroupsExcludedImportTypes,
isSortingTypesGroup
);
}
}, named.require && {
VariableDeclarator(node) {
if (node.id.type === "ObjectPattern" && isRequireExpression(node.init)) {
const { properties } = node.id;
for (const p of properties) {
if (!("key" in p) || p.key.type !== "Identifier" || p.value.type !== "Identifier") {
return;
}
}
makeNamedOrderReport(
context,
node.id.properties.map((prop_) => {
const prop = prop_;
const key = prop.key;
const value = prop.value;
return __spreadValues$1({
node: prop,
value: key.name,
type: "require"
}, key.range[0] !== value.range[0] && {
alias: value.name
});
})
);
}
}
}), named.export && {
ExportNamedDeclaration(node) {
makeNamedOrderReport(
context,
node.specifiers.map((specifier) => __spreadValues$1({
node: specifier,
value: getValue(specifier.local),
type: "export",
kind: specifier.exportKind
}, specifier.local.range[0] !== specifier.exported.range[0] && {
alias: getValue(specifier.exported)
}))
);
}
}), named.cjsExports && {
AssignmentExpression(node) {
if (node.parent.type === "ExpressionStatement") {
if (isCJSExports(context, node.left)) {
if (node.right.type === "ObjectExpression") {
const { properties } = node.right;
for (const p of properties) {
if (!("key" in p) || p.key.type !== "Identifier" || p.value.type !== "Identifier") {
return;
}
}
makeNamedOrderReport(
context,
properties.map((prop_) => {
const prop = prop_;
const key = prop.key;
const value = prop.value;
return __spreadValues$1({
node: prop,
value: key.name,
type: "export"
}, key.range[0] !== value.range[0] && {
alias: value.name
});
})
);
}
} else {
const nameParts = getNamedCJSExports(context, node.left);
if (nameParts && nameParts.length > 0) {
const name = nameParts.join(".");
getBlockExports(node.parent.parent).push({
node,
value: name,
displayName: name,
type: "export",
rank: 0
});
}
}
}
}
}), {
"Program:exit"() {
for (const imported of importMap.values()) {
if (newlinesBetweenImports !== "ignore" || newlinesBetweenTypeOnlyImports !== "ignore") {
makeNewlinesBetweenReport(
context,
imported,
newlinesBetweenImports,
newlinesBetweenTypeOnlyImports,
distinctGroup,
isSortingTypesGroup,
consolidateIslands === "inside-groups" && (newlinesBetweenImports === "always-and-inside-groups" || newlinesBetweenTypeOnlyImports === "always-and-inside-groups")
);
}
if (alphabetize.order !== "ignore") {
mutateRanksToAlphabetize(imported, alphabetize);
}
makeOutOfOrderReport(context, imported, categories.import);
}
for (const exported of exportMap.values()) {
if (alphabetize.order !== "ignore") {
mutateRanksToAlphabetize(exported, alphabetize);
makeOutOfOrderReport(context, exported, categories.exports);
}
}
importMap.clear();
exportMap.clear();
}
});
}
});
var preferDefaultExport = createRule({
name: "prefer-default-export",
meta: {
type: "suggestion",
docs: {
category: "Style guide",
description: "Prefer a default export if module exports a single name or multiple names."
},
schema: [
{
type: "object",
properties: {
target: {
type: "string",
enum: ["single", "any"],
default: "single"
}
},
additionalProperties: false
}
],
messages: {
single: "Prefer default export on a file with single export.",
any: "Prefer default export to be present on every file that has export."
}
},
defaultOptions: [],
create(context) {
let specifierExportCount = 0;
let hasDefaultExport = false;
let hasStarExport = false;
let hasTypeExport = false;
let namedExportNode;
const { target = "single" } = context.options[0] || {};
function captureDeclaration(identifierOrPattern) {
if ((identifierOrPattern == null ? void 0 : identifierOrPattern.type) === "ObjectPattern") {
for (const property of identifierOrPattern.properties) {
captureDeclaration(property.value);
}
} else if ((identifierOrPattern == null ? void 0 : identifierOrPattern.type) === "ArrayPattern") {
for (const el of identifierOrPattern.elements) {
captureDeclaration(el);
}
} else {
specifierExportCount++;
}
}
return {
ExportDefaultSpecifier() {
hasDefaultExport = true;
},
ExportSpecifier(node) {
if (getValue(node.exported) === "default") {
hasDefaultExport = true;
} else {
specifierExportCount++;
namedExportNode = node;
}
},
ExportNamedDeclaration(node) {
if (!node.declaration) {
return;
}
const { type } = node.declaration;
if (type === "TSTypeAliasDeclaration" || type === "TSInterfaceDeclaration" || // @ts-expect-error - legacy parser type
type === "TypeAlias" || // @ts-expect-error - legacy parser type
type === "InterfaceDeclaration") {
specifierExportCount++;
hasTypeExport = true;
return;
}
if ("declarations" in node.declaration && node.declaration.declarations) {
for (const declaration of node.declaration.declarations) {
captureDeclaration(declaration.id);
}
} else {
specifierExportCount++;
}
namedExportNode = node;
},
ExportDefaultDeclaration() {
hasDefaultExport = true;
},
ExportAllDeclaration() {
hasStarExport = true;
},
"Program:exit"() {
if (hasDefaultExport || hasStarExport || hasTypeExport) {
return;
}
if (target === "single" && specifierExportCount === 1) {
context.report({
node: namedExportNode,
messageId: "single"
});
} else if (target === "any" && specifierExportCount > 0) {
context.report({
node: namedExportNode,
messageId: "any"
});
}
}
};
}
});
var unambiguous = createRule({
name: "unambiguous",
meta: {
type: "suggestion",
docs: {
category: "Module systems",
description: "Forbid potentially ambiguous parse goal (`script` vs. `module`)."
},
schema: [],
messages: {
module: "This module could be parsed as a valid script."
}
},
defaultOptions: [],
create(context) {
if (sourceType(context) !== "module") {
return {};
}
return {
Program(ast) {
if (!isUnambiguousModule(ast)) {
context.report({
node: ast,
messageId: "module"
});
}
}
};
}
});
var __defProp = Object.defineProperty;
var __defProps = Object.defineProperties;
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __propIsEnum = Object.prototype.propertyIsEnumerable;
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
var __spreadValues = (a, b) => {
for (var prop in b || (b = {}))
if (__hasOwnProp.call(b, prop))
__defNormalProp(a, prop, b[prop]);
if (__getOwnPropSymbols)
for (var prop of __getOwnPropSymbols(b)) {
if (__propIsEnum.call(b, prop))
__defNormalProp(a, prop, b[prop]);
}
return a;
};
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
const rules = {
"no-unresolved": noUnresolved,
named,
default: default_,
namespace,
"no-namespace": noNamespace,
export: export_,
"no-mutable-exports": noMutableExports,
extensions,
"no-restricted-paths": noRestrictedPaths,
"no-internal-modules": noInternalModules,
"group-exports": groupExports,
"no-relative-packages": noRelativePackages,
"no-relative-parent-imports": noRelativeParentImports,
"consistent-type-specifier-style": consistentTypeSpecifierStyle,
"no-self-import": noSelfImport,
"no-cycle": noCycle,
"no-named-default": noNamedDefault,
"no-named-as-default": noNamedAsDefault,
"no-named-as-default-member": noNamedAsDefaultMember,
"no-anonymous-default-export": noAnonymousDefaultExport,
"no-rename-default": noRenameDefault,
"no-unused-modules": noUnusedModules,
"no-commonjs": noCommonjs,
"no-amd": noAmd,
"no-duplicates": noDuplicates,
first,
"max-dependencies": maxDependencies,
"no-extraneous-dependencies": noExtraneousDependencies,
"no-absolute-path": noAbsolutePath,
"no-nodejs-modules": noNodejsModules,
"no-webpack-loader-syntax": noWebpackLoaderSyntax,
order,
"newline-after-import": newlineAfterImport,
"prefer-default-export": preferDefaultExport,
"no-default-export": noDefaultExport,
"no-named-export": noNamedExport,
"no-dynamic-require": noDynamicRequire,
unambiguous,
"no-unassigned-import": noUnassignedImport,
"no-useless-path-segments": noUselessPathSegments,
"dynamic-import-chunkname": dynamicImportChunkname,
"no-import-module-exports": noImportModuleExports,
"no-empty-named-blocks": noEmptyNamedBlocks,
// export
"exports-last": exportsLast,
// metadata-based
"no-deprecated": noDeprecated,
// deprecated aliases to rules
"imports-first": importsFirst
};
const configs = {
recommended,
errors,
warnings,
// shhhh... work in progress "secret" rules
"stage-0": stage0,
// useful stuff for folks using various environments
react,
"react-native": reactNative,
electron,
typescript
};
const plugin = {
meta,
rules
};
const createFlatConfig = (baseConfig, configName) => __spreadProps(__spreadValues({}, baseConfig), {
name: `import-x/${configName}`,
plugins: { "import-x": plugin }
});
const flatConfigs = {
recommended: createFlatConfig(recommendedFlat, "recommended"),
errors: createFlatConfig(errorsFlat, "errors"),
warnings: createFlatConfig(warningsFlat, "warnings"),
// shhhh... work in progress "secret" rules
"stage-0": createFlatConfig(stage0Flat, "stage-0"),
// useful stuff for folks using various environments
react: createFlatConfig(reactFlat, "react"),
"react-native": createFlatConfig(reactNativeFlat, "react-native"),
electron: createFlatConfig(electronFlat, "electron"),
typescript: createFlatConfig(typescriptFlat, "typescript")
};
var index = {
meta,
configs,
flatConfigs,
rules,
cjsRequire,
importXResolverCompat,
createNodeResolver
};
exports.cjsRequire = cjsRequire;
exports.configs = configs;
exports.createNodeResolver = createNodeResolver;
exports.default = index;
exports.flatConfigs = flatConfigs;
exports.importXResolverCompat = importXResolverCompat;
exports.meta = meta;
exports.rules = rules;