@ec0lint/plugin-css
Version:
ec0lint plugin that provides rules to verify CSS definition objects
156 lines (155 loc) • 5.73 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractCallReferences = void 0;
const regexp_1 = require("./regexp");
const ast_utils_1 = require("./ast-utils");
class TargetPaths {
constructor(targetPaths) {
this.targets = [];
for (const paths of targetPaths) {
const [key, ...next] = paths.target;
this.targets.push({
tester: (0, regexp_1.toRegExp)(key),
next: next.length ? next : null,
define: paths.define,
});
}
}
consumePath(name) {
if (name == null) {
return this;
}
const next = [];
for (const target of this.targets) {
if (!target.tester.test(name)) {
continue;
}
if (target.next) {
next.push({
target: target.next,
define: target.define,
});
}
}
return next.length ? new TargetPaths(next) : null;
}
getTargetCallPaths(name) {
if (name == null) {
return [];
}
const paths = [];
for (const target of this.targets) {
if (!target.tester.test(name)) {
continue;
}
if (target.next) {
continue;
}
paths.push(target.define);
}
return paths;
}
}
function* extractCallReferences(node, functionPaths, context) {
const paths = new TargetPaths(functionPaths.map((define) => ({ define, target: define })));
for (const specifier of node.specifiers) {
const variable = (0, ast_utils_1.findVariable)(context, specifier.local);
if (!variable) {
continue;
}
if (specifier.type === "ImportDefaultSpecifier") {
yield* extractCallReferencesForVariable(variable, "default", paths, context);
}
else if (specifier.type === "ImportNamespaceSpecifier") {
yield* extractCallReferencesForVariable(variable, null, paths, context);
}
else if (specifier.type === "ImportSpecifier") {
yield* extractCallReferencesForVariable(variable, specifier.imported.name, paths, context);
}
}
}
exports.extractCallReferences = extractCallReferences;
function* extractCallReferencesForVariable(variable, name, paths, context) {
for (const reference of variable.references) {
if (!reference.isRead()) {
continue;
}
yield* extractCallReferencesForExpression(reference.identifier, name, paths, context);
}
}
function* extractCallReferencesForExpression(expression, name, paths, context) {
var _a;
let node = expression;
let parent = (0, ast_utils_1.getParent)(node);
while ((parent === null || parent === void 0 ? void 0 : parent.type) === "ChainExpression" ||
(parent === null || parent === void 0 ? void 0 : parent.type) === "TSNonNullExpression" ||
(parent === null || parent === void 0 ? void 0 : parent.type) === "TSAsExpression") {
node = parent;
parent = (0, ast_utils_1.getParent)(node);
}
if (!parent) {
return;
}
if (parent.type === "MemberExpression") {
if (parent.object === node) {
const nextPaths = paths.consumePath(name);
if (!nextPaths) {
return;
}
const memberName = (0, ast_utils_1.getPropertyName)(context, parent);
if (memberName == null) {
return;
}
yield* extractCallReferencesForExpression(parent, memberName, nextPaths, context);
}
}
else if (parent.type === "VariableDeclarator") {
if (parent.init === node &&
((_a = (0, ast_utils_1.getParent)(parent)) === null || _a === void 0 ? void 0 : _a.kind) === "const") {
yield* extractCallReferencesForPattern(parent.id, name, paths, context);
}
}
else if (parent.type === "CallExpression") {
const target = paths.getTargetCallPaths(name);
if (target.length) {
yield {
node: parent,
paths: target,
};
}
if (name) {
yield* extractCallReferencesForExpression(parent, `${name}()`, paths, context);
}
}
}
function* extractCallReferencesForPattern(pattern, name, paths, context) {
let target = pattern;
while (target.type === "AssignmentPattern") {
target = target.left;
}
if (target.type === "Identifier") {
const variable = (0, ast_utils_1.findVariable)(context, target);
if (!variable) {
return;
}
yield* extractCallReferencesForVariable(variable, name, paths, context);
}
else if (target.type === "ObjectPattern") {
for (const prop of target.properties) {
if (prop.type === "Property") {
const nextPaths = paths.consumePath(name);
if (!nextPaths) {
continue;
}
const propName = (0, ast_utils_1.getPropertyName)(context, prop);
if (propName == null) {
continue;
}
yield* extractCallReferencesForPattern(prop.value, propName, paths, context);
}
else if (prop.type === "RestElement") {
yield* extractCallReferencesForPattern(prop.argument, name, paths, context);
}
}
}
}