eslint-plugin-ore-ui 1.0.0
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/Changelog.md +3 -0
- package/LICENSE +21 -0
- package/README.md +604 -0
- package/dist/index.cjs +121 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +274 -0
- package/dist/rules/no-bugged.cjs +621 -0
- package/dist/rules/no-bugged.cjs.map +1 -0
- package/dist/rules/no-bugged.d.cts +9 -0
- package/dist/rules/no-critically-bugged.cjs +623 -0
- package/dist/rules/no-critically-bugged.cjs.map +1 -0
- package/dist/rules/no-critically-bugged.d.cts +9 -0
- package/dist/rules/no-illegal-constructors.cjs +516 -0
- package/dist/rules/no-illegal-constructors.cjs.map +1 -0
- package/dist/rules/no-illegal-constructors.d.cts +9 -0
- package/dist/rules/no-regex-unicode-properties.cjs +34 -0
- package/dist/rules/no-regex-unicode-properties.cjs.map +1 -0
- package/dist/rules/no-regex-unicode-properties.d.cts +17 -0
- package/dist/rules/no-regex-v-flag.cjs +26 -0
- package/dist/rules/no-regex-v-flag.cjs.map +1 -0
- package/dist/rules/no-regex-v-flag.d.cts +17 -0
- package/dist/rules/no-using-keyword.cjs +57 -0
- package/dist/rules/no-using-keyword.cjs.map +1 -0
- package/dist/rules/no-using-keyword.d.cts +35 -0
- package/package.json +109 -0
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ESLintUtils } from "@typescript-eslint/utils";
|
|
2
|
+
declare const _default: ESLintUtils.RuleModule<"bugged" | "buggedWithReason" | "buggedReasonOverride", {
|
|
3
|
+
allow: never[];
|
|
4
|
+
ignoreBuiltInBuggedMessages: boolean;
|
|
5
|
+
additionalBuggedMessages: never[];
|
|
6
|
+
}[], unknown, ESLintUtils.RuleListener> & {
|
|
7
|
+
name: string;
|
|
8
|
+
};
|
|
9
|
+
export = _default;
|
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This is based on the `no-deprecated` rule from `@typescript-eslint/eslint-plugin`.
|
|
3
|
+
*
|
|
4
|
+
* Original File Source: https://github.com/typescript-eslint/typescript-eslint/blob/c4d5a56925e588d0e84e18f6f2d7756d0248d3be/packages/eslint-plugin/src/rules/no-deprecated.ts
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2019 typescript-eslint and other contributors
|
|
7
|
+
* Licensed under the MIT License.
|
|
8
|
+
*
|
|
9
|
+
* Modifications by 8Crafter (2026)
|
|
10
|
+
*/
|
|
11
|
+
"LICENSE";
|
|
12
|
+
"use strict";
|
|
13
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
14
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
15
|
+
};
|
|
16
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
17
|
+
const tsutils = require("ts-api-utils");
|
|
18
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
19
|
+
const type_utils_1 = require("@typescript-eslint/type-utils");
|
|
20
|
+
const eslint_utils_1 = require("@typescript-eslint/utils/eslint-utils");
|
|
21
|
+
const createRule = utils_1.ESLintUtils.RuleCreator((name) => name /* `https://typescript-eslint.io/rules/${name}` */);
|
|
22
|
+
const builtInCriticallyBuggedMessages = [
|
|
23
|
+
{
|
|
24
|
+
prefix: {
|
|
25
|
+
tagName: [
|
|
26
|
+
{ regex: "^criticallyBugged$", flags: "i" },
|
|
27
|
+
{ regex: "^criticalBug$", flags: "i" },
|
|
28
|
+
{ regex: "^bugged2$", flags: "i" },
|
|
29
|
+
{ regex: "^bug2$", flags: "i" },
|
|
30
|
+
],
|
|
31
|
+
prefix: ["Critical Bug", "Bug (Critical)", "Bug!!", "!!Bug"],
|
|
32
|
+
},
|
|
33
|
+
},
|
|
34
|
+
];
|
|
35
|
+
function getReportedNodeName(node) {
|
|
36
|
+
if (node.type === utils_1.AST_NODE_TYPES.Super) {
|
|
37
|
+
return "super";
|
|
38
|
+
}
|
|
39
|
+
if (node.type === utils_1.AST_NODE_TYPES.PrivateIdentifier) {
|
|
40
|
+
return `#${node.name}`;
|
|
41
|
+
}
|
|
42
|
+
return node.name;
|
|
43
|
+
}
|
|
44
|
+
module.exports = createRule({
|
|
45
|
+
name: "no-critically-bugged",
|
|
46
|
+
meta: {
|
|
47
|
+
type: "problem",
|
|
48
|
+
docs: {
|
|
49
|
+
description: "Disallow critically bugged symbols",
|
|
50
|
+
// recommended: true,
|
|
51
|
+
// requiresTypeChecking: true,
|
|
52
|
+
},
|
|
53
|
+
messages: {
|
|
54
|
+
criticallyBugged: `\`{{name}}\` has a critical bug`,
|
|
55
|
+
criticallyBuggedWithReason: `\`{{name}}\` has a critical bug. {{reason}}`,
|
|
56
|
+
criticallyBuggedReasonOverride: `{{reason}}`,
|
|
57
|
+
},
|
|
58
|
+
schema: [
|
|
59
|
+
{
|
|
60
|
+
type: "object",
|
|
61
|
+
additionalProperties: false,
|
|
62
|
+
properties: {
|
|
63
|
+
allow: {
|
|
64
|
+
...type_utils_1.typeOrValueSpecifiersSchema,
|
|
65
|
+
description: "Type specifiers that can be allowed.",
|
|
66
|
+
},
|
|
67
|
+
ignoreBuiltInCriticallyBuggedMessages: {
|
|
68
|
+
type: "boolean",
|
|
69
|
+
description: "Whether to ignore the built-in critically bugged messages.",
|
|
70
|
+
},
|
|
71
|
+
additionalCriticallyBuggedMessages: {
|
|
72
|
+
type: "array",
|
|
73
|
+
items: {
|
|
74
|
+
type: "object",
|
|
75
|
+
properties: {
|
|
76
|
+
message: {
|
|
77
|
+
oneOf: [
|
|
78
|
+
{ type: "string" },
|
|
79
|
+
{ type: "object", required: ["regex"], properties: { regex: { type: "string" }, flags: { type: "string" } } },
|
|
80
|
+
],
|
|
81
|
+
description: "The message to filter JSDoc comments by, only matching JSDoc comments will cause a violation. If not provided, any JSDoc tag of the specified name will cause a violation.",
|
|
82
|
+
},
|
|
83
|
+
prefix: {
|
|
84
|
+
type: "object",
|
|
85
|
+
oneOf: [
|
|
86
|
+
{
|
|
87
|
+
type: "object",
|
|
88
|
+
required: ["tagName"],
|
|
89
|
+
},
|
|
90
|
+
{
|
|
91
|
+
type: "object",
|
|
92
|
+
required: ["prefix"],
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
type: "object",
|
|
96
|
+
required: ["tagName", "prefix"],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
properties: {
|
|
100
|
+
tagName: {
|
|
101
|
+
oneOf: [
|
|
102
|
+
{ type: "string" },
|
|
103
|
+
{ type: "object", required: ["regex"], properties: { regex: { type: "string" }, flags: { type: "string" } } },
|
|
104
|
+
{
|
|
105
|
+
type: "array",
|
|
106
|
+
items: {
|
|
107
|
+
oneOf: [
|
|
108
|
+
{ type: "string" },
|
|
109
|
+
{
|
|
110
|
+
type: "object",
|
|
111
|
+
required: ["regex"],
|
|
112
|
+
properties: { regex: { type: "string" }, flags: { type: "string" } },
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
],
|
|
118
|
+
description: "The JSDoc tag name or a list of JSDoc tag names to filter by, should not be prefixed with '@'. ex. 'throws'",
|
|
119
|
+
},
|
|
120
|
+
prefix: {
|
|
121
|
+
oneOf: [
|
|
122
|
+
{ type: "string" },
|
|
123
|
+
{ type: "object", required: ["regex"], properties: { regex: { type: "string" }, flags: { type: "string" } } },
|
|
124
|
+
{
|
|
125
|
+
type: "array",
|
|
126
|
+
items: {
|
|
127
|
+
oneOf: [
|
|
128
|
+
{ type: "string" },
|
|
129
|
+
{
|
|
130
|
+
type: "object",
|
|
131
|
+
required: ["regex"],
|
|
132
|
+
properties: { regex: { type: "string" }, flags: { type: "string" } },
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
},
|
|
136
|
+
},
|
|
137
|
+
],
|
|
138
|
+
description: "The prefix to filter by, this is text that would be at the start of a line in the JSDoc, immediately followed by a colon, should not be suffixed with a colon. ex. 'Critical Bug' or 'Bug!!'",
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
description: "The prefix filtering options, these are used to find the start of the bug description, only matching JSDoc comments will cause a violation.",
|
|
142
|
+
},
|
|
143
|
+
reason: {
|
|
144
|
+
type: "string",
|
|
145
|
+
description: "The reason for the violation, this is what will be reported, if not specified, the message will be the bug description. ex. If the reason is 'This does not work at all in CoHTML (Ore UI).', the message will be '`{{name}}` has a critical bug. This does not work at all in CoHTML (Ore UI).'",
|
|
146
|
+
},
|
|
147
|
+
reasonOverride: {
|
|
148
|
+
type: "string",
|
|
149
|
+
description: "The error message to report. This will take precedence over `reason`. Unlike reason, this does not prepend '`{{name}}` has a critical bug.' to the reason. ex. If the reason override is 'This does not work at all in CoHTML (Ore UI).', the message will be 'This does not work at all in CoHTML (Ore UI).'",
|
|
150
|
+
},
|
|
151
|
+
},
|
|
152
|
+
required: ["tagName"],
|
|
153
|
+
additionalProperties: false,
|
|
154
|
+
description: "An additional critically bugged message to check for.",
|
|
155
|
+
},
|
|
156
|
+
description: "Additional critically bugged messages to check for.",
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
],
|
|
161
|
+
defaultOptions: [
|
|
162
|
+
{
|
|
163
|
+
allow: [],
|
|
164
|
+
ignoreBuiltInCriticallyBuggedMessages: false,
|
|
165
|
+
additionalCriticallyBuggedMessages: [],
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
},
|
|
169
|
+
defaultOptions: [
|
|
170
|
+
{
|
|
171
|
+
allow: [],
|
|
172
|
+
ignoreBuiltInCriticallyBuggedMessages: false,
|
|
173
|
+
additionalCriticallyBuggedMessages: [],
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
create(context) {
|
|
177
|
+
const { jsDocParsingMode } = context.parserOptions;
|
|
178
|
+
const allow = context.options[0]?.allow;
|
|
179
|
+
const criticallyBuggedMessages = (context.options[0]?.additionalCriticallyBuggedMessages ?? [])
|
|
180
|
+
.concat((context.options[0]?.ignoreBuiltInCriticallyBuggedMessages ?? false) ? [] : builtInCriticallyBuggedMessages)
|
|
181
|
+
.map((message) => ({
|
|
182
|
+
...message,
|
|
183
|
+
message: message.message ?
|
|
184
|
+
typeof message.message === "string" ?
|
|
185
|
+
message.message
|
|
186
|
+
: new RegExp(message.message.regex, message.message.flags)
|
|
187
|
+
: undefined,
|
|
188
|
+
prefix: Object.fromEntries(Object.entries(message.prefix).map(([key, value]) => [
|
|
189
|
+
key,
|
|
190
|
+
typeof value === "string" ? value
|
|
191
|
+
: value instanceof Array ?
|
|
192
|
+
value.map((item) => typeof item === "string" ? item : new RegExp(item.regex, item.flags))
|
|
193
|
+
: new RegExp(value.regex, value.flags),
|
|
194
|
+
])),
|
|
195
|
+
}));
|
|
196
|
+
if (!criticallyBuggedMessages.length)
|
|
197
|
+
return {};
|
|
198
|
+
if (jsDocParsingMode === "none" || jsDocParsingMode === "type-info") {
|
|
199
|
+
throw new Error(`Cannot be used with jsDocParsingMode: '${jsDocParsingMode}'.`);
|
|
200
|
+
}
|
|
201
|
+
const services = (0, eslint_utils_1.getParserServices)(context);
|
|
202
|
+
const checker = services.program.getTypeChecker();
|
|
203
|
+
// Deprecated jsdoc tags can be added on some symbol alias, e.g.
|
|
204
|
+
//
|
|
205
|
+
// export { /** @deprecated */ foo }
|
|
206
|
+
//
|
|
207
|
+
// When we import foo, its symbol is an alias of the exported foo (the one
|
|
208
|
+
// with the deprecated tag), which is itself an alias of the original foo.
|
|
209
|
+
// Therefore, we carefully go through the chain of aliases and check each
|
|
210
|
+
// immediate alias for deprecated tags
|
|
211
|
+
function searchForCriticallyBuggedInAliasesChain(symbol, checkDeprecationsOfAliasedSymbol) {
|
|
212
|
+
if (!symbol || !tsutils.isSymbolFlagSet(symbol, typescript_1.default.SymbolFlags.Alias)) {
|
|
213
|
+
return checkDeprecationsOfAliasedSymbol ? getJsDocCriticallyBugged(symbol) : undefined;
|
|
214
|
+
}
|
|
215
|
+
const targetSymbol = checker.getAliasedSymbol(symbol);
|
|
216
|
+
while (tsutils.isSymbolFlagSet(symbol, typescript_1.default.SymbolFlags.Alias)) {
|
|
217
|
+
const reason = getJsDocCriticallyBugged(symbol);
|
|
218
|
+
if (reason != null) {
|
|
219
|
+
return reason;
|
|
220
|
+
}
|
|
221
|
+
const immediateAliasedSymbol = symbol.getDeclarations() && checker.getImmediateAliasedSymbol(symbol);
|
|
222
|
+
if (!immediateAliasedSymbol) {
|
|
223
|
+
break;
|
|
224
|
+
}
|
|
225
|
+
symbol = immediateAliasedSymbol;
|
|
226
|
+
if (checkDeprecationsOfAliasedSymbol && symbol === targetSymbol) {
|
|
227
|
+
return getJsDocCriticallyBugged(symbol);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
function isDeclaration(node) {
|
|
233
|
+
const { parent } = node;
|
|
234
|
+
switch (parent.type) {
|
|
235
|
+
case utils_1.AST_NODE_TYPES.ArrayPattern:
|
|
236
|
+
return parent.elements.includes(node);
|
|
237
|
+
case utils_1.AST_NODE_TYPES.ClassExpression:
|
|
238
|
+
case utils_1.AST_NODE_TYPES.ClassDeclaration:
|
|
239
|
+
case utils_1.AST_NODE_TYPES.VariableDeclarator:
|
|
240
|
+
case utils_1.AST_NODE_TYPES.TSEnumMember:
|
|
241
|
+
return parent.id === node;
|
|
242
|
+
case utils_1.AST_NODE_TYPES.MethodDefinition:
|
|
243
|
+
case utils_1.AST_NODE_TYPES.PropertyDefinition:
|
|
244
|
+
case utils_1.AST_NODE_TYPES.AccessorProperty:
|
|
245
|
+
return parent.key === node;
|
|
246
|
+
case utils_1.AST_NODE_TYPES.Property:
|
|
247
|
+
// foo in "const { foo } = bar" will be processed twice, as parent.key
|
|
248
|
+
// and parent.value. The second is treated as a declaration.
|
|
249
|
+
if (parent.shorthand && parent.value === node) {
|
|
250
|
+
return parent.parent.type === utils_1.AST_NODE_TYPES.ObjectPattern;
|
|
251
|
+
}
|
|
252
|
+
if (parent.value === node) {
|
|
253
|
+
return false;
|
|
254
|
+
}
|
|
255
|
+
return parent.parent.type === utils_1.AST_NODE_TYPES.ObjectExpression;
|
|
256
|
+
case utils_1.AST_NODE_TYPES.AssignmentPattern:
|
|
257
|
+
// foo in "const { foo = "" } = bar" will be processed twice, as parent.parent.key
|
|
258
|
+
// and parent.left. The second is treated as a declaration.
|
|
259
|
+
return parent.left === node;
|
|
260
|
+
case utils_1.AST_NODE_TYPES.ArrowFunctionExpression:
|
|
261
|
+
case utils_1.AST_NODE_TYPES.FunctionDeclaration:
|
|
262
|
+
case utils_1.AST_NODE_TYPES.FunctionExpression:
|
|
263
|
+
case utils_1.AST_NODE_TYPES.TSDeclareFunction:
|
|
264
|
+
case utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression:
|
|
265
|
+
case utils_1.AST_NODE_TYPES.TSEnumDeclaration:
|
|
266
|
+
case utils_1.AST_NODE_TYPES.TSInterfaceDeclaration:
|
|
267
|
+
case utils_1.AST_NODE_TYPES.TSMethodSignature:
|
|
268
|
+
case utils_1.AST_NODE_TYPES.TSModuleDeclaration:
|
|
269
|
+
case utils_1.AST_NODE_TYPES.TSParameterProperty:
|
|
270
|
+
case utils_1.AST_NODE_TYPES.TSPropertySignature:
|
|
271
|
+
case utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration:
|
|
272
|
+
case utils_1.AST_NODE_TYPES.TSTypeParameter:
|
|
273
|
+
return true;
|
|
274
|
+
// treat `export import Bar = Foo;` (and `import Foo = require('...')`) as declarations
|
|
275
|
+
case utils_1.AST_NODE_TYPES.TSImportEqualsDeclaration:
|
|
276
|
+
return parent.id === node;
|
|
277
|
+
default:
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
function isInsideImport(node) {
|
|
282
|
+
let current = node;
|
|
283
|
+
while (true) {
|
|
284
|
+
switch (current.type) {
|
|
285
|
+
case utils_1.AST_NODE_TYPES.ImportDeclaration:
|
|
286
|
+
return true;
|
|
287
|
+
case utils_1.AST_NODE_TYPES.ArrowFunctionExpression:
|
|
288
|
+
case utils_1.AST_NODE_TYPES.ExportAllDeclaration:
|
|
289
|
+
case utils_1.AST_NODE_TYPES.ExportNamedDeclaration:
|
|
290
|
+
case utils_1.AST_NODE_TYPES.BlockStatement:
|
|
291
|
+
case utils_1.AST_NODE_TYPES.ClassDeclaration:
|
|
292
|
+
case utils_1.AST_NODE_TYPES.TSInterfaceDeclaration:
|
|
293
|
+
case utils_1.AST_NODE_TYPES.FunctionDeclaration:
|
|
294
|
+
case utils_1.AST_NODE_TYPES.FunctionExpression:
|
|
295
|
+
case utils_1.AST_NODE_TYPES.Program:
|
|
296
|
+
case utils_1.AST_NODE_TYPES.TSUnionType:
|
|
297
|
+
case utils_1.AST_NODE_TYPES.VariableDeclarator:
|
|
298
|
+
return false;
|
|
299
|
+
default:
|
|
300
|
+
current = current.parent;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
function getJsDocCriticallyBugged(symbol) {
|
|
305
|
+
let jsDocTags;
|
|
306
|
+
try {
|
|
307
|
+
jsDocTags = symbol?.getJsDocTags(checker);
|
|
308
|
+
}
|
|
309
|
+
catch {
|
|
310
|
+
// workaround for https://github.com/microsoft/TypeScript/issues/60024
|
|
311
|
+
return undefined;
|
|
312
|
+
}
|
|
313
|
+
let tag;
|
|
314
|
+
let messageRule;
|
|
315
|
+
let messageString;
|
|
316
|
+
jsDocTagLoop: for (const jsDocTag of jsDocTags ?? []) {
|
|
317
|
+
let displayPartsString;
|
|
318
|
+
for (const currentRule of criticallyBuggedMessages) {
|
|
319
|
+
if (!("tagName" in currentRule.prefix && currentRule.prefix.tagName))
|
|
320
|
+
continue;
|
|
321
|
+
if (!(currentRule.prefix.tagName instanceof Array ?
|
|
322
|
+
currentRule.prefix.tagName.some((tagName) => typeof tagName === "string" ? tagName === jsDocTag.name : tagName.test(jsDocTag.name))
|
|
323
|
+
: typeof currentRule.prefix.tagName === "string" ? currentRule.prefix.tagName === jsDocTag.name
|
|
324
|
+
: currentRule.prefix.tagName.test(jsDocTag.name)))
|
|
325
|
+
continue;
|
|
326
|
+
if (!currentRule.message) {
|
|
327
|
+
tag = jsDocTag;
|
|
328
|
+
messageRule = currentRule;
|
|
329
|
+
messageString = displayPartsString;
|
|
330
|
+
break jsDocTagLoop;
|
|
331
|
+
}
|
|
332
|
+
if (typeof currentRule.message === "string") {
|
|
333
|
+
if (!jsDocTag.text || currentRule.message !== (displayPartsString ?? (displayPartsString = typescript_1.default.displayPartsToString(jsDocTag.text))))
|
|
334
|
+
continue;
|
|
335
|
+
tag = jsDocTag;
|
|
336
|
+
messageRule = currentRule;
|
|
337
|
+
messageString = displayPartsString;
|
|
338
|
+
break jsDocTagLoop;
|
|
339
|
+
}
|
|
340
|
+
if (currentRule.message && currentRule.message.test(displayPartsString ?? (displayPartsString = typescript_1.default.displayPartsToString(jsDocTag.text)))) {
|
|
341
|
+
tag = jsDocTag;
|
|
342
|
+
messageRule = currentRule;
|
|
343
|
+
messageString = displayPartsString;
|
|
344
|
+
break jsDocTagLoop;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
if (!tag || !messageRule) {
|
|
349
|
+
let documentationComments;
|
|
350
|
+
try {
|
|
351
|
+
documentationComments = symbol?.getDocumentationComment(checker);
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// workaround for https://github.com/microsoft/TypeScript/issues/60024
|
|
355
|
+
return undefined;
|
|
356
|
+
}
|
|
357
|
+
let comment;
|
|
358
|
+
let commentEntry;
|
|
359
|
+
let messageRule;
|
|
360
|
+
let message;
|
|
361
|
+
documentationCommentLoop: for (const documentationComment of documentationComments ?? []) {
|
|
362
|
+
if (documentationComment.kind !== "text")
|
|
363
|
+
continue;
|
|
364
|
+
const documentationCommentEntries = documentationComment.text.split(/(?:\r?\n){2,}/g).map((v) => v.trim());
|
|
365
|
+
for (const documentationCommentEntry of documentationCommentEntries) {
|
|
366
|
+
if (!documentationCommentEntry)
|
|
367
|
+
continue;
|
|
368
|
+
for (const currentRule of criticallyBuggedMessages) {
|
|
369
|
+
if (!("prefix" in currentRule.prefix && currentRule.prefix.prefix))
|
|
370
|
+
continue;
|
|
371
|
+
for (const prefix of currentRule.prefix.prefix instanceof Array ? currentRule.prefix.prefix : [currentRule.prefix.prefix]) {
|
|
372
|
+
let documentationMessage;
|
|
373
|
+
if (typeof prefix === "string") {
|
|
374
|
+
if (prefix && documentationCommentEntry.split(":")[0] !== prefix)
|
|
375
|
+
continue;
|
|
376
|
+
documentationMessage =
|
|
377
|
+
prefix ? documentationCommentEntry.split(":").slice(1).join(":").trimStart() : documentationCommentEntry;
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
if (!prefix.test(documentationCommentEntry.split(":")[0]))
|
|
381
|
+
continue;
|
|
382
|
+
documentationMessage = documentationCommentEntry.split(":").slice(1).join(":").trimStart();
|
|
383
|
+
}
|
|
384
|
+
if (!currentRule.message) {
|
|
385
|
+
comment = documentationComment;
|
|
386
|
+
commentEntry = documentationCommentEntry;
|
|
387
|
+
messageRule = currentRule;
|
|
388
|
+
message = documentationMessage;
|
|
389
|
+
break documentationCommentLoop;
|
|
390
|
+
}
|
|
391
|
+
if (typeof currentRule.message === "string") {
|
|
392
|
+
if (!documentationCommentEntry || currentRule.message !== documentationMessage)
|
|
393
|
+
continue;
|
|
394
|
+
comment = documentationComment;
|
|
395
|
+
commentEntry = documentationCommentEntry;
|
|
396
|
+
messageRule = currentRule;
|
|
397
|
+
message = documentationMessage;
|
|
398
|
+
break documentationCommentLoop;
|
|
399
|
+
}
|
|
400
|
+
if (currentRule.message.test(documentationMessage)) {
|
|
401
|
+
comment = documentationComment;
|
|
402
|
+
commentEntry = documentationCommentEntry;
|
|
403
|
+
messageRule = currentRule;
|
|
404
|
+
message = documentationMessage;
|
|
405
|
+
break documentationCommentLoop;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
if (!comment || !commentEntry || !messageRule)
|
|
412
|
+
return undefined;
|
|
413
|
+
if (messageRule.reasonOverride)
|
|
414
|
+
return { override: messageRule.reasonOverride };
|
|
415
|
+
if (messageRule.reason)
|
|
416
|
+
return messageRule.reason;
|
|
417
|
+
return message;
|
|
418
|
+
}
|
|
419
|
+
if (messageRule.reasonOverride)
|
|
420
|
+
return { override: messageRule.reasonOverride };
|
|
421
|
+
if (messageRule.reason)
|
|
422
|
+
return messageRule.reason;
|
|
423
|
+
return messageString;
|
|
424
|
+
}
|
|
425
|
+
function isNodeCalleeOfParent(node) {
|
|
426
|
+
switch (node.parent?.type) {
|
|
427
|
+
case utils_1.AST_NODE_TYPES.NewExpression:
|
|
428
|
+
case utils_1.AST_NODE_TYPES.CallExpression:
|
|
429
|
+
return node.parent.callee === node;
|
|
430
|
+
case utils_1.AST_NODE_TYPES.TaggedTemplateExpression:
|
|
431
|
+
return node.parent.tag === node;
|
|
432
|
+
case utils_1.AST_NODE_TYPES.JSXOpeningElement:
|
|
433
|
+
return node.parent.name === node;
|
|
434
|
+
default:
|
|
435
|
+
return false;
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
function getCallLikeNode(node) {
|
|
439
|
+
let callee = node;
|
|
440
|
+
while (callee.parent?.type === utils_1.AST_NODE_TYPES.MemberExpression && callee.parent.property === callee) {
|
|
441
|
+
callee = callee.parent;
|
|
442
|
+
}
|
|
443
|
+
return isNodeCalleeOfParent(callee) ? callee : undefined;
|
|
444
|
+
}
|
|
445
|
+
function getCallLikeCriticallyBugged(node) {
|
|
446
|
+
const tsNode = services.esTreeNodeToTSNodeMap.get(node.parent);
|
|
447
|
+
// If the node is a direct function call, we look for its signature.
|
|
448
|
+
const signature = (0, eslint_utils_1.nullThrows)(checker.getResolvedSignature(tsNode), "Expected call like node to have signature");
|
|
449
|
+
const symbol = services.getSymbolAtLocation(node);
|
|
450
|
+
const aliasedSymbol = symbol != null && tsutils.isSymbolFlagSet(symbol, typescript_1.default.SymbolFlags.Alias) ? checker.getAliasedSymbol(symbol) : symbol;
|
|
451
|
+
const symbolDeclarationKind = aliasedSymbol?.declarations?.[0]?.kind;
|
|
452
|
+
// Properties with function-like types have "deprecated" jsdoc
|
|
453
|
+
// on their symbols, not on their signatures:
|
|
454
|
+
//
|
|
455
|
+
// interface Props {
|
|
456
|
+
// /** @deprecated */
|
|
457
|
+
// property: () => 'foo'
|
|
458
|
+
// ^symbol^ ^signature^
|
|
459
|
+
// }
|
|
460
|
+
if (symbolDeclarationKind !== typescript_1.default.SyntaxKind.MethodDeclaration &&
|
|
461
|
+
symbolDeclarationKind !== typescript_1.default.SyntaxKind.FunctionDeclaration &&
|
|
462
|
+
symbolDeclarationKind !== typescript_1.default.SyntaxKind.MethodSignature) {
|
|
463
|
+
return searchForCriticallyBuggedInAliasesChain(symbol, true) ?? getJsDocCriticallyBugged(signature) ?? getJsDocCriticallyBugged(aliasedSymbol);
|
|
464
|
+
}
|
|
465
|
+
return (searchForCriticallyBuggedInAliasesChain(symbol,
|
|
466
|
+
// Here we're working with a function declaration or method.
|
|
467
|
+
// Both can have 1 or more overloads, each overload creates one
|
|
468
|
+
// ts.Declaration which is placed in symbol.declarations.
|
|
469
|
+
//
|
|
470
|
+
// Imagine the following code:
|
|
471
|
+
//
|
|
472
|
+
// function foo(): void
|
|
473
|
+
// /** @deprecated Some Reason */
|
|
474
|
+
// function foo(arg: string): void
|
|
475
|
+
// function foo(arg?: string): void {}
|
|
476
|
+
//
|
|
477
|
+
// foo() // <- foo is our symbol
|
|
478
|
+
//
|
|
479
|
+
// If we call getJsDocDeprecation(checker.getAliasedSymbol(symbol)),
|
|
480
|
+
// we get 'Some Reason', but after all, we are calling foo with
|
|
481
|
+
// a signature that is not deprecated!
|
|
482
|
+
// It works this way because symbol.getJsDocTags returns tags from
|
|
483
|
+
// all symbol declarations combined into one array. And AFAIK there is
|
|
484
|
+
// no publicly exported TS function that can tell us if a particular
|
|
485
|
+
// declaration is deprecated or not.
|
|
486
|
+
//
|
|
487
|
+
// So, in case of function and method declarations, we don't check original
|
|
488
|
+
// aliased symbol, but rely on the getJsDocDeprecation(signature) call below.
|
|
489
|
+
false) ?? getJsDocCriticallyBugged(signature));
|
|
490
|
+
}
|
|
491
|
+
function getJSXAttributeCriticallyBugged(openingElement, propertyName) {
|
|
492
|
+
const tsNode = services.esTreeNodeToTSNodeMap.get(openingElement.name);
|
|
493
|
+
const contextualType = (0, eslint_utils_1.nullThrows)(checker.getContextualType(tsNode), "Expected JSX opening element name to have contextualType");
|
|
494
|
+
const symbol = contextualType.getProperty(propertyName);
|
|
495
|
+
return getJsDocCriticallyBugged(symbol);
|
|
496
|
+
}
|
|
497
|
+
function getCriticallyBuggedReason(node) {
|
|
498
|
+
const callLikeNode = getCallLikeNode(node);
|
|
499
|
+
if (callLikeNode) {
|
|
500
|
+
return getCallLikeCriticallyBugged(callLikeNode);
|
|
501
|
+
}
|
|
502
|
+
if (node.parent.type === utils_1.AST_NODE_TYPES.JSXAttribute && node.type !== utils_1.AST_NODE_TYPES.Super) {
|
|
503
|
+
return getJSXAttributeCriticallyBugged(node.parent.parent, node.name);
|
|
504
|
+
}
|
|
505
|
+
if (node.parent.type === utils_1.AST_NODE_TYPES.Property && node.type !== utils_1.AST_NODE_TYPES.Super) {
|
|
506
|
+
const property = services.getTypeAtLocation(node.parent.parent).getProperty(node.name);
|
|
507
|
+
const propertySymbol = services.getSymbolAtLocation(node);
|
|
508
|
+
const valueSymbol = checker.getShorthandAssignmentValueSymbol(propertySymbol?.valueDeclaration);
|
|
509
|
+
return (searchForCriticallyBuggedInAliasesChain(propertySymbol, true) ??
|
|
510
|
+
getJsDocCriticallyBugged(property) ??
|
|
511
|
+
getJsDocCriticallyBugged(propertySymbol) ??
|
|
512
|
+
getJsDocCriticallyBugged(valueSymbol));
|
|
513
|
+
}
|
|
514
|
+
return searchForCriticallyBuggedInAliasesChain(services.getSymbolAtLocation(node), true);
|
|
515
|
+
}
|
|
516
|
+
function checkIdentifier(node) {
|
|
517
|
+
if (isDeclaration(node) || isInsideImport(node)) {
|
|
518
|
+
return;
|
|
519
|
+
}
|
|
520
|
+
const reason = getCriticallyBuggedReason(node);
|
|
521
|
+
if (reason == null) {
|
|
522
|
+
return;
|
|
523
|
+
}
|
|
524
|
+
const type = services.getTypeAtLocation(node);
|
|
525
|
+
if ((0, type_utils_1.typeMatchesSomeSpecifier)(type, allow, services.program) || (0, type_utils_1.valueMatchesSomeSpecifier)(node, allow, services.program, type)) {
|
|
526
|
+
return;
|
|
527
|
+
}
|
|
528
|
+
const name = getReportedNodeName(node);
|
|
529
|
+
context.report({
|
|
530
|
+
...(reason ?
|
|
531
|
+
typeof reason === "object" ?
|
|
532
|
+
{
|
|
533
|
+
messageId: "criticallyBuggedReasonOverride",
|
|
534
|
+
data: { name, reason: reason.override },
|
|
535
|
+
}
|
|
536
|
+
: {
|
|
537
|
+
messageId: "criticallyBuggedWithReason",
|
|
538
|
+
data: { name, reason },
|
|
539
|
+
}
|
|
540
|
+
: {
|
|
541
|
+
messageId: "criticallyBugged",
|
|
542
|
+
data: { name },
|
|
543
|
+
}),
|
|
544
|
+
node,
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
function checkMemberExpression(node) {
|
|
548
|
+
if (!node.computed) {
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
const propertyType = services.getTypeAtLocation(node.property);
|
|
552
|
+
if (propertyType.isLiteral()) {
|
|
553
|
+
const objectType = services.getTypeAtLocation(node.object);
|
|
554
|
+
const propertyName = propertyType.isStringLiteral() ? propertyType.value : String(propertyType.value);
|
|
555
|
+
const property = objectType.getProperty(propertyName);
|
|
556
|
+
const reason = getJsDocCriticallyBugged(property);
|
|
557
|
+
if (reason == null) {
|
|
558
|
+
return;
|
|
559
|
+
}
|
|
560
|
+
if ((0, type_utils_1.typeMatchesSomeSpecifier)(objectType, allow, services.program)) {
|
|
561
|
+
return;
|
|
562
|
+
}
|
|
563
|
+
context.report({
|
|
564
|
+
...(reason ?
|
|
565
|
+
typeof reason === "object" ?
|
|
566
|
+
{
|
|
567
|
+
messageId: "criticallyBuggedReasonOverride",
|
|
568
|
+
data: { name: propertyName, reason: reason.override },
|
|
569
|
+
}
|
|
570
|
+
: {
|
|
571
|
+
messageId: "criticallyBuggedWithReason",
|
|
572
|
+
data: { name: propertyName, reason },
|
|
573
|
+
}
|
|
574
|
+
: {
|
|
575
|
+
messageId: "criticallyBugged",
|
|
576
|
+
data: { name: propertyName },
|
|
577
|
+
}),
|
|
578
|
+
node: node.property,
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
}
|
|
582
|
+
return {
|
|
583
|
+
Identifier(node) {
|
|
584
|
+
const { parent } = node;
|
|
585
|
+
if (parent.type === utils_1.AST_NODE_TYPES.ExportNamedDeclaration || parent.type === utils_1.AST_NODE_TYPES.ExportAllDeclaration) {
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
// Computed identifier expressions are handled by checkMemberExpression
|
|
589
|
+
if (parent.type === utils_1.AST_NODE_TYPES.MemberExpression && parent.computed && parent.property === node) {
|
|
590
|
+
return;
|
|
591
|
+
}
|
|
592
|
+
if (parent.type === utils_1.AST_NODE_TYPES.ExportSpecifier) {
|
|
593
|
+
// only deal with the alias (exported) side, not the local binding
|
|
594
|
+
if (parent.exported !== node) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
const symbol = services.getSymbolAtLocation(node);
|
|
598
|
+
const aliasDeprecation = getJsDocCriticallyBugged(symbol);
|
|
599
|
+
if (aliasDeprecation != null) {
|
|
600
|
+
return;
|
|
601
|
+
}
|
|
602
|
+
}
|
|
603
|
+
// whether it's a plain identifier or the exported alias
|
|
604
|
+
checkIdentifier(node);
|
|
605
|
+
},
|
|
606
|
+
JSXIdentifier(node) {
|
|
607
|
+
if (node.parent.type !== utils_1.AST_NODE_TYPES.JSXClosingElement) {
|
|
608
|
+
checkIdentifier(node);
|
|
609
|
+
}
|
|
610
|
+
},
|
|
611
|
+
MemberExpression(node) {
|
|
612
|
+
checkMemberExpression(node);
|
|
613
|
+
},
|
|
614
|
+
PrivateIdentifier(node) {
|
|
615
|
+
checkIdentifier(node);
|
|
616
|
+
},
|
|
617
|
+
Super(node) {
|
|
618
|
+
checkIdentifier(node);
|
|
619
|
+
},
|
|
620
|
+
};
|
|
621
|
+
},
|
|
622
|
+
});
|
|
623
|
+
//# sourceMappingURL=no-critically-bugged.cjs.map
|