📄 ClassVisitor.ts
¶
📊 Analysis Summary¶
Metric | Count |
---|---|
🔧 Functions | 21 |
🧱 Classes | 1 |
📦 Imports | 7 |
📊 Variables & Constants | 2 |
📚 Table of Contents¶
🛠️ File Location:¶
📂 packages/scope-manager/src/referencer/ClassVisitor.ts
📦 Imports¶
Name | Source |
---|---|
TSESTree |
@typescript-eslint/types |
AST_NODE_TYPES |
@typescript-eslint/types |
Referencer |
./Referencer |
ClassNameDefinition |
../definition |
ParameterDefinition |
../definition |
TypeVisitor |
./TypeVisitor |
Visitor |
./Visitor |
Variables & Constants¶
Name | Type | Kind | Value | Exported |
---|---|---|---|---|
classVisitor |
ClassVisitor |
const | new ClassVisitor(referencer, node) |
✗ |
withMethodDecorators |
boolean |
let/var | !!methodNode.decorators.length |
✗ |
Functions¶
ClassVisitor.visit(referencer: Referencer, node: TSESTree.ClassDeclaration | TSESTree.ClassExpression): void
¶
Code
- Parameters:
referencer: Referencer
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression
- Return Type:
void
- Calls:
classVisitor.visitClass
ClassVisitor.visit(node: TSESTree.Node | null | undefined): void
¶
Code
- Parameters:
node: TSESTree.Node | null | undefined
- Return Type:
void
- Calls:
super.visit
this.#referencer.visit
- Internal Comments:
ClassVisitor.visitClass(node: TSESTree.ClassDeclaration | TSESTree.ClassExpression): void
¶
Code
protected visitClass(
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression,
): void {
if (node.type === AST_NODE_TYPES.ClassDeclaration && node.id) {
this.#referencer
.currentScope()
.defineIdentifier(node.id, new ClassNameDefinition(node.id, node));
}
node.decorators.forEach(d => this.#referencer.visit(d));
this.#referencer.scopeManager.nestClassScope(node);
if (node.id) {
// define the class name again inside the new scope
// references to the class should not resolve directly to the parent class
this.#referencer
.currentScope()
.defineIdentifier(node.id, new ClassNameDefinition(node.id, node));
}
this.#referencer.visit(node.superClass);
// visit the type param declarations
this.visitType(node.typeParameters);
// then the usages
this.visitType(node.superTypeArguments);
node.implements.forEach(imp => this.visitType(imp));
this.visit(node.body);
this.#referencer.close(node);
}
- Parameters:
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression
- Return Type:
void
- Calls:
this.#referencer .currentScope() .defineIdentifier
node.decorators.forEach
this.#referencer.visit
this.#referencer.scopeManager.nestClassScope
this.visitType
node.implements.forEach
this.visit
this.#referencer.close
- Internal Comments:
ClassVisitor.visitFunctionParameterTypeAnnotation(node: TSESTree.Parameter): void
¶
Code
protected visitFunctionParameterTypeAnnotation(
node: TSESTree.Parameter,
): void {
switch (node.type) {
case AST_NODE_TYPES.AssignmentPattern:
this.visitType(node.left.typeAnnotation);
break;
case AST_NODE_TYPES.TSParameterProperty:
this.visitFunctionParameterTypeAnnotation(node.parameter);
break;
default:
this.visitType(node.typeAnnotation);
}
}
- Parameters:
node: TSESTree.Parameter
- Return Type:
void
- Calls:
this.visitType
this.visitFunctionParameterTypeAnnotation
ClassVisitor.visitMethod(node: TSESTree.MethodDefinition): void
¶
Code
protected visitMethod(node: TSESTree.MethodDefinition): void {
if (node.computed) {
this.#referencer.visit(node.key);
}
if (node.value.type === AST_NODE_TYPES.FunctionExpression) {
this.visitMethodFunction(node.value, node);
} else {
this.#referencer.visit(node.value);
}
node.decorators.forEach(d => this.#referencer.visit(d));
}
- Parameters:
node: TSESTree.MethodDefinition
- Return Type:
void
- Calls:
this.#referencer.visit
this.visitMethodFunction
node.decorators.forEach
ClassVisitor.visitMethodFunction(node: TSESTree.FunctionExpression, methodNode: TSESTree.MethodDefinition): void
¶
Code
protected visitMethodFunction(
node: TSESTree.FunctionExpression,
methodNode: TSESTree.MethodDefinition,
): void {
if (node.id) {
// FunctionExpression with name creates its special scope;
// FunctionExpressionNameScope.
this.#referencer.scopeManager.nestFunctionExpressionNameScope(node);
}
node.params.forEach(param => {
param.decorators.forEach(d => this.visit(d));
});
// 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(
param,
(pattern, info) => {
this.#referencer
.currentScope()
.defineIdentifier(
pattern,
new ParameterDefinition(pattern, node, info.rest),
);
this.#referencer.referencingDefaultValue(
pattern,
info.assignments,
null,
true,
);
},
{ processRightHandNodes: true },
);
this.visitFunctionParameterTypeAnnotation(param);
}
this.visitType(node.returnType);
this.visitType(node.typeParameters);
this.#referencer.visitChildren(node.body);
this.#referencer.close(node);
}
- Parameters:
node: TSESTree.FunctionExpression
methodNode: TSESTree.MethodDefinition
- Return Type:
void
- Calls:
this.#referencer.scopeManager.nestFunctionExpressionNameScope
node.params.forEach
param.decorators.forEach
this.visit
this.#referencer.scopeManager.nestFunctionScope
node.params.some
getLiteralMethodKeyName
this.#classNode.body.body.find
this.visitPattern
this.#referencer .currentScope() .defineIdentifier
this.#referencer.referencingDefaultValue
this.visitFunctionParameterTypeAnnotation
this.visitType
this.#referencer.visitChildren
this.#referencer.close
- Internal Comments:
// FunctionExpression with name creates its special scope; (x6) // FunctionExpressionNameScope. (x6) // Consider this function is in the MethodDefinition. (x6) /** * class A { * @meta // <--- check this * foo(a: Type) {} * * @meta // <--- check this * foo(): Type {} * } */ (x2) /** * class A { * foo( * @meta // <--- check this * a: Type * ) {} * * set foo( * @meta // <--- EXCEPT this. TS do nothing for this * a: Type * ) {} * } */ (x3) /** * class A { * @meta // <--- check this * get a() {} * set ['a'](v: Type) {} * } */ // Node must both be static or not (x3) /** * @meta // <--- check this * class A { * constructor(a: Type) {} * } */ // Process parameter declarations.
`ClassVisitor.visitPropertyBase(node: | TSESTree.AccessorProperty¶
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractMethodDefinition
| TSESTree.TSAbstractPropertyDefinition): void`
Code
protected visitPropertyBase(
node:
| TSESTree.AccessorProperty
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractMethodDefinition
| TSESTree.TSAbstractPropertyDefinition,
): void {
if (node.computed) {
this.#referencer.visit(node.key);
}
if (node.value) {
if (
node.type === AST_NODE_TYPES.PropertyDefinition ||
node.type === AST_NODE_TYPES.AccessorProperty
) {
this.#referencer.scopeManager.nestClassFieldInitializerScope(
node.value,
);
}
this.#referencer.visit(node.value);
if (
node.type === AST_NODE_TYPES.PropertyDefinition ||
node.type === AST_NODE_TYPES.AccessorProperty
) {
this.#referencer.close(node.value);
}
}
node.decorators.forEach(d => this.#referencer.visit(d));
}
- Parameters:
node: | TSESTree.AccessorProperty | TSESTree.PropertyDefinition | TSESTree.TSAbstractAccessorProperty | TSESTree.TSAbstractMethodDefinition | TSESTree.TSAbstractPropertyDefinition
- Return Type:
void
- Calls:
this.#referencer.visit
this.#referencer.scopeManager.nestClassFieldInitializerScope
this.#referencer.close
node.decorators.forEach
`ClassVisitor.visitPropertyDefinition(node: | TSESTree.AccessorProperty¶
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractPropertyDefinition): void`
Code
protected visitPropertyDefinition(
node:
| TSESTree.AccessorProperty
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractPropertyDefinition,
): void {
this.visitPropertyBase(node);
/**
* class A {
* @meta // <--- check this
* foo: Type;
* }
*/
this.visitType(node.typeAnnotation);
}
- Parameters:
node: | TSESTree.AccessorProperty | TSESTree.PropertyDefinition | TSESTree.TSAbstractAccessorProperty | TSESTree.TSAbstractPropertyDefinition
- Return Type:
void
- Calls:
this.visitPropertyBase
this.visitType
- Internal Comments:
ClassVisitor.visitType(node: TSESTree.Node | null | undefined): void
¶
Code
- Parameters:
node: TSESTree.Node | null | undefined
- Return Type:
void
- Calls:
TypeVisitor.visit
ClassVisitor.AccessorProperty(node: TSESTree.AccessorProperty): void
¶
Code
- Parameters:
node: TSESTree.AccessorProperty
- Return Type:
void
- Calls:
this.visitPropertyDefinition
ClassVisitor.ClassBody(node: TSESTree.ClassBody): void
¶
Code
- Parameters:
node: TSESTree.ClassBody
- Return Type:
void
- Calls:
this.visitChildren
- Internal Comments:
ClassVisitor.Identifier(node: TSESTree.Identifier): void
¶
- Parameters:
node: TSESTree.Identifier
- Return Type:
void
- Calls:
this.#referencer.visit
ClassVisitor.MethodDefinition(node: TSESTree.MethodDefinition): void
¶
- Parameters:
node: TSESTree.MethodDefinition
- Return Type:
void
- Calls:
this.visitMethod
ClassVisitor.PrivateIdentifier(): void
¶
- Return Type:
void
ClassVisitor.PropertyDefinition(node: TSESTree.PropertyDefinition): void
¶
Code
- Parameters:
node: TSESTree.PropertyDefinition
- Return Type:
void
- Calls:
this.visitPropertyDefinition
ClassVisitor.StaticBlock(node: TSESTree.StaticBlock): void
¶
Code
- Parameters:
node: TSESTree.StaticBlock
- Return Type:
void
- Calls:
this.#referencer.scopeManager.nestClassStaticBlockScope
node.body.forEach
this.visit
this.#referencer.close
ClassVisitor.TSAbstractAccessorProperty(node: TSESTree.TSAbstractAccessorProperty): void
¶
Code
- Parameters:
node: TSESTree.TSAbstractAccessorProperty
- Return Type:
void
- Calls:
this.visitPropertyDefinition
ClassVisitor.TSAbstractMethodDefinition(node: TSESTree.TSAbstractMethodDefinition): void
¶
Code
- Parameters:
node: TSESTree.TSAbstractMethodDefinition
- Return Type:
void
- Calls:
this.visitPropertyBase
ClassVisitor.TSAbstractPropertyDefinition(node: TSESTree.TSAbstractPropertyDefinition): void
¶
Code
- Parameters:
node: TSESTree.TSAbstractPropertyDefinition
- Return Type:
void
- Calls:
this.visitPropertyDefinition
ClassVisitor.TSIndexSignature(node: TSESTree.TSIndexSignature): void
¶
- Parameters:
node: TSESTree.TSIndexSignature
- Return Type:
void
- Calls:
this.visitType
getLiteralMethodKeyName(node: TSESTree.MethodDefinition): number | string | null
¶
Code
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;
}
-
JSDoc:
/** * 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']() {} * } */
-
Parameters:
node: TSESTree.MethodDefinition
- Return Type:
number | string | null
Classes¶
ClassVisitor
¶
Class Code
export class ClassVisitor extends Visitor {
readonly #classNode: TSESTree.ClassDeclaration | TSESTree.ClassExpression;
readonly #referencer: Referencer;
constructor(
referencer: Referencer,
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression,
) {
super(referencer);
this.#referencer = referencer;
this.#classNode = node;
}
static visit(
referencer: Referencer,
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression,
): void {
const classVisitor = new ClassVisitor(referencer, node);
classVisitor.visitClass(node);
}
override visit(node: TSESTree.Node | null | undefined): void {
// make sure we only handle the nodes we are designed to handle
if (node && node.type in this) {
super.visit(node);
} else {
this.#referencer.visit(node);
}
}
///////////////////
// Visit helpers //
///////////////////
protected visitClass(
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression,
): void {
if (node.type === AST_NODE_TYPES.ClassDeclaration && node.id) {
this.#referencer
.currentScope()
.defineIdentifier(node.id, new ClassNameDefinition(node.id, node));
}
node.decorators.forEach(d => this.#referencer.visit(d));
this.#referencer.scopeManager.nestClassScope(node);
if (node.id) {
// define the class name again inside the new scope
// references to the class should not resolve directly to the parent class
this.#referencer
.currentScope()
.defineIdentifier(node.id, new ClassNameDefinition(node.id, node));
}
this.#referencer.visit(node.superClass);
// visit the type param declarations
this.visitType(node.typeParameters);
// then the usages
this.visitType(node.superTypeArguments);
node.implements.forEach(imp => this.visitType(imp));
this.visit(node.body);
this.#referencer.close(node);
}
protected visitFunctionParameterTypeAnnotation(
node: TSESTree.Parameter,
): void {
switch (node.type) {
case AST_NODE_TYPES.AssignmentPattern:
this.visitType(node.left.typeAnnotation);
break;
case AST_NODE_TYPES.TSParameterProperty:
this.visitFunctionParameterTypeAnnotation(node.parameter);
break;
default:
this.visitType(node.typeAnnotation);
}
}
protected visitMethod(node: TSESTree.MethodDefinition): void {
if (node.computed) {
this.#referencer.visit(node.key);
}
if (node.value.type === AST_NODE_TYPES.FunctionExpression) {
this.visitMethodFunction(node.value, node);
} else {
this.#referencer.visit(node.value);
}
node.decorators.forEach(d => this.#referencer.visit(d));
}
protected visitMethodFunction(
node: TSESTree.FunctionExpression,
methodNode: TSESTree.MethodDefinition,
): void {
if (node.id) {
// FunctionExpression with name creates its special scope;
// FunctionExpressionNameScope.
this.#referencer.scopeManager.nestFunctionExpressionNameScope(node);
}
node.params.forEach(param => {
param.decorators.forEach(d => this.visit(d));
});
// 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(
param,
(pattern, info) => {
this.#referencer
.currentScope()
.defineIdentifier(
pattern,
new ParameterDefinition(pattern, node, info.rest),
);
this.#referencer.referencingDefaultValue(
pattern,
info.assignments,
null,
true,
);
},
{ processRightHandNodes: true },
);
this.visitFunctionParameterTypeAnnotation(param);
}
this.visitType(node.returnType);
this.visitType(node.typeParameters);
this.#referencer.visitChildren(node.body);
this.#referencer.close(node);
}
protected visitPropertyBase(
node:
| TSESTree.AccessorProperty
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractMethodDefinition
| TSESTree.TSAbstractPropertyDefinition,
): void {
if (node.computed) {
this.#referencer.visit(node.key);
}
if (node.value) {
if (
node.type === AST_NODE_TYPES.PropertyDefinition ||
node.type === AST_NODE_TYPES.AccessorProperty
) {
this.#referencer.scopeManager.nestClassFieldInitializerScope(
node.value,
);
}
this.#referencer.visit(node.value);
if (
node.type === AST_NODE_TYPES.PropertyDefinition ||
node.type === AST_NODE_TYPES.AccessorProperty
) {
this.#referencer.close(node.value);
}
}
node.decorators.forEach(d => this.#referencer.visit(d));
}
protected visitPropertyDefinition(
node:
| TSESTree.AccessorProperty
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractPropertyDefinition,
): void {
this.visitPropertyBase(node);
/**
* class A {
* @meta // <--- check this
* foo: Type;
* }
*/
this.visitType(node.typeAnnotation);
}
protected visitType(node: TSESTree.Node | null | undefined): void {
if (!node) {
return;
}
TypeVisitor.visit(this.#referencer, node);
}
/////////////////////
// Visit selectors //
/////////////////////
protected AccessorProperty(node: TSESTree.AccessorProperty): void {
this.visitPropertyDefinition(node);
}
protected ClassBody(node: TSESTree.ClassBody): void {
// this is here on purpose so that this visitor explicitly declares visitors
// for all nodes it cares about (see the instance visit method above)
this.visitChildren(node);
}
protected Identifier(node: TSESTree.Identifier): void {
this.#referencer.visit(node);
}
protected MethodDefinition(node: TSESTree.MethodDefinition): void {
this.visitMethod(node);
}
protected PrivateIdentifier(): void {
// intentionally skip
}
protected PropertyDefinition(node: TSESTree.PropertyDefinition): void {
this.visitPropertyDefinition(node);
}
protected StaticBlock(node: TSESTree.StaticBlock): void {
this.#referencer.scopeManager.nestClassStaticBlockScope(node);
node.body.forEach(b => this.visit(b));
this.#referencer.close(node);
}
protected TSAbstractAccessorProperty(
node: TSESTree.TSAbstractAccessorProperty,
): void {
this.visitPropertyDefinition(node);
}
protected TSAbstractMethodDefinition(
node: TSESTree.TSAbstractMethodDefinition,
): void {
this.visitPropertyBase(node);
}
protected TSAbstractPropertyDefinition(
node: TSESTree.TSAbstractPropertyDefinition,
): void {
this.visitPropertyDefinition(node);
}
protected TSIndexSignature(node: TSESTree.TSIndexSignature): void {
this.visitType(node);
}
}
Methods¶
visit(referencer: Referencer, node: TSESTree.ClassDeclaration | TSESTree.ClassExpression): void
¶
Code
visit(node: TSESTree.Node | null | undefined): void
¶
Code
visitClass(node: TSESTree.ClassDeclaration | TSESTree.ClassExpression): void
¶
Code
protected visitClass(
node: TSESTree.ClassDeclaration | TSESTree.ClassExpression,
): void {
if (node.type === AST_NODE_TYPES.ClassDeclaration && node.id) {
this.#referencer
.currentScope()
.defineIdentifier(node.id, new ClassNameDefinition(node.id, node));
}
node.decorators.forEach(d => this.#referencer.visit(d));
this.#referencer.scopeManager.nestClassScope(node);
if (node.id) {
// define the class name again inside the new scope
// references to the class should not resolve directly to the parent class
this.#referencer
.currentScope()
.defineIdentifier(node.id, new ClassNameDefinition(node.id, node));
}
this.#referencer.visit(node.superClass);
// visit the type param declarations
this.visitType(node.typeParameters);
// then the usages
this.visitType(node.superTypeArguments);
node.implements.forEach(imp => this.visitType(imp));
this.visit(node.body);
this.#referencer.close(node);
}
visitFunctionParameterTypeAnnotation(node: TSESTree.Parameter): void
¶
Code
protected visitFunctionParameterTypeAnnotation(
node: TSESTree.Parameter,
): void {
switch (node.type) {
case AST_NODE_TYPES.AssignmentPattern:
this.visitType(node.left.typeAnnotation);
break;
case AST_NODE_TYPES.TSParameterProperty:
this.visitFunctionParameterTypeAnnotation(node.parameter);
break;
default:
this.visitType(node.typeAnnotation);
}
}
visitMethod(node: TSESTree.MethodDefinition): void
¶
Code
protected visitMethod(node: TSESTree.MethodDefinition): void {
if (node.computed) {
this.#referencer.visit(node.key);
}
if (node.value.type === AST_NODE_TYPES.FunctionExpression) {
this.visitMethodFunction(node.value, node);
} else {
this.#referencer.visit(node.value);
}
node.decorators.forEach(d => this.#referencer.visit(d));
}
visitMethodFunction(node: TSESTree.FunctionExpression, methodNode: TSESTree.MethodDefinition): void
¶
Code
protected visitMethodFunction(
node: TSESTree.FunctionExpression,
methodNode: TSESTree.MethodDefinition,
): void {
if (node.id) {
// FunctionExpression with name creates its special scope;
// FunctionExpressionNameScope.
this.#referencer.scopeManager.nestFunctionExpressionNameScope(node);
}
node.params.forEach(param => {
param.decorators.forEach(d => this.visit(d));
});
// 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(
param,
(pattern, info) => {
this.#referencer
.currentScope()
.defineIdentifier(
pattern,
new ParameterDefinition(pattern, node, info.rest),
);
this.#referencer.referencingDefaultValue(
pattern,
info.assignments,
null,
true,
);
},
{ processRightHandNodes: true },
);
this.visitFunctionParameterTypeAnnotation(param);
}
this.visitType(node.returnType);
this.visitType(node.typeParameters);
this.#referencer.visitChildren(node.body);
this.#referencer.close(node);
}
`visitPropertyBase(node: | TSESTree.AccessorProperty¶
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractMethodDefinition
| TSESTree.TSAbstractPropertyDefinition): void`
Code
protected visitPropertyBase(
node:
| TSESTree.AccessorProperty
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractMethodDefinition
| TSESTree.TSAbstractPropertyDefinition,
): void {
if (node.computed) {
this.#referencer.visit(node.key);
}
if (node.value) {
if (
node.type === AST_NODE_TYPES.PropertyDefinition ||
node.type === AST_NODE_TYPES.AccessorProperty
) {
this.#referencer.scopeManager.nestClassFieldInitializerScope(
node.value,
);
}
this.#referencer.visit(node.value);
if (
node.type === AST_NODE_TYPES.PropertyDefinition ||
node.type === AST_NODE_TYPES.AccessorProperty
) {
this.#referencer.close(node.value);
}
}
node.decorators.forEach(d => this.#referencer.visit(d));
}
`visitPropertyDefinition(node: | TSESTree.AccessorProperty¶
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractPropertyDefinition): void`
Code
protected visitPropertyDefinition(
node:
| TSESTree.AccessorProperty
| TSESTree.PropertyDefinition
| TSESTree.TSAbstractAccessorProperty
| TSESTree.TSAbstractPropertyDefinition,
): void {
this.visitPropertyBase(node);
/**
* class A {
* @meta // <--- check this
* foo: Type;
* }
*/
this.visitType(node.typeAnnotation);
}