Website Structure

This commit is contained in:
supalerk-ar66 2026-01-13 10:46:40 +07:00
parent 62812f2090
commit 71f0676a62
22365 changed files with 4265753 additions and 791 deletions

View file

@ -0,0 +1,33 @@
import type { Rule } from "eslint";
import type { ArrayPattern, CallExpression, Expression, ForOfStatement, Identifier, MemberExpression, ObjectPattern } from "estree";
export type ExpressionReference = {
type: "unused";
node: Expression;
} | {
type: "unknown";
node: Expression;
} | {
type: "exported";
node: Expression;
} | {
type: "member";
node: Expression;
memberExpression: MemberExpression;
} | {
type: "destructuring";
node: Expression;
pattern: ObjectPattern | ArrayPattern;
} | {
type: "argument";
node: Expression;
callExpression: CallExpression;
} | {
type: "call";
node: Expression;
} | {
type: "iteration";
node: Expression;
for: ForOfStatement;
};
export declare function extractExpressionReferences(node: Expression, context: Rule.RuleContext): Iterable<ExpressionReference>;
export declare function extractExpressionReferencesForVariable(node: Identifier, context: Rule.RuleContext): Iterable<ExpressionReference>;

View file

@ -0,0 +1,171 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractExpressionReferences = extractExpressionReferences;
exports.extractExpressionReferencesForVariable = extractExpressionReferencesForVariable;
const utils_1 = require("./utils");
function* extractExpressionReferences(node, context) {
yield* iterateReferencesForExpression(node, context, {
variables: new Set(),
functions: new Map(),
});
}
function* extractExpressionReferencesForVariable(node, context) {
yield* iterateReferencesForVariable(node, context, {
variables: new Set(),
functions: new Map(),
});
}
function* iterateReferencesForExpression(expression, context, alreadyChecked) {
let node = expression;
let parent = (0, 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, utils_1.getParent)(node);
}
if (!parent || parent.type === "ExpressionStatement") {
yield { node, type: "unused" };
return;
}
if (parent.type === "MemberExpression") {
if (parent.object === node) {
yield { node, type: "member", memberExpression: parent };
}
else {
yield { node, type: "unknown" };
}
}
else if (parent.type === "AssignmentExpression") {
if (parent.right === node && parent.operator === "=") {
yield* iterateReferencesForESPattern(node, parent.left, context, alreadyChecked);
}
else {
yield { node, type: "unknown" };
}
}
else if (parent.type === "VariableDeclarator") {
if (parent.init === node) {
const pp = (0, utils_1.getParent)((0, utils_1.getParent)(parent));
if ((pp === null || pp === void 0 ? void 0 : pp.type) === "ExportNamedDeclaration") {
yield { node, type: "exported" };
}
yield* iterateReferencesForESPattern(node, parent.id, context, alreadyChecked);
}
else {
yield { node, type: "unknown" };
}
}
else if (parent.type === "CallExpression") {
const argIndex = parent.arguments.indexOf(node);
if (argIndex > -1) {
if (parent.callee.type === "Identifier") {
const fn = (0, utils_1.findFunction)(context, parent.callee);
if (fn) {
yield* iterateReferencesForFunctionArgument(node, fn, argIndex, context, alreadyChecked);
return;
}
}
yield { node, type: "argument", callExpression: parent };
}
else {
yield { node, type: "call" };
}
}
else if (parent.type === "ExportSpecifier" ||
parent.type === "ExportDefaultDeclaration") {
yield { node, type: "exported" };
}
else if (parent.type === "ForOfStatement") {
if (parent.right === node) {
yield { node, type: "iteration", for: parent };
}
else {
yield { node, type: "unknown" };
}
}
else if (parent.type === "IfStatement" ||
parent.type === "ConditionalExpression" ||
parent.type === "LogicalExpression" ||
parent.type === "UnaryExpression") {
if (isUsedInTest(parent, node)) {
}
else {
yield { node, type: "unknown" };
}
}
else {
yield { node, type: "unknown" };
}
}
function isUsedInTest(parent, node) {
if (parent.type === "IfStatement") {
return parent.test === node;
}
if (parent.type === "ConditionalExpression") {
return parent.test === node;
}
if (parent.type === "LogicalExpression") {
return parent.operator === "&&" && parent.left === node;
}
if (parent.type === "UnaryExpression") {
return parent.operator === "!" && parent.argument === node;
}
return false;
}
function* iterateReferencesForESPattern(expression, pattern, context, alreadyChecked) {
let target = pattern;
while (target.type === "AssignmentPattern") {
target = target.left;
}
if (target.type === "Identifier") {
yield* iterateReferencesForVariable(target, context, alreadyChecked);
}
else if (target.type === "ObjectPattern" ||
target.type === "ArrayPattern") {
yield { node: expression, type: "destructuring", pattern: target };
}
else {
yield { node: expression, type: "unknown" };
}
}
function* iterateReferencesForVariable(identifier, context, alreadyChecked) {
const variable = (0, utils_1.findVariable)(context, identifier);
if (!variable) {
yield { node: identifier, type: "unknown" };
return;
}
if (alreadyChecked.variables.has(variable)) {
return;
}
alreadyChecked.variables.add(variable);
if (variable.eslintUsed) {
yield { node: identifier, type: "exported" };
}
const readReferences = variable.references.filter((ref) => ref.isRead());
if (!readReferences.length) {
yield { node: identifier, type: "unused" };
return;
}
for (const reference of readReferences) {
yield* iterateReferencesForExpression(reference.identifier, context, alreadyChecked);
}
}
function* iterateReferencesForFunctionArgument(expression, fn, argIndex, context, alreadyChecked) {
let alreadyIndexes = alreadyChecked.functions.get(fn);
if (!alreadyIndexes) {
alreadyIndexes = new Set();
alreadyChecked.functions.set(fn, alreadyIndexes);
}
if (alreadyIndexes.has(argIndex)) {
return;
}
alreadyIndexes.add(argIndex);
const params = fn.params.slice(0, argIndex + 1);
const argNode = params[argIndex];
if (!argNode || params.some((param) => (param === null || param === void 0 ? void 0 : param.type) === "RestElement")) {
yield { node: expression, type: "unknown" };
return;
}
yield* iterateReferencesForESPattern(expression, argNode, context, alreadyChecked);
}

View file

@ -0,0 +1,23 @@
import type { Rule } from "eslint";
import type { ForOfStatement, AssignmentProperty, Expression, MemberExpression, Pattern } from "estree";
export type PropertyReference = {
type: "unknown";
node: Pattern | AssignmentProperty | Expression | ForOfStatement;
extractPropertyReferences?: () => Iterable<PropertyReference>;
} | {
type: "member";
name: string;
node: MemberExpression;
extractPropertyReferences: () => Iterable<PropertyReference>;
} | {
type: "destructuring";
name: string;
node: AssignmentProperty | Pattern;
extractPropertyReferences: () => Iterable<PropertyReference>;
} | {
type: "iteration";
node: ForOfStatement;
extractPropertyReferences: () => Iterable<PropertyReference>;
};
export declare function extractPropertyReferences(node: Expression, context: Rule.RuleContext): Iterable<PropertyReference>;
export declare function extractPropertyReferencesForPattern(node: Pattern, context: Rule.RuleContext): Iterable<PropertyReference>;

View file

@ -0,0 +1,231 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractPropertyReferences = extractPropertyReferences;
exports.extractPropertyReferencesForPattern = extractPropertyReferencesForPattern;
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 };
}
}
}
function* extractPropertyReferencesForPattern(node, context) {
yield* iteratePropertyReferencesForPattern(node, context);
}
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 { ...ref, name: String(num) };
}
}
return ref;
}

View file

@ -0,0 +1,7 @@
export { getParent, findVariable, getStringIfConstant, getStaticValue, getScope, isKnownMethodCall, parseReplacements, } from "./utils";
export type { KnownMethodCall, ReferenceElement } from "./utils";
export { extractExpressionReferences } from "./extract-expression-references";
export type { ExpressionReference } from "./extract-expression-references";
export { extractPropertyReferences } from "./extract-property-references";
export * from "./regex";
export type { PropertyReference } from "./extract-property-references";

View file

@ -0,0 +1,30 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __exportStar = (this && this.__exportStar) || function(m, exports) {
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractPropertyReferences = exports.extractExpressionReferences = exports.parseReplacements = exports.isKnownMethodCall = exports.getScope = exports.getStaticValue = exports.getStringIfConstant = exports.findVariable = exports.getParent = void 0;
var utils_1 = require("./utils");
Object.defineProperty(exports, "getParent", { enumerable: true, get: function () { return utils_1.getParent; } });
Object.defineProperty(exports, "findVariable", { enumerable: true, get: function () { return utils_1.findVariable; } });
Object.defineProperty(exports, "getStringIfConstant", { enumerable: true, get: function () { return utils_1.getStringIfConstant; } });
Object.defineProperty(exports, "getStaticValue", { enumerable: true, get: function () { return utils_1.getStaticValue; } });
Object.defineProperty(exports, "getScope", { enumerable: true, get: function () { return utils_1.getScope; } });
Object.defineProperty(exports, "isKnownMethodCall", { enumerable: true, get: function () { return utils_1.isKnownMethodCall; } });
Object.defineProperty(exports, "parseReplacements", { enumerable: true, get: function () { return utils_1.parseReplacements; } });
var extract_expression_references_1 = require("./extract-expression-references");
Object.defineProperty(exports, "extractExpressionReferences", { enumerable: true, get: function () { return extract_expression_references_1.extractExpressionReferences; } });
var extract_property_references_1 = require("./extract-property-references");
Object.defineProperty(exports, "extractPropertyReferences", { enumerable: true, get: function () { return extract_property_references_1.extractPropertyReferences; } });
__exportStar(require("./regex"), exports);

View file

@ -0,0 +1,43 @@
import type { Rule, AST, SourceCode } from "eslint";
import type { Expression, Literal, RegExpLiteral } from "estree";
export interface PatternRange {
readonly start: number;
readonly end: number;
}
export declare class PatternReplaceRange {
range: AST.Range;
type: "RegExp" | "SingleQuotedString" | "DoubleQuotedString";
constructor(range: AST.Range, type: PatternReplaceRange["type"]);
static fromLiteral(node: Literal, sourceCode: SourceCode, nodeRange: PatternRange, range: PatternRange): PatternReplaceRange | null;
getAstLocation(sourceCode: SourceCode): AST.SourceLocation;
escape(text: string): string;
replace(fixer: Rule.RuleFixer, text: string): Rule.Fix;
remove(fixer: Rule.RuleFixer): Rule.Fix;
insertAfter(fixer: Rule.RuleFixer, text: string): Rule.Fix;
insertBefore(fixer: Rule.RuleFixer, text: string): Rule.Fix;
}
export interface RegExpValue {
readonly source: string;
readonly flags: string;
readonly ownedNode: RegExpLiteral | null;
}
export declare class PatternSource {
private readonly sourceCode;
readonly node: Expression;
readonly value: string;
private readonly segments;
readonly regexpValue: RegExpValue | null;
isStringValue(): this is PatternSource & {
readonly regexpValue: null;
};
private constructor();
static fromExpression(context: Rule.RuleContext, expression: Expression): PatternSource | null;
private static fromRegExpObject;
static fromRegExpLiteral(context: Rule.RuleContext, expression: RegExpLiteral): PatternSource;
private getSegment;
private getSegments;
getReplaceRange(range: PatternRange): PatternReplaceRange | null;
getAstRange(range: PatternRange): AST.Range;
getAstLocation(range: PatternRange): AST.SourceLocation;
getOwnedRegExpLiterals(): readonly RegExpLiteral[];
}

View file

@ -0,0 +1,226 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PatternSource = exports.PatternReplaceRange = void 0;
const utils_1 = require("./utils");
class PatternReplaceRange {
constructor(range, type) {
if (!range || range[0] < 0 || range[0] > range[1]) {
throw new Error(`Invalid range: ${JSON.stringify(range)}`);
}
this.range = range;
this.type = type;
}
static fromLiteral(node, sourceCode, nodeRange, range) {
if (!node.range) {
return null;
}
const start = range.start - nodeRange.start;
const end = range.end - nodeRange.start;
if ((0, utils_1.isRegexpLiteral)(node)) {
const nodeStart = node.range[0] + "/".length;
return new PatternReplaceRange([nodeStart + start, nodeStart + end], "RegExp");
}
if ((0, utils_1.isStringLiteral)(node)) {
const astRange = (0, utils_1.getStringValueRange)(sourceCode, node, start, end);
if (astRange) {
const quote = sourceCode.text[node.range[0]];
return new PatternReplaceRange(astRange, quote === "'" ? "SingleQuotedString" : "DoubleQuotedString");
}
}
return null;
}
getAstLocation(sourceCode) {
return (0, utils_1.astRangeToLocation)(sourceCode, this.range);
}
escape(text) {
if (this.type === "DoubleQuotedString" ||
this.type === "SingleQuotedString") {
const base = text
.replace(/\\/gu, "\\\\")
.replace(/\n/gu, "\\n")
.replace(/\r/gu, "\\r")
.replace(/\t/gu, "\\t");
if (this.type === "DoubleQuotedString") {
return base.replace(/"/gu, '\\"');
}
return base.replace(/'/gu, "\\'");
}
return text.replace(/\n/gu, "\\n").replace(/\r/gu, "\\r");
}
replace(fixer, text) {
return fixer.replaceTextRange(this.range, this.escape(text));
}
remove(fixer) {
return fixer.removeRange(this.range);
}
insertAfter(fixer, text) {
return fixer.insertTextAfterRange(this.range, this.escape(text));
}
insertBefore(fixer, text) {
return fixer.insertTextBeforeRange(this.range, this.escape(text));
}
}
exports.PatternReplaceRange = PatternReplaceRange;
class PatternSegment {
constructor(sourceCode, node, value, start) {
this.sourceCode = sourceCode;
this.node = node;
this.value = value;
this.start = start;
this.end = start + value.length;
}
contains(range) {
return this.start <= range.start && range.end <= this.end;
}
getOwnedRegExpLiteral() {
if ((0, utils_1.isRegexpLiteral)(this.node)) {
return this.node;
}
if (this.node.type === "MemberExpression" &&
this.node.object.type !== "Super" &&
(0, utils_1.isRegexpLiteral)(this.node.object) &&
(0, utils_1.getPropertyName)(this.node) === "source") {
return this.node.object;
}
return null;
}
getReplaceRange(range) {
if (!this.contains(range)) {
return null;
}
const regexp = this.getOwnedRegExpLiteral();
if (regexp) {
return PatternReplaceRange.fromLiteral(regexp, this.sourceCode, this, range);
}
if (this.node.type === "Literal") {
return PatternReplaceRange.fromLiteral(this.node, this.sourceCode, this, range);
}
return null;
}
getAstRange(range) {
const replaceRange = this.getReplaceRange(range);
if (replaceRange) {
return replaceRange.range;
}
return this.node.range;
}
}
class PatternSource {
isStringValue() {
return this.regexpValue === null;
}
constructor(sourceCode, node, value, segments, regexpValue) {
this.sourceCode = sourceCode;
this.node = node;
this.value = value;
this.segments = segments;
this.regexpValue = regexpValue;
}
static fromExpression(context, expression) {
expression = (0, utils_1.dereferenceOwnedVariable)(context, expression);
if ((0, utils_1.isRegexpLiteral)(expression)) {
return PatternSource.fromRegExpLiteral(context, expression);
}
const sourceCode = context.sourceCode;
const flat = flattenPlus(context, expression);
const items = [];
let value = "";
for (const e of flat) {
if (e.type === "PrivateIdentifier")
return null;
const staticValue = (0, utils_1.getStaticValue)(context, e);
if (!staticValue) {
return null;
}
if (flat.length === 1 && staticValue.value instanceof RegExp) {
return PatternSource.fromRegExpObject(context, e, staticValue.value.source, staticValue.value.flags);
}
if (typeof staticValue.value !== "string") {
return null;
}
items.push(new PatternSegment(sourceCode, e, staticValue.value, value.length));
value += staticValue.value;
}
return new PatternSource(sourceCode, expression, value, items, null);
}
static fromRegExpObject(context, expression, source, flags) {
const sourceCode = context.sourceCode;
return new PatternSource(sourceCode, expression, source, [new PatternSegment(sourceCode, expression, source, 0)], {
source,
flags,
ownedNode: null,
});
}
static fromRegExpLiteral(context, expression) {
const sourceCode = context.sourceCode;
return new PatternSource(sourceCode, expression, expression.regex.pattern, [
new PatternSegment(sourceCode, expression, expression.regex.pattern, 0),
], {
source: expression.regex.pattern,
flags: expression.regex.flags,
ownedNode: expression,
});
}
getSegment(range) {
const segments = this.getSegments(range);
if (segments.length === 1) {
return segments[0];
}
return null;
}
getSegments(range) {
return this.segments.filter((item) => item.start < range.end && range.start < item.end);
}
getReplaceRange(range) {
const segment = this.getSegment(range);
if (segment) {
return segment.getReplaceRange(range);
}
return null;
}
getAstRange(range) {
const overlapping = this.getSegments(range);
if (overlapping.length === 1) {
return overlapping[0].getAstRange(range);
}
let min = Infinity;
let max = -Infinity;
for (const item of overlapping) {
min = Math.min(min, item.node.range[0]);
max = Math.max(max, item.node.range[1]);
}
if (min > max) {
return this.node.range;
}
return [min, max];
}
getAstLocation(range) {
return (0, utils_1.astRangeToLocation)(this.sourceCode, this.getAstRange(range));
}
getOwnedRegExpLiterals() {
const literals = [];
for (const segment of this.segments) {
const regexp = segment.getOwnedRegExpLiteral();
if (regexp) {
literals.push(regexp);
}
}
return literals;
}
}
exports.PatternSource = PatternSource;
function flattenPlus(context, e) {
if (e.type === "BinaryExpression" && e.operator === "+") {
return [
...(e.left.type !== "PrivateIdentifier"
? flattenPlus(context, e.left)
: [e.left]),
...flattenPlus(context, e.right),
];
}
const deRef = (0, utils_1.dereferenceOwnedVariable)(context, e);
if (deRef !== e) {
return flattenPlus(context, deRef);
}
return [e];
}

View file

@ -0,0 +1,7 @@
import type { AST, SourceCode } from "eslint";
import type * as ESTree from "estree";
export declare function getFlagsRange(flagsNode: ESTree.RegExpLiteral): AST.Range;
export declare function getFlagsRange(flagsNode: ESTree.Expression | null): AST.Range | null;
export declare function getFlagsLocation(sourceCode: SourceCode, regexpNode: ESTree.CallExpression | ESTree.RegExpLiteral, flagsNode: ESTree.Expression | null): AST.SourceLocation;
export declare function getFlagRange(sourceCode: SourceCode, flagsNode: ESTree.Expression | null, flag: string): AST.Range | null;
export declare function getFlagLocation(sourceCode: SourceCode, regexpNode: ESTree.CallExpression | ESTree.RegExpLiteral, flagsNode: ESTree.Expression | null, flag: string): AST.SourceLocation;

View file

@ -0,0 +1,68 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFlagsRange = getFlagsRange;
exports.getFlagsLocation = getFlagsLocation;
exports.getFlagRange = getFlagRange;
exports.getFlagLocation = getFlagLocation;
const utils_1 = require("./utils");
function getFlagsRange(flagsNode) {
if (!flagsNode) {
return null;
}
if ((0, utils_1.isRegexpLiteral)(flagsNode)) {
return [
flagsNode.range[1] - flagsNode.regex.flags.length,
flagsNode.range[1],
];
}
if ((0, utils_1.isStringLiteral)(flagsNode)) {
return [flagsNode.range[0] + 1, flagsNode.range[1] - 1];
}
return null;
}
function getFlagsLocation(sourceCode, regexpNode, flagsNode) {
var _a;
const range = getFlagsRange(flagsNode);
if (range == null) {
return (_a = flagsNode === null || flagsNode === void 0 ? void 0 : flagsNode.loc) !== null && _a !== void 0 ? _a : regexpNode.loc;
}
if (range[0] === range[1]) {
range[0]--;
}
return {
start: sourceCode.getLocFromIndex(range[0]),
end: sourceCode.getLocFromIndex(range[1]),
};
}
function getFlagRange(sourceCode, flagsNode, flag) {
if (!flagsNode || !flag) {
return null;
}
if ((0, utils_1.isRegexpLiteral)(flagsNode)) {
const index = flagsNode.regex.flags.indexOf(flag);
if (index === -1) {
return null;
}
const start = flagsNode.range[1] - flagsNode.regex.flags.length + index;
return [start, start + 1];
}
if ((0, utils_1.isStringLiteral)(flagsNode)) {
const index = flagsNode.value.indexOf(flag);
if (index === -1) {
return null;
}
return (0, utils_1.getStringValueRange)(sourceCode, flagsNode, index, index + 1);
}
return null;
}
function getFlagLocation(sourceCode, regexpNode, flagsNode, flag) {
var _a;
const range = getFlagRange(sourceCode, flagsNode, flag);
if (range == null) {
return (_a = flagsNode === null || flagsNode === void 0 ? void 0 : flagsNode.loc) !== null && _a !== void 0 ? _a : regexpNode.loc;
}
return {
start: sourceCode.getLocFromIndex(range[0]),
end: sourceCode.getLocFromIndex(range[1]),
};
}

View file

@ -0,0 +1,54 @@
import type { Rule, SourceCode, AST, Scope } from "eslint";
import type { ArrowFunctionExpression, CallExpression, Expression, FunctionDeclaration, FunctionExpression, Identifier, Literal, MemberExpression, Node, RegExpLiteral } from "estree";
export declare function getParent<E extends Node>(node: Node | null): E | null;
export declare function findVariable(context: Rule.RuleContext, node: Identifier): Scope.Variable | null;
export declare function getStringIfConstant(context: Rule.RuleContext, node: Node): string | null;
type GetStaticValueResult = {
value: unknown;
} | {
value: undefined;
optional?: true;
};
export declare function getStaticValue(context: Rule.RuleContext, node: Node): GetStaticValueResult | null;
export declare function getScope(context: Rule.RuleContext, currentNode: Node): Scope.Scope;
export declare function findFunction(context: Rule.RuleContext, id: Identifier): FunctionDeclaration | FunctionExpression | ArrowFunctionExpression | null;
export type KnownMethodCall = CallExpression & {
callee: MemberExpression & {
object: Expression;
property: Identifier;
};
arguments: Expression[];
parent: Node;
};
export declare function isKnownMethodCall(node: CallExpression, methods: Record<string, number>): node is KnownMethodCall;
interface BaseElement {
type: string;
range: [number, number];
}
export type ReplacementElement = CharacterElement | DollarElement | ReferenceElement;
export interface CharacterElement extends BaseElement {
type: "CharacterElement";
value: string;
}
export interface DollarElement extends BaseElement {
type: "DollarElement";
kind: "$" | "&" | "`" | "'";
}
export interface ReferenceElement extends BaseElement {
type: "ReferenceElement";
ref: number | string;
refText: string;
}
export declare function parseReplacements(context: Rule.RuleContext, node: Literal): ReplacementElement[];
export declare function getStringValueRange(sourceCode: SourceCode, node: Literal & {
value: string;
}, startOffset: number, endOffset: number): AST.Range | null;
export declare function isRegexpLiteral(node: Expression): node is RegExpLiteral;
export declare function isStringLiteral(node: Expression): node is Literal & {
value: string;
};
export declare function getPropertyName(node: MemberExpression, context?: Rule.RuleContext): string | null;
export declare function astRangeToLocation(sourceCode: SourceCode, range: AST.Range): AST.SourceLocation;
export declare function dereferenceOwnedVariable(context: Rule.RuleContext, expression: Expression): Expression;
export declare function dereferenceVariable(context: Rule.RuleContext, expression: Expression): Expression;
export {};

View file

@ -0,0 +1,316 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.getParent = getParent;
exports.findVariable = findVariable;
exports.getStringIfConstant = getStringIfConstant;
exports.getStaticValue = getStaticValue;
exports.getScope = getScope;
exports.findFunction = findFunction;
exports.isKnownMethodCall = isKnownMethodCall;
exports.parseReplacements = parseReplacements;
exports.getStringValueRange = getStringValueRange;
exports.isRegexpLiteral = isRegexpLiteral;
exports.isStringLiteral = isStringLiteral;
exports.getPropertyName = getPropertyName;
exports.astRangeToLocation = astRangeToLocation;
exports.dereferenceOwnedVariable = dereferenceOwnedVariable;
exports.dereferenceVariable = dereferenceVariable;
const replacements_utils_1 = require("../replacements-utils");
const string_literal_parser_1 = require("../string-literal-parser");
const eslintUtils = __importStar(require("@eslint-community/eslint-utils"));
function getParent(node) {
if (!node) {
return null;
}
return node.parent;
}
function findVariable(context, node) {
return eslintUtils.findVariable(getScope(context, node), node);
}
function findSimpleVariable(context, identifier) {
const variable = findVariable(context, identifier);
if (!variable || variable.defs.length !== 1) {
return null;
}
const def = variable.defs[0];
if (def.type !== "Variable" || def.node.id.type !== "Identifier") {
return null;
}
return variable;
}
function getStringIfConstant(context, node) {
if (node.type === "BinaryExpression" ||
node.type === "MemberExpression" ||
node.type === "Identifier" ||
node.type === "TemplateLiteral") {
const evaluated = getStaticValue(context, node);
return evaluated && String(evaluated.value);
}
return eslintUtils.getStringIfConstant(node, getScope(context, node));
}
function getStaticValue(context, node) {
if (node.type === "BinaryExpression") {
if (node.operator === "+") {
const left = getStaticValue(context, node.left);
if (left == null) {
return null;
}
const right = getStaticValue(context, node.right);
if (right == null) {
return null;
}
return {
value: left.value + right.value,
};
}
}
else if (node.type === "MemberExpression") {
const propName = getPropertyName(node, context);
if (propName === "source") {
const object = getStaticValue(context, node.object);
if (object && object.value instanceof RegExp) {
return { value: object.value.source };
}
}
}
else if (node.type === "TemplateLiteral") {
const expressions = [];
for (const expr of node.expressions) {
const exprValue = getStaticValue(context, expr);
if (!exprValue) {
return null;
}
expressions.push(exprValue);
}
let value = node.quasis[0].value.cooked;
for (let i = 0; i < expressions.length; ++i) {
value += String(expressions[i].value);
value += node.quasis[i + 1].value.cooked;
}
return { value };
}
else if (node.type === "Identifier") {
const deRef = dereferenceVariable(context, node);
if (deRef !== node) {
return getStaticValue(context, deRef);
}
}
return eslintUtils.getStaticValue(node, getScope(context, node));
}
function getScope(context, currentNode) {
const scopeManager = context.sourceCode.scopeManager;
let node = currentNode;
for (; node; node = node.parent || null) {
const scope = scopeManager.acquire(node, false);
if (scope) {
if (scope.type === "function-expression-name") {
return scope.childScopes[0];
}
return scope;
}
}
return scopeManager.scopes[0];
}
function findFunction(context, id) {
let target = id;
const set = new Set();
for (;;) {
if (set.has(target)) {
return null;
}
set.add(target);
const calleeVariable = findVariable(context, target);
if (!calleeVariable) {
return null;
}
if (calleeVariable.defs.length === 1) {
const def = calleeVariable.defs[0];
if (def.node.type === "FunctionDeclaration") {
return def.node;
}
if (def.type === "Variable" &&
def.parent.kind === "const" &&
def.node.init) {
if (def.node.init.type === "FunctionExpression" ||
def.node.init.type === "ArrowFunctionExpression") {
return def.node.init;
}
if (def.node.init.type === "Identifier") {
target = def.node.init;
continue;
}
}
}
return null;
}
}
function isKnownMethodCall(node, methods) {
const mem = node.callee;
if (mem.type !== "MemberExpression" ||
mem.computed ||
mem.property.type !== "Identifier") {
return false;
}
const argLength = methods[mem.property.name];
if (node.arguments.length !== argLength) {
return false;
}
if (node.arguments.some((arg) => arg.type === "SpreadElement")) {
return false;
}
const object = mem.object;
if (object.type === "Super") {
return false;
}
return true;
}
function parseReplacements(context, node) {
const stringLiteral = (0, string_literal_parser_1.parseStringLiteral)(context.sourceCode.text, {
start: node.range[0],
end: node.range[1],
});
const tokens = stringLiteral.tokens.filter((t) => t.value);
return (0, replacements_utils_1.baseParseReplacements)(tokens, (start, end) => {
return {
range: [start.range[0], end.range[1]],
};
});
}
function getStringValueRange(sourceCode, node, startOffset, endOffset) {
if (!node.range) {
return null;
}
if (node.value.length < endOffset) {
return null;
}
try {
const raw = sourceCode.text.slice(node.range[0] + 1, node.range[1] - 1);
let valueIndex = 0;
let start = null;
for (const t of (0, string_literal_parser_1.parseStringTokens)(raw)) {
const endIndex = valueIndex + t.value.length;
if (start == null &&
valueIndex <= startOffset &&
startOffset < endIndex) {
start = t.range[0];
}
if (start != null &&
valueIndex < endOffset &&
endOffset <= endIndex) {
const end = t.range[1];
const nodeStart = node.range[0] + 1;
return [nodeStart + start, nodeStart + end];
}
valueIndex = endIndex;
}
}
catch (_a) {
}
return null;
}
function isRegexpLiteral(node) {
return node.type === "Literal" && "regex" in node;
}
function isStringLiteral(node) {
return node.type === "Literal" && typeof node.value === "string";
}
function getPropertyName(node, context) {
const prop = node.property;
if (prop.type === "PrivateIdentifier") {
return null;
}
if (!node.computed) {
return prop.name;
}
if (context) {
return getStringIfConstant(context, prop);
}
if (isStringLiteral(prop)) {
return prop.value;
}
return null;
}
function astRangeToLocation(sourceCode, range) {
return {
start: sourceCode.getLocFromIndex(range[0]),
end: sourceCode.getLocFromIndex(range[1]),
};
}
function dereferenceOwnedVariable(context, expression) {
if (expression.type === "Identifier") {
const variable = findSimpleVariable(context, expression);
if (!variable) {
return expression;
}
const def = variable.defs[0];
const grandParent = getParent(def.parent);
if (grandParent && grandParent.type === "ExportNamedDeclaration") {
return expression;
}
if (variable.references.length !== 2) {
return expression;
}
const [initRef, thisRef] = variable.references;
if (!(initRef.init &&
initRef.writeExpr &&
initRef.writeExpr === def.node.init) ||
thisRef.identifier !== expression) {
return expression;
}
return dereferenceOwnedVariable(context, def.node.init);
}
return expression;
}
function dereferenceVariable(context, expression) {
if (expression.type === "Identifier") {
const variable = findSimpleVariable(context, expression);
if (variable) {
const def = variable.defs[0];
if (def.node.init) {
if (def.parent.kind === "const") {
return dereferenceVariable(context, def.node.init);
}
const refs = variable.references;
const inits = refs.filter((r) => r.init).length;
const reads = refs.filter((r) => r.isReadOnly()).length;
if (inits === 1 && reads + inits === refs.length) {
return dereferenceVariable(context, def.node.init);
}
}
}
}
return expression;
}