pasika 0.10.74 → 0.10.76
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/eslint/pasika/index.js +143 -1
- package/package.json +1 -1
|
@@ -6092,6 +6092,86 @@ function directPropertyBinding(context, declarator) {
|
|
|
6092
6092
|
function canGroupSource(source) {
|
|
6093
6093
|
return source.type === "Identifier" || source.type === "ThisExpression";
|
|
6094
6094
|
}
|
|
6095
|
+
function isStableObjectSource(source) {
|
|
6096
|
+
if (source.type === "Identifier" || source.type === "ThisExpression") return true;
|
|
6097
|
+
if (source.type !== "MemberExpression") return false;
|
|
6098
|
+
if (source.computed || source.optional || source.property.type !== "Identifier") return false;
|
|
6099
|
+
return isStableObjectSource(source.object);
|
|
6100
|
+
}
|
|
6101
|
+
function objectUsage(scope, sourceText) {
|
|
6102
|
+
let usage = scope.objects.get(sourceText);
|
|
6103
|
+
if (!usage) {
|
|
6104
|
+
usage = { propertyNames: /* @__PURE__ */ new Set(), directMembers: [] };
|
|
6105
|
+
scope.objects.set(sourceText, usage);
|
|
6106
|
+
}
|
|
6107
|
+
return usage;
|
|
6108
|
+
}
|
|
6109
|
+
function memberIsRead(context, member) {
|
|
6110
|
+
const parent = context.sourceCode.getAncestors(member).at(-1);
|
|
6111
|
+
if (!parent) return true;
|
|
6112
|
+
if (parent.type === "AssignmentExpression" && parent.left === member) return false;
|
|
6113
|
+
if (parent.type === "UpdateExpression" && parent.argument === member) return false;
|
|
6114
|
+
if (parent.type === "UnaryExpression" && parent.operator === "delete" && parent.argument === member) return false;
|
|
6115
|
+
if ((parent.type === "ForInStatement" || parent.type === "ForOfStatement") && parent.left === member) return false;
|
|
6116
|
+
if ((parent.type === "CallExpression" || parent.type === "NewExpression") && parent.callee === member) return false;
|
|
6117
|
+
if (parent.type === "TaggedTemplateExpression" && parent.tag === member) return false;
|
|
6118
|
+
return true;
|
|
6119
|
+
}
|
|
6120
|
+
function memberIsDirectVariableInitializer(context, member) {
|
|
6121
|
+
const parent = context.sourceCode.getAncestors(member).at(-1);
|
|
6122
|
+
return parent?.type === "VariableDeclarator" && parent.init === member;
|
|
6123
|
+
}
|
|
6124
|
+
function recordMemberUsage(context, scope, member) {
|
|
6125
|
+
if (!scope || member.computed || member.optional || member.property.type !== "Identifier") return;
|
|
6126
|
+
if (!isStableObjectSource(member.object) || !memberIsRead(context, member)) return;
|
|
6127
|
+
const sourceText = context.sourceCode.getText(member.object);
|
|
6128
|
+
const usage = objectUsage(scope, sourceText);
|
|
6129
|
+
const propertyName5 = member.property.name;
|
|
6130
|
+
usage.propertyNames.add(propertyName5);
|
|
6131
|
+
if (!memberIsDirectVariableInitializer(context, member)) {
|
|
6132
|
+
usage.directMembers.push({ member, propertyName: propertyName5 });
|
|
6133
|
+
}
|
|
6134
|
+
}
|
|
6135
|
+
function recordDestructuringUsage(context, scope, declaration) {
|
|
6136
|
+
if (!scope) return;
|
|
6137
|
+
for (const declarator of declaration.declarations) {
|
|
6138
|
+
if (declarator.id.type !== "ObjectPattern" || !declarator.init || !isStableObjectSource(declarator.init)) continue;
|
|
6139
|
+
const sourceText = context.sourceCode.getText(declarator.init);
|
|
6140
|
+
const usage = objectUsage(scope, sourceText);
|
|
6141
|
+
const propertyNames = /* @__PURE__ */ new Set();
|
|
6142
|
+
for (const property of declarator.id.properties) {
|
|
6143
|
+
if (property.type !== "Property" || property.computed || property.key.type !== "Identifier") continue;
|
|
6144
|
+
propertyNames.add(property.key.name);
|
|
6145
|
+
usage.propertyNames.add(property.key.name);
|
|
6146
|
+
}
|
|
6147
|
+
usage.destructuring ??= { pattern: declarator.id, propertyNames };
|
|
6148
|
+
}
|
|
6149
|
+
}
|
|
6150
|
+
function scopeUsageMessage(sourceText, propertyNames) {
|
|
6151
|
+
const names = [...propertyNames].map((name) => `"${name}"`).join(", ");
|
|
6152
|
+
return `${names} are read from "${sourceText}" in the same block. Destructure them together in one declaration. ${DOC5}`;
|
|
6153
|
+
}
|
|
6154
|
+
function hasBinding(context, node, name) {
|
|
6155
|
+
const initialScope = context.sourceCode.getScope(node);
|
|
6156
|
+
if (initialScope.variables.some((variable) => variable.name === name)) return true;
|
|
6157
|
+
for (let scope = initialScope.upper; scope !== null; scope = scope.upper) {
|
|
6158
|
+
if (scope.variables.some((variable) => variable.name === name)) return true;
|
|
6159
|
+
}
|
|
6160
|
+
return false;
|
|
6161
|
+
}
|
|
6162
|
+
function containingStatement(context, scopeNode, node) {
|
|
6163
|
+
if (scopeNode.type !== "Program" && scopeNode.type !== "BlockStatement") return void 0;
|
|
6164
|
+
const [nodeStart, nodeEnd] = context.sourceCode.getRange(node);
|
|
6165
|
+
return scopeNode.body.find((statement) => {
|
|
6166
|
+
const [statementStart, statementEnd] = context.sourceCode.getRange(statement);
|
|
6167
|
+
return statementStart <= nodeStart && statementEnd >= nodeEnd;
|
|
6168
|
+
});
|
|
6169
|
+
}
|
|
6170
|
+
function statementIndentation(context, statement) {
|
|
6171
|
+
const [start] = context.sourceCode.getRange(statement);
|
|
6172
|
+
const lineStart = context.sourceCode.text.lastIndexOf("\n", start - 1) + 1;
|
|
6173
|
+
return context.sourceCode.text.slice(lineStart, start);
|
|
6174
|
+
}
|
|
6095
6175
|
function whitespaceKeepsStatementsAdjacent(text) {
|
|
6096
6176
|
if (text.trim() !== "") return false;
|
|
6097
6177
|
return (text.match(/\n/gu) ?? []).length <= 1;
|
|
@@ -6202,13 +6282,75 @@ var preferObjectDestructuringRule = {
|
|
|
6202
6282
|
type: "problem",
|
|
6203
6283
|
fixable: "code",
|
|
6204
6284
|
docs: {
|
|
6205
|
-
description: "Require
|
|
6285
|
+
description: "Require related object-property reads to use one object destructuring declaration."
|
|
6206
6286
|
}
|
|
6207
6287
|
},
|
|
6208
6288
|
create(context) {
|
|
6209
6289
|
const grouped = /* @__PURE__ */ new Set();
|
|
6290
|
+
const usageScopes = [];
|
|
6291
|
+
const currentUsageScope = () => usageScopes.at(-1);
|
|
6292
|
+
const enterUsageScope = (node) => {
|
|
6293
|
+
usageScopes.push({ node, objects: /* @__PURE__ */ new Map() });
|
|
6294
|
+
};
|
|
6295
|
+
const exitUsageScope = () => {
|
|
6296
|
+
const scope = usageScopes.pop();
|
|
6297
|
+
if (!scope) return;
|
|
6298
|
+
for (const [sourceText, usage] of scope.objects) {
|
|
6299
|
+
if (usage.propertyNames.size < 2 || usage.directMembers.length === 0) continue;
|
|
6300
|
+
const firstDirectUsage = usage.directMembers[0];
|
|
6301
|
+
if (!firstDirectUsage) continue;
|
|
6302
|
+
const { member: firstDirectMember } = firstDirectUsage;
|
|
6303
|
+
context.report({
|
|
6304
|
+
node: firstDirectMember,
|
|
6305
|
+
message: scopeUsageMessage(sourceText, usage.propertyNames),
|
|
6306
|
+
fix(fixer) {
|
|
6307
|
+
const propertyNames = [...usage.propertyNames];
|
|
6308
|
+
const missingPropertyNames = propertyNames.filter(
|
|
6309
|
+
(propertyName5) => !usage.destructuring?.propertyNames.has(propertyName5)
|
|
6310
|
+
);
|
|
6311
|
+
if (missingPropertyNames.some((propertyName5) => hasBinding(context, firstDirectMember, propertyName5))) {
|
|
6312
|
+
return null;
|
|
6313
|
+
}
|
|
6314
|
+
const memberFixes = usage.directMembers.map(
|
|
6315
|
+
({ member, propertyName: propertyName5 }) => fixer.replaceText(member, propertyName5)
|
|
6316
|
+
);
|
|
6317
|
+
if (usage.destructuring) {
|
|
6318
|
+
if (missingPropertyNames.length === 0) return memberFixes;
|
|
6319
|
+
const patternText = context.sourceCode.getText(usage.destructuring.pattern);
|
|
6320
|
+
const closeIndex = patternText.lastIndexOf("}");
|
|
6321
|
+
const beforeClose = patternText.slice(0, closeIndex);
|
|
6322
|
+
const contentEnd = beforeClose.trimEnd().length;
|
|
6323
|
+
const trailingWhitespace = beforeClose.slice(contentEnd);
|
|
6324
|
+
const separator = usage.destructuring.propertyNames.size > 0 ? ", " : "";
|
|
6325
|
+
const replacement = `${beforeClose.slice(0, contentEnd)}${separator}${missingPropertyNames.join(", ")}${trailingWhitespace}${patternText.slice(closeIndex)}`;
|
|
6326
|
+
return [fixer.replaceText(usage.destructuring.pattern, replacement), ...memberFixes];
|
|
6327
|
+
}
|
|
6328
|
+
const statement = containingStatement(context, scope.node, firstDirectMember);
|
|
6329
|
+
if (!statement) return null;
|
|
6330
|
+
const indentation = statementIndentation(context, statement);
|
|
6331
|
+
const declaration = `const { ${propertyNames.join(", ")} } = ${sourceText};
|
|
6332
|
+
${indentation}`;
|
|
6333
|
+
return [fixer.insertTextBefore(statement, declaration), ...memberFixes];
|
|
6334
|
+
}
|
|
6335
|
+
});
|
|
6336
|
+
}
|
|
6337
|
+
};
|
|
6210
6338
|
return {
|
|
6339
|
+
Program: enterUsageScope,
|
|
6340
|
+
"Program:exit": exitUsageScope,
|
|
6341
|
+
BlockStatement: enterUsageScope,
|
|
6342
|
+
"BlockStatement:exit": exitUsageScope,
|
|
6343
|
+
FunctionDeclaration: enterUsageScope,
|
|
6344
|
+
"FunctionDeclaration:exit": exitUsageScope,
|
|
6345
|
+
FunctionExpression: enterUsageScope,
|
|
6346
|
+
"FunctionExpression:exit": exitUsageScope,
|
|
6347
|
+
ArrowFunctionExpression: enterUsageScope,
|
|
6348
|
+
"ArrowFunctionExpression:exit": exitUsageScope,
|
|
6349
|
+
MemberExpression(node) {
|
|
6350
|
+
recordMemberUsage(context, currentUsageScope(), node);
|
|
6351
|
+
},
|
|
6211
6352
|
VariableDeclaration(node) {
|
|
6353
|
+
recordDestructuringUsage(context, currentUsageScope(), node);
|
|
6212
6354
|
if (grouped.has(node)) return;
|
|
6213
6355
|
const selection = destructuringSelection(context, node);
|
|
6214
6356
|
if (selection) {
|