UNPKG

eslint-plugin-regexp

Version:

ESLint plugin for finding RegExp mistakes and RegExp style guide violations.

233 lines (232 loc) 8.28 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.extractPropertyReferencesForPattern = exports.extractPropertyReferences = void 0; const extract_expression_references_1 = require("./extract-expression-references"); const utils_1 = require("./utils"); function* extractPropertyReferences(node, context) { if (isShallowCopy(node)) { yield* iteratePropertyReferencesForShallowCopy(node, context); return; } for (const ref of (0, extract_expression_references_1.extractExpressionReferences)(node, context)) { if (ref.type === "member") { yield* iteratePropertyReferencesForMemberExpression(ref.memberExpression, context); } else if (ref.type === "destructuring") { yield* iteratePropertyReferencesForPattern(ref.pattern, context); } else if (ref.type === "iteration") { yield* iteratePropertyReferencesForForOf(ref.for, context); } else { if (ref.node !== node && isShallowCopy(ref.node)) { yield* iteratePropertyReferencesForShallowCopy(ref.node, context); return; } yield { type: "unknown", node: ref.node }; } } } exports.extractPropertyReferences = extractPropertyReferences; function* extractPropertyReferencesForPattern(node, context) { yield* iteratePropertyReferencesForPattern(node, context); } exports.extractPropertyReferencesForPattern = extractPropertyReferencesForPattern; function isShallowCopy(node) { const parent = (0, utils_1.getParent)(node); if ((parent === null || parent === void 0 ? void 0 : parent.type) === "SpreadElement") { const spreadParent = (0, utils_1.getParent)(parent); if ((spreadParent === null || spreadParent === void 0 ? void 0 : spreadParent.type) === "ObjectExpression" || (spreadParent === null || spreadParent === void 0 ? void 0 : spreadParent.type) === "ArrayExpression") { return true; } } return false; } function* iteratePropertyReferencesForMemberExpression(node, context) { const property = getProperty(node, context); if (property == null) { yield { type: "unknown", node, *extractPropertyReferences() { yield* extractPropertyReferences(node, context); }, }; return; } yield { type: "member", name: property, node, *extractPropertyReferences() { yield* extractPropertyReferences(node, context); }, }; } function* iteratePropertyReferencesForObjectPattern(node, context) { for (const prop of node.properties) { if (prop.type === "RestElement") { yield* iteratePropertyReferencesForPattern(prop.argument, context); continue; } const property = getProperty(prop, context); if (property == null) { yield { type: "unknown", node, *extractPropertyReferences() { yield* iteratePropertyReferencesForPattern(prop.value, context); }, }; continue; } yield { type: "destructuring", name: property, node: prop, *extractPropertyReferences() { yield* iteratePropertyReferencesForPattern(prop.value, context); }, }; } } function* iteratePropertyReferencesForArrayPattern(node, context) { let index = 0; for (; index < node.elements.length; index++) { const element = node.elements[index]; if (!element) { continue; } if (element.type === "RestElement") { for (const ref of iteratePropertyReferencesForPattern(element.argument, context)) { yield offsetRef(ref, index); } index++; break; } yield { type: "destructuring", name: String(index), node: element, *extractPropertyReferences() { yield* iteratePropertyReferencesForPattern(element, context); }, }; } for (; index < node.elements.length; index++) { const element = node.elements[index]; if (!element) { continue; } yield { type: "unknown", node: element, *extractPropertyReferences() { yield* iteratePropertyReferencesForPattern(element, context); }, }; } } function* iteratePropertyReferencesForForOf(node, context) { yield { type: "iteration", node, *extractPropertyReferences() { let left = node.left; if (left.type === "VariableDeclaration") { left = left.declarations[0].id; } yield* iteratePropertyReferencesForPattern(left, context); }, }; } function* iteratePropertyReferencesForPattern(node, context) { let target = node; while (target.type === "AssignmentPattern") { target = target.left; } if (target.type === "Identifier") { for (const exprRef of (0, extract_expression_references_1.extractExpressionReferencesForVariable)(target, context)) { yield* extractPropertyReferences(exprRef.node, context); } } else if (target.type === "ObjectPattern") { yield* iteratePropertyReferencesForObjectPattern(target, context); } else if (target.type === "ArrayPattern") { yield* iteratePropertyReferencesForArrayPattern(target, context); } else { yield { type: "unknown", node: target }; } } function* iteratePropertyReferencesForShallowCopy(node, context) { const spread = node.parent; const spreadParent = spread.parent; if (spreadParent.type === "ObjectExpression") { yield* extractPropertyReferences(spreadParent, context); } else if (spreadParent.type === "ArrayExpression") { const index = spreadParent.elements.indexOf(spread); if (index === 0) { yield* extractPropertyReferences(spreadParent, context); return; } const hasSpread = spreadParent.elements .slice(0, index) .some((e) => (e === null || e === void 0 ? void 0 : e.type) === "SpreadElement"); if (hasSpread) { for (const ref of extractPropertyReferences(spreadParent, context)) { yield { type: "unknown", node: ref.node, extractPropertyReferences: ref.extractPropertyReferences, }; } } else { for (const ref of extractPropertyReferences(spreadParent, context)) { yield offsetRef(ref, -index); } } } } function getProperty(node, context) { if (node.type === "MemberExpression") { if (node.computed) { if (node.property.type === "Literal") { if (typeof node.property.value === "string" || typeof node.property.value === "number") return String(node.property.value); } return (0, utils_1.getStringIfConstant)(context, node.property); } else if (node.property.type === "Identifier") { return node.property.name; } } if (node.type === "Property") { if (node.key.type === "Literal") { if (typeof node.key.value === "string" || typeof node.key.value === "number") return String(node.key.value); } if (node.computed) { return (0, utils_1.getStringIfConstant)(context, node.key); } else if (node.key.type === "Identifier") { return node.key.name; } } return null; } function offsetRef(ref, offset) { if (ref.type === "member" || ref.type === "destructuring") { const num = Number(ref.name) + offset; if (!Number.isNaN(num)) { return Object.assign(Object.assign({}, ref), { name: String(num) }); } } return ref; }