@typescript-eslint/eslint-plugin 8.46.5-alpha.0 → 8.46.5-alpha.2
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/configs/eslintrc/all.d.ts +2 -0
- package/dist/configs/eslintrc/all.js +2 -0
- package/dist/configs/flat/all.js +2 -0
- package/dist/index.d.ts +3 -0
- package/dist/raw-plugin.d.ts +3 -0
- package/dist/rules/index.d.ts +1 -0
- package/dist/rules/index.js +2 -0
- package/dist/rules/no-unused-private-class-members.d.ts +4 -0
- package/dist/rules/no-unused-private-class-members.js +44 -0
- package/dist/util/class-scope-analyzer/classScopeAnalyzer.d.ts +52 -0
- package/dist/util/class-scope-analyzer/classScopeAnalyzer.js +519 -0
- package/dist/util/class-scope-analyzer/extractComputedName.d.ts +17 -0
- package/dist/util/class-scope-analyzer/extractComputedName.js +80 -0
- package/dist/util/class-scope-analyzer/types.d.ts +12 -0
- package/dist/util/class-scope-analyzer/types.js +10 -0
- package/package.json +8 -8
|
@@ -103,6 +103,8 @@ declare const _default: {
|
|
|
103
103
|
'@typescript-eslint/no-unsafe-unary-minus': "error";
|
|
104
104
|
'no-unused-expressions': "off";
|
|
105
105
|
'@typescript-eslint/no-unused-expressions': "error";
|
|
106
|
+
'no-unused-private-class-members': "off";
|
|
107
|
+
'@typescript-eslint/no-unused-private-class-members': "error";
|
|
106
108
|
'no-unused-vars': "off";
|
|
107
109
|
'@typescript-eslint/no-unused-vars': "error";
|
|
108
110
|
'no-use-before-define': "off";
|
|
@@ -110,6 +110,8 @@ module.exports = {
|
|
|
110
110
|
'@typescript-eslint/no-unsafe-unary-minus': 'error',
|
|
111
111
|
'no-unused-expressions': 'off',
|
|
112
112
|
'@typescript-eslint/no-unused-expressions': 'error',
|
|
113
|
+
'no-unused-private-class-members': 'off',
|
|
114
|
+
'@typescript-eslint/no-unused-private-class-members': 'error',
|
|
113
115
|
'no-unused-vars': 'off',
|
|
114
116
|
'@typescript-eslint/no-unused-vars': 'error',
|
|
115
117
|
'no-use-before-define': 'off',
|
package/dist/configs/flat/all.js
CHANGED
|
@@ -123,6 +123,8 @@ exports.default = (plugin, parser) => [
|
|
|
123
123
|
'@typescript-eslint/no-unsafe-unary-minus': 'error',
|
|
124
124
|
'no-unused-expressions': 'off',
|
|
125
125
|
'@typescript-eslint/no-unused-expressions': 'error',
|
|
126
|
+
'no-unused-private-class-members': 'off',
|
|
127
|
+
'@typescript-eslint/no-unused-private-class-members': 'error',
|
|
126
128
|
'no-unused-vars': 'off',
|
|
127
129
|
'@typescript-eslint/no-unused-vars': 'error',
|
|
128
130
|
'no-use-before-define': 'off',
|
package/dist/index.d.ts
CHANGED
|
@@ -105,6 +105,8 @@ declare const _default: {
|
|
|
105
105
|
'@typescript-eslint/no-unsafe-unary-minus': "error";
|
|
106
106
|
'no-unused-expressions': "off";
|
|
107
107
|
'@typescript-eslint/no-unused-expressions': "error";
|
|
108
|
+
'no-unused-private-class-members': "off";
|
|
109
|
+
'@typescript-eslint/no-unused-private-class-members': "error";
|
|
108
110
|
'no-unused-vars': "off";
|
|
109
111
|
'@typescript-eslint/no-unused-vars': "error";
|
|
110
112
|
'no-use-before-define': "off";
|
|
@@ -794,6 +796,7 @@ declare const _default: {
|
|
|
794
796
|
allowTaggedTemplates?: boolean;
|
|
795
797
|
allowTernary?: boolean;
|
|
796
798
|
}], import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
799
|
+
'no-unused-private-class-members': import("@typescript-eslint/utils/ts-eslint").RuleModule<"unusedPrivateClassMember", [], import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
797
800
|
'no-unused-vars': import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./rules/no-unused-vars").MessageIds, import("./rules/no-unused-vars").Options, import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
798
801
|
'no-use-before-define': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noUseBeforeDefine", import("./rules/no-use-before-define").Options, import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
799
802
|
'no-useless-constructor': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noUselessConstructor" | "removeConstructor", [], import("../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
package/dist/raw-plugin.d.ts
CHANGED
|
@@ -127,6 +127,8 @@ declare const _default: {
|
|
|
127
127
|
'@typescript-eslint/no-unsafe-unary-minus': "error";
|
|
128
128
|
'no-unused-expressions': "off";
|
|
129
129
|
'@typescript-eslint/no-unused-expressions': "error";
|
|
130
|
+
'no-unused-private-class-members': "off";
|
|
131
|
+
'@typescript-eslint/no-unused-private-class-members': "error";
|
|
130
132
|
'no-unused-vars': "off";
|
|
131
133
|
'@typescript-eslint/no-unused-vars': "error";
|
|
132
134
|
'no-use-before-define': "off";
|
|
@@ -817,6 +819,7 @@ declare const _default: {
|
|
|
817
819
|
allowTaggedTemplates?: boolean;
|
|
818
820
|
allowTernary?: boolean;
|
|
819
821
|
}], import("../rules").ESLintPluginDocs, TSESLint.RuleListener>;
|
|
822
|
+
'no-unused-private-class-members': TSESLint.RuleModule<"unusedPrivateClassMember", [], import("../rules").ESLintPluginDocs, TSESLint.RuleListener>;
|
|
820
823
|
'no-unused-vars': TSESLint.RuleModule<import("./rules/no-unused-vars").MessageIds, import("./rules/no-unused-vars").Options, import("../rules").ESLintPluginDocs, TSESLint.RuleListener>;
|
|
821
824
|
'no-use-before-define': TSESLint.RuleModule<"noUseBeforeDefine", import("./rules/no-use-before-define").Options, import("../rules").ESLintPluginDocs, TSESLint.RuleListener>;
|
|
822
825
|
'no-useless-constructor': TSESLint.RuleModule<"noUselessConstructor" | "removeConstructor", [], import("../rules").ESLintPluginDocs, TSESLint.RuleListener>;
|
package/dist/rules/index.d.ts
CHANGED
|
@@ -124,6 +124,7 @@ declare const rules: {
|
|
|
124
124
|
allowTaggedTemplates?: boolean;
|
|
125
125
|
allowTernary?: boolean;
|
|
126
126
|
}], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
127
|
+
'no-unused-private-class-members': import("@typescript-eslint/utils/ts-eslint").RuleModule<"unusedPrivateClassMember", [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
127
128
|
'no-unused-vars': import("@typescript-eslint/utils/ts-eslint").RuleModule<import("./no-unused-vars").MessageIds, import("./no-unused-vars").Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
128
129
|
'no-use-before-define': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noUseBeforeDefine", import("./no-use-before-define").Options, import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
|
129
130
|
'no-useless-constructor': import("@typescript-eslint/utils/ts-eslint").RuleModule<"noUselessConstructor" | "removeConstructor", [], import("../../rules").ESLintPluginDocs, import("@typescript-eslint/utils/ts-eslint").RuleListener>;
|
package/dist/rules/index.js
CHANGED
|
@@ -90,6 +90,7 @@ const no_unsafe_return_1 = __importDefault(require("./no-unsafe-return"));
|
|
|
90
90
|
const no_unsafe_type_assertion_1 = __importDefault(require("./no-unsafe-type-assertion"));
|
|
91
91
|
const no_unsafe_unary_minus_1 = __importDefault(require("./no-unsafe-unary-minus"));
|
|
92
92
|
const no_unused_expressions_1 = __importDefault(require("./no-unused-expressions"));
|
|
93
|
+
const no_unused_private_class_members_1 = __importDefault(require("./no-unused-private-class-members"));
|
|
93
94
|
const no_unused_vars_1 = __importDefault(require("./no-unused-vars"));
|
|
94
95
|
const no_use_before_define_1 = __importDefault(require("./no-use-before-define"));
|
|
95
96
|
const no_useless_constructor_1 = __importDefault(require("./no-useless-constructor"));
|
|
@@ -222,6 +223,7 @@ const rules = {
|
|
|
222
223
|
'no-unsafe-type-assertion': no_unsafe_type_assertion_1.default,
|
|
223
224
|
'no-unsafe-unary-minus': no_unsafe_unary_minus_1.default,
|
|
224
225
|
'no-unused-expressions': no_unused_expressions_1.default,
|
|
226
|
+
'no-unused-private-class-members': no_unused_private_class_members_1.default,
|
|
225
227
|
'no-unused-vars': no_unused_vars_1.default,
|
|
226
228
|
'no-use-before-define': no_use_before_define_1.default,
|
|
227
229
|
'no-useless-constructor': no_useless_constructor_1.default,
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { ESLintUtils } from '@typescript-eslint/utils';
|
|
2
|
+
export type MessageIds = 'unusedPrivateClassMember';
|
|
3
|
+
declare const _default: ESLintUtils.RuleModule<"unusedPrivateClassMember", [], import("../../rules").ESLintPluginDocs, ESLintUtils.RuleListener>;
|
|
4
|
+
export default _default;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
4
|
+
const util_1 = require("../util");
|
|
5
|
+
const classScopeAnalyzer_1 = require("../util/class-scope-analyzer/classScopeAnalyzer");
|
|
6
|
+
exports.default = (0, util_1.createRule)({
|
|
7
|
+
name: 'no-unused-private-class-members',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'problem',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Disallow unused private class members',
|
|
12
|
+
extendsBaseRule: true,
|
|
13
|
+
requiresTypeChecking: false,
|
|
14
|
+
},
|
|
15
|
+
messages: {
|
|
16
|
+
unusedPrivateClassMember: "Private class member '{{classMemberName}}' is defined but never used.",
|
|
17
|
+
},
|
|
18
|
+
schema: [],
|
|
19
|
+
},
|
|
20
|
+
defaultOptions: [],
|
|
21
|
+
create(context) {
|
|
22
|
+
return {
|
|
23
|
+
'Program:exit'(node) {
|
|
24
|
+
const result = (0, classScopeAnalyzer_1.analyzeClassMemberUsage)(node, utils_1.ESLintUtils.nullThrows(context.sourceCode.scopeManager, 'Missing required scope manager'));
|
|
25
|
+
for (const classScope of result.values()) {
|
|
26
|
+
for (const member of [
|
|
27
|
+
...classScope.members.instance.values(),
|
|
28
|
+
...classScope.members.static.values(),
|
|
29
|
+
]) {
|
|
30
|
+
if ((!member.isPrivate() && !member.isHashPrivate()) ||
|
|
31
|
+
member.isUsed()) {
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
context.report({
|
|
35
|
+
node: member.nameNode,
|
|
36
|
+
messageId: 'unusedPrivateClassMember',
|
|
37
|
+
data: { classMemberName: member.name },
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
},
|
|
44
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { ScopeManager } from '@typescript-eslint/scope-manager';
|
|
2
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
3
|
+
import type { ClassNode, Key, MemberNode } from './types';
|
|
4
|
+
export declare class Member {
|
|
5
|
+
/**
|
|
6
|
+
* The node that declares this member
|
|
7
|
+
*/
|
|
8
|
+
readonly node: MemberNode;
|
|
9
|
+
/**
|
|
10
|
+
* The resolved, unique key for this member.
|
|
11
|
+
*/
|
|
12
|
+
readonly key: Key;
|
|
13
|
+
/**
|
|
14
|
+
* The member name, as given in the source code.
|
|
15
|
+
*/
|
|
16
|
+
readonly name: string;
|
|
17
|
+
/**
|
|
18
|
+
* The node that represents the member name in the source code.
|
|
19
|
+
* Used for reporting errors.
|
|
20
|
+
*/
|
|
21
|
+
readonly nameNode: TSESTree.Node;
|
|
22
|
+
/**
|
|
23
|
+
* The number of writes to this member.
|
|
24
|
+
*/
|
|
25
|
+
writeCount: number;
|
|
26
|
+
/**
|
|
27
|
+
* The number of reads from this member.
|
|
28
|
+
*/
|
|
29
|
+
readCount: number;
|
|
30
|
+
private constructor();
|
|
31
|
+
static create(node: MemberNode): Member | null;
|
|
32
|
+
isAccessor(): boolean;
|
|
33
|
+
isHashPrivate(): boolean;
|
|
34
|
+
isPrivate(): boolean;
|
|
35
|
+
isStatic(): boolean;
|
|
36
|
+
isUsed(): boolean;
|
|
37
|
+
}
|
|
38
|
+
export interface ClassScopeResult {
|
|
39
|
+
/**
|
|
40
|
+
* The classes name as given in the source code.
|
|
41
|
+
* If this is `null` then the class is an anonymous class.
|
|
42
|
+
*/
|
|
43
|
+
readonly className: string | null;
|
|
44
|
+
/**
|
|
45
|
+
* The class's members, keyed by their name
|
|
46
|
+
*/
|
|
47
|
+
readonly members: {
|
|
48
|
+
readonly instance: Map<Key, Member>;
|
|
49
|
+
readonly static: Map<Key, Member>;
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
export declare function analyzeClassMemberUsage(program: TSESTree.Program, scopeManager: ScopeManager): ReadonlyMap<ClassNode, ClassScopeResult>;
|
|
@@ -0,0 +1,519 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Member = void 0;
|
|
4
|
+
exports.analyzeClassMemberUsage = analyzeClassMemberUsage;
|
|
5
|
+
const scope_manager_1 = require("@typescript-eslint/scope-manager");
|
|
6
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
7
|
+
const __1 = require("..");
|
|
8
|
+
const extractComputedName_1 = require("./extractComputedName");
|
|
9
|
+
const types_1 = require("./types");
|
|
10
|
+
class Member {
|
|
11
|
+
/**
|
|
12
|
+
* The node that declares this member
|
|
13
|
+
*/
|
|
14
|
+
node;
|
|
15
|
+
/**
|
|
16
|
+
* The resolved, unique key for this member.
|
|
17
|
+
*/
|
|
18
|
+
key;
|
|
19
|
+
/**
|
|
20
|
+
* The member name, as given in the source code.
|
|
21
|
+
*/
|
|
22
|
+
name;
|
|
23
|
+
/**
|
|
24
|
+
* The node that represents the member name in the source code.
|
|
25
|
+
* Used for reporting errors.
|
|
26
|
+
*/
|
|
27
|
+
nameNode;
|
|
28
|
+
/**
|
|
29
|
+
* The number of writes to this member.
|
|
30
|
+
*/
|
|
31
|
+
writeCount = 0;
|
|
32
|
+
/**
|
|
33
|
+
* The number of reads from this member.
|
|
34
|
+
*/
|
|
35
|
+
readCount = 0;
|
|
36
|
+
constructor(node, key, name, nameNode) {
|
|
37
|
+
this.node = node;
|
|
38
|
+
this.key = key;
|
|
39
|
+
this.name = name;
|
|
40
|
+
this.nameNode = nameNode;
|
|
41
|
+
}
|
|
42
|
+
static create(node) {
|
|
43
|
+
const name = (0, extractComputedName_1.extractNameForMember)(node);
|
|
44
|
+
if (name == null) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
return new Member(node, name.key, name.codeName, name.nameNode);
|
|
48
|
+
}
|
|
49
|
+
isAccessor() {
|
|
50
|
+
if (this.node.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
|
|
51
|
+
this.node.type === utils_1.AST_NODE_TYPES.TSAbstractMethodDefinition) {
|
|
52
|
+
return this.node.kind === 'set' || this.node.kind === 'get';
|
|
53
|
+
}
|
|
54
|
+
return (this.node.type === utils_1.AST_NODE_TYPES.AccessorProperty ||
|
|
55
|
+
this.node.type === utils_1.AST_NODE_TYPES.TSAbstractAccessorProperty);
|
|
56
|
+
}
|
|
57
|
+
isHashPrivate() {
|
|
58
|
+
return ('key' in this.node &&
|
|
59
|
+
this.node.key.type === utils_1.AST_NODE_TYPES.PrivateIdentifier);
|
|
60
|
+
}
|
|
61
|
+
isPrivate() {
|
|
62
|
+
return this.node.accessibility === 'private';
|
|
63
|
+
}
|
|
64
|
+
isStatic() {
|
|
65
|
+
return this.node.static;
|
|
66
|
+
}
|
|
67
|
+
isUsed() {
|
|
68
|
+
return (this.readCount > 0 ||
|
|
69
|
+
// any usage of an accessor is considered a usage as accessor can have side effects
|
|
70
|
+
(this.writeCount > 0 && this.isAccessor()));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
exports.Member = Member;
|
|
74
|
+
function isWriteOnlyUsage(node, parent) {
|
|
75
|
+
if (parent.type !== utils_1.AST_NODE_TYPES.AssignmentExpression &&
|
|
76
|
+
parent.type !== utils_1.AST_NODE_TYPES.ForInStatement &&
|
|
77
|
+
parent.type !== utils_1.AST_NODE_TYPES.ForOfStatement &&
|
|
78
|
+
parent.type !== utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
// If it's on the right then it's a read not a write
|
|
82
|
+
if (parent.left !== node) {
|
|
83
|
+
return false;
|
|
84
|
+
}
|
|
85
|
+
if (parent.type === utils_1.AST_NODE_TYPES.AssignmentExpression &&
|
|
86
|
+
// For any other operator (such as '+=') we still consider it a read operation
|
|
87
|
+
parent.operator !== '=') {
|
|
88
|
+
// if the read operation is "discarded" in an empty statement, then it is write only.
|
|
89
|
+
return parent.parent.type === utils_1.AST_NODE_TYPES.ExpressionStatement;
|
|
90
|
+
}
|
|
91
|
+
return true;
|
|
92
|
+
}
|
|
93
|
+
function countReference(identifierParent, member) {
|
|
94
|
+
const identifierGrandparent = (0, __1.nullThrows)(identifierParent.parent, __1.NullThrowsReasons.MissingParent);
|
|
95
|
+
if (isWriteOnlyUsage(identifierParent, identifierGrandparent)) {
|
|
96
|
+
member.writeCount += 1;
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const identifierGreatGrandparent = identifierGrandparent.parent;
|
|
100
|
+
// A statement which only increments (`this.#x++;`)
|
|
101
|
+
if (identifierGrandparent.type === utils_1.AST_NODE_TYPES.UpdateExpression &&
|
|
102
|
+
identifierGreatGrandparent?.type === utils_1.AST_NODE_TYPES.ExpressionStatement) {
|
|
103
|
+
member.writeCount += 1;
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
/*
|
|
107
|
+
* ({ x: this.#usedInDestructuring } = bar);
|
|
108
|
+
*
|
|
109
|
+
* But should treat the following as a read:
|
|
110
|
+
* ({ [this.#x]: a } = foo);
|
|
111
|
+
*/
|
|
112
|
+
if (identifierGrandparent.type === utils_1.AST_NODE_TYPES.Property &&
|
|
113
|
+
identifierGreatGrandparent?.type === utils_1.AST_NODE_TYPES.ObjectPattern &&
|
|
114
|
+
identifierGrandparent.value === identifierParent) {
|
|
115
|
+
member.writeCount += 1;
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// [...this.#unusedInRestPattern] = bar;
|
|
119
|
+
if (identifierGrandparent.type === utils_1.AST_NODE_TYPES.RestElement) {
|
|
120
|
+
member.writeCount += 1;
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
// [this.#unusedInAssignmentPattern] = bar;
|
|
124
|
+
if (identifierGrandparent.type === utils_1.AST_NODE_TYPES.ArrayPattern) {
|
|
125
|
+
member.writeCount += 1;
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
member.readCount += 1;
|
|
129
|
+
}
|
|
130
|
+
class ThisScope extends scope_manager_1.Visitor {
|
|
131
|
+
/**
|
|
132
|
+
* True if the context is considered a static context and so `this` refers to
|
|
133
|
+
* the class and not an instance (eg a static method or a static block).
|
|
134
|
+
*/
|
|
135
|
+
isStaticThisContext;
|
|
136
|
+
/**
|
|
137
|
+
* The classes directly declared within this class -- for example a class declared within a method.
|
|
138
|
+
* This does not include grandchild classes.
|
|
139
|
+
*/
|
|
140
|
+
childScopes = [];
|
|
141
|
+
/**
|
|
142
|
+
* The scope manager instance used to resolve variables to improve discovery of usages.
|
|
143
|
+
*/
|
|
144
|
+
scopeManager;
|
|
145
|
+
/**
|
|
146
|
+
* The parent class scope if one exists.
|
|
147
|
+
*/
|
|
148
|
+
upper;
|
|
149
|
+
/**
|
|
150
|
+
* The context of the `this` reference in the current scope.
|
|
151
|
+
*/
|
|
152
|
+
thisContext;
|
|
153
|
+
constructor(scopeManager, upper, thisContext, isStaticThisContext) {
|
|
154
|
+
super({});
|
|
155
|
+
this.scopeManager = scopeManager;
|
|
156
|
+
this.upper = upper;
|
|
157
|
+
this.isStaticThisContext = isStaticThisContext;
|
|
158
|
+
if (thisContext === 'self') {
|
|
159
|
+
if (!(this instanceof ClassScope)) {
|
|
160
|
+
throw new Error('Cannot use `self` unless it is in a ClassScope');
|
|
161
|
+
}
|
|
162
|
+
this.thisContext = this;
|
|
163
|
+
}
|
|
164
|
+
else if (thisContext === 'none') {
|
|
165
|
+
this.thisContext = null;
|
|
166
|
+
}
|
|
167
|
+
else {
|
|
168
|
+
this.thisContext = thisContext;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
findNearestScope(node) {
|
|
172
|
+
let currentScope;
|
|
173
|
+
let currentNode = node;
|
|
174
|
+
do {
|
|
175
|
+
currentScope = this.scopeManager.acquire(currentNode);
|
|
176
|
+
if (currentNode.parent == null) {
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
currentNode = currentNode.parent;
|
|
180
|
+
} while (currentScope == null);
|
|
181
|
+
return currentScope;
|
|
182
|
+
}
|
|
183
|
+
findVariableInScope(node, name) {
|
|
184
|
+
let currentScope = this.findNearestScope(node);
|
|
185
|
+
let variable = null;
|
|
186
|
+
while (currentScope != null) {
|
|
187
|
+
variable = currentScope.set.get(name) ?? null;
|
|
188
|
+
if (variable != null) {
|
|
189
|
+
break;
|
|
190
|
+
}
|
|
191
|
+
currentScope = currentScope.upper;
|
|
192
|
+
}
|
|
193
|
+
return variable;
|
|
194
|
+
}
|
|
195
|
+
getObjectClass(node) {
|
|
196
|
+
switch (node.object.type) {
|
|
197
|
+
case utils_1.AST_NODE_TYPES.ThisExpression: {
|
|
198
|
+
if (this.thisContext == null) {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
thisContext: this.thisContext,
|
|
203
|
+
type: this.isStaticThisContext ? 'static' : 'instance',
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
case utils_1.AST_NODE_TYPES.Identifier: {
|
|
207
|
+
const thisContext = this.findClassScopeWithName(node.object.name);
|
|
208
|
+
if (thisContext != null) {
|
|
209
|
+
return { thisContext, type: 'static' };
|
|
210
|
+
}
|
|
211
|
+
// the following code does some very rudimentary scope analysis to handle some trivial cases
|
|
212
|
+
const variable = this.findVariableInScope(node, node.object.name);
|
|
213
|
+
if (variable == null || variable.defs.length === 0) {
|
|
214
|
+
return null;
|
|
215
|
+
}
|
|
216
|
+
const firstDef = variable.defs[0];
|
|
217
|
+
switch (firstDef.node.type) {
|
|
218
|
+
// detect simple reassignment of `this`
|
|
219
|
+
// ```
|
|
220
|
+
// class Foo {
|
|
221
|
+
// private prop: number;
|
|
222
|
+
// method(thing: Foo) {
|
|
223
|
+
// const self = this;
|
|
224
|
+
// return self.prop;
|
|
225
|
+
// }
|
|
226
|
+
// }
|
|
227
|
+
// ```
|
|
228
|
+
case utils_1.AST_NODE_TYPES.VariableDeclarator: {
|
|
229
|
+
const value = firstDef.node.init;
|
|
230
|
+
if (value == null || value.type !== utils_1.AST_NODE_TYPES.ThisExpression) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
if (variable.references.some(ref => ref.isWrite() && ref.init !== true)) {
|
|
234
|
+
// variable is assigned to multiple times so we can't be sure that it's still the same class
|
|
235
|
+
return null;
|
|
236
|
+
}
|
|
237
|
+
// we have a case like `const self = this` or `let self = this` that is not reassigned
|
|
238
|
+
// so we can safely assume that it's still the same class!
|
|
239
|
+
return {
|
|
240
|
+
thisContext: this.thisContext,
|
|
241
|
+
type: this.isStaticThisContext ? 'static' : 'instance',
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
// Look for variables typed as the current class:
|
|
245
|
+
// ```
|
|
246
|
+
// class Foo {
|
|
247
|
+
// private prop: number;
|
|
248
|
+
// method(thing: Foo) {
|
|
249
|
+
// // this references the private instance member but not via `this` so we can't see it
|
|
250
|
+
// thing.prop = 1;
|
|
251
|
+
// }
|
|
252
|
+
// }
|
|
253
|
+
// ```
|
|
254
|
+
default: {
|
|
255
|
+
const typeAnnotation = (() => {
|
|
256
|
+
if ('typeAnnotation' in firstDef.name &&
|
|
257
|
+
firstDef.name.typeAnnotation != null) {
|
|
258
|
+
return firstDef.name.typeAnnotation.typeAnnotation;
|
|
259
|
+
}
|
|
260
|
+
return null;
|
|
261
|
+
})();
|
|
262
|
+
if (typeAnnotation == null) {
|
|
263
|
+
return null;
|
|
264
|
+
}
|
|
265
|
+
// Cases like `method(thing: Foo) { ... }`
|
|
266
|
+
if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
|
267
|
+
typeAnnotation.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
268
|
+
const typeName = typeAnnotation.typeName.name;
|
|
269
|
+
const typeScope = this.findClassScopeWithName(typeName);
|
|
270
|
+
if (typeScope != null) {
|
|
271
|
+
return { thisContext: typeScope, type: 'instance' };
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
// Cases like `method(thing: typeof Foo) { ... }`
|
|
275
|
+
if (typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeQuery &&
|
|
276
|
+
typeAnnotation.exprName.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
277
|
+
const exprName = typeAnnotation.exprName.name;
|
|
278
|
+
const exprScope = this.findClassScopeWithName(exprName);
|
|
279
|
+
if (exprScope != null) {
|
|
280
|
+
return { thisContext: exprScope, type: 'static' };
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
return null;
|
|
286
|
+
}
|
|
287
|
+
case utils_1.AST_NODE_TYPES.MemberExpression:
|
|
288
|
+
// TODO - we could probably recurse here to do some more complex analysis and support like `foo.bar.baz` nested references
|
|
289
|
+
return null;
|
|
290
|
+
default:
|
|
291
|
+
return null;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
visitClass(node) {
|
|
295
|
+
const classScope = new ClassScope(node, this, this.scopeManager);
|
|
296
|
+
this.childScopes.push(classScope);
|
|
297
|
+
classScope.visitChildren(node);
|
|
298
|
+
}
|
|
299
|
+
visitIntermediate(node) {
|
|
300
|
+
const intermediateScope = new IntermediateScope(this.scopeManager, this, node);
|
|
301
|
+
this.childScopes.push(intermediateScope);
|
|
302
|
+
intermediateScope.visitChildren(node);
|
|
303
|
+
}
|
|
304
|
+
/**
|
|
305
|
+
* Gets the nearest class scope with the given name.
|
|
306
|
+
*/
|
|
307
|
+
findClassScopeWithName(name) {
|
|
308
|
+
let currentScope = this;
|
|
309
|
+
while (currentScope != null) {
|
|
310
|
+
if (currentScope instanceof ClassScope &&
|
|
311
|
+
currentScope.className === name) {
|
|
312
|
+
return currentScope;
|
|
313
|
+
}
|
|
314
|
+
currentScope = currentScope.upper;
|
|
315
|
+
}
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
/////////////////////
|
|
319
|
+
// Visit selectors //
|
|
320
|
+
/////////////////////
|
|
321
|
+
ClassDeclaration(node) {
|
|
322
|
+
this.visitClass(node);
|
|
323
|
+
}
|
|
324
|
+
ClassExpression(node) {
|
|
325
|
+
this.visitClass(node);
|
|
326
|
+
}
|
|
327
|
+
FunctionDeclaration(node) {
|
|
328
|
+
this.visitIntermediate(node);
|
|
329
|
+
}
|
|
330
|
+
FunctionExpression(node) {
|
|
331
|
+
this.visitIntermediate(node);
|
|
332
|
+
}
|
|
333
|
+
MemberExpression(node) {
|
|
334
|
+
this.visitChildren(node);
|
|
335
|
+
if (node.property.type === utils_1.AST_NODE_TYPES.PrivateIdentifier) {
|
|
336
|
+
// will be handled by the PrivateIdentifier visitor
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
const propertyName = (0, extractComputedName_1.extractNameForMemberExpression)(node);
|
|
340
|
+
if (propertyName == null) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const objectClassName = this.getObjectClass(node);
|
|
344
|
+
if (objectClassName == null) {
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
if (objectClassName.thisContext == null) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const members = objectClassName.type === 'instance'
|
|
351
|
+
? objectClassName.thisContext.members.instance
|
|
352
|
+
: objectClassName.thisContext.members.static;
|
|
353
|
+
const member = members.get(propertyName.key);
|
|
354
|
+
if (member == null) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
countReference(node, member);
|
|
358
|
+
}
|
|
359
|
+
PrivateIdentifier(node) {
|
|
360
|
+
this.visitChildren(node);
|
|
361
|
+
if ((node.parent.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
|
|
362
|
+
node.parent.type === utils_1.AST_NODE_TYPES.PropertyDefinition) &&
|
|
363
|
+
node.parent.key === node) {
|
|
364
|
+
// ignore the member definition
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
// We can actually be pretty loose with our code here thanks to how private
|
|
368
|
+
// members are designed.
|
|
369
|
+
//
|
|
370
|
+
// 1) classes CANNOT have a static and instance private member with the
|
|
371
|
+
// same name, so we don't need to match up static access.
|
|
372
|
+
// 2) nested classes CANNOT access a private member of their parent class if
|
|
373
|
+
// the member has the same name as a private member of the nested class.
|
|
374
|
+
//
|
|
375
|
+
// together this means that we can just look for the member upwards until we
|
|
376
|
+
// find a match and we know that will be the correct match!
|
|
377
|
+
let currentScope = this;
|
|
378
|
+
const key = (0, types_1.privateKey)(node);
|
|
379
|
+
while (currentScope != null) {
|
|
380
|
+
if (currentScope.thisContext != null) {
|
|
381
|
+
const member = currentScope.thisContext.members.instance.get(key) ??
|
|
382
|
+
currentScope.thisContext.members.static.get(key);
|
|
383
|
+
if (member != null) {
|
|
384
|
+
countReference(node.parent, member);
|
|
385
|
+
return;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
currentScope = currentScope.upper;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
StaticBlock(node) {
|
|
392
|
+
this.visitIntermediate(node);
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* Any other scope that is not a class scope
|
|
397
|
+
*
|
|
398
|
+
* When we visit a function declaration/expression the `this` reference is
|
|
399
|
+
* rebound so it no longer refers to the class.
|
|
400
|
+
*
|
|
401
|
+
* This also supports a function's `this` parameter.
|
|
402
|
+
*/
|
|
403
|
+
class IntermediateScope extends ThisScope {
|
|
404
|
+
constructor(scopeManager, upper, node) {
|
|
405
|
+
if (node.type === utils_1.AST_NODE_TYPES.Program) {
|
|
406
|
+
super(scopeManager, upper, 'none', false);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
if (node.type === utils_1.AST_NODE_TYPES.StaticBlock) {
|
|
410
|
+
if (upper == null || !(upper instanceof ClassScope)) {
|
|
411
|
+
throw new Error('Cannot have a static block without an upper ClassScope');
|
|
412
|
+
}
|
|
413
|
+
super(scopeManager, upper, upper, true);
|
|
414
|
+
return;
|
|
415
|
+
}
|
|
416
|
+
// method definition
|
|
417
|
+
if ((node.parent.type === utils_1.AST_NODE_TYPES.MethodDefinition ||
|
|
418
|
+
node.parent.type === utils_1.AST_NODE_TYPES.PropertyDefinition) &&
|
|
419
|
+
node.parent.value === node) {
|
|
420
|
+
if (upper == null || !(upper instanceof ClassScope)) {
|
|
421
|
+
throw new Error('Cannot have a class method/property without an upper ClassScope');
|
|
422
|
+
}
|
|
423
|
+
super(scopeManager, upper, upper, node.parent.static);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
// function with a `this` parameter
|
|
427
|
+
if (upper != null &&
|
|
428
|
+
node.params.length > 0 &&
|
|
429
|
+
node.params[0].type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
430
|
+
node.params[0].name === 'this') {
|
|
431
|
+
const thisType = node.params[0].typeAnnotation?.typeAnnotation;
|
|
432
|
+
if (thisType?.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
|
433
|
+
thisType.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
434
|
+
const thisContext = upper.findClassScopeWithName(thisType.typeName.name);
|
|
435
|
+
if (thisContext != null) {
|
|
436
|
+
super(scopeManager, upper, thisContext, false);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
super(scopeManager, upper, 'none', false);
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
class ClassScope extends ThisScope {
|
|
445
|
+
className;
|
|
446
|
+
/**
|
|
447
|
+
* The class's members, keyed by their name
|
|
448
|
+
*/
|
|
449
|
+
members = {
|
|
450
|
+
instance: new Map(),
|
|
451
|
+
static: new Map(),
|
|
452
|
+
};
|
|
453
|
+
/**
|
|
454
|
+
* The node that declares this class.
|
|
455
|
+
*/
|
|
456
|
+
theClass;
|
|
457
|
+
constructor(theClass, upper, scopeManager) {
|
|
458
|
+
super(scopeManager, upper, 'self', false);
|
|
459
|
+
this.theClass = theClass;
|
|
460
|
+
this.className = theClass.id?.name ?? null;
|
|
461
|
+
for (const memberNode of theClass.body.body) {
|
|
462
|
+
switch (memberNode.type) {
|
|
463
|
+
case utils_1.AST_NODE_TYPES.MethodDefinition:
|
|
464
|
+
if (memberNode.kind === 'constructor') {
|
|
465
|
+
for (const parameter of memberNode.value.params) {
|
|
466
|
+
if (parameter.type !== utils_1.AST_NODE_TYPES.TSParameterProperty) {
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
const member = Member.create(parameter);
|
|
470
|
+
if (member == null) {
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
this.members.instance.set(member.key, member);
|
|
474
|
+
}
|
|
475
|
+
// break instead of falling through because the constructor is not a "member" we track
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
// intentional fallthrough
|
|
479
|
+
case utils_1.AST_NODE_TYPES.AccessorProperty:
|
|
480
|
+
case utils_1.AST_NODE_TYPES.PropertyDefinition:
|
|
481
|
+
case utils_1.AST_NODE_TYPES.TSAbstractAccessorProperty:
|
|
482
|
+
case utils_1.AST_NODE_TYPES.TSAbstractMethodDefinition:
|
|
483
|
+
case utils_1.AST_NODE_TYPES.TSAbstractPropertyDefinition: {
|
|
484
|
+
const member = Member.create(memberNode);
|
|
485
|
+
if (member == null) {
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
if (member.isStatic()) {
|
|
489
|
+
this.members.static.set(member.key, member);
|
|
490
|
+
}
|
|
491
|
+
else {
|
|
492
|
+
this.members.instance.set(member.key, member);
|
|
493
|
+
}
|
|
494
|
+
break;
|
|
495
|
+
}
|
|
496
|
+
case utils_1.AST_NODE_TYPES.StaticBlock:
|
|
497
|
+
// static blocks declare no members
|
|
498
|
+
continue;
|
|
499
|
+
case utils_1.AST_NODE_TYPES.TSIndexSignature:
|
|
500
|
+
// index signatures are type signatures only and are fully computed
|
|
501
|
+
continue;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
function analyzeClassMemberUsage(program, scopeManager) {
|
|
507
|
+
const rootScope = new IntermediateScope(scopeManager, null, program);
|
|
508
|
+
rootScope.visit(program);
|
|
509
|
+
return traverseScopes(rootScope);
|
|
510
|
+
}
|
|
511
|
+
function traverseScopes(currentScope, analysisResults = new Map()) {
|
|
512
|
+
if (currentScope instanceof ClassScope) {
|
|
513
|
+
analysisResults.set(currentScope.theClass, currentScope);
|
|
514
|
+
}
|
|
515
|
+
for (const childScope of currentScope.childScopes) {
|
|
516
|
+
traverseScopes(childScope, analysisResults);
|
|
517
|
+
}
|
|
518
|
+
return analysisResults;
|
|
519
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
import type { Key, MemberNode } from './types';
|
|
3
|
+
export interface ExtractedName {
|
|
4
|
+
key: Key;
|
|
5
|
+
codeName: string;
|
|
6
|
+
nameNode: TSESTree.Node;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Extracts the string name for a member.
|
|
10
|
+
* @returns `null` if the name cannot be extracted due to it being computed.
|
|
11
|
+
*/
|
|
12
|
+
export declare function extractNameForMember(node: MemberNode): ExtractedName | null;
|
|
13
|
+
/**
|
|
14
|
+
* Extracts the string property name for a member.
|
|
15
|
+
* @returns `null` if the name cannot be extracted due to it being a computed.
|
|
16
|
+
*/
|
|
17
|
+
export declare function extractNameForMemberExpression(node: TSESTree.MemberExpression): ExtractedName | null;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.extractNameForMember = extractNameForMember;
|
|
4
|
+
exports.extractNameForMemberExpression = extractNameForMemberExpression;
|
|
5
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
6
|
+
const types_1 = require("./types");
|
|
7
|
+
function extractComputedName(computedName) {
|
|
8
|
+
if (computedName.type === utils_1.AST_NODE_TYPES.Literal) {
|
|
9
|
+
const name = computedName.value?.toString() ?? 'null';
|
|
10
|
+
return {
|
|
11
|
+
codeName: name,
|
|
12
|
+
key: (0, types_1.publicKey)(name),
|
|
13
|
+
nameNode: computedName,
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
if (computedName.type === utils_1.AST_NODE_TYPES.TemplateLiteral &&
|
|
17
|
+
computedName.expressions.length === 0) {
|
|
18
|
+
const name = computedName.quasis[0].value.raw;
|
|
19
|
+
return {
|
|
20
|
+
codeName: name,
|
|
21
|
+
key: (0, types_1.publicKey)(name),
|
|
22
|
+
nameNode: computedName,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
function extractNonComputedName(nonComputedName) {
|
|
28
|
+
const name = nonComputedName.name;
|
|
29
|
+
if (nonComputedName.type === utils_1.AST_NODE_TYPES.PrivateIdentifier) {
|
|
30
|
+
return {
|
|
31
|
+
codeName: `#${name}`,
|
|
32
|
+
key: (0, types_1.privateKey)(nonComputedName),
|
|
33
|
+
nameNode: nonComputedName,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
return {
|
|
37
|
+
codeName: name,
|
|
38
|
+
key: (0, types_1.publicKey)(name),
|
|
39
|
+
nameNode: nonComputedName,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Extracts the string name for a member.
|
|
44
|
+
* @returns `null` if the name cannot be extracted due to it being computed.
|
|
45
|
+
*/
|
|
46
|
+
function extractNameForMember(node) {
|
|
47
|
+
if (node.type === utils_1.AST_NODE_TYPES.TSParameterProperty) {
|
|
48
|
+
switch (node.parameter.type) {
|
|
49
|
+
case utils_1.AST_NODE_TYPES.ArrayPattern:
|
|
50
|
+
case utils_1.AST_NODE_TYPES.ObjectPattern:
|
|
51
|
+
case utils_1.AST_NODE_TYPES.RestElement:
|
|
52
|
+
// Nonsensical properties -- see https://github.com/typescript-eslint/typescript-eslint/issues/11708
|
|
53
|
+
return null;
|
|
54
|
+
case utils_1.AST_NODE_TYPES.AssignmentPattern:
|
|
55
|
+
if (node.parameter.left.type !== utils_1.AST_NODE_TYPES.Identifier) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return extractNonComputedName(node.parameter.left);
|
|
59
|
+
case utils_1.AST_NODE_TYPES.Identifier:
|
|
60
|
+
return extractNonComputedName(node.parameter);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (node.computed) {
|
|
64
|
+
return extractComputedName(node.key);
|
|
65
|
+
}
|
|
66
|
+
if (node.key.type === utils_1.AST_NODE_TYPES.Literal) {
|
|
67
|
+
return extractComputedName(node.key);
|
|
68
|
+
}
|
|
69
|
+
return extractNonComputedName(node.key);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extracts the string property name for a member.
|
|
73
|
+
* @returns `null` if the name cannot be extracted due to it being a computed.
|
|
74
|
+
*/
|
|
75
|
+
function extractNameForMemberExpression(node) {
|
|
76
|
+
if (node.computed) {
|
|
77
|
+
return extractComputedName(node.property);
|
|
78
|
+
}
|
|
79
|
+
return extractNonComputedName(node.property);
|
|
80
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { TSESTree } from '@typescript-eslint/utils';
|
|
2
|
+
export type ClassNode = TSESTree.ClassDeclaration | TSESTree.ClassExpression;
|
|
3
|
+
export type MemberNode = TSESTree.AccessorProperty | TSESTree.MethodDefinition | TSESTree.PropertyDefinition | TSESTree.TSAbstractAccessorProperty | TSESTree.TSAbstractMethodDefinition | TSESTree.TSAbstractPropertyDefinition | TSESTree.TSParameterProperty;
|
|
4
|
+
export type PrivateKey = string & {
|
|
5
|
+
__brand: 'private-key';
|
|
6
|
+
};
|
|
7
|
+
export type PublicKey = string & {
|
|
8
|
+
__brand: 'public-key';
|
|
9
|
+
};
|
|
10
|
+
export type Key = PrivateKey | PublicKey;
|
|
11
|
+
export declare function publicKey(name: string): PublicKey;
|
|
12
|
+
export declare function privateKey(node: TSESTree.PrivateIdentifier): PrivateKey;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.publicKey = publicKey;
|
|
4
|
+
exports.privateKey = privateKey;
|
|
5
|
+
function publicKey(name) {
|
|
6
|
+
return name;
|
|
7
|
+
}
|
|
8
|
+
function privateKey(node) {
|
|
9
|
+
return `#private@@${node.name}`;
|
|
10
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@typescript-eslint/eslint-plugin",
|
|
3
|
-
"version": "8.46.5-alpha.
|
|
3
|
+
"version": "8.46.5-alpha.2",
|
|
4
4
|
"description": "TypeScript plugin for ESLint",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -59,10 +59,10 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@eslint-community/regexpp": "^4.10.0",
|
|
62
|
-
"@typescript-eslint/scope-manager": "8.46.5-alpha.
|
|
63
|
-
"@typescript-eslint/type-utils": "8.46.5-alpha.
|
|
64
|
-
"@typescript-eslint/utils": "8.46.5-alpha.
|
|
65
|
-
"@typescript-eslint/visitor-keys": "8.46.5-alpha.
|
|
62
|
+
"@typescript-eslint/scope-manager": "8.46.5-alpha.2",
|
|
63
|
+
"@typescript-eslint/type-utils": "8.46.5-alpha.2",
|
|
64
|
+
"@typescript-eslint/utils": "8.46.5-alpha.2",
|
|
65
|
+
"@typescript-eslint/visitor-keys": "8.46.5-alpha.2",
|
|
66
66
|
"graphemer": "^1.4.0",
|
|
67
67
|
"ignore": "^7.0.0",
|
|
68
68
|
"natural-compare": "^1.4.0",
|
|
@@ -71,8 +71,8 @@
|
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/mdast": "^4.0.3",
|
|
73
73
|
"@types/natural-compare": "*",
|
|
74
|
-
"@typescript-eslint/rule-schema-to-typescript-types": "8.46.5-alpha.
|
|
75
|
-
"@typescript-eslint/rule-tester": "8.46.5-alpha.
|
|
74
|
+
"@typescript-eslint/rule-schema-to-typescript-types": "8.46.5-alpha.2",
|
|
75
|
+
"@typescript-eslint/rule-tester": "8.46.5-alpha.2",
|
|
76
76
|
"@vitest/coverage-v8": "^3.1.3",
|
|
77
77
|
"ajv": "^6.12.6",
|
|
78
78
|
"cross-fetch": "*",
|
|
@@ -92,7 +92,7 @@
|
|
|
92
92
|
"vitest": "^3.1.3"
|
|
93
93
|
},
|
|
94
94
|
"peerDependencies": {
|
|
95
|
-
"@typescript-eslint/parser": "^8.46.5-alpha.
|
|
95
|
+
"@typescript-eslint/parser": "^8.46.5-alpha.2",
|
|
96
96
|
"eslint": "^8.57.0 || ^9.0.0",
|
|
97
97
|
"typescript": ">=4.8.4 <6.0.0"
|
|
98
98
|
},
|