eslint-plugin-mocha
Version:
Eslint rules for mocha.
85 lines • 3.84 kB
JavaScript
import { flatMapWithArgs, mapWithArgs } from "../list.js";
import { getUniqueBaseNames } from "../mocha/path.js";
import { isRecord } from "../record.js";
import { isConstantPath } from "./member-expression.js";
import { getParentNode } from "./node-types.js";
import { findParentNodeAndPathForIdentifier } from "./resolved-reference.js";
function isLiteralWithValue(node, expectedValue) {
return node.type === 'Literal' && (expectedValue === null || node.value === expectedValue);
}
function getFirstChildScope(scope) {
return scope?.childScopes[0];
}
function isImportSpecifierNode(node) {
return isRecord(node) &&
node.type === 'ImportSpecifier' &&
isRecord(node.imported) &&
typeof node.imported.name === 'string';
}
function isExclusiveNamedImportBindingWithMatchingSource(variable, expectedSource) {
const importDef = variable.defs[0];
const importNode = importDef?.node;
return (importDef?.type === 'ImportBinding' &&
isImportSpecifierNode(importNode) &&
isLiteralWithValue(importDef.parent.source, expectedSource));
}
function getAllNamedImportBindingVariables(moduleScope, expectedSource) {
return moduleScope.variables.filter(function (variable) {
return isExclusiveNamedImportBindingWithMatchingSource(variable, expectedSource);
});
}
function isNonAssignmentReference(reference) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- bad eslint core typings
const node = reference.identifier;
const parent = getParentNode(node);
return parent.type !== 'AssignmentExpression' ||
!Object.is(parent.left, node);
}
function isBindingConstant(variable) {
return variable.references.every(isNonAssignmentReference);
}
function replaceFirstSegment(path, replacement) {
if (isConstantPath(path)) {
const [firstSegment, ...remainingPath] = path;
if (firstSegment === undefined) {
return [replacement];
}
const suffix = firstSegment.endsWith('()') ? '()' : '';
return [`${replacement}${suffix}`, ...remainingPath];
}
return path;
}
function resolveImportPathWithOriginalName(reference, sourceCode, originalName) {
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -- bad eslint core typings
const { node, path } = findParentNodeAndPathForIdentifier(sourceCode, reference.identifier);
return {
node,
path,
resolvedPath: replaceFirstSegment(path, originalName)
};
}
function resolveReferencesForNamedImport(variable, sourceCode, identifierNames) {
const originalName = variable.defs[0].node.imported.name;
if (identifierNames.includes(originalName)) {
return mapWithArgs(variable.references, resolveImportPathWithOriginalName, sourceCode, originalName);
}
return [];
}
function processNamedImports(sourceCode, moduleScope, identifierNames, importSource) {
const namedImportVariables = getAllNamedImportBindingVariables(moduleScope, importSource);
const constantNamedImports = namedImportVariables.filter(isBindingConstant);
return flatMapWithArgs(constantNamedImports, resolveReferencesForNamedImport, sourceCode, identifierNames);
}
export function findImportReferencesByName(context, nameDetailsList, importSource) {
const { sourceCode } = context;
const { globalScope } = sourceCode.scopeManager;
const maybeModuleScope = getFirstChildScope(globalScope);
if (maybeModuleScope?.type !== 'module') {
return [];
}
const identifierNames = getUniqueBaseNames(nameDetailsList);
const moduleScope = maybeModuleScope;
const namedImportReferences = processNamedImports(sourceCode, moduleScope, identifierNames, importSource);
return namedImportReferences;
}
//# sourceMappingURL=find-import-references.js.map