@blumintinc/eslint-plugin-blumint 1.12.6 → 1.13.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/README.md +140 -99
- package/lib/index.js +111 -17
- package/lib/rules/array-methods-this-context.js +20 -2
- package/lib/rules/avoid-utils-directory.js +11 -2
- package/lib/rules/dynamic-https-errors.d.ts +3 -1
- package/lib/rules/dynamic-https-errors.js +48 -10
- package/lib/rules/enforce-assert-safe-object-key.d.ts +8 -0
- package/lib/rules/{enforce-assertSafe-object-key.js → enforce-assert-safe-object-key.js} +51 -95
- package/lib/rules/enforce-assert-throws.d.ts +3 -1
- package/lib/rules/enforce-assert-throws.js +493 -51
- package/lib/rules/enforce-boolean-naming-prefixes.d.ts +3 -1
- package/lib/rules/enforce-boolean-naming-prefixes.js +832 -39
- package/lib/rules/enforce-callable-types.js +4 -4
- package/lib/rules/enforce-callback-memo.js +143 -18
- package/lib/rules/enforce-centralized-mock-firestore.js +4 -1
- package/lib/rules/enforce-console-error.d.ts +3 -0
- package/lib/rules/enforce-console-error.js +250 -0
- package/lib/rules/enforce-css-media-queries.js +24 -46
- package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
- package/lib/rules/enforce-dynamic-imports.js +1 -1
- package/lib/rules/enforce-exported-function-types.js +3 -3
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +212 -0
- package/lib/rules/enforce-firestore-doc-ref-generic.js +335 -0
- package/lib/rules/enforce-firestore-facade.js +347 -157
- package/lib/rules/enforce-firestore-rules-get-access.d.ts +3 -0
- package/lib/rules/enforce-firestore-rules-get-access.js +109 -0
- package/lib/rules/enforce-global-constants.d.ts +4 -1
- package/lib/rules/enforce-global-constants.js +240 -12
- package/lib/rules/enforce-memoize-async.d.ts +2 -1
- package/lib/rules/enforce-memoize-async.js +96 -27
- package/lib/rules/enforce-memoize-getters.d.ts +3 -0
- package/lib/rules/enforce-memoize-getters.js +123 -0
- package/lib/rules/enforce-microdiff.js +2 -1
- package/lib/rules/enforce-positive-naming.js +5 -7
- package/lib/rules/enforce-props-argument-name.d.ts +2 -7
- package/lib/rules/enforce-props-argument-name.js +165 -151
- package/lib/rules/enforce-props-naming-consistency.d.ts +2 -0
- package/lib/rules/enforce-props-naming-consistency.js +145 -0
- package/lib/rules/enforce-querykey-ts.d.ts +9 -0
- package/lib/rules/enforce-querykey-ts.js +274 -0
- package/lib/rules/enforce-singular-type-names.js +9 -5
- package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
- package/lib/rules/enforce-typescript-markdown-code-blocks.js +96 -0
- package/lib/rules/enforce-verb-noun-naming.js +85 -10
- package/lib/rules/extract-global-constants.js +57 -45
- package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
- package/lib/rules/fast-deep-equal-over-microdiff.js +356 -78
- package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
- package/lib/rules/firestore-transaction-reads-before-writes.js +231 -0
- package/lib/rules/generic-starts-with-t.js +8 -2
- package/lib/rules/memoize-root-level-hocs.d.ts +7 -0
- package/lib/rules/memoize-root-level-hocs.js +242 -0
- package/lib/rules/no-array-length-in-deps.d.ts +12 -0
- package/lib/rules/no-array-length-in-deps.js +308 -0
- package/lib/rules/no-async-array-filter.js +5 -2
- package/lib/rules/no-complex-cloud-params.js +15 -2
- package/lib/rules/no-compositing-layer-props.js +4 -2
- package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
- package/lib/rules/no-entire-object-hook-deps.js +317 -63
- package/lib/rules/no-excessive-parent-chain.d.ts +5 -0
- package/lib/rules/no-excessive-parent-chain.js +273 -0
- package/lib/rules/no-firestore-object-arrays.js +345 -30
- package/lib/rules/no-hungarian.js +13 -13
- package/lib/rules/no-margin-properties.d.ts +7 -1
- package/lib/rules/no-margin-properties.js +16 -3
- package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
- package/lib/rules/no-misleading-boolean-prefixes.js +327 -0
- package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
- package/lib/rules/no-overridable-method-calls-in-constructor.js +260 -0
- package/lib/rules/no-passthrough-getters.d.ts +4 -0
- package/lib/rules/no-passthrough-getters.js +170 -0
- package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
- package/lib/rules/no-redundant-usecallback-wrapper.js +315 -0
- package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
- package/lib/rules/no-restricted-properties-fix.js +172 -0
- package/lib/rules/no-separate-loading-state.d.ts +8 -0
- package/lib/rules/no-separate-loading-state.js +142 -0
- package/lib/rules/no-stale-state-across-await.d.ts +1 -0
- package/lib/rules/no-stale-state-across-await.js +185 -0
- package/lib/rules/no-static-constants-in-dynamic-files.d.ts +3 -0
- package/lib/rules/no-static-constants-in-dynamic-files.js +149 -0
- package/lib/rules/no-try-catch-already-exists-in-transaction.d.ts +1 -0
- package/lib/rules/no-try-catch-already-exists-in-transaction.js +342 -0
- package/lib/rules/no-type-assertion-returns.js +6 -0
- package/lib/rules/no-undefined-null-passthrough.js +166 -19
- package/lib/rules/no-unnecessary-verb-suffix.js +0 -2
- package/lib/rules/no-unsafe-firestore-spread.js +8 -5
- package/lib/rules/no-unused-props.d.ts +3 -0
- package/lib/rules/no-unused-props.js +213 -78
- package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
- package/lib/rules/optimize-object-boolean-conditions.js +234 -0
- package/lib/rules/parallelize-async-operations.d.ts +8 -0
- package/lib/rules/parallelize-async-operations.js +375 -0
- package/lib/rules/prefer-batch-operations.js +199 -33
- package/lib/rules/prefer-block-comments-for-declarations.js +13 -3
- package/lib/rules/prefer-document-flattening.d.ts +4 -0
- package/lib/rules/prefer-document-flattening.js +239 -0
- package/lib/rules/prefer-field-paths-in-transforms.d.ts +7 -0
- package/lib/rules/prefer-field-paths-in-transforms.js +250 -0
- package/lib/rules/prefer-fragment-component.js +3 -3
- package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
- package/lib/rules/prefer-global-router-state-key.js +230 -31
- package/lib/rules/prefer-next-dynamic.d.ts +9 -0
- package/lib/rules/prefer-next-dynamic.js +366 -0
- package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
- package/lib/rules/prefer-nullish-coalescing-boolean-props.js +430 -0
- package/lib/rules/prefer-nullish-coalescing-override.d.ts +6 -0
- package/lib/rules/prefer-nullish-coalescing-override.js +182 -0
- package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
- package/lib/rules/prefer-params-over-parent-id.js +228 -0
- package/lib/rules/prefer-settings-object.js +23 -15
- package/lib/rules/prefer-type-alias-over-typeof-constant.d.ts +3 -0
- package/lib/rules/prefer-type-alias-over-typeof-constant.js +259 -0
- package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
- package/lib/rules/prefer-url-tostring-over-tojson.js +166 -0
- package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
- package/lib/rules/prefer-use-deep-compare-memo.js +428 -0
- package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +24 -1
- package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
- package/lib/rules/react-usememo-should-be-component.d.ts +2 -1
- package/lib/rules/react-usememo-should-be-component.js +144 -78
- package/lib/rules/require-dynamic-firebase-imports.js +2 -1
- package/lib/rules/require-image-optimized.js +1 -1
- package/lib/rules/require-memo.js +11 -1
- package/lib/rules/require-usememo-object-literals.js +7 -1
- package/lib/rules/semantic-function-prefixes.js +38 -18
- package/lib/rules/sync-onwrite-name-func.js +5 -1
- package/lib/rules/test-file-location-enforcement.d.ts +1 -0
- package/lib/rules/test-file-location-enforcement.js +57 -0
- package/lib/rules/use-custom-link.js +6 -1
- package/lib/rules/use-custom-router.js +6 -1
- package/lib/rules/use-latest-callback.d.ts +3 -0
- package/lib/rules/use-latest-callback.js +270 -0
- package/lib/utils/ASTHelpers.js +10 -0
- package/lib/utils/createRule.js +1 -1
- package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
- package/lib/utils/ruleTester.d.ts +1 -0
- package/lib/utils/ruleTester.js +4 -1
- package/package.json +21 -14
- package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
|
@@ -1 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
type MessageIds = 'useGlobalConstant' | 'extractDefaultToGlobalConstant';
|
|
3
|
+
export declare const enforceGlobalConstants: TSESLint.RuleModule<MessageIds, [], TSESLint.RuleListener>;
|
|
4
|
+
export {};
|
|
@@ -3,48 +3,250 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.enforceGlobalConstants = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
5
|
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
const ASTHelpers_1 = require("../utils/ASTHelpers");
|
|
6
7
|
exports.enforceGlobalConstants = (0, createRule_1.createRule)({
|
|
7
8
|
name: 'enforce-global-constants',
|
|
8
9
|
meta: {
|
|
9
10
|
type: 'suggestion',
|
|
10
11
|
docs: {
|
|
11
|
-
description: 'Enforce using global static constants instead of useMemo with empty dependency arrays for object literals',
|
|
12
|
+
description: 'Enforce using global static constants instead of useMemo with empty dependency arrays for object literals, and extract inline destructuring defaults in React components/hooks to global constants',
|
|
12
13
|
recommended: 'error',
|
|
13
14
|
},
|
|
15
|
+
fixable: 'code',
|
|
14
16
|
schema: [],
|
|
15
17
|
messages: {
|
|
16
18
|
useGlobalConstant: 'Use a global static constant instead of useMemo with an empty dependency array for object literals',
|
|
19
|
+
extractDefaultToGlobalConstant: 'Extract inline default value to a module-level constant for stable reference',
|
|
17
20
|
},
|
|
18
21
|
},
|
|
19
22
|
defaultOptions: [],
|
|
20
23
|
create(context) {
|
|
24
|
+
const sourceCode = context.getSourceCode();
|
|
25
|
+
function isHookName(name) {
|
|
26
|
+
return /^use[A-Z]/.test(name);
|
|
27
|
+
}
|
|
28
|
+
function isComponentOrHookFunction(fn) {
|
|
29
|
+
if (fn.type === utils_1.AST_NODE_TYPES.FunctionDeclaration) {
|
|
30
|
+
const n = fn.id?.name ?? '';
|
|
31
|
+
return /^[A-Z]/.test(n) || isHookName(n);
|
|
32
|
+
}
|
|
33
|
+
const parent = fn.parent;
|
|
34
|
+
if (parent &&
|
|
35
|
+
parent.type === utils_1.AST_NODE_TYPES.VariableDeclarator &&
|
|
36
|
+
parent.id.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
37
|
+
const n = parent.id.name;
|
|
38
|
+
return /^[A-Z]/.test(n) || isHookName(n);
|
|
39
|
+
}
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
function getEnclosingFunction(node) {
|
|
43
|
+
let current = node;
|
|
44
|
+
while (current) {
|
|
45
|
+
if (current.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
|
|
46
|
+
current.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression ||
|
|
47
|
+
current.type === utils_1.AST_NODE_TYPES.FunctionExpression) {
|
|
48
|
+
return current;
|
|
49
|
+
}
|
|
50
|
+
current = current.parent;
|
|
51
|
+
}
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
function toUpperSnakeCase(name) {
|
|
55
|
+
return name
|
|
56
|
+
.replace(/([A-Z])/g, '_$1')
|
|
57
|
+
.toUpperCase()
|
|
58
|
+
.replace(/^_/, '');
|
|
59
|
+
}
|
|
60
|
+
function collectAssignmentDefaultsFromPattern(pattern) {
|
|
61
|
+
const results = [];
|
|
62
|
+
const visitPattern = (p) => {
|
|
63
|
+
if (p.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
64
|
+
for (const prop of p.properties) {
|
|
65
|
+
if (prop.type === utils_1.AST_NODE_TYPES.Property) {
|
|
66
|
+
const value = prop.value;
|
|
67
|
+
if (value &&
|
|
68
|
+
value.type ===
|
|
69
|
+
utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
70
|
+
const assign = value;
|
|
71
|
+
const left = assign.left;
|
|
72
|
+
if (left.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
73
|
+
results.push({ assignment: assign, localName: left.name });
|
|
74
|
+
}
|
|
75
|
+
if (left.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
76
|
+
left.type === utils_1.AST_NODE_TYPES.ArrayPattern) {
|
|
77
|
+
// Nested pattern on the left of an assignment; uncommon, ignore naming
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
else if (value &&
|
|
81
|
+
value
|
|
82
|
+
.type &&
|
|
83
|
+
(value
|
|
84
|
+
.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
85
|
+
value
|
|
86
|
+
.type === utils_1.AST_NODE_TYPES.ArrayPattern)) {
|
|
87
|
+
visitPattern(value);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
else if (p.type === utils_1.AST_NODE_TYPES.ArrayPattern) {
|
|
93
|
+
for (const elem of p.elements) {
|
|
94
|
+
if (!elem)
|
|
95
|
+
continue;
|
|
96
|
+
if (elem.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
97
|
+
const left = elem.left;
|
|
98
|
+
if (left.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
99
|
+
results.push({ assignment: elem, localName: left.name });
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else if (elem.type === utils_1.AST_NODE_TYPES.ArrayPattern ||
|
|
103
|
+
elem.type === utils_1.AST_NODE_TYPES.ObjectPattern) {
|
|
104
|
+
visitPattern(elem);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
else if (p.type === utils_1.AST_NODE_TYPES.AssignmentPattern) {
|
|
109
|
+
const left = p.left;
|
|
110
|
+
if (left.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
111
|
+
results.push({ assignment: p, localName: left.name });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
};
|
|
115
|
+
visitPattern(pattern);
|
|
116
|
+
return results;
|
|
117
|
+
}
|
|
118
|
+
function hasIdentifiers(node) {
|
|
119
|
+
return !!node && ASTHelpers_1.ASTHelpers.declarationIncludesIdentifier(node);
|
|
120
|
+
}
|
|
121
|
+
function alreadyHasConst(program, constName) {
|
|
122
|
+
for (const stmt of program.body) {
|
|
123
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.VariableDeclaration &&
|
|
124
|
+
stmt.kind === 'const') {
|
|
125
|
+
for (const d of stmt.declarations) {
|
|
126
|
+
if (d.id.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
127
|
+
d.id.name === constName) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return false;
|
|
134
|
+
}
|
|
135
|
+
function buildConstDeclarationLine(constName, initText) {
|
|
136
|
+
const needsAsConst = /^(?:true|false|-?\d|\[|\{|[`'"])/.test(initText) &&
|
|
137
|
+
!/\bas const\b/.test(initText);
|
|
138
|
+
const initializer = needsAsConst ? `${initText} as const` : initText;
|
|
139
|
+
return `const ${constName} = ${initializer};`;
|
|
140
|
+
}
|
|
141
|
+
function reportStaticDefaults(patterns, enclosingFn, nodeForReport) {
|
|
142
|
+
if (!enclosingFn || !isComponentOrHookFunction(enclosingFn))
|
|
143
|
+
return;
|
|
144
|
+
const defaults = [];
|
|
145
|
+
for (const pattern of patterns) {
|
|
146
|
+
defaults.push(...collectAssignmentDefaultsFromPattern(pattern));
|
|
147
|
+
}
|
|
148
|
+
if (defaults.length === 0)
|
|
149
|
+
return;
|
|
150
|
+
const staticDefaults = defaults.filter((def) => {
|
|
151
|
+
const right = def.assignment.right;
|
|
152
|
+
return right && !hasIdentifiers(right);
|
|
153
|
+
});
|
|
154
|
+
if (staticDefaults.length === 0)
|
|
155
|
+
return;
|
|
156
|
+
context.report({
|
|
157
|
+
node: nodeForReport,
|
|
158
|
+
messageId: 'extractDefaultToGlobalConstant',
|
|
159
|
+
fix(fixer) {
|
|
160
|
+
const fixes = [];
|
|
161
|
+
const programNode = sourceCode.ast;
|
|
162
|
+
const declLines = [];
|
|
163
|
+
for (const def of staticDefaults) {
|
|
164
|
+
const { assignment, localName } = def;
|
|
165
|
+
const right = assignment.right;
|
|
166
|
+
const rightText = sourceCode.getText(right);
|
|
167
|
+
const constName = `DEFAULT_${toUpperSnakeCase(localName)}`;
|
|
168
|
+
if (!alreadyHasConst(programNode, constName)) {
|
|
169
|
+
declLines.push(buildConstDeclarationLine(constName, rightText));
|
|
170
|
+
}
|
|
171
|
+
fixes.push(fixer.replaceText(right, constName));
|
|
172
|
+
}
|
|
173
|
+
if (declLines.length > 0) {
|
|
174
|
+
const program = sourceCode.ast;
|
|
175
|
+
const constSection = declLines.length === 1
|
|
176
|
+
? declLines[0]
|
|
177
|
+
: `${declLines[0]}\n\n${declLines.slice(1).join('\n')}`;
|
|
178
|
+
const text = sourceCode.text;
|
|
179
|
+
const findNextNonWhitespace = (start) => {
|
|
180
|
+
let idx = start;
|
|
181
|
+
while (idx < text.length && /\s/.test(text[idx])) {
|
|
182
|
+
idx += 1;
|
|
183
|
+
}
|
|
184
|
+
return idx;
|
|
185
|
+
};
|
|
186
|
+
const buildBlock = (extraSpacing, insertPos, nextPos) => {
|
|
187
|
+
const whitespace = text.slice(insertPos, nextPos);
|
|
188
|
+
const lastNewline = whitespace.lastIndexOf('\n');
|
|
189
|
+
const nextIndentRaw = lastNewline === -1
|
|
190
|
+
? ''
|
|
191
|
+
: whitespace.slice(lastNewline + 1).replace(/[^\t ]/g, '');
|
|
192
|
+
const separator = extraSpacing ? '\n\n\n' : '\n\n';
|
|
193
|
+
const nextIndent = extraSpacing ? nextIndentRaw : '';
|
|
194
|
+
return `\n${constSection}${separator}${nextIndent}`;
|
|
195
|
+
};
|
|
196
|
+
const imports = program.body.filter((s) => s.type === utils_1.AST_NODE_TYPES.ImportDeclaration);
|
|
197
|
+
if (imports.length > 0) {
|
|
198
|
+
const lastImport = imports[imports.length - 1];
|
|
199
|
+
const insertPos = lastImport.range[1];
|
|
200
|
+
const nextPos = findNextNonWhitespace(insertPos);
|
|
201
|
+
fixes.push(fixer.replaceTextRange([insertPos, nextPos], buildBlock(false, insertPos, nextPos)));
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const body = program.body;
|
|
205
|
+
let insertPos = 0;
|
|
206
|
+
let afterDirectiveIdx = -1;
|
|
207
|
+
for (let i = 0; i < body.length; i++) {
|
|
208
|
+
const stmt = body[i];
|
|
209
|
+
if (stmt.type === utils_1.AST_NODE_TYPES.ExpressionStatement &&
|
|
210
|
+
stmt.expression.type === utils_1.AST_NODE_TYPES.Literal &&
|
|
211
|
+
typeof stmt.expression.value === 'string') {
|
|
212
|
+
afterDirectiveIdx = i;
|
|
213
|
+
}
|
|
214
|
+
else {
|
|
215
|
+
break;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (afterDirectiveIdx >= 0) {
|
|
219
|
+
insertPos = body[afterDirectiveIdx].range[1];
|
|
220
|
+
}
|
|
221
|
+
const nextPos = findNextNonWhitespace(insertPos);
|
|
222
|
+
fixes.push(fixer.replaceTextRange([insertPos, nextPos], buildBlock(afterDirectiveIdx < 0, insertPos, nextPos)));
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return fixes;
|
|
226
|
+
},
|
|
227
|
+
});
|
|
228
|
+
}
|
|
21
229
|
return {
|
|
22
230
|
CallExpression(node) {
|
|
23
|
-
// Check if it's a useMemo call
|
|
24
231
|
if (node.callee.type !== utils_1.AST_NODE_TYPES.Identifier ||
|
|
25
232
|
node.callee.name !== 'useMemo') {
|
|
26
233
|
return;
|
|
27
234
|
}
|
|
28
|
-
// Check if it has exactly two arguments
|
|
29
235
|
if (node.arguments.length !== 2) {
|
|
30
236
|
return;
|
|
31
237
|
}
|
|
32
|
-
// Check if the second argument is an empty array
|
|
33
238
|
const depsArray = node.arguments[1];
|
|
34
239
|
if (depsArray.type !== utils_1.AST_NODE_TYPES.ArrayExpression ||
|
|
35
240
|
depsArray.elements.length !== 0) {
|
|
36
241
|
return;
|
|
37
242
|
}
|
|
38
|
-
// Check if the first argument is an arrow function
|
|
39
243
|
const callback = node.arguments[0];
|
|
40
|
-
if (callback.type !== utils_1.AST_NODE_TYPES.ArrowFunctionExpression
|
|
244
|
+
if (callback.type !== utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
|
|
245
|
+
callback.type !== utils_1.AST_NODE_TYPES.FunctionExpression) {
|
|
41
246
|
return;
|
|
42
247
|
}
|
|
43
|
-
// Check if the arrow function body is a block statement with a return statement
|
|
44
|
-
// or a direct expression (implicit return)
|
|
45
248
|
let returnValue = null;
|
|
46
249
|
if (callback.body.type === utils_1.AST_NODE_TYPES.BlockStatement) {
|
|
47
|
-
// If it's a block, find the return statement
|
|
48
250
|
const returnStatement = callback.body.body.find((stmt) => stmt.type === utils_1.AST_NODE_TYPES.ReturnStatement);
|
|
49
251
|
if (!returnStatement || !returnStatement.argument) {
|
|
50
252
|
return;
|
|
@@ -52,15 +254,12 @@ exports.enforceGlobalConstants = (0, createRule_1.createRule)({
|
|
|
52
254
|
returnValue = returnStatement.argument;
|
|
53
255
|
}
|
|
54
256
|
else {
|
|
55
|
-
// If it's an expression (implicit return)
|
|
56
257
|
returnValue = callback.body;
|
|
57
258
|
}
|
|
58
|
-
// Handle 'as const' type assertions
|
|
59
259
|
let actualReturnValue = returnValue;
|
|
60
260
|
if (returnValue.type === utils_1.AST_NODE_TYPES.TSAsExpression) {
|
|
61
261
|
actualReturnValue = returnValue.expression;
|
|
62
262
|
}
|
|
63
|
-
// Check if the return value is an object literal or an array of object literals
|
|
64
263
|
if (actualReturnValue.type === utils_1.AST_NODE_TYPES.ObjectExpression ||
|
|
65
264
|
(actualReturnValue.type === utils_1.AST_NODE_TYPES.ArrayExpression &&
|
|
66
265
|
actualReturnValue.elements.some((element) => element !== null &&
|
|
@@ -71,6 +270,35 @@ exports.enforceGlobalConstants = (0, createRule_1.createRule)({
|
|
|
71
270
|
});
|
|
72
271
|
}
|
|
73
272
|
},
|
|
273
|
+
VariableDeclaration(node) {
|
|
274
|
+
const relevantDeclarators = node.declarations.filter((d) => d.id.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
275
|
+
d.id.type === utils_1.AST_NODE_TYPES.ArrayPattern);
|
|
276
|
+
if (relevantDeclarators.length === 0)
|
|
277
|
+
return;
|
|
278
|
+
const enclosingFn = getEnclosingFunction(node);
|
|
279
|
+
reportStaticDefaults(relevantDeclarators.map((d) => d.id), enclosingFn, node);
|
|
280
|
+
},
|
|
281
|
+
FunctionDeclaration(node) {
|
|
282
|
+
const patterns = node.params.filter((p) => p.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
283
|
+
p.type === utils_1.AST_NODE_TYPES.ArrayPattern);
|
|
284
|
+
if (patterns.length === 0)
|
|
285
|
+
return;
|
|
286
|
+
reportStaticDefaults(patterns, node, node);
|
|
287
|
+
},
|
|
288
|
+
FunctionExpression(node) {
|
|
289
|
+
const patterns = node.params.filter((p) => p.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
290
|
+
p.type === utils_1.AST_NODE_TYPES.ArrayPattern);
|
|
291
|
+
if (patterns.length === 0)
|
|
292
|
+
return;
|
|
293
|
+
reportStaticDefaults(patterns, node, node);
|
|
294
|
+
},
|
|
295
|
+
ArrowFunctionExpression(node) {
|
|
296
|
+
const patterns = node.params.filter((p) => p.type === utils_1.AST_NODE_TYPES.ObjectPattern ||
|
|
297
|
+
p.type === utils_1.AST_NODE_TYPES.ArrayPattern);
|
|
298
|
+
if (patterns.length === 0)
|
|
299
|
+
return;
|
|
300
|
+
reportStaticDefaults(patterns, node, node);
|
|
301
|
+
},
|
|
74
302
|
};
|
|
75
303
|
},
|
|
76
304
|
});
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
export declare const enforceMemoizeAsync: TSESLint.RuleModule<"requireMemoize", [], TSESLint.RuleListener>;
|
|
@@ -3,6 +3,36 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.enforceMemoizeAsync = void 0;
|
|
4
4
|
const utils_1 = require("@typescript-eslint/utils");
|
|
5
5
|
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
const MEMOIZE_MODULE = 'typescript-memoize';
|
|
7
|
+
/**
|
|
8
|
+
* Matches a memoize decorator in supported syntaxes:
|
|
9
|
+
* - @Alias()
|
|
10
|
+
* - @Alias
|
|
11
|
+
* - @ns.Alias
|
|
12
|
+
*/
|
|
13
|
+
function isMemoizeDecorator(decorator, alias) {
|
|
14
|
+
const expression = decorator.expression;
|
|
15
|
+
/* @Alias() */
|
|
16
|
+
if (expression.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
17
|
+
const callee = expression.callee;
|
|
18
|
+
return ((callee.type === utils_1.AST_NODE_TYPES.Identifier && callee.name === alias) ||
|
|
19
|
+
(callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
20
|
+
!callee.computed &&
|
|
21
|
+
callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
22
|
+
callee.property.name === alias));
|
|
23
|
+
}
|
|
24
|
+
/* @Alias */
|
|
25
|
+
if (expression.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
26
|
+
return expression.name === alias;
|
|
27
|
+
}
|
|
28
|
+
/* @ns.Alias */
|
|
29
|
+
if (expression.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
30
|
+
!expression.computed &&
|
|
31
|
+
expression.property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
32
|
+
return expression.property.name === alias;
|
|
33
|
+
}
|
|
34
|
+
return false;
|
|
35
|
+
}
|
|
6
36
|
exports.enforceMemoizeAsync = (0, createRule_1.createRule)({
|
|
7
37
|
name: 'enforce-memoize-async',
|
|
8
38
|
meta: {
|
|
@@ -21,17 +51,22 @@ exports.enforceMemoizeAsync = (0, createRule_1.createRule)({
|
|
|
21
51
|
create(context) {
|
|
22
52
|
let hasMemoizeImport = false;
|
|
23
53
|
let memoizeAlias = 'Memoize';
|
|
54
|
+
let memoizeNamespace = null;
|
|
55
|
+
let scheduledImportFix = false;
|
|
24
56
|
return {
|
|
25
57
|
ImportDeclaration(node) {
|
|
26
|
-
if (node.source.value ===
|
|
27
|
-
|
|
28
|
-
spec.
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
memoizeAlias = memoizeSpecifier.local.name;
|
|
58
|
+
if (node.source.value === MEMOIZE_MODULE) {
|
|
59
|
+
node.specifiers.forEach((spec) => {
|
|
60
|
+
if (spec.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
|
|
61
|
+
spec.imported.name === 'Memoize') {
|
|
62
|
+
hasMemoizeImport = true;
|
|
63
|
+
memoizeAlias = spec.local?.name ?? memoizeAlias;
|
|
33
64
|
}
|
|
34
|
-
|
|
65
|
+
else if (spec.type === utils_1.AST_NODE_TYPES.ImportNamespaceSpecifier) {
|
|
66
|
+
hasMemoizeImport = true;
|
|
67
|
+
memoizeNamespace = spec.local.name;
|
|
68
|
+
}
|
|
69
|
+
});
|
|
35
70
|
}
|
|
36
71
|
},
|
|
37
72
|
MethodDefinition(node) {
|
|
@@ -45,26 +80,60 @@ exports.enforceMemoizeAsync = (0, createRule_1.createRule)({
|
|
|
45
80
|
if (node.value.params.length > 1) {
|
|
46
81
|
return;
|
|
47
82
|
}
|
|
48
|
-
// Check if method already has @Memoize decorator
|
|
49
|
-
const hasDecorator = node.decorators?.some((decorator) =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
}
|
|
53
|
-
const callee = decorator.expression.callee;
|
|
54
|
-
return (callee.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
55
|
-
callee.name === memoizeAlias);
|
|
56
|
-
});
|
|
57
|
-
if (!hasDecorator && hasMemoizeImport) {
|
|
58
|
-
context.report({
|
|
59
|
-
node,
|
|
60
|
-
messageId: 'requireMemoize',
|
|
61
|
-
fix(fixer) {
|
|
62
|
-
// Add import if needed
|
|
63
|
-
// Add decorator
|
|
64
|
-
return fixer.insertTextBefore(node, `@${memoizeAlias}()\n${' '.repeat(node.loc.start.column)}`);
|
|
65
|
-
},
|
|
66
|
-
});
|
|
83
|
+
// Check if method already has @Memoize or @Memoize() decorator
|
|
84
|
+
const hasDecorator = node.decorators?.some((decorator) => isMemoizeDecorator(decorator, memoizeAlias));
|
|
85
|
+
if (hasDecorator) {
|
|
86
|
+
return;
|
|
67
87
|
}
|
|
88
|
+
context.report({
|
|
89
|
+
node,
|
|
90
|
+
messageId: 'requireMemoize',
|
|
91
|
+
fix(fixer) {
|
|
92
|
+
const fixes = [];
|
|
93
|
+
const sourceCode = context.getSourceCode();
|
|
94
|
+
const decoratorIdent = memoizeNamespace
|
|
95
|
+
? `${memoizeNamespace}.Memoize`
|
|
96
|
+
: memoizeAlias;
|
|
97
|
+
const importStatement = `import { Memoize } from '${MEMOIZE_MODULE}';`;
|
|
98
|
+
// Add import if it's not already present; ensure we only add once per file
|
|
99
|
+
if (!hasMemoizeImport &&
|
|
100
|
+
!memoizeNamespace &&
|
|
101
|
+
!scheduledImportFix &&
|
|
102
|
+
!sourceCode.text.includes(importStatement)) {
|
|
103
|
+
const programBody = sourceCode.ast.body;
|
|
104
|
+
const firstImport = programBody.find((n) => n.type === utils_1.AST_NODE_TYPES.ImportDeclaration);
|
|
105
|
+
const anchorNode = (firstImport ?? programBody[0]);
|
|
106
|
+
if (anchorNode) {
|
|
107
|
+
const text = sourceCode.text;
|
|
108
|
+
const anchorStart = anchorNode.range[0];
|
|
109
|
+
const lineStart = text.lastIndexOf('\n', anchorStart - 1) + 1;
|
|
110
|
+
const leadingWhitespace = text.slice(lineStart, anchorStart).match(/^[ \t]*/)?.[0] ??
|
|
111
|
+
'';
|
|
112
|
+
const importLine = `${leadingWhitespace}${importStatement}\n`;
|
|
113
|
+
fixes.push(fixer.insertTextBeforeRange([lineStart, lineStart], importLine));
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
// Fallback: empty file
|
|
117
|
+
fixes.push(fixer.insertTextBeforeRange([0, 0], `import { Memoize } from '${MEMOIZE_MODULE}';\n`));
|
|
118
|
+
}
|
|
119
|
+
scheduledImportFix = true;
|
|
120
|
+
}
|
|
121
|
+
// Add decorator for this method
|
|
122
|
+
const insertionTarget = node.decorators && node.decorators.length > 0
|
|
123
|
+
? node.decorators[0]
|
|
124
|
+
: node;
|
|
125
|
+
const insertionStart = insertionTarget.range
|
|
126
|
+
? insertionTarget.range[0]
|
|
127
|
+
: node.range
|
|
128
|
+
? node.range[0]
|
|
129
|
+
: 0;
|
|
130
|
+
const text = sourceCode.text;
|
|
131
|
+
const lineStart = text.lastIndexOf('\n', insertionStart - 1) + 1;
|
|
132
|
+
const leadingWhitespace = text.slice(lineStart, insertionStart).match(/^[ \t]*/)?.[0] ?? '';
|
|
133
|
+
fixes.push(fixer.insertTextBeforeRange([lineStart, lineStart], `${leadingWhitespace}@${decoratorIdent}()\n`));
|
|
134
|
+
return fixes;
|
|
135
|
+
},
|
|
136
|
+
});
|
|
68
137
|
},
|
|
69
138
|
};
|
|
70
139
|
},
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enforceMemoizeGetters = void 0;
|
|
4
|
+
const utils_1 = require("@typescript-eslint/utils");
|
|
5
|
+
const createRule_1 = require("../utils/createRule");
|
|
6
|
+
const MEMOIZE_PREFERRED_MODULE = '@blumintinc/typescript-memoize';
|
|
7
|
+
const MEMOIZE_MODULES = new Set([
|
|
8
|
+
MEMOIZE_PREFERRED_MODULE,
|
|
9
|
+
'typescript-memoize',
|
|
10
|
+
]);
|
|
11
|
+
function isMemoizeDecorator(decorator, alias) {
|
|
12
|
+
const expression = decorator.expression;
|
|
13
|
+
// @Alias()
|
|
14
|
+
if (expression.type === utils_1.AST_NODE_TYPES.CallExpression) {
|
|
15
|
+
const callee = expression.callee;
|
|
16
|
+
return ((callee.type === utils_1.AST_NODE_TYPES.Identifier && callee.name === alias) ||
|
|
17
|
+
(callee.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
18
|
+
!callee.computed &&
|
|
19
|
+
callee.property.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
20
|
+
callee.property.name === alias));
|
|
21
|
+
}
|
|
22
|
+
// @Alias
|
|
23
|
+
if (expression.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
24
|
+
return expression.name === alias;
|
|
25
|
+
}
|
|
26
|
+
// @ns.Alias
|
|
27
|
+
if (expression.type === utils_1.AST_NODE_TYPES.MemberExpression &&
|
|
28
|
+
!expression.computed &&
|
|
29
|
+
expression.property.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
30
|
+
return expression.property.name === alias;
|
|
31
|
+
}
|
|
32
|
+
return false;
|
|
33
|
+
}
|
|
34
|
+
exports.enforceMemoizeGetters = (0, createRule_1.createRule)({
|
|
35
|
+
name: 'enforce-memoize-getters',
|
|
36
|
+
meta: {
|
|
37
|
+
type: 'suggestion',
|
|
38
|
+
docs: {
|
|
39
|
+
description: 'Enforce @Memoize() decorator on private class getters to avoid re-instantiation and preserve state across accesses.',
|
|
40
|
+
recommended: 'error',
|
|
41
|
+
},
|
|
42
|
+
fixable: 'code',
|
|
43
|
+
schema: [],
|
|
44
|
+
messages: {
|
|
45
|
+
requireMemoizeGetter: 'Private getters should be decorated with @Memoize() to preserve instance state and avoid redundant instantiation. Import Memoize from "@blumintinc/typescript-memoize".',
|
|
46
|
+
},
|
|
47
|
+
},
|
|
48
|
+
defaultOptions: [],
|
|
49
|
+
create(context) {
|
|
50
|
+
// Only apply in TS/TSX files to avoid JS environments without decorators
|
|
51
|
+
const filename = context.getFilename();
|
|
52
|
+
if (!/\.tsx?$/i.test(filename)) {
|
|
53
|
+
return {};
|
|
54
|
+
}
|
|
55
|
+
let hasMemoizeImport = false;
|
|
56
|
+
let memoizeAlias = 'Memoize';
|
|
57
|
+
let scheduledImportFix = false;
|
|
58
|
+
return {
|
|
59
|
+
ImportDeclaration(node) {
|
|
60
|
+
if (MEMOIZE_MODULES.has(String(node.source.value))) {
|
|
61
|
+
const spec = node.specifiers.find((s) => s.type === utils_1.AST_NODE_TYPES.ImportSpecifier &&
|
|
62
|
+
s.imported.name === 'Memoize');
|
|
63
|
+
if (spec) {
|
|
64
|
+
hasMemoizeImport = true;
|
|
65
|
+
memoizeAlias = spec.local?.name ?? 'Memoize';
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
},
|
|
69
|
+
MethodDefinition(node) {
|
|
70
|
+
// Target: instance private getters
|
|
71
|
+
if (node.kind !== 'get')
|
|
72
|
+
return;
|
|
73
|
+
// skip static getters
|
|
74
|
+
if (node.static)
|
|
75
|
+
return;
|
|
76
|
+
// enforce only "private" accessibility (undefined => public)
|
|
77
|
+
if (node.accessibility !== 'private')
|
|
78
|
+
return;
|
|
79
|
+
// Already memoized?
|
|
80
|
+
const hasDecorator = node.decorators?.some((d) => isMemoizeDecorator(d, memoizeAlias));
|
|
81
|
+
if (hasDecorator)
|
|
82
|
+
return;
|
|
83
|
+
context.report({
|
|
84
|
+
node,
|
|
85
|
+
messageId: 'requireMemoizeGetter',
|
|
86
|
+
fix(fixer) {
|
|
87
|
+
const fixes = [];
|
|
88
|
+
const sourceCode = context.getSourceCode();
|
|
89
|
+
// Insert import if needed, at the top alongside other imports
|
|
90
|
+
if (!hasMemoizeImport && !scheduledImportFix) {
|
|
91
|
+
const programBody = sourceCode.ast.body;
|
|
92
|
+
const firstImport = programBody.find((n) => n.type === utils_1.AST_NODE_TYPES.ImportDeclaration);
|
|
93
|
+
const anchorNode = (firstImport ?? programBody[0]);
|
|
94
|
+
if (anchorNode) {
|
|
95
|
+
const text = sourceCode.text;
|
|
96
|
+
const anchorStart = anchorNode.range[0];
|
|
97
|
+
const lineStart = text.lastIndexOf('\n', anchorStart - 1) + 1;
|
|
98
|
+
const leadingWhitespace = text.slice(lineStart, anchorStart).match(/^[ \t]*/)?.[0] ??
|
|
99
|
+
'';
|
|
100
|
+
const importLine = `${leadingWhitespace}import { Memoize } from '${MEMOIZE_PREFERRED_MODULE}';\n`;
|
|
101
|
+
fixes.push(fixer.insertTextBeforeRange([lineStart, lineStart], importLine));
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
fixes.push(fixer.insertTextBeforeRange([0, 0], `import { Memoize } from '${MEMOIZE_PREFERRED_MODULE}';\n`));
|
|
105
|
+
}
|
|
106
|
+
scheduledImportFix = true;
|
|
107
|
+
}
|
|
108
|
+
// Insert decorator above the getter (or before the first decorator), preserving indentation
|
|
109
|
+
const indent = ' '.repeat(node.loc.start.column);
|
|
110
|
+
const lineStart = node.range
|
|
111
|
+
? sourceCode.text.lastIndexOf('\n', node.range[0] - 1) + 1
|
|
112
|
+
: 0;
|
|
113
|
+
const insertPosition = Math.max(0, lineStart);
|
|
114
|
+
fixes.push(fixer.insertTextBeforeRange([insertPosition, insertPosition], `${indent}@${memoizeAlias}()\n`));
|
|
115
|
+
return fixes;
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
},
|
|
119
|
+
};
|
|
120
|
+
},
|
|
121
|
+
});
|
|
122
|
+
exports.default = exports.enforceMemoizeGetters;
|
|
123
|
+
//# sourceMappingURL=enforce-memoize-getters.js.map
|
|
@@ -144,7 +144,8 @@ exports.enforceMicrodiff = (0, createRule_1.createRule)({
|
|
|
144
144
|
// Get the source of the imported function
|
|
145
145
|
const importSource = importedFunctions.get(name);
|
|
146
146
|
// Skip reporting if it's from fast-deep-equal
|
|
147
|
-
if (importSource === 'fast-deep-equal' ||
|
|
147
|
+
if (importSource === 'fast-deep-equal' ||
|
|
148
|
+
importSource === 'fast-deep-equal/es6') {
|
|
148
149
|
return;
|
|
149
150
|
}
|
|
150
151
|
// Report it if it's from any other tracked library
|
|
@@ -333,6 +333,7 @@ const IN_EXCEPTIONS = [
|
|
|
333
333
|
'insurgents',
|
|
334
334
|
'insurrection',
|
|
335
335
|
'intake',
|
|
336
|
+
'integer',
|
|
336
337
|
'integers',
|
|
337
338
|
'intel',
|
|
338
339
|
'intellect',
|
|
@@ -424,6 +425,8 @@ const IN_EXCEPTIONS = [
|
|
|
424
425
|
'interruptions',
|
|
425
426
|
'interrupts',
|
|
426
427
|
'intersect',
|
|
428
|
+
'intersected',
|
|
429
|
+
'intersecting',
|
|
427
430
|
'intersection',
|
|
428
431
|
'intersections',
|
|
429
432
|
'interspersed',
|
|
@@ -846,12 +849,7 @@ const DIS_EXCEPTIONS = [
|
|
|
846
849
|
'disks',
|
|
847
850
|
];
|
|
848
851
|
// Words that contain negative prefixes but should be treated as valid
|
|
849
|
-
const
|
|
850
|
-
...IN_EXCEPTIONS,
|
|
851
|
-
...NO_EXCEPTIONS,
|
|
852
|
-
...UN_EXCEPTIONS,
|
|
853
|
-
...DIS_EXCEPTIONS,
|
|
854
|
-
];
|
|
852
|
+
const EXCEPTION_WORDS_SET = new Set([...IN_EXCEPTIONS, ...NO_EXCEPTIONS, ...UN_EXCEPTIONS, ...DIS_EXCEPTIONS].map((word) => word.toLowerCase()));
|
|
855
853
|
/**
|
|
856
854
|
* Splits a variable name into individual words based on naming conventions:
|
|
857
855
|
* - camelCase or PascalCase: split on uppercase letters
|
|
@@ -957,7 +955,7 @@ exports.enforcePositiveNaming = (0, createRule_1.createRule)({
|
|
|
957
955
|
// Make sure words[1] exists before trying to access it
|
|
958
956
|
if (words.length > 1) {
|
|
959
957
|
const secondWord = words[1].toLowerCase();
|
|
960
|
-
if (
|
|
958
|
+
if (EXCEPTION_WORDS_SET.has(secondWord)) {
|
|
961
959
|
return { isNegative: false, alternatives: [] };
|
|
962
960
|
}
|
|
963
961
|
}
|
|
@@ -1,8 +1,3 @@
|
|
|
1
|
-
type
|
|
2
|
-
|
|
3
|
-
enforceDestructuring?: boolean;
|
|
4
|
-
ignoreExternalInterfaces?: boolean;
|
|
5
|
-
}
|
|
6
|
-
];
|
|
7
|
-
export declare const enforcePropsArgumentName: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<"usePropsForType", Options, import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
1
|
+
type MessageIds = 'usePropsParameterName' | 'usePropsParameterNameWithPrefix';
|
|
2
|
+
export declare const enforcePropsArgumentName: import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleModule<MessageIds, [], import("@typescript-eslint/utils/dist/ts-eslint/Rule").RuleListener>;
|
|
8
3
|
export {};
|