🌐 AI搜索 & 代理 主页
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,9 @@ export default defineConfig(
'no-lonely-if': 'error',
'no-mixed-operators': 'error',
'no-process-exit': 'error',
'no-unassigned-vars': 'error',
'no-unreachable-loop': 'error',
'no-useless-assignment': 'error',
'no-useless-call': 'error',
'no-useless-computed-key': 'error',
'no-useless-concat': 'error',
Expand Down
4 changes: 2 additions & 2 deletions packages/eslint-plugin/src/util/getFunctionHeadLoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ export function getFunctionHeadLoc(
sourceCode: TSESLint.SourceCode,
): TSESTree.SourceLocation {
const parent = node.parent;
let start: TSESTree.Position | null = null;
let end: TSESTree.Position | null = null;
let start: TSESTree.Position;
let end: TSESTree.Position;

if (
parent.type === AST_NODE_TYPES.MethodDefinition ||
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-plugin/tools/generate-breaking-changes.mts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ async function getNewRulesAsOfMajorVersion(
// Normally we wouldn't condone using the 'eval' API...
// But this is an internal-only script and it's the easiest way to convert
// the JS raw text into a runtime object. 🤷
// eslint-disable-next-line no-unassigned-vars -- assigned by eval
let oldRulesObject!: { rules: TypeScriptESLintRules };
eval(`oldRulesObject = ${oldObjectText}`);
const oldRuleNames = new Set(Object.keys(oldRulesObject.rules));
Expand Down
4 changes: 2 additions & 2 deletions packages/rule-tester/src/RuleTester.ts
Original file line number Diff line number Diff line change
Expand Up @@ -761,8 +761,8 @@ export class RuleTester extends TestFramework {

// Verify the code.
let initialMessages: Linter.LintMessage[] | null = null;
let messages: Linter.LintMessage[] | null = null;
let fixedResult: SourceCodeFixer.AppliedFixes | null = null;
let messages: Linter.LintMessage[];
let fixedResult: SourceCodeFixer.AppliedFixes;
let passNumber = 0;
const outputs: string[] = [];
const configWithoutCustomKeys = omitCustomConfigProperties(config);
Expand Down
117 changes: 4 additions & 113 deletions packages/scope-manager/src/referencer/ClassVisitor.ts
Copy link
Member Author

@kirkwaiblinger kirkwaiblinger Sep 1, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was dead code left from the cleanup in #8335

Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,18 @@ import { TypeVisitor } from './TypeVisitor';
import { Visitor } from './Visitor';

export class ClassVisitor extends Visitor {
readonly #classNode: TSESTree.ClassDeclaration | TSESTree.ClassExpression;
readonly #referencer: Referencer;

constructor(
referencer: Referencer,
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression,
) {
constructor(referencer: Referencer) {
super(referencer);
this.#referencer = referencer;
this.#classNode = node;
}

static visit(
referencer: Referencer,
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression,
): void {
const classVisitor = new ClassVisitor(referencer, node);
const classVisitor = new ClassVisitor(referencer);
classVisitor.visitClass(node);
}

Expand Down Expand Up @@ -97,18 +92,15 @@ export class ClassVisitor extends Visitor {
}

if (node.value.type === AST_NODE_TYPES.FunctionExpression) {
this.visitMethodFunction(node.value, node);
this.visitMethodFunction(node.value);
} else {
this.#referencer.visit(node.value);
}

node.decorators.forEach(d => this.#referencer.visit(d));
}

protected visitMethodFunction(
node: TSESTree.FunctionExpression,
methodNode: TSESTree.MethodDefinition,
): void {
protected visitMethodFunction(node: TSESTree.FunctionExpression): void {
if (node.id) {
// FunctionExpression with name creates its special scope;
// FunctionExpressionNameScope.
Expand All @@ -122,71 +114,6 @@ export class ClassVisitor extends Visitor {
// Consider this function is in the MethodDefinition.
this.#referencer.scopeManager.nestFunctionScope(node, true);

/**
* class A {
* @meta // <--- check this
* foo(a: Type) {}
*
* @meta // <--- check this
* foo(): Type {}
* }
*/
let withMethodDecorators = !!methodNode.decorators.length;
/**
* class A {
* foo(
* @meta // <--- check this
* a: Type
* ) {}
*
* set foo(
* @meta // <--- EXCEPT this. TS do nothing for this
* a: Type
* ) {}
* }
*/
withMethodDecorators ||=
methodNode.kind !== 'set' &&
node.params.some(param => param.decorators.length);
if (!withMethodDecorators && methodNode.kind === 'set') {
const keyName = getLiteralMethodKeyName(methodNode);

/**
* class A {
* @meta // <--- check this
* get a() {}
* set ['a'](v: Type) {}
* }
*/
if (
keyName != null &&
this.#classNode.body.body.find(
(node): node is TSESTree.MethodDefinition =>
node !== methodNode &&
node.type === AST_NODE_TYPES.MethodDefinition &&
// Node must both be static or not
node.static === methodNode.static &&
getLiteralMethodKeyName(node) === keyName,
)?.decorators.length
) {
withMethodDecorators = true;
}
}

/**
* @meta // <--- check this
* class A {
* constructor(a: Type) {}
* }
*/
if (
!withMethodDecorators &&
methodNode.kind === 'constructor' &&
this.#classNode.decorators.length
) {
withMethodDecorators = true;
}

// Process parameter declarations.
for (const param of node.params) {
this.visitPattern(
Expand Down Expand Up @@ -337,39 +264,3 @@ export class ClassVisitor extends Visitor {
this.visitType(node);
}
}

/**
* Only if key is one of [identifier, string, number], ts will combine metadata of accessors .
* class A {
* get a() {}
* set ['a'](v: Type) {}
*
* get [1]() {}
* set [1](v: Type) {}
*
* // Following won't be combined
* get [key]() {}
* set [key](v: Type) {}
*
* get [true]() {}
* set [true](v: Type) {}
*
* get ['a'+'b']() {}
* set ['a'+'b']() {}
* }
*/
function getLiteralMethodKeyName(
node: TSESTree.MethodDefinition,
): number | string | null {
if (node.computed && node.key.type === AST_NODE_TYPES.Literal) {
if (
typeof node.key.value === 'string' ||
typeof node.key.value === 'number'
) {
return node.key.value;
}
} else if (!node.computed && node.key.type === AST_NODE_TYPES.Identifier) {
return node.key.name;
}
return null;
}
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ describe('ES6 class', () => {
assert.isScopeOfType(scope, ScopeType.global);
expect(scope.block.type).toBe(AST_NODE_TYPES.Program);
expect(scope.isStrict).toBe(false);
expect(variables).toHaveLength(0);

scope = scopeManager.scopes[1];
variables = getRealVariables(scope.variables);
Expand Down
2 changes: 2 additions & 0 deletions packages/scope-manager/tests/eslint-scope/es6-object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ describe('ES6 object', () => {
assert.isScopeOfType(scope, ScopeType.global);
expect(scope.block.type).toBe(AST_NODE_TYPES.Program);
expect(scope.isStrict).toBe(false);
expect(variables).toHaveLength(0);

scope = scopeManager.scopes[1];
variables = getRealVariables(scope.variables);
Expand Down Expand Up @@ -51,6 +52,7 @@ describe('ES6 object', () => {
assert.isScopeOfType(scope, ScopeType.global);
expect(scope.block.type).toBe(AST_NODE_TYPES.Program);
expect(scope.isStrict).toBe(false);
expect(variables).toHaveLength(0);

scope = scopeManager.scopes[1];
variables = getRealVariables(scope.variables);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,9 @@ import type * as ts from 'typescript';
import type { SandboxInstance } from './useSandboxServices';

function findTwoshashQueries(code: string): RegExpExecArray[] {
let match: RegExpExecArray | null = null;
const matches: RegExpExecArray[] = [];
// RegExp that matches '^<spaces>//?<spaces>$'
const twoslashQueryRegex = /^(\s*\/\/\s*\^\?)\s*$/gm;
while ((match = twoslashQueryRegex.exec(code))) {
matches.push(match);
}
return matches;
const twoslashQueryRegex = /^(\s*\/\/\s*\^\?)\s*$/m;
return [...code.matchAll(twoslashQueryRegex)];
}

export function createTwoslashInlayProvider(
Expand Down
Loading