@blumintinc/eslint-plugin-blumint 1.11.0 → 1.12.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/lib/index.js +4 -1
- package/lib/rules/enforce-boolean-naming-prefixes.js +109 -18
- package/lib/rules/enforce-global-constants.d.ts +1 -0
- package/lib/rules/enforce-global-constants.js +77 -0
- package/lib/rules/enforce-positive-naming.js +943 -27
- package/lib/rules/no-hungarian.js +1 -1
- package/lib/rules/no-type-assertion-returns.js +13 -1
- package/package.json +1 -1
package/lib/index.js
CHANGED
|
@@ -15,6 +15,7 @@ const enforce_mui_rounded_icons_1 = require("./rules/enforce-mui-rounded-icons")
|
|
|
15
15
|
const enforce_react_type_naming_1 = require("./rules/enforce-react-type-naming");
|
|
16
16
|
const export_if_in_doubt_1 = require("./rules/export-if-in-doubt");
|
|
17
17
|
const extract_global_constants_1 = require("./rules/extract-global-constants");
|
|
18
|
+
const enforce_global_constants_1 = require("./rules/enforce-global-constants");
|
|
18
19
|
const generic_starts_with_t_1 = require("./rules/generic-starts-with-t");
|
|
19
20
|
const global_const_style_1 = __importDefault(require("./rules/global-const-style"));
|
|
20
21
|
const no_async_array_filter_1 = require("./rules/no-async-array-filter");
|
|
@@ -105,7 +106,7 @@ const enforce_boolean_naming_prefixes_1 = require("./rules/enforce-boolean-namin
|
|
|
105
106
|
module.exports = {
|
|
106
107
|
meta: {
|
|
107
108
|
name: '@blumintinc/eslint-plugin-blumint',
|
|
108
|
-
version: '1.
|
|
109
|
+
version: '1.12.0',
|
|
109
110
|
},
|
|
110
111
|
parseOptions: {
|
|
111
112
|
ecmaVersion: 2020,
|
|
@@ -130,6 +131,7 @@ module.exports = {
|
|
|
130
131
|
'@blumintinc/blumint/enforce-react-type-naming': 'error',
|
|
131
132
|
// '@blumintinc/blumint/export-if-in-doubt': 'warn',
|
|
132
133
|
'@blumintinc/blumint/extract-global-constants': 'error',
|
|
134
|
+
'@blumintinc/blumint/enforce-global-constants': 'error',
|
|
133
135
|
'@blumintinc/blumint/generic-starts-with-t': 'error',
|
|
134
136
|
'@blumintinc/blumint/global-const-style': 'error',
|
|
135
137
|
'@blumintinc/blumint/no-async-array-filter': 'error',
|
|
@@ -236,6 +238,7 @@ module.exports = {
|
|
|
236
238
|
'enforce-mui-rounded-icons': enforce_mui_rounded_icons_1.enforceMuiRoundedIcons,
|
|
237
239
|
'export-if-in-doubt': export_if_in_doubt_1.exportIfInDoubt,
|
|
238
240
|
'extract-global-constants': extract_global_constants_1.extractGlobalConstants,
|
|
241
|
+
'enforce-global-constants': enforce_global_constants_1.enforceGlobalConstants,
|
|
239
242
|
'generic-starts-with-t': generic_starts_with_t_1.genericStartsWithT,
|
|
240
243
|
'global-const-style': global_const_style_1.default,
|
|
241
244
|
'no-async-array-filter': no_async_array_filter_1.noAsyncArrayFilter,
|
|
@@ -349,6 +349,17 @@ exports.enforceBooleanNamingPrefixes = (0, createRule_1.createRule)({
|
|
|
349
349
|
});
|
|
350
350
|
}
|
|
351
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* Check if an identifier is imported from an external module
|
|
354
|
+
*/
|
|
355
|
+
function isImportedIdentifier(name) {
|
|
356
|
+
const scope = context.getScope();
|
|
357
|
+
const variable = scope.variables.find((v) => v.name === name);
|
|
358
|
+
if (!variable)
|
|
359
|
+
return false;
|
|
360
|
+
// Check if it's an import binding
|
|
361
|
+
return variable.defs.some((def) => def.type === 'ImportBinding');
|
|
362
|
+
}
|
|
352
363
|
/**
|
|
353
364
|
* Check property definitions for boolean values
|
|
354
365
|
*/
|
|
@@ -370,16 +381,51 @@ exports.enforceBooleanNamingPrefixes = (0, createRule_1.createRule)({
|
|
|
370
381
|
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
371
382
|
isBooleanProperty = true;
|
|
372
383
|
}
|
|
384
|
+
// Skip checking if this property is part of an object literal passed to an external function
|
|
373
385
|
if (isBooleanProperty && !hasApprovedPrefix(propertyName)) {
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
386
|
+
// Special cases for common Node.js API boolean properties
|
|
387
|
+
if ((propertyName === 'recursive' || propertyName === 'keepAlive') &&
|
|
388
|
+
node.parent?.type === utils_1.AST_NODE_TYPES.ObjectExpression &&
|
|
389
|
+
node.parent.parent?.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
390
|
+
return; // Skip checking for these properties in object literals passed to functions
|
|
391
|
+
}
|
|
392
|
+
// Check if this property is in an object literal that's an argument to a function call
|
|
393
|
+
let isExternalApiCall = false;
|
|
394
|
+
// Navigate up to find if we're in an object expression that's an argument to a function call
|
|
395
|
+
if (node.parent?.type === utils_1.AST_NODE_TYPES.ObjectExpression &&
|
|
396
|
+
node.parent.parent?.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
397
|
+
const callExpression = node.parent.parent;
|
|
398
|
+
// Check if the function being called is an identifier (like mkdirSync, createServer, etc.)
|
|
399
|
+
if (callExpression.callee.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
400
|
+
const calleeName = callExpression.callee.name;
|
|
401
|
+
if (isImportedIdentifier(calleeName)) {
|
|
402
|
+
isExternalApiCall = true;
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
// Also check for member expressions like fs.mkdirSync
|
|
406
|
+
if (callExpression.callee.type === utils_1.AST_NODE_TYPES.MemberExpression) {
|
|
407
|
+
// For member expressions, check if the object is imported
|
|
408
|
+
const objectNode = callExpression.callee.object;
|
|
409
|
+
if (objectNode.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
410
|
+
const objectName = objectNode.name;
|
|
411
|
+
if (isImportedIdentifier(objectName)) {
|
|
412
|
+
isExternalApiCall = true;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
// Only report if it's not an external API call
|
|
418
|
+
if (!isExternalApiCall) {
|
|
419
|
+
context.report({
|
|
420
|
+
node: node.key,
|
|
421
|
+
messageId: 'missingBooleanPrefix',
|
|
422
|
+
data: {
|
|
423
|
+
type: 'property',
|
|
424
|
+
name: propertyName,
|
|
425
|
+
prefixes: formatPrefixes(),
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
}
|
|
383
429
|
}
|
|
384
430
|
}
|
|
385
431
|
/**
|
|
@@ -394,15 +440,35 @@ exports.enforceBooleanNamingPrefixes = (0, createRule_1.createRule)({
|
|
|
394
440
|
node.typeAnnotation.typeAnnotation.type ===
|
|
395
441
|
utils_1.AST_NODE_TYPES.TSBooleanKeyword &&
|
|
396
442
|
!hasApprovedPrefix(propertyName)) {
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
443
|
+
// Skip if this property is part of a parameter's type annotation
|
|
444
|
+
// Check if this property signature is inside a parameter's type annotation
|
|
445
|
+
let isInParameterType = false;
|
|
446
|
+
let parent = node.parent;
|
|
447
|
+
while (parent) {
|
|
448
|
+
if (parent.type === utils_1.AST_NODE_TYPES.TSTypeLiteral) {
|
|
449
|
+
const grandParent = parent.parent;
|
|
450
|
+
if (grandParent?.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation &&
|
|
451
|
+
grandParent.parent?.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
452
|
+
grandParent.parent.parent?.type ===
|
|
453
|
+
utils_1.AST_NODE_TYPES.FunctionDeclaration) {
|
|
454
|
+
isInParameterType = true;
|
|
455
|
+
break;
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
parent = parent.parent;
|
|
459
|
+
}
|
|
460
|
+
// Only report if not in a parameter type annotation
|
|
461
|
+
if (!isInParameterType) {
|
|
462
|
+
context.report({
|
|
463
|
+
node: node.key,
|
|
464
|
+
messageId: 'missingBooleanPrefix',
|
|
465
|
+
data: {
|
|
466
|
+
type: 'property',
|
|
467
|
+
name: propertyName,
|
|
468
|
+
prefixes: formatPrefixes(),
|
|
469
|
+
},
|
|
470
|
+
});
|
|
471
|
+
}
|
|
406
472
|
}
|
|
407
473
|
}
|
|
408
474
|
/**
|
|
@@ -427,6 +493,31 @@ exports.enforceBooleanNamingPrefixes = (0, createRule_1.createRule)({
|
|
|
427
493
|
},
|
|
428
494
|
});
|
|
429
495
|
}
|
|
496
|
+
// Check if the parameter has an object type with boolean properties
|
|
497
|
+
if (node.typeAnnotation?.typeAnnotation &&
|
|
498
|
+
node.typeAnnotation.typeAnnotation.type === utils_1.AST_NODE_TYPES.TSTypeLiteral) {
|
|
499
|
+
const typeLiteral = node.typeAnnotation.typeAnnotation;
|
|
500
|
+
// Check each member of the type literal
|
|
501
|
+
for (const member of typeLiteral.members) {
|
|
502
|
+
if (member.type === utils_1.AST_NODE_TYPES.TSPropertySignature &&
|
|
503
|
+
member.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
504
|
+
member.typeAnnotation?.typeAnnotation.type ===
|
|
505
|
+
utils_1.AST_NODE_TYPES.TSBooleanKeyword) {
|
|
506
|
+
const propertyName = member.key.name;
|
|
507
|
+
if (!hasApprovedPrefix(propertyName)) {
|
|
508
|
+
context.report({
|
|
509
|
+
node: member.key,
|
|
510
|
+
messageId: 'missingBooleanPrefix',
|
|
511
|
+
data: {
|
|
512
|
+
type: 'property',
|
|
513
|
+
name: propertyName,
|
|
514
|
+
prefixes: formatPrefixes(),
|
|
515
|
+
},
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
430
521
|
}
|
|
431
522
|
return {
|
|
432
523
|
VariableDeclarator: checkVariableDeclaration,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const enforceGlobalConstants: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"useGlobalConstant", [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enforceGlobalConstants = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
exports.enforceGlobalConstants = (0, createRule_1.createRule)({
|
|
7
|
+
name: 'enforce-global-constants',
|
|
8
|
+
meta: {
|
|
9
|
+
type: 'suggestion',
|
|
10
|
+
docs: {
|
|
11
|
+
description: 'Enforce using global static constants instead of useMemo with empty dependency arrays for object literals',
|
|
12
|
+
recommended: 'error',
|
|
13
|
+
},
|
|
14
|
+
schema: [],
|
|
15
|
+
messages: {
|
|
16
|
+
useGlobalConstant: 'Use a global static constant instead of useMemo with an empty dependency array for object literals',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultOptions: [],
|
|
20
|
+
create(context) {
|
|
21
|
+
return {
|
|
22
|
+
CallExpression(node) {
|
|
23
|
+
// Check if it's a useMemo call
|
|
24
|
+
if (node.callee.type !== utils_1.AST_NODE_TYPES.Identifier ||
|
|
25
|
+
node.callee.name !== 'useMemo') {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
// Check if it has exactly two arguments
|
|
29
|
+
if (node.arguments.length !== 2) {
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
// Check if the second argument is an empty array
|
|
33
|
+
const depsArray = node.arguments[1];
|
|
34
|
+
if (depsArray.type !== utils_1.AST_NODE_TYPES.ArrayExpression ||
|
|
35
|
+
depsArray.elements.length !== 0) {
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
// Check if the first argument is an arrow function
|
|
39
|
+
const callback = node.arguments[0];
|
|
40
|
+
if (callback.type !== utils_1.AST_NODE_TYPES.ArrowFunctionExpression) {
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
// Check if the arrow function body is a block statement with a return statement
|
|
44
|
+
// or a direct expression (implicit return)
|
|
45
|
+
let returnValue = null;
|
|
46
|
+
if (callback.body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
47
|
+
// If it's a block, find the return statement
|
|
48
|
+
const returnStatement = callback.body.body.find((stmt) => stmt.type === utils_1.AST_NODE_TYPES.ReturnStatement);
|
|
49
|
+
if (!returnStatement || !returnStatement.argument) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
returnValue = returnStatement.argument;
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// If it's an expression (implicit return)
|
|
56
|
+
returnValue = callback.body;
|
|
57
|
+
}
|
|
58
|
+
// Handle 'as const' type assertions
|
|
59
|
+
let actualReturnValue = returnValue;
|
|
60
|
+
if (returnValue.type === utils_1.AST_NODE_TYPES.TSAsExpression) {
|
|
61
|
+
actualReturnValue = returnValue.expression;
|
|
62
|
+
}
|
|
63
|
+
// Check if the return value is an object literal or an array of object literals
|
|
64
|
+
if (actualReturnValue.type === utils_1.AST_NODE_TYPES.ObjectExpression ||
|
|
65
|
+
(actualReturnValue.type === utils_1.AST_NODE_TYPES.ArrayExpression &&
|
|
66
|
+
actualReturnValue.elements.some((element) => element !== null &&
|
|
67
|
+
element.type === utils_1.AST_NODE_TYPES.ObjectExpression))) {
|
|
68
|
+
context.report({
|
|
69
|
+
node,
|
|
70
|
+
messageId: 'useGlobalConstant',
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
//# sourceMappingURL=enforce-global-constants.js.map
|
|
@@ -5,11 +5,853 @@ const utils_1 = require("@typescript-eslint/utils");
|
|
|
5
5
|
const createRule_1 = require("../utils/createRule");
|
|
6
6
|
// Common negative prefixes for boolean variables
|
|
7
7
|
const BOOLEAN_NEGATIVE_PREFIXES = ['not', 'no', 'non', 'un', 'in', 'dis'];
|
|
8
|
+
const IN_EXCEPTIONS = [
|
|
9
|
+
'in',
|
|
10
|
+
'inane',
|
|
11
|
+
'inaugural',
|
|
12
|
+
'inaugurated',
|
|
13
|
+
'inauguration',
|
|
14
|
+
'inbound',
|
|
15
|
+
'inbox',
|
|
16
|
+
'incandescent',
|
|
17
|
+
'incarcerated',
|
|
18
|
+
'incarceration',
|
|
19
|
+
'incarnation',
|
|
20
|
+
'incendiary',
|
|
21
|
+
'incense',
|
|
22
|
+
'incentive',
|
|
23
|
+
'incentives',
|
|
24
|
+
'inception',
|
|
25
|
+
'incest',
|
|
26
|
+
'inch',
|
|
27
|
+
'inches',
|
|
28
|
+
'incidence',
|
|
29
|
+
'incident',
|
|
30
|
+
'incidental',
|
|
31
|
+
'incidentally',
|
|
32
|
+
'incidents',
|
|
33
|
+
'incision',
|
|
34
|
+
'incite',
|
|
35
|
+
'inciting',
|
|
36
|
+
'inclination',
|
|
37
|
+
'incline',
|
|
38
|
+
'inclined',
|
|
39
|
+
'include',
|
|
40
|
+
'included',
|
|
41
|
+
'includes',
|
|
42
|
+
'including',
|
|
43
|
+
'inclusion',
|
|
44
|
+
'inclusive',
|
|
45
|
+
'income',
|
|
46
|
+
'incomes',
|
|
47
|
+
'incoming',
|
|
48
|
+
'incorporate',
|
|
49
|
+
'incorporated',
|
|
50
|
+
'incorporates',
|
|
51
|
+
'incorporating',
|
|
52
|
+
'incorporation',
|
|
53
|
+
'increase',
|
|
54
|
+
'increased',
|
|
55
|
+
'increases',
|
|
56
|
+
'increasing',
|
|
57
|
+
'increasingly',
|
|
58
|
+
'incremental',
|
|
59
|
+
'increments',
|
|
60
|
+
'incriminating',
|
|
61
|
+
'incubation',
|
|
62
|
+
'incubator',
|
|
63
|
+
'incumbent',
|
|
64
|
+
'incumbents',
|
|
65
|
+
'incur',
|
|
66
|
+
'incurred',
|
|
67
|
+
'indebted',
|
|
68
|
+
'indeed',
|
|
69
|
+
'index',
|
|
70
|
+
'indexed',
|
|
71
|
+
'indexes',
|
|
72
|
+
'indexing',
|
|
73
|
+
'indicate',
|
|
74
|
+
'indicated',
|
|
75
|
+
'indicates',
|
|
76
|
+
'indicating',
|
|
77
|
+
'indication',
|
|
78
|
+
'indications',
|
|
79
|
+
'indicative',
|
|
80
|
+
'indicator',
|
|
81
|
+
'indicators',
|
|
82
|
+
'indices',
|
|
83
|
+
'indicted',
|
|
84
|
+
'indictment',
|
|
85
|
+
'indictments',
|
|
86
|
+
'indie',
|
|
87
|
+
'indies',
|
|
88
|
+
'indigenous',
|
|
89
|
+
'indignation',
|
|
90
|
+
'indigo',
|
|
91
|
+
'indoor',
|
|
92
|
+
'indoors',
|
|
93
|
+
'induce',
|
|
94
|
+
'induced',
|
|
95
|
+
'induces',
|
|
96
|
+
'inducing',
|
|
97
|
+
'inducted',
|
|
98
|
+
'induction',
|
|
99
|
+
'indulge',
|
|
100
|
+
'indulgence',
|
|
101
|
+
'indulgent',
|
|
102
|
+
'indulging',
|
|
103
|
+
'industrial',
|
|
104
|
+
'industrialized',
|
|
105
|
+
'industries',
|
|
106
|
+
'industry',
|
|
107
|
+
'inexpensive',
|
|
108
|
+
'infancy',
|
|
109
|
+
'infant',
|
|
110
|
+
'infantry',
|
|
111
|
+
'infants',
|
|
112
|
+
'infect',
|
|
113
|
+
'infected',
|
|
114
|
+
'infection',
|
|
115
|
+
'infections',
|
|
116
|
+
'infectious',
|
|
117
|
+
'infer',
|
|
118
|
+
'inference',
|
|
119
|
+
'inferior',
|
|
120
|
+
'inferno',
|
|
121
|
+
'inferred',
|
|
122
|
+
'infertility',
|
|
123
|
+
'infestation',
|
|
124
|
+
'infested',
|
|
125
|
+
'infidelity',
|
|
126
|
+
'infield',
|
|
127
|
+
'infiltrate',
|
|
128
|
+
'infiltrated',
|
|
129
|
+
'infiltration',
|
|
130
|
+
'infinite',
|
|
131
|
+
'infinitely',
|
|
132
|
+
'infinity',
|
|
133
|
+
'infirmary',
|
|
134
|
+
'inflamed',
|
|
135
|
+
'inflammation',
|
|
136
|
+
'inflammatory',
|
|
137
|
+
'inflatable',
|
|
138
|
+
'inflate',
|
|
139
|
+
'inflated',
|
|
140
|
+
'inflation',
|
|
141
|
+
'inflict',
|
|
142
|
+
'inflicted',
|
|
143
|
+
'inflicting',
|
|
144
|
+
'influence',
|
|
145
|
+
'influenced',
|
|
146
|
+
'influencers',
|
|
147
|
+
'influences',
|
|
148
|
+
'influencing',
|
|
149
|
+
'influential',
|
|
150
|
+
'influenza',
|
|
151
|
+
'influx',
|
|
152
|
+
'info',
|
|
153
|
+
'infographic',
|
|
154
|
+
'inform',
|
|
155
|
+
'informant',
|
|
156
|
+
'informants',
|
|
157
|
+
'informatics',
|
|
158
|
+
'information',
|
|
159
|
+
'informational',
|
|
160
|
+
'informative',
|
|
161
|
+
'informed',
|
|
162
|
+
'informing',
|
|
163
|
+
'informs',
|
|
164
|
+
'infrared',
|
|
165
|
+
'infrastructure',
|
|
166
|
+
'infringed',
|
|
167
|
+
'infringement',
|
|
168
|
+
'infringing',
|
|
169
|
+
'infuriating',
|
|
170
|
+
'infused',
|
|
171
|
+
'infusion',
|
|
172
|
+
'ingenious',
|
|
173
|
+
'ingenuity',
|
|
174
|
+
'ingested',
|
|
175
|
+
'ingot',
|
|
176
|
+
'ingrained',
|
|
177
|
+
'ingredient',
|
|
178
|
+
'ingredients',
|
|
179
|
+
'inhabit',
|
|
180
|
+
'inhabitants',
|
|
181
|
+
'inhabited',
|
|
182
|
+
'inhalation',
|
|
183
|
+
'inhale',
|
|
184
|
+
'inhaled',
|
|
185
|
+
'inhaling',
|
|
186
|
+
'inherent',
|
|
187
|
+
'inherently',
|
|
188
|
+
'inheritance',
|
|
189
|
+
'inherited',
|
|
190
|
+
'initial',
|
|
191
|
+
'initially',
|
|
192
|
+
'initials',
|
|
193
|
+
'initiate',
|
|
194
|
+
'initiated',
|
|
195
|
+
'initiates',
|
|
196
|
+
'initiating',
|
|
197
|
+
'initiation',
|
|
198
|
+
'initiative',
|
|
199
|
+
'initiatives',
|
|
200
|
+
'inject',
|
|
201
|
+
'injected',
|
|
202
|
+
'injecting',
|
|
203
|
+
'injection',
|
|
204
|
+
'injections',
|
|
205
|
+
'injunction',
|
|
206
|
+
'injure',
|
|
207
|
+
'injured',
|
|
208
|
+
'injuries',
|
|
209
|
+
'injuring',
|
|
210
|
+
'injury',
|
|
211
|
+
'ink',
|
|
212
|
+
'inked',
|
|
213
|
+
'inks',
|
|
214
|
+
'inland',
|
|
215
|
+
'inlay',
|
|
216
|
+
'inlet',
|
|
217
|
+
'inmate',
|
|
218
|
+
'inmates',
|
|
219
|
+
'inn',
|
|
220
|
+
'innate',
|
|
221
|
+
'inner',
|
|
222
|
+
'inning',
|
|
223
|
+
'innings',
|
|
224
|
+
'innovate',
|
|
225
|
+
'innovation',
|
|
226
|
+
'innovations',
|
|
227
|
+
'innovative',
|
|
228
|
+
'innovator',
|
|
229
|
+
'innovators',
|
|
230
|
+
'inns',
|
|
231
|
+
'inpatient',
|
|
232
|
+
'input',
|
|
233
|
+
'inputs',
|
|
234
|
+
'inquest',
|
|
235
|
+
'inquire',
|
|
236
|
+
'inquiries',
|
|
237
|
+
'inquiry',
|
|
238
|
+
'inquisition',
|
|
239
|
+
'ins',
|
|
240
|
+
'inscribed',
|
|
241
|
+
'inscription',
|
|
242
|
+
'inscriptions',
|
|
243
|
+
'insect',
|
|
244
|
+
'insects',
|
|
245
|
+
'insert',
|
|
246
|
+
'inserted',
|
|
247
|
+
'inserting',
|
|
248
|
+
'insertion',
|
|
249
|
+
'inserts',
|
|
250
|
+
'inside',
|
|
251
|
+
'insider',
|
|
252
|
+
'insiders',
|
|
253
|
+
'insides',
|
|
254
|
+
'insidious',
|
|
255
|
+
'insight',
|
|
256
|
+
'insightful',
|
|
257
|
+
'insights',
|
|
258
|
+
'insignia',
|
|
259
|
+
'insist',
|
|
260
|
+
'insisted',
|
|
261
|
+
'insistence',
|
|
262
|
+
'insistent',
|
|
263
|
+
'insisting',
|
|
264
|
+
'insists',
|
|
265
|
+
'insofar',
|
|
266
|
+
'inspect',
|
|
267
|
+
'inspected',
|
|
268
|
+
'inspecting',
|
|
269
|
+
'inspection',
|
|
270
|
+
'inspections',
|
|
271
|
+
'inspector',
|
|
272
|
+
'inspectors',
|
|
273
|
+
'inspiration',
|
|
274
|
+
'inspirational',
|
|
275
|
+
'inspirations',
|
|
276
|
+
'inspire',
|
|
277
|
+
'inspired',
|
|
278
|
+
'inspires',
|
|
279
|
+
'inspiring',
|
|
280
|
+
'install',
|
|
281
|
+
'installation',
|
|
282
|
+
'installations',
|
|
283
|
+
'installed',
|
|
284
|
+
'installing',
|
|
285
|
+
'installment',
|
|
286
|
+
'installments',
|
|
287
|
+
'instalment',
|
|
288
|
+
'instance',
|
|
289
|
+
'instances',
|
|
290
|
+
'instant',
|
|
291
|
+
'instantaneous',
|
|
292
|
+
'instantly',
|
|
293
|
+
'instead',
|
|
294
|
+
'instigated',
|
|
295
|
+
'instinct',
|
|
296
|
+
'instinctive',
|
|
297
|
+
'instinctively',
|
|
298
|
+
'instincts',
|
|
299
|
+
'institute',
|
|
300
|
+
'instituted',
|
|
301
|
+
'institutes',
|
|
302
|
+
'institution',
|
|
303
|
+
'institutional',
|
|
304
|
+
'institutions',
|
|
305
|
+
'instruct',
|
|
306
|
+
'instructed',
|
|
307
|
+
'instructing',
|
|
308
|
+
'instruction',
|
|
309
|
+
'instructional',
|
|
310
|
+
'instructions',
|
|
311
|
+
'instructor',
|
|
312
|
+
'instructors',
|
|
313
|
+
'instrument',
|
|
314
|
+
'instrumental',
|
|
315
|
+
'instrumentation',
|
|
316
|
+
'instruments',
|
|
317
|
+
'insular',
|
|
318
|
+
'insulated',
|
|
319
|
+
'insulating',
|
|
320
|
+
'insulation',
|
|
321
|
+
'insulin',
|
|
322
|
+
'insult',
|
|
323
|
+
'insulted',
|
|
324
|
+
'insulting',
|
|
325
|
+
'insults',
|
|
326
|
+
'insurance',
|
|
327
|
+
'insure',
|
|
328
|
+
'insured',
|
|
329
|
+
'insurer',
|
|
330
|
+
'insurers',
|
|
331
|
+
'insurgency',
|
|
332
|
+
'insurgent',
|
|
333
|
+
'insurgents',
|
|
334
|
+
'insurrection',
|
|
335
|
+
'intake',
|
|
336
|
+
'integers',
|
|
337
|
+
'intel',
|
|
338
|
+
'intellect',
|
|
339
|
+
'intellectual',
|
|
340
|
+
'intellectually',
|
|
341
|
+
'intellectuals',
|
|
342
|
+
'intelligence',
|
|
343
|
+
'intelligent',
|
|
344
|
+
'intelligently',
|
|
345
|
+
'intend',
|
|
346
|
+
'intended',
|
|
347
|
+
'intending',
|
|
348
|
+
'intends',
|
|
349
|
+
'intense',
|
|
350
|
+
'intensely',
|
|
351
|
+
'intensified',
|
|
352
|
+
'intensifies',
|
|
353
|
+
'intensify',
|
|
354
|
+
'intensity',
|
|
355
|
+
'intensive',
|
|
356
|
+
'intent',
|
|
357
|
+
'intention',
|
|
358
|
+
'intentional',
|
|
359
|
+
'intentionally',
|
|
360
|
+
'intentions',
|
|
361
|
+
'inter',
|
|
362
|
+
'interact',
|
|
363
|
+
'interacted',
|
|
364
|
+
'interacting',
|
|
365
|
+
'interaction',
|
|
366
|
+
'interactions',
|
|
367
|
+
'interactive',
|
|
368
|
+
'interacts',
|
|
369
|
+
'intercept',
|
|
370
|
+
'intercepted',
|
|
371
|
+
'interception',
|
|
372
|
+
'interceptions',
|
|
373
|
+
'interchange',
|
|
374
|
+
'interchangeable',
|
|
375
|
+
'interconnected',
|
|
376
|
+
'intercourse',
|
|
377
|
+
'interest',
|
|
378
|
+
'interested',
|
|
379
|
+
'interesting',
|
|
380
|
+
'interestingly',
|
|
381
|
+
'interests',
|
|
382
|
+
'interface',
|
|
383
|
+
'interfaces',
|
|
384
|
+
'interfere',
|
|
385
|
+
'interfered',
|
|
386
|
+
'interference',
|
|
387
|
+
'interferes',
|
|
388
|
+
'interfering',
|
|
389
|
+
'interim',
|
|
390
|
+
'interior',
|
|
391
|
+
'interiors',
|
|
392
|
+
'interlude',
|
|
393
|
+
'intermediary',
|
|
394
|
+
'intermediate',
|
|
395
|
+
'intermission',
|
|
396
|
+
'intermittent',
|
|
397
|
+
'intermittently',
|
|
398
|
+
'intern',
|
|
399
|
+
'internal',
|
|
400
|
+
'internally',
|
|
401
|
+
'international',
|
|
402
|
+
'internationally',
|
|
403
|
+
'internationals',
|
|
404
|
+
'interns',
|
|
405
|
+
'internship',
|
|
406
|
+
'internships',
|
|
407
|
+
'interpersonal',
|
|
408
|
+
'interplay',
|
|
409
|
+
'interpret',
|
|
410
|
+
'interpretation',
|
|
411
|
+
'interpretations',
|
|
412
|
+
'interpreted',
|
|
413
|
+
'interpreter',
|
|
414
|
+
'interpreters',
|
|
415
|
+
'interpreting',
|
|
416
|
+
'interpretive',
|
|
417
|
+
'interracial',
|
|
418
|
+
'interrogated',
|
|
419
|
+
'interrogation',
|
|
420
|
+
'interrupt',
|
|
421
|
+
'interrupted',
|
|
422
|
+
'interrupting',
|
|
423
|
+
'interruption',
|
|
424
|
+
'interruptions',
|
|
425
|
+
'interrupts',
|
|
426
|
+
'intersect',
|
|
427
|
+
'intersection',
|
|
428
|
+
'intersections',
|
|
429
|
+
'interspersed',
|
|
430
|
+
'interstate',
|
|
431
|
+
'interstellar',
|
|
432
|
+
'intertwined',
|
|
433
|
+
'interval',
|
|
434
|
+
'intervals',
|
|
435
|
+
'intervene',
|
|
436
|
+
'intervened',
|
|
437
|
+
'intervening',
|
|
438
|
+
'intervention',
|
|
439
|
+
'interventions',
|
|
440
|
+
'interview',
|
|
441
|
+
'interviewed',
|
|
442
|
+
'interviewer',
|
|
443
|
+
'interviewing',
|
|
444
|
+
'interviews',
|
|
445
|
+
'intestinal',
|
|
446
|
+
'intestine',
|
|
447
|
+
'intestines',
|
|
448
|
+
'intimacy',
|
|
449
|
+
'intimate',
|
|
450
|
+
'intimately',
|
|
451
|
+
'intimidate',
|
|
452
|
+
'intimidated',
|
|
453
|
+
'intimidating',
|
|
454
|
+
'intimidation',
|
|
455
|
+
'into',
|
|
456
|
+
'intoxicated',
|
|
457
|
+
'intoxication',
|
|
458
|
+
'intracellular',
|
|
459
|
+
'intravenous',
|
|
460
|
+
'intricate',
|
|
461
|
+
'intrigue',
|
|
462
|
+
'intrigued',
|
|
463
|
+
'intriguing',
|
|
464
|
+
'intrinsic',
|
|
465
|
+
'intrinsically',
|
|
466
|
+
'intro',
|
|
467
|
+
'introduce',
|
|
468
|
+
'introduced',
|
|
469
|
+
'introduces',
|
|
470
|
+
'introducing',
|
|
471
|
+
'introduction',
|
|
472
|
+
'introductions',
|
|
473
|
+
'introductory',
|
|
474
|
+
'intruder',
|
|
475
|
+
'intruders',
|
|
476
|
+
'intrusion',
|
|
477
|
+
'intrusive',
|
|
478
|
+
'intuition',
|
|
479
|
+
'intuitive',
|
|
480
|
+
'intuitively',
|
|
481
|
+
'inundated',
|
|
482
|
+
'invade',
|
|
483
|
+
'invaded',
|
|
484
|
+
'invaders',
|
|
485
|
+
'invading',
|
|
486
|
+
'invasion',
|
|
487
|
+
'invasions',
|
|
488
|
+
'invasive',
|
|
489
|
+
'invent',
|
|
490
|
+
'invented',
|
|
491
|
+
'inventing',
|
|
492
|
+
'invention',
|
|
493
|
+
'inventions',
|
|
494
|
+
'inventive',
|
|
495
|
+
'inventor',
|
|
496
|
+
'inventories',
|
|
497
|
+
'inventors',
|
|
498
|
+
'inventory',
|
|
499
|
+
'inverness',
|
|
500
|
+
'inverse',
|
|
501
|
+
'inversion',
|
|
502
|
+
'inverted',
|
|
503
|
+
'invest',
|
|
504
|
+
'invested',
|
|
505
|
+
'investigate',
|
|
506
|
+
'investigated',
|
|
507
|
+
'investigates',
|
|
508
|
+
'investigating',
|
|
509
|
+
'investigation',
|
|
510
|
+
'investigations',
|
|
511
|
+
'investigative',
|
|
512
|
+
'investigator',
|
|
513
|
+
'investigators',
|
|
514
|
+
'investing',
|
|
515
|
+
'investment',
|
|
516
|
+
'investments',
|
|
517
|
+
'investor',
|
|
518
|
+
'investors',
|
|
519
|
+
'invests',
|
|
520
|
+
'invitation',
|
|
521
|
+
'invitational',
|
|
522
|
+
'invitations',
|
|
523
|
+
'invite',
|
|
524
|
+
'invited',
|
|
525
|
+
'invites',
|
|
526
|
+
'inviting',
|
|
527
|
+
'invoice',
|
|
528
|
+
'invoices',
|
|
529
|
+
'invoke',
|
|
530
|
+
'invoked',
|
|
531
|
+
'invoking',
|
|
532
|
+
'involve',
|
|
533
|
+
'involved',
|
|
534
|
+
'involvement',
|
|
535
|
+
'involves',
|
|
536
|
+
'involving',
|
|
537
|
+
'inward',
|
|
538
|
+
'init',
|
|
539
|
+
'initial',
|
|
540
|
+
'initialization',
|
|
541
|
+
'initialize',
|
|
542
|
+
'initialized',
|
|
543
|
+
'initializing',
|
|
544
|
+
'initializes',
|
|
545
|
+
'initializing',
|
|
546
|
+
'initializes',
|
|
547
|
+
];
|
|
548
|
+
const NO_EXCEPTIONS = [
|
|
549
|
+
'nobility',
|
|
550
|
+
'noble',
|
|
551
|
+
'nobleman',
|
|
552
|
+
'nobles',
|
|
553
|
+
'nobly',
|
|
554
|
+
'nocturnal',
|
|
555
|
+
'nod',
|
|
556
|
+
'nodded',
|
|
557
|
+
'nodding',
|
|
558
|
+
'node',
|
|
559
|
+
'nodes',
|
|
560
|
+
'nods',
|
|
561
|
+
'noel',
|
|
562
|
+
'noir',
|
|
563
|
+
'noise',
|
|
564
|
+
'noises',
|
|
565
|
+
'noisy',
|
|
566
|
+
'nomad',
|
|
567
|
+
'nomadic',
|
|
568
|
+
'nomenclature',
|
|
569
|
+
'nominal',
|
|
570
|
+
'nominally',
|
|
571
|
+
'nominate',
|
|
572
|
+
'nominated',
|
|
573
|
+
'nominating',
|
|
574
|
+
'nomination',
|
|
575
|
+
'nominations',
|
|
576
|
+
'nominee',
|
|
577
|
+
'nominees',
|
|
578
|
+
'noodle',
|
|
579
|
+
'noodles',
|
|
580
|
+
'nook',
|
|
581
|
+
'noon',
|
|
582
|
+
'noose',
|
|
583
|
+
'norM',
|
|
584
|
+
'norma',
|
|
585
|
+
'normal',
|
|
586
|
+
'normalized',
|
|
587
|
+
'normally',
|
|
588
|
+
'normative',
|
|
589
|
+
'norms',
|
|
590
|
+
'north',
|
|
591
|
+
'northbound',
|
|
592
|
+
'northeast',
|
|
593
|
+
'northeastern',
|
|
594
|
+
'northern',
|
|
595
|
+
'northward',
|
|
596
|
+
'northwest',
|
|
597
|
+
'northwestern',
|
|
598
|
+
'nose',
|
|
599
|
+
'nosey',
|
|
600
|
+
'nostalgia',
|
|
601
|
+
'nostalgic',
|
|
602
|
+
'nostrils',
|
|
603
|
+
'notable',
|
|
604
|
+
'notably',
|
|
605
|
+
'notary',
|
|
606
|
+
'notation',
|
|
607
|
+
'notch',
|
|
608
|
+
'notched',
|
|
609
|
+
'notebook',
|
|
610
|
+
'notebooks',
|
|
611
|
+
'noted',
|
|
612
|
+
'notes',
|
|
613
|
+
'noteworthy',
|
|
614
|
+
'notice',
|
|
615
|
+
'noticeable',
|
|
616
|
+
'noticeably',
|
|
617
|
+
'noticed',
|
|
618
|
+
'notices',
|
|
619
|
+
'noticing',
|
|
620
|
+
'notification',
|
|
621
|
+
'notifications',
|
|
622
|
+
'notified',
|
|
623
|
+
'notify',
|
|
624
|
+
'notifying',
|
|
625
|
+
'notion',
|
|
626
|
+
'notions',
|
|
627
|
+
'notoriety',
|
|
628
|
+
'notorious',
|
|
629
|
+
'notoriously',
|
|
630
|
+
'noun',
|
|
631
|
+
'nouns',
|
|
632
|
+
'nourishment',
|
|
633
|
+
'nouveau',
|
|
634
|
+
'nova',
|
|
635
|
+
'novel',
|
|
636
|
+
'novelist',
|
|
637
|
+
'novelists',
|
|
638
|
+
'novella',
|
|
639
|
+
'novels',
|
|
640
|
+
'novelty',
|
|
641
|
+
'novice',
|
|
642
|
+
'now',
|
|
643
|
+
'nowadays',
|
|
644
|
+
'nozzle',
|
|
645
|
+
];
|
|
646
|
+
const UN_EXCEPTIONS = [
|
|
647
|
+
'unanimous',
|
|
648
|
+
'unanimously',
|
|
649
|
+
'uncle',
|
|
650
|
+
'uncles',
|
|
651
|
+
'under',
|
|
652
|
+
'underage',
|
|
653
|
+
'undercover',
|
|
654
|
+
'undercut',
|
|
655
|
+
'underdog',
|
|
656
|
+
'underestimate',
|
|
657
|
+
'underestimated',
|
|
658
|
+
'undergo',
|
|
659
|
+
'undergoes',
|
|
660
|
+
'undergoing',
|
|
661
|
+
'undergone',
|
|
662
|
+
'undergraduate',
|
|
663
|
+
'undergraduates',
|
|
664
|
+
'underground',
|
|
665
|
+
'underlined',
|
|
666
|
+
'underlying',
|
|
667
|
+
'undermine',
|
|
668
|
+
'undermined',
|
|
669
|
+
'undermines',
|
|
670
|
+
'undermining',
|
|
671
|
+
'underneath',
|
|
672
|
+
'underrated',
|
|
673
|
+
'underside',
|
|
674
|
+
'understand',
|
|
675
|
+
'understandable',
|
|
676
|
+
'understandably',
|
|
677
|
+
'understanding',
|
|
678
|
+
'understands',
|
|
679
|
+
'understated',
|
|
680
|
+
'understatement',
|
|
681
|
+
'understood',
|
|
682
|
+
'undertake',
|
|
683
|
+
'undertaken',
|
|
684
|
+
'undertaker',
|
|
685
|
+
'undertaking',
|
|
686
|
+
'undertook',
|
|
687
|
+
'underwater',
|
|
688
|
+
'underway',
|
|
689
|
+
'underwear',
|
|
690
|
+
'underwent',
|
|
691
|
+
'underwood',
|
|
692
|
+
'underworld',
|
|
693
|
+
'underwriting',
|
|
694
|
+
'unicorn',
|
|
695
|
+
'unicorns',
|
|
696
|
+
'unification',
|
|
697
|
+
'unified',
|
|
698
|
+
'uniform',
|
|
699
|
+
'uniformed',
|
|
700
|
+
'uniformity',
|
|
701
|
+
'uniformly',
|
|
702
|
+
'uniforms',
|
|
703
|
+
'unify',
|
|
704
|
+
'unifying',
|
|
705
|
+
'unilateral',
|
|
706
|
+
'unilaterally',
|
|
707
|
+
'union',
|
|
708
|
+
'unionist',
|
|
709
|
+
'unionists',
|
|
710
|
+
'unions',
|
|
711
|
+
'unique',
|
|
712
|
+
'uniquely',
|
|
713
|
+
'uniqueness',
|
|
714
|
+
'unison',
|
|
715
|
+
'unit',
|
|
716
|
+
'unitary',
|
|
717
|
+
'unite',
|
|
718
|
+
'united',
|
|
719
|
+
'unites',
|
|
720
|
+
'uniting',
|
|
721
|
+
'units',
|
|
722
|
+
'unity',
|
|
723
|
+
'universal',
|
|
724
|
+
'universally',
|
|
725
|
+
'universe',
|
|
726
|
+
'universes',
|
|
727
|
+
'universities',
|
|
728
|
+
'university',
|
|
729
|
+
'unless',
|
|
730
|
+
'until',
|
|
731
|
+
'unto',
|
|
732
|
+
];
|
|
733
|
+
const DIS_EXCEPTIONS = [
|
|
734
|
+
'disc',
|
|
735
|
+
'disciple',
|
|
736
|
+
'disciples',
|
|
737
|
+
'disciplinary',
|
|
738
|
+
'discipline',
|
|
739
|
+
'disciplined',
|
|
740
|
+
'disciplines',
|
|
741
|
+
'disco',
|
|
742
|
+
'discography',
|
|
743
|
+
'discern',
|
|
744
|
+
'discerning',
|
|
745
|
+
'discourse',
|
|
746
|
+
'discreet',
|
|
747
|
+
'discreetly',
|
|
748
|
+
'discrepancies',
|
|
749
|
+
'discrepancy',
|
|
750
|
+
'discrete',
|
|
751
|
+
'discretion',
|
|
752
|
+
'discretionary',
|
|
753
|
+
'discriminate',
|
|
754
|
+
'discriminated',
|
|
755
|
+
'discriminating',
|
|
756
|
+
'discrimination',
|
|
757
|
+
'discriminatory',
|
|
758
|
+
'discs',
|
|
759
|
+
'discuss',
|
|
760
|
+
'discussed',
|
|
761
|
+
'discusses',
|
|
762
|
+
'discussing',
|
|
763
|
+
'discussion',
|
|
764
|
+
'discussions',
|
|
765
|
+
'disengage',
|
|
766
|
+
'disparate',
|
|
767
|
+
'dispensary',
|
|
768
|
+
'dispense',
|
|
769
|
+
'dispenser',
|
|
770
|
+
'dispensing',
|
|
771
|
+
'disperse',
|
|
772
|
+
'dispersed',
|
|
773
|
+
'dispersion',
|
|
774
|
+
'disposition',
|
|
775
|
+
'disseminate',
|
|
776
|
+
'dissemination',
|
|
777
|
+
'dissertation',
|
|
778
|
+
'dissident',
|
|
779
|
+
'dissidents',
|
|
780
|
+
'dissimilar',
|
|
781
|
+
'dissipated',
|
|
782
|
+
'dissolution',
|
|
783
|
+
'dissolve',
|
|
784
|
+
'dissolved',
|
|
785
|
+
'dissolving',
|
|
786
|
+
'distal',
|
|
787
|
+
'distance',
|
|
788
|
+
'distances',
|
|
789
|
+
'distancing',
|
|
790
|
+
'distant',
|
|
791
|
+
'distillation',
|
|
792
|
+
'distilled',
|
|
793
|
+
'distillery',
|
|
794
|
+
'distinct',
|
|
795
|
+
'distinction',
|
|
796
|
+
'distinctions',
|
|
797
|
+
'distinctive',
|
|
798
|
+
'distinctly',
|
|
799
|
+
'distinguish',
|
|
800
|
+
'distinguished',
|
|
801
|
+
'distinguishes',
|
|
802
|
+
'distinguishing',
|
|
803
|
+
'distort',
|
|
804
|
+
'distorted',
|
|
805
|
+
'distortion',
|
|
806
|
+
'distortions',
|
|
807
|
+
'distract',
|
|
808
|
+
'distracted',
|
|
809
|
+
'distracting',
|
|
810
|
+
'distraction',
|
|
811
|
+
'distractions',
|
|
812
|
+
'distraught',
|
|
813
|
+
'distribute',
|
|
814
|
+
'distributed',
|
|
815
|
+
'distributes',
|
|
816
|
+
'distributing',
|
|
817
|
+
'distribution',
|
|
818
|
+
'distributions',
|
|
819
|
+
'distributor',
|
|
820
|
+
'distributors',
|
|
821
|
+
'district',
|
|
822
|
+
'districts',
|
|
823
|
+
'dismal',
|
|
824
|
+
'disaster',
|
|
825
|
+
'disasters',
|
|
826
|
+
'disastrous',
|
|
827
|
+
];
|
|
8
828
|
// Words that contain negative prefixes but should be treated as valid
|
|
9
|
-
const EXCEPTION_WORDS = [
|
|
829
|
+
const EXCEPTION_WORDS = [
|
|
830
|
+
...IN_EXCEPTIONS,
|
|
831
|
+
...NO_EXCEPTIONS,
|
|
832
|
+
...UN_EXCEPTIONS,
|
|
833
|
+
...DIS_EXCEPTIONS,
|
|
834
|
+
];
|
|
835
|
+
/**
|
|
836
|
+
* Splits a variable name into individual words based on naming conventions:
|
|
837
|
+
* - camelCase or PascalCase: split on uppercase letters
|
|
838
|
+
* - SCREAMING_SNAKE_CASE: split on underscores
|
|
839
|
+
* @param name Variable name to split
|
|
840
|
+
* @returns Array of individual words in lowercase
|
|
841
|
+
*/
|
|
842
|
+
function splitNameIntoWords(name) {
|
|
843
|
+
// Handle SCREAMING_SNAKE_CASE
|
|
844
|
+
if (name.includes('_')) {
|
|
845
|
+
return name.toLowerCase().split('_').filter(Boolean);
|
|
846
|
+
}
|
|
847
|
+
// Handle camelCase and PascalCase
|
|
848
|
+
// Add space before uppercase letters and then split
|
|
849
|
+
const spacedName = name.replace(/([A-Z])/g, ' $1');
|
|
850
|
+
return spacedName.toLowerCase().trim().split(/\s+/).filter(Boolean);
|
|
851
|
+
}
|
|
10
852
|
// Map of negative boolean terms to suggested positive alternatives
|
|
11
853
|
const BOOLEAN_POSITIVE_ALTERNATIVES = {
|
|
12
|
-
// Boolean prefixes
|
|
854
|
+
// Boolean prefixes - These will be removed from suggestions
|
|
13
855
|
isNot: ['is'],
|
|
14
856
|
isUn: ['is'],
|
|
15
857
|
isDis: ['is'],
|
|
@@ -21,6 +863,28 @@ const BOOLEAN_POSITIVE_ALTERNATIVES = {
|
|
|
21
863
|
shouldNot: ['should'],
|
|
22
864
|
willNot: ['will'],
|
|
23
865
|
doesNot: ['does'],
|
|
866
|
+
IsNot: ['Is'],
|
|
867
|
+
IsUn: ['Is'],
|
|
868
|
+
IsDis: ['Is'],
|
|
869
|
+
IsIn: ['Is'],
|
|
870
|
+
IsNon: ['Is'],
|
|
871
|
+
HasNo: ['Has'],
|
|
872
|
+
HasNot: ['Has'],
|
|
873
|
+
CanNot: ['Can'],
|
|
874
|
+
ShouldNot: ['Should'],
|
|
875
|
+
WillNot: ['Will'],
|
|
876
|
+
DoesNot: ['Does'],
|
|
877
|
+
IS_NOT: ['IS'],
|
|
878
|
+
IS_UN: ['IS'],
|
|
879
|
+
IS_DIS: ['IS'],
|
|
880
|
+
IS_IN: ['IS'],
|
|
881
|
+
IS_NON: ['IS'],
|
|
882
|
+
HAS_NO: ['HAS'],
|
|
883
|
+
HAS_NOT: ['HAS'],
|
|
884
|
+
CAN_NOT: ['CAN'],
|
|
885
|
+
SHOULD_NOT: ['SHOULD'],
|
|
886
|
+
WILL_NOT: ['WILL'],
|
|
887
|
+
DOES_NOT: ['DOES'],
|
|
24
888
|
};
|
|
25
889
|
exports.enforcePositiveNaming = (0, createRule_1.createRule)({
|
|
26
890
|
name: 'enforce-positive-naming',
|
|
@@ -63,46 +927,98 @@ exports.enforcePositiveNaming = (0, createRule_1.createRule)({
|
|
|
63
927
|
alternatives: BOOLEAN_POSITIVE_ALTERNATIVES[name],
|
|
64
928
|
};
|
|
65
929
|
}
|
|
930
|
+
// Split the name into words
|
|
931
|
+
const words = splitNameIntoWords(name);
|
|
932
|
+
// Check if this follows the pattern IS_NOT_SOMETHING or HAS_NO_SOMETHING
|
|
933
|
+
const secondWord = words[1].toLowerCase();
|
|
934
|
+
if (EXCEPTION_WORDS.some((exception) => secondWord === exception.toLowerCase())) {
|
|
935
|
+
return { isNegative: false, alternatives: [] };
|
|
936
|
+
}
|
|
937
|
+
const nameLowercase = name.toLowerCase();
|
|
66
938
|
// Check for negative prefixes in boolean-like variables
|
|
67
|
-
if (
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
//
|
|
74
|
-
for (const exceptionWord of EXCEPTION_WORDS) {
|
|
75
|
-
const lowerCaseName = name.toLowerCase();
|
|
76
|
-
if (lowerCaseName.includes(exceptionWord.toLowerCase())) {
|
|
77
|
-
return { isNegative: false, alternatives: [] };
|
|
78
|
-
}
|
|
79
|
-
}
|
|
939
|
+
if (nameLowercase.startsWith('is') ||
|
|
940
|
+
nameLowercase.startsWith('has') ||
|
|
941
|
+
nameLowercase.startsWith('can') ||
|
|
942
|
+
nameLowercase.startsWith('should') ||
|
|
943
|
+
nameLowercase.startsWith('will') ||
|
|
944
|
+
nameLowercase.startsWith('does')) {
|
|
945
|
+
// We already checked exception words above, so no need to check again
|
|
80
946
|
for (const prefix of BOOLEAN_NEGATIVE_PREFIXES) {
|
|
947
|
+
const prefixCapitalized = prefix.charAt(0).toUpperCase() + prefix.slice(1);
|
|
948
|
+
const prefixUppercase = prefix.toUpperCase();
|
|
81
949
|
// Check for patterns like isNot, hasNo, canNot, etc.
|
|
82
950
|
const prefixPatterns = [
|
|
83
951
|
{
|
|
84
|
-
pattern: new RegExp(`^is${
|
|
85
|
-
key: `is${
|
|
952
|
+
pattern: new RegExp(`^is${prefixCapitalized}`, 'i'),
|
|
953
|
+
key: `is${prefixCapitalized}`,
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
pattern: new RegExp(`^has${prefixCapitalized}`, 'i'),
|
|
957
|
+
key: `has${prefixCapitalized}`,
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
pattern: new RegExp(`^can${prefixCapitalized}`, 'i'),
|
|
961
|
+
key: `can${prefixCapitalized}`,
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
pattern: new RegExp(`^should${prefixCapitalized}`, 'i'),
|
|
965
|
+
key: `should${prefixCapitalized}`,
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
pattern: new RegExp(`^will${prefixCapitalized}`, 'i'),
|
|
969
|
+
key: `will${prefixCapitalized}`,
|
|
970
|
+
},
|
|
971
|
+
{
|
|
972
|
+
pattern: new RegExp(`^does${prefixCapitalized}`, 'i'),
|
|
973
|
+
key: `does${prefixCapitalized}`,
|
|
974
|
+
},
|
|
975
|
+
{
|
|
976
|
+
pattern: new RegExp(`^Is${prefixCapitalized}`, 'i'),
|
|
977
|
+
key: `Is${prefixCapitalized}`,
|
|
978
|
+
},
|
|
979
|
+
{
|
|
980
|
+
pattern: new RegExp(`^Has${prefixCapitalized}`, 'i'),
|
|
981
|
+
key: `Has${prefixCapitalized}`,
|
|
982
|
+
},
|
|
983
|
+
{
|
|
984
|
+
pattern: new RegExp(`^Can${prefixCapitalized}`, 'i'),
|
|
985
|
+
key: `Can${prefixCapitalized}`,
|
|
986
|
+
},
|
|
987
|
+
{
|
|
988
|
+
pattern: new RegExp(`^Should${prefixCapitalized}`, 'i'),
|
|
989
|
+
key: `Should${prefixCapitalized}`,
|
|
990
|
+
},
|
|
991
|
+
{
|
|
992
|
+
pattern: new RegExp(`^Will${prefixCapitalized}`, 'i'),
|
|
993
|
+
key: `Will${prefixCapitalized}`,
|
|
994
|
+
},
|
|
995
|
+
{
|
|
996
|
+
pattern: new RegExp(`^Does${prefixCapitalized}`, 'i'),
|
|
997
|
+
key: `Does${prefixCapitalized}`,
|
|
998
|
+
},
|
|
999
|
+
{
|
|
1000
|
+
pattern: new RegExp(`^IS_${prefixUppercase}`, 'i'),
|
|
1001
|
+
key: `IS_${prefixUppercase}`,
|
|
86
1002
|
},
|
|
87
1003
|
{
|
|
88
|
-
pattern: new RegExp(`^
|
|
89
|
-
key: `
|
|
1004
|
+
pattern: new RegExp(`^HAS_${prefixUppercase}`, 'i'),
|
|
1005
|
+
key: `HAS_${prefixUppercase}`,
|
|
90
1006
|
},
|
|
91
1007
|
{
|
|
92
|
-
pattern: new RegExp(`^
|
|
93
|
-
key: `
|
|
1008
|
+
pattern: new RegExp(`^CAN_${prefixUppercase}`, 'i'),
|
|
1009
|
+
key: `CAN_${prefixUppercase}`,
|
|
94
1010
|
},
|
|
95
1011
|
{
|
|
96
|
-
pattern: new RegExp(`^
|
|
97
|
-
key: `
|
|
1012
|
+
pattern: new RegExp(`^SHOULD_${prefixUppercase}`, 'i'),
|
|
1013
|
+
key: `SHOULD_${prefixUppercase}`,
|
|
98
1014
|
},
|
|
99
1015
|
{
|
|
100
|
-
pattern: new RegExp(`^
|
|
101
|
-
key: `
|
|
1016
|
+
pattern: new RegExp(`^WILL_${prefixUppercase}`, 'i'),
|
|
1017
|
+
key: `WILL_${prefixUppercase}`,
|
|
102
1018
|
},
|
|
103
1019
|
{
|
|
104
|
-
pattern: new RegExp(`^
|
|
105
|
-
key: `
|
|
1020
|
+
pattern: new RegExp(`^DOES_${prefixUppercase}`, 'i'),
|
|
1021
|
+
key: `DOES_${prefixUppercase}`,
|
|
106
1022
|
},
|
|
107
1023
|
];
|
|
108
1024
|
for (const { pattern, key } of prefixPatterns) {
|
|
@@ -168,9 +168,21 @@ exports.noTypeAssertionReturns = (0, createRule_1.createRule)({
|
|
|
168
168
|
return true;
|
|
169
169
|
}
|
|
170
170
|
// Allow type assertions as arguments to constructors
|
|
171
|
-
if (node.parent?.type === utils_1.AST_NODE_TYPES.NewExpression
|
|
171
|
+
if (node.parent?.type === utils_1.AST_NODE_TYPES.NewExpression ||
|
|
172
|
+
(node.parent?.type === utils_1.AST_NODE_TYPES.CallExpression &&
|
|
173
|
+
node.parent.parent?.type === utils_1.AST_NODE_TYPES.NewExpression)) {
|
|
172
174
|
return true;
|
|
173
175
|
}
|
|
176
|
+
// Allow type assertions as arguments to constructor calls
|
|
177
|
+
if (node.parent?.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
178
|
+
let current = node.parent;
|
|
179
|
+
while (current?.parent) {
|
|
180
|
+
if (current.parent.type === utils_1.AST_NODE_TYPES.NewExpression) {
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
current = current.parent;
|
|
184
|
+
}
|
|
185
|
+
}
|
|
174
186
|
// Allow type assertions in JSX attributes/props or object properties
|
|
175
187
|
if (isInsideJSXAttributeOrObjectProperty(node)) {
|
|
176
188
|
return true;
|