eslint-plugin-regexp
Version:
ESLint plugin for finding RegExp mistakes and RegExp style guide violations.
233 lines (232 loc) • 8.28 kB
JavaScript
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;
}
;