first commit
This commit is contained in:
754
node_modules/eslint-plugin-import-x/lib/rules/no-unused-modules.js
generated
vendored
Normal file
754
node_modules/eslint-plugin-import-x/lib/rules/no-unused-modules.js
generated
vendored
Normal file
@@ -0,0 +1,754 @@
|
||||
import path from 'node:path';
|
||||
import { TSESTree } from '@typescript-eslint/types';
|
||||
import eslintUnsupportedApi from 'eslint/use-at-your-own-risk';
|
||||
import { ExportMap, recursivePatternCapture, createRule, resolve, getFileExtensions, readPkgUp, visit, getValue, } from '../utils/index.js';
|
||||
const { FileEnumerator, shouldUseFlatConfig } = eslintUnsupportedApi;
|
||||
function listFilesUsingFileEnumerator(src, extensions) {
|
||||
const { ESLINT_USE_FLAT_CONFIG } = process.env;
|
||||
let isUsingFlatConfig;
|
||||
try {
|
||||
isUsingFlatConfig =
|
||||
shouldUseFlatConfig && ESLINT_USE_FLAT_CONFIG !== 'false';
|
||||
}
|
||||
catch {
|
||||
isUsingFlatConfig =
|
||||
!!ESLINT_USE_FLAT_CONFIG && ESLINT_USE_FLAT_CONFIG !== 'false';
|
||||
}
|
||||
const enumerator = new FileEnumerator({ extensions });
|
||||
try {
|
||||
return Array.from(enumerator.iterateFiles(src), ({ filePath, ignored }) => ({ filename: filePath, ignored }));
|
||||
}
|
||||
catch (error) {
|
||||
if (isUsingFlatConfig &&
|
||||
error.message.includes('No ESLint configuration found')) {
|
||||
throw new Error(`
|
||||
Due to the exclusion of certain internal ESLint APIs when using flat config,
|
||||
the import-x/no-unused-modules rule requires an .eslintrc file (even empty) to know which
|
||||
files to ignore (even when using flat config).
|
||||
The .eslintrc file only needs to contain "ignorePatterns", or can be empty if
|
||||
you do not want to ignore any files.
|
||||
|
||||
See https://github.com/import-js/eslint-plugin-import/issues/3079
|
||||
for additional context.
|
||||
`);
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
const DEFAULT = 'default';
|
||||
const { AST_NODE_TYPES } = 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?.type === AST_NODE_TYPES.Identifier) {
|
||||
cb(el.name, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
cb(id.name, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const importList = new Map();
|
||||
const exportList = new Map();
|
||||
const visitorKeyMap = new Map();
|
||||
const ignoredFiles = new Set();
|
||||
const filesOutsideSrc = new Set();
|
||||
const isNodeModule = (path) => /([/\\])(node_modules)\1/.test(path);
|
||||
const resolveFiles = (src, ignoreExports, context) => {
|
||||
const extensions = [...getFileExtensions(context.settings)];
|
||||
const srcFileList = listFilesUsingFileEnumerator(src, extensions);
|
||||
const ignoredFilesList = listFilesUsingFileEnumerator(ignoreExports, extensions);
|
||||
for (const { filename } of ignoredFilesList)
|
||||
ignoredFiles.add(filename);
|
||||
return new Set(srcFileList.flatMap(({ filename }) => isNodeModule(filename) ? [] : filename));
|
||||
};
|
||||
const prepareImportsAndExports = (srcFiles, context) => {
|
||||
const exportAll = new Map();
|
||||
for (const file of srcFiles) {
|
||||
const exports = new Map();
|
||||
const imports = new Map();
|
||||
const currentExports = ExportMap.get(file, context);
|
||||
if (currentExports) {
|
||||
const { dependencies, reexports, imports: localImportList, namespace, visitorKeys, } = currentExports;
|
||||
visitorKeyMap.set(file, visitorKeys);
|
||||
const currentExportAll = 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: new Set(),
|
||||
});
|
||||
}
|
||||
else {
|
||||
exports.set(key, { whereUsed: 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 === undefined
|
||||
? new Set([currentValue])
|
||||
: 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) || 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: new Set(),
|
||||
});
|
||||
}
|
||||
else {
|
||||
exports.set(key, { whereUsed: new Set() });
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.set(AST_NODE_TYPES.ExportAllDeclaration, {
|
||||
whereUsed: new Set(),
|
||||
});
|
||||
exports.set(AST_NODE_TYPES.ImportNamespaceSpecifier, {
|
||||
whereUsed: 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 !== undefined) {
|
||||
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 !== undefined) {
|
||||
const exportStatement = exports.get(specifier);
|
||||
if (exportStatement !== undefined) {
|
||||
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;
|
||||
};
|
||||
export default 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) => {
|
||||
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: node.body[0] ?? 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 !== undefined &&
|
||||
exportedValue !== AST_NODE_TYPES.ImportDefaultSpecifier &&
|
||||
exportAll.whereUsed.size > 0) {
|
||||
return;
|
||||
}
|
||||
const namespaceImports = exports.get(AST_NODE_TYPES.ImportNamespaceSpecifier);
|
||||
if (namespaceImports !== undefined &&
|
||||
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 === undefined) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'unused',
|
||||
data: {
|
||||
value,
|
||||
},
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (exportStatement.whereUsed.size === 0) {
|
||||
context.report({
|
||||
node,
|
||||
messageId: 'unused',
|
||||
data: {
|
||||
value,
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
const updateExportUsage = (node) => {
|
||||
if (ignoredFiles.has(filename)) {
|
||||
return;
|
||||
}
|
||||
const exports = exportList.get(filename) ??
|
||||
new Map();
|
||||
const newExports = new Map();
|
||||
const newExportIdentifiers = 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: new Set() });
|
||||
}
|
||||
}
|
||||
const exportAll = exports.get(AST_NODE_TYPES.ExportAllDeclaration);
|
||||
const namespaceImports = exports.get(AST_NODE_TYPES.ImportNamespaceSpecifier) ?? { whereUsed: new Set() };
|
||||
newExports.set(AST_NODE_TYPES.ExportAllDeclaration, exportAll);
|
||||
newExports.set(AST_NODE_TYPES.ImportNamespaceSpecifier, namespaceImports);
|
||||
exportList.set(filename, newExports);
|
||||
};
|
||||
const updateImportUsage = (node) => {
|
||||
if (!unusedExports) {
|
||||
return;
|
||||
}
|
||||
const oldImportPaths = importList.get(filename) ?? new Map();
|
||||
const oldNamespaceImports = new Set();
|
||||
const newNamespaceImports = new Set();
|
||||
const oldExportAll = new Set();
|
||||
const newExportAll = new Set();
|
||||
const oldDefaultImports = new Set();
|
||||
const newDefaultImports = new Set();
|
||||
const oldImports = new Map();
|
||||
const newImports = 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(specifier => specifier.type !== AST_NODE_TYPES.ImportDefaultSpecifier &&
|
||||
specifier.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 = oldImportPaths.get(value) ?? new Set();
|
||||
imports.add(AST_NODE_TYPES.ExportAllDeclaration);
|
||||
oldImportPaths.set(value, imports);
|
||||
let exports = exportList.get(value);
|
||||
let currentExport;
|
||||
if (exports === undefined) {
|
||||
exports = new Map();
|
||||
exportList.set(value, exports);
|
||||
}
|
||||
else {
|
||||
currentExport = exports.get(AST_NODE_TYPES.ExportAllDeclaration);
|
||||
}
|
||||
if (currentExport === undefined) {
|
||||
const whereUsed = 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 !== undefined) {
|
||||
const currentExport = exports.get(AST_NODE_TYPES.ExportAllDeclaration);
|
||||
if (currentExport !== undefined) {
|
||||
currentExport.whereUsed.delete(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const value of newDefaultImports) {
|
||||
if (!oldDefaultImports.has(value)) {
|
||||
let imports = oldImportPaths.get(value);
|
||||
if (imports === undefined) {
|
||||
imports = new Set();
|
||||
}
|
||||
imports.add(AST_NODE_TYPES.ImportDefaultSpecifier);
|
||||
oldImportPaths.set(value, imports);
|
||||
let exports = exportList.get(value);
|
||||
let currentExport;
|
||||
if (exports === undefined) {
|
||||
exports = new Map();
|
||||
exportList.set(value, exports);
|
||||
}
|
||||
else {
|
||||
currentExport = exports.get(AST_NODE_TYPES.ImportDefaultSpecifier);
|
||||
}
|
||||
if (currentExport === undefined) {
|
||||
const whereUsed = 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 !== undefined) {
|
||||
const currentExport = exports.get(AST_NODE_TYPES.ImportDefaultSpecifier);
|
||||
if (currentExport !== undefined) {
|
||||
currentExport.whereUsed.delete(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const value of newNamespaceImports) {
|
||||
if (!oldNamespaceImports.has(value)) {
|
||||
let imports = oldImportPaths.get(value);
|
||||
if (imports === undefined) {
|
||||
imports = new Set();
|
||||
}
|
||||
imports.add(AST_NODE_TYPES.ImportNamespaceSpecifier);
|
||||
oldImportPaths.set(value, imports);
|
||||
let exports = exportList.get(value);
|
||||
let currentExport;
|
||||
if (exports === undefined) {
|
||||
exports = new Map();
|
||||
exportList.set(value, exports);
|
||||
}
|
||||
else {
|
||||
currentExport = exports.get(AST_NODE_TYPES.ImportNamespaceSpecifier);
|
||||
}
|
||||
if (currentExport === undefined) {
|
||||
const whereUsed = 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 !== undefined) {
|
||||
const currentExport = exports.get(AST_NODE_TYPES.ImportNamespaceSpecifier);
|
||||
if (currentExport !== undefined) {
|
||||
currentExport.whereUsed.delete(filename);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const [key, value] of newImports.entries()) {
|
||||
if (!oldImports.has(key)) {
|
||||
let imports = oldImportPaths.get(value);
|
||||
if (imports === undefined) {
|
||||
imports = new Set();
|
||||
}
|
||||
imports.add(key);
|
||||
oldImportPaths.set(value, imports);
|
||||
let exports = exportList.get(value);
|
||||
let currentExport;
|
||||
if (exports === undefined) {
|
||||
exports = new Map();
|
||||
exportList.set(value, exports);
|
||||
}
|
||||
else {
|
||||
currentExport = exports.get(key);
|
||||
}
|
||||
if (currentExport === undefined) {
|
||||
const whereUsed = 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 !== undefined) {
|
||||
const currentExport = exports.get(key);
|
||||
if (currentExport !== undefined) {
|
||||
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);
|
||||
});
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
//# sourceMappingURL=no-unused-modules.js.map
|
||||
Reference in New Issue
Block a user