UNPKG

@ec0lint/plugin-css

Version:

ec0lint plugin that provides rules to verify CSS definition objects

156 lines (155 loc) 5.73 kB
"use strict"; 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); } } } }