@blumintinc/eslint-plugin-blumint 1.12.6 → 1.14.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 +171 -99
- package/lib/index.js +300 -17
- package/lib/rules/array-methods-this-context.js +20 -2
- package/lib/rules/avoid-utils-directory.js +11 -2
- package/lib/rules/class-methods-read-top-to-bottom.js +24 -5
- package/lib/rules/consistent-callback-naming.js +1 -1
- package/lib/rules/dynamic-https-errors.d.ts +3 -1
- package/lib/rules/dynamic-https-errors.js +48 -11
- 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} +52 -96
- 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 +820 -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 +5 -2
- package/lib/rules/enforce-console-error.d.ts +3 -0
- package/lib/rules/enforce-console-error.js +278 -0
- package/lib/rules/enforce-css-media-queries.js +24 -46
- package/lib/rules/enforce-dynamic-file-naming.d.ts +2 -0
- package/lib/rules/enforce-dynamic-file-naming.js +53 -28
- package/lib/rules/enforce-dynamic-firebase-imports.js +100 -19
- package/lib/rules/enforce-dynamic-imports.js +1 -1
- package/lib/rules/enforce-early-destructuring.d.ts +2 -0
- package/lib/rules/enforce-early-destructuring.js +980 -0
- package/lib/rules/enforce-empty-object-check.d.ts +11 -0
- package/lib/rules/enforce-empty-object-check.js +502 -0
- package/lib/rules/enforce-exported-function-types.js +4 -4
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.d.ts +2 -0
- package/lib/rules/enforce-fieldpath-syntax-in-docsetter.js +262 -0
- package/lib/rules/enforce-firestore-doc-ref-generic.js +350 -3
- package/lib/rules/enforce-firestore-facade.js +349 -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-firestore-set-merge.js +3 -4
- package/lib/rules/enforce-global-constants.d.ts +4 -1
- package/lib/rules/enforce-global-constants.js +240 -12
- package/lib/rules/enforce-identifiable-firestore-type.js +108 -58
- package/lib/rules/enforce-memoize-async.d.ts +2 -1
- package/lib/rules/enforce-memoize-async.js +92 -27
- package/lib/rules/enforce-memoize-getters.d.ts +3 -0
- package/lib/rules/enforce-memoize-getters.js +147 -0
- package/lib/rules/enforce-microdiff.js +3 -2
- package/lib/rules/enforce-object-literal-as-const.js +4 -4
- package/lib/rules/enforce-positive-naming.js +9 -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-safe-stringify.js +1 -1
- package/lib/rules/enforce-serializable-params.js +3 -3
- package/lib/rules/enforce-singular-type-names.js +10 -6
- package/lib/rules/enforce-stable-hash-spread-props.d.ts +13 -0
- package/lib/rules/enforce-stable-hash-spread-props.js +342 -0
- package/lib/rules/enforce-storage-context.d.ts +9 -0
- package/lib/rules/enforce-storage-context.js +646 -0
- package/lib/rules/enforce-timestamp-now.js +23 -7
- package/lib/rules/enforce-transform-memoization.d.ts +4 -0
- package/lib/rules/enforce-transform-memoization.js +416 -0
- package/lib/rules/enforce-typescript-markdown-code-blocks.d.ts +1 -0
- package/lib/rules/enforce-typescript-markdown-code-blocks.js +100 -0
- package/lib/rules/enforce-unique-cursor-headers.d.ts +16 -0
- package/lib/rules/enforce-unique-cursor-headers.js +365 -0
- package/lib/rules/enforce-verb-noun-naming.js +90 -14
- package/lib/rules/ensure-pointer-events-none.js +28 -2
- package/lib/rules/export-if-in-doubt.js +27 -4
- package/lib/rules/extract-global-constants.js +92 -53
- package/lib/rules/fast-deep-equal-over-microdiff.d.ts +2 -1
- package/lib/rules/fast-deep-equal-over-microdiff.js +351 -83
- package/lib/rules/firestore-transaction-reads-before-writes.d.ts +1 -0
- package/lib/rules/firestore-transaction-reads-before-writes.js +277 -0
- package/lib/rules/flatten-push-calls.d.ts +2 -0
- package/lib/rules/flatten-push-calls.js +428 -0
- package/lib/rules/generic-starts-with-t.js +8 -2
- package/lib/rules/global-const-style.js +50 -19
- package/lib/rules/jsdoc-above-field.d.ts +11 -0
- package/lib/rules/jsdoc-above-field.js +208 -0
- package/lib/rules/key-only-outermost-element.js +21 -3
- package/lib/rules/logical-top-to-bottom-grouping.d.ts +5 -0
- package/lib/rules/logical-top-to-bottom-grouping.js +1258 -0
- package/lib/rules/memo-compare-deeply-complex-props.d.ts +3 -0
- package/lib/rules/memo-compare-deeply-complex-props.js +788 -0
- package/lib/rules/memo-nested-react-components.d.ts +8 -0
- package/lib/rules/memo-nested-react-components.js +410 -0
- 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-always-true-false-conditions.d.ts +2 -1
- package/lib/rules/no-always-true-false-conditions.js +68 -8
- package/lib/rules/no-array-length-in-deps.d.ts +12 -0
- package/lib/rules/no-array-length-in-deps.js +314 -0
- package/lib/rules/no-async-array-filter.js +5 -2
- package/lib/rules/no-async-foreach.js +210 -12
- package/lib/rules/no-circular-references.js +18 -17
- package/lib/rules/no-class-instance-destructuring.js +55 -12
- package/lib/rules/no-complex-cloud-params.js +22 -5
- package/lib/rules/no-compositing-layer-props.js +6 -4
- package/lib/rules/no-conditional-literals-in-jsx.js +37 -12
- package/lib/rules/no-console-error.d.ts +9 -0
- package/lib/rules/no-console-error.js +525 -0
- package/lib/rules/no-curly-brackets-around-commented-properties.d.ts +2 -0
- package/lib/rules/no-curly-brackets-around-commented-properties.js +258 -0
- package/lib/rules/no-empty-dependency-use-callbacks.d.ts +11 -0
- package/lib/rules/no-empty-dependency-use-callbacks.js +576 -0
- package/lib/rules/no-entire-object-hook-deps.d.ts +3 -1
- package/lib/rules/no-entire-object-hook-deps.js +320 -68
- 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-explicit-return-type.d.ts +2 -1
- package/lib/rules/no-explicit-return-type.js +215 -26
- package/lib/rules/no-filter-without-return.js +5 -1
- package/lib/rules/no-firestore-jest-mock.d.ts +2 -1
- package/lib/rules/no-firestore-jest-mock.js +126 -8
- package/lib/rules/no-firestore-object-arrays.js +398 -28
- package/lib/rules/no-handler-suffix.d.ts +12 -0
- package/lib/rules/no-handler-suffix.js +305 -0
- package/lib/rules/no-hungarian.js +14 -14
- package/lib/rules/no-inline-component-prop.d.ts +10 -0
- package/lib/rules/no-inline-component-prop.js +456 -0
- package/lib/rules/no-jsx-in-hooks.js +6 -1
- package/lib/rules/no-jsx-whitespace-literal.js +8 -2
- package/lib/rules/no-margin-properties.d.ts +7 -1
- package/lib/rules/no-margin-properties.js +22 -9
- package/lib/rules/no-memoize-on-static.js +9 -1
- package/lib/rules/no-misleading-boolean-prefixes.d.ts +7 -0
- package/lib/rules/no-misleading-boolean-prefixes.js +331 -0
- package/lib/rules/no-misused-switch-case.js +22 -1
- package/lib/rules/no-mixed-firestore-transactions.d.ts +3 -1
- package/lib/rules/no-mixed-firestore-transactions.js +296 -34
- package/lib/rules/no-mock-firebase-admin.js +5 -2
- package/lib/rules/no-object-values-on-strings.js +10 -2
- package/lib/rules/no-overridable-method-calls-in-constructor.d.ts +1 -0
- package/lib/rules/no-overridable-method-calls-in-constructor.js +272 -0
- package/lib/rules/no-passthrough-getters.d.ts +4 -0
- package/lib/rules/no-passthrough-getters.js +206 -0
- package/lib/rules/no-redundant-annotation-assertion.d.ts +2 -0
- package/lib/rules/no-redundant-annotation-assertion.js +402 -0
- package/lib/rules/no-redundant-param-types.js +16 -6
- package/lib/rules/no-redundant-this-params.d.ts +3 -0
- package/lib/rules/no-redundant-this-params.js +459 -0
- package/lib/rules/no-redundant-usecallback-wrapper.d.ts +8 -0
- package/lib/rules/no-redundant-usecallback-wrapper.js +328 -0
- package/lib/rules/no-res-error-status-in-onrequest.d.ts +4 -0
- package/lib/rules/no-res-error-status-in-onrequest.js +521 -0
- package/lib/rules/no-restricted-properties-fix.d.ts +12 -0
- package/lib/rules/no-restricted-properties-fix.js +173 -0
- package/lib/rules/no-separate-loading-state.d.ts +8 -0
- package/lib/rules/no-separate-loading-state.js +133 -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 +49 -49
- package/lib/rules/no-undefined-null-passthrough.js +217 -40
- package/lib/rules/no-unmemoized-memo-without-props.d.ts +8 -0
- package/lib/rules/no-unmemoized-memo-without-props.js +426 -0
- package/lib/rules/no-unnecessary-destructuring-rename.d.ts +2 -0
- package/lib/rules/no-unnecessary-destructuring-rename.js +347 -0
- package/lib/rules/no-unnecessary-destructuring.js +14 -4
- package/lib/rules/no-unnecessary-verb-suffix.js +2 -3
- package/lib/rules/no-unpinned-dependencies.js +36 -5
- package/lib/rules/no-unsafe-firestore-spread.js +8 -5
- package/lib/rules/no-unused-props.d.ts +5 -2
- package/lib/rules/no-unused-props.js +451 -112
- package/lib/rules/no-unused-usestate.js +6 -2
- package/lib/rules/no-useless-fragment.js +28 -2
- package/lib/rules/no-useless-usememo-primitives.d.ts +9 -0
- package/lib/rules/no-useless-usememo-primitives.js +393 -0
- package/lib/rules/no-usememo-for-pass-by-value.d.ts +13 -0
- package/lib/rules/no-usememo-for-pass-by-value.js +757 -0
- package/lib/rules/no-uuidv4-base62-as-key.js +18 -13
- package/lib/rules/omit-index-html.d.ts +2 -1
- package/lib/rules/omit-index-html.js +62 -7
- package/lib/rules/optimize-object-boolean-conditions.d.ts +1 -0
- package/lib/rules/optimize-object-boolean-conditions.js +236 -0
- package/lib/rules/parallelize-async-operations.d.ts +8 -0
- package/lib/rules/parallelize-async-operations.js +394 -0
- package/lib/rules/prefer-batch-operations.d.ts +1 -3
- package/lib/rules/prefer-batch-operations.js +228 -35
- package/lib/rules/prefer-block-comments-for-declarations.js +22 -7
- package/lib/rules/prefer-clone-deep.js +3 -3
- package/lib/rules/prefer-destructuring-no-class.d.ts +2 -1
- package/lib/rules/prefer-destructuring-no-class.js +244 -59
- package/lib/rules/prefer-docsetter-setall.d.ts +2 -0
- package/lib/rules/prefer-docsetter-setall.js +243 -0
- 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 +251 -0
- package/lib/rules/prefer-fragment-component.js +4 -4
- package/lib/rules/prefer-fragment-shorthand.js +2 -1
- package/lib/rules/prefer-getter-over-parameterless-method.d.ts +13 -0
- package/lib/rules/prefer-getter-over-parameterless-method.js +648 -0
- package/lib/rules/prefer-global-router-state-key.d.ts +7 -3
- package/lib/rules/prefer-global-router-state-key.js +305 -31
- package/lib/rules/prefer-memoized-props.d.ts +3 -0
- package/lib/rules/prefer-memoized-props.js +445 -0
- package/lib/rules/prefer-next-dynamic.d.ts +9 -0
- package/lib/rules/prefer-next-dynamic.js +357 -0
- package/lib/rules/prefer-nullish-coalescing-boolean-props.d.ts +1 -0
- package/lib/rules/prefer-nullish-coalescing-boolean-props.js +435 -0
- package/lib/rules/prefer-nullish-coalescing-override.d.ts +7 -0
- package/lib/rules/prefer-nullish-coalescing-override.js +188 -0
- package/lib/rules/prefer-params-over-parent-id.d.ts +5 -0
- package/lib/rules/prefer-params-over-parent-id.js +277 -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-type-over-interface.js +7 -2
- package/lib/rules/prefer-url-tostring-over-tojson.d.ts +2 -0
- package/lib/rules/prefer-url-tostring-over-tojson.js +169 -0
- package/lib/rules/prefer-use-deep-compare-memo.d.ts +4 -0
- package/lib/rules/prefer-use-deep-compare-memo.js +431 -0
- package/lib/rules/prefer-usecallback-over-usememo-for-functions.js +25 -2
- package/lib/rules/prefer-usememo-over-useeffect-usestate.js +24 -5
- package/lib/rules/prefer-utility-function-over-private-static.js +34 -2
- package/lib/rules/prevent-children-clobber.d.ts +2 -0
- package/lib/rules/prevent-children-clobber.js +536 -0
- package/lib/rules/react-memoize-literals.d.ts +4 -0
- package/lib/rules/react-memoize-literals.js +495 -0
- 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-hooks-default-params.js +17 -16
- package/lib/rules/require-https-error-cause.d.ts +4 -0
- package/lib/rules/require-https-error-cause.js +136 -0
- package/lib/rules/require-https-error.js +43 -21
- package/lib/rules/require-image-optimized.js +2 -2
- package/lib/rules/require-memo.js +12 -2
- package/lib/rules/require-memoize-jsx-returners.d.ts +3 -0
- package/lib/rules/require-memoize-jsx-returners.js +485 -0
- package/lib/rules/require-usememo-object-literals.js +9 -4
- 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 +271 -0
- package/lib/rules/vertically-group-related-functions.d.ts +16 -0
- package/lib/rules/vertically-group-related-functions.js +480 -0
- package/lib/utils/ASTHelpers.d.ts +13 -1
- package/lib/utils/ASTHelpers.js +34 -0
- package/lib/utils/createRule.js +1 -1
- package/lib/utils/getMethodName.d.ts +27 -0
- package/lib/utils/getMethodName.js +35 -0
- package/lib/utils/graph/ClassGraphSorterReadability.js +1 -1
- package/lib/utils/ruleTester.d.ts +1 -0
- package/lib/utils/ruleTester.js +4 -1
- package/lib/utils/tsTypeClassifier.d.ts +30 -0
- package/lib/utils/tsTypeClassifier.js +149 -0
- package/package.json +23 -14
- package/lib/rules/enforce-assertSafe-object-key.d.ts +0 -2
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.enforceFirestoreSetMerge = 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.enforceFirestoreSetMerge = (0, createRule_1.createRule)({
|
|
7
8
|
name: 'enforce-firestore-set-merge',
|
|
8
9
|
meta: {
|
|
@@ -93,9 +94,7 @@ exports.enforceFirestoreSetMerge = (0, createRule_1.createRule)({
|
|
|
93
94
|
return true;
|
|
94
95
|
}
|
|
95
96
|
// Check if it's a Firestore document reference by looking at imports
|
|
96
|
-
const program = context
|
|
97
|
-
.getAncestors()
|
|
98
|
-
.find((node) => node.type === utils_1.AST_NODE_TYPES.Program);
|
|
97
|
+
const program = ASTHelpers_1.ASTHelpers.getAncestors(context, node).find((node) => node.type === utils_1.AST_NODE_TYPES.Program);
|
|
99
98
|
if (program) {
|
|
100
99
|
for (const node of program.body) {
|
|
101
100
|
if (node.type === utils_1.AST_NODE_TYPES.VariableDeclaration) {
|
|
@@ -212,7 +211,7 @@ exports.enforceFirestoreSetMerge = (0, createRule_1.createRule)({
|
|
|
212
211
|
node,
|
|
213
212
|
messageId: 'preferSetMerge',
|
|
214
213
|
fix(fixer) {
|
|
215
|
-
const newText = convertUpdateToSetMerge(node, context.
|
|
214
|
+
const newText = convertUpdateToSetMerge(node, context.sourceCode);
|
|
216
215
|
return fixer.replaceText(node, newText);
|
|
217
216
|
},
|
|
218
217
|
});
|
|
@@ -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.sourceCode;
|
|
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
|
});
|
|
@@ -5,8 +5,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.enforceIdentifiableFirestoreType = void 0;
|
|
7
7
|
const utils_1 = require("@typescript-eslint/utils");
|
|
8
|
-
const createRule_1 = require("../utils/createRule");
|
|
9
8
|
const path_1 = __importDefault(require("path"));
|
|
9
|
+
const createRule_1 = require("../utils/createRule");
|
|
10
|
+
const TRANSPARENT_TYPE_NAMES = new Set(['Readonly', 'Resolve']);
|
|
10
11
|
exports.enforceIdentifiableFirestoreType = (0, createRule_1.createRule)({
|
|
11
12
|
name: 'enforce-identifiable-firestore-type',
|
|
12
13
|
meta: {
|
|
@@ -63,94 +64,143 @@ exports.enforceIdentifiableFirestoreType = (0, createRule_1.createRule)({
|
|
|
63
64
|
TSTypeAliasDeclaration(node) {
|
|
64
65
|
if (node.id.name === folderName) {
|
|
65
66
|
hasExpectedType = true;
|
|
66
|
-
|
|
67
|
+
const findTypeAliasAnnotation = (typeName) => {
|
|
68
|
+
let scope = context.getScope();
|
|
69
|
+
while (scope) {
|
|
70
|
+
const variable = scope.variables.find((variableNode) => variableNode.name === typeName);
|
|
71
|
+
if (variable) {
|
|
72
|
+
const definition = variable.defs.find((definition) => definition.node.type ===
|
|
73
|
+
utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration);
|
|
74
|
+
if (definition &&
|
|
75
|
+
definition.node.type ===
|
|
76
|
+
utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration &&
|
|
77
|
+
definition.node.typeAnnotation) {
|
|
78
|
+
return definition.node.typeAnnotation;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
scope = scope.upper;
|
|
82
|
+
}
|
|
83
|
+
return null;
|
|
84
|
+
};
|
|
85
|
+
const isParenthesizedType = (node) => node?.type === 'TSParenthesizedType';
|
|
86
|
+
const isReadonlyTypeOperator = (node) => node?.type === utils_1.AST_NODE_TYPES.TSTypeOperator &&
|
|
87
|
+
node.operator === 'readonly';
|
|
88
|
+
const unwrapTransparentType = (typeNode) => {
|
|
89
|
+
let current = typeNode;
|
|
90
|
+
while (current) {
|
|
91
|
+
if (isParenthesizedType(current)) {
|
|
92
|
+
const parenthesized = current;
|
|
93
|
+
current = parenthesized.typeAnnotation ?? null;
|
|
94
|
+
continue;
|
|
95
|
+
}
|
|
96
|
+
if (isReadonlyTypeOperator(current)) {
|
|
97
|
+
current = current.typeAnnotation ?? null;
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
return current ?? null;
|
|
103
|
+
};
|
|
67
104
|
const findIdentifiable = (type, checkedTypes = new Set()) => {
|
|
68
|
-
|
|
105
|
+
const resolvedType = unwrapTransparentType(type);
|
|
106
|
+
if (!resolvedType) {
|
|
69
107
|
return false;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
108
|
+
}
|
|
109
|
+
if (resolvedType.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
|
110
|
+
resolvedType.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
111
|
+
const typeName = resolvedType.typeName.name;
|
|
73
112
|
if (typeName === 'Identifiable') {
|
|
74
113
|
return true;
|
|
75
114
|
}
|
|
76
|
-
if (
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
const def = variable.defs.find((d) => d.node.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration);
|
|
83
|
-
if (def &&
|
|
84
|
-
'typeAnnotation' in def.node &&
|
|
85
|
-
def.node.typeAnnotation) {
|
|
86
|
-
return findIdentifiable(def.node.typeAnnotation, checkedTypes);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
// Try looking in the parent scope
|
|
90
|
-
if (scope.upper) {
|
|
91
|
-
const parentVariable = scope.upper.variables.find((v) => v.name === typeName);
|
|
92
|
-
if (parentVariable) {
|
|
93
|
-
const def = parentVariable.defs.find((d) => d.node.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration);
|
|
94
|
-
if (def &&
|
|
95
|
-
'typeAnnotation' in def.node &&
|
|
96
|
-
def.node.typeAnnotation) {
|
|
97
|
-
return findIdentifiable(def.node.typeAnnotation, checkedTypes);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
115
|
+
if (TRANSPARENT_TYPE_NAMES.has(typeName) &&
|
|
116
|
+
resolvedType.typeParameters?.params?.some((param) => findIdentifiable(param, checkedTypes))) {
|
|
117
|
+
return true;
|
|
118
|
+
}
|
|
119
|
+
if (checkedTypes.has(typeName)) {
|
|
120
|
+
return false;
|
|
101
121
|
}
|
|
122
|
+
checkedTypes.add(typeName);
|
|
123
|
+
const aliasAnnotation = findTypeAliasAnnotation(typeName);
|
|
124
|
+
return findIdentifiable(aliasAnnotation, checkedTypes);
|
|
102
125
|
}
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
return type.types.some((part) => findIdentifiable(part, checkedTypes));
|
|
126
|
+
if (resolvedType.type === utils_1.AST_NODE_TYPES.TSIntersectionType) {
|
|
127
|
+
return resolvedType.types.some((part) => findIdentifiable(part, new Set(checkedTypes)));
|
|
106
128
|
}
|
|
107
129
|
return false;
|
|
108
130
|
};
|
|
109
|
-
// Check if type extends Identifiable
|
|
110
|
-
const checkIdentifiableExtension = (type) => {
|
|
111
|
-
if (!type)
|
|
112
|
-
return false;
|
|
113
|
-
return findIdentifiable(type);
|
|
114
|
-
};
|
|
115
131
|
// Check if type has id: string field
|
|
116
|
-
const checkIdField = (type) => {
|
|
117
|
-
|
|
118
|
-
if (
|
|
119
|
-
return
|
|
132
|
+
const checkIdField = (type, visitedTypes = new Set()) => {
|
|
133
|
+
const resolvedType = unwrapTransparentType(type);
|
|
134
|
+
if (!resolvedType) {
|
|
135
|
+
return false;
|
|
136
|
+
}
|
|
137
|
+
if (resolvedType.type === utils_1.AST_NODE_TYPES.TSTypeLiteral) {
|
|
138
|
+
return resolvedType.members.some((member) => member.type === utils_1.AST_NODE_TYPES.TSPropertySignature &&
|
|
120
139
|
member.key.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
121
140
|
member.key.name === 'id' &&
|
|
122
141
|
member.typeAnnotation?.typeAnnotation.type ===
|
|
123
142
|
utils_1.AST_NODE_TYPES.TSStringKeyword);
|
|
124
143
|
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
144
|
+
if (resolvedType.type === utils_1.AST_NODE_TYPES.TSIntersectionType) {
|
|
145
|
+
return resolvedType.types.some((part) => checkIdField(part, new Set(visitedTypes)));
|
|
146
|
+
}
|
|
147
|
+
if (resolvedType.type === utils_1.AST_NODE_TYPES.TSTypeReference) {
|
|
148
|
+
if (resolvedType.typeName.type !== utils_1.AST_NODE_TYPES.Identifier) {
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
const typeName = resolvedType.typeName.name;
|
|
152
|
+
if (typeName === 'Identifiable') {
|
|
153
|
+
return true;
|
|
154
|
+
}
|
|
155
|
+
if (TRANSPARENT_TYPE_NAMES.has(typeName) &&
|
|
156
|
+
resolvedType.typeParameters?.params?.some((param) => checkIdField(param, visitedTypes))) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
if (visitedTypes.has(typeName)) {
|
|
160
|
+
return false;
|
|
161
|
+
}
|
|
162
|
+
visitedTypes.add(typeName);
|
|
163
|
+
const referencedType = findTypeAliasAnnotation(typeName);
|
|
164
|
+
return checkIdField(referencedType, visitedTypes);
|
|
128
165
|
}
|
|
129
166
|
return false;
|
|
130
167
|
};
|
|
131
168
|
// Check if type is wrapped in a utility type
|
|
132
169
|
const isUtilityType = (type) => {
|
|
170
|
+
if (!type) {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
133
173
|
return (type.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
|
134
174
|
type.typeName.type === utils_1.AST_NODE_TYPES.Identifier &&
|
|
135
175
|
type.typeName.name === 'Resolve');
|
|
136
176
|
};
|
|
137
177
|
// Recursively check the type and its parameters
|
|
138
|
-
const checkType = (type) => {
|
|
139
|
-
|
|
140
|
-
if (
|
|
178
|
+
const checkType = (type, visitedTypes = new Set()) => {
|
|
179
|
+
const resolvedType = unwrapTransparentType(type);
|
|
180
|
+
if (!resolvedType) {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
if (findIdentifiable(resolvedType)) {
|
|
141
184
|
return true;
|
|
142
185
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
checkIdField(
|
|
186
|
+
if (isUtilityType(resolvedType) &&
|
|
187
|
+
resolvedType.typeParameters?.params?.[0] &&
|
|
188
|
+
checkIdField(resolvedType.typeParameters.params[0])) {
|
|
146
189
|
return true;
|
|
147
190
|
}
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
191
|
+
if (resolvedType.type === utils_1.AST_NODE_TYPES.TSTypeReference &&
|
|
192
|
+
resolvedType.typeName.type === utils_1.AST_NODE_TYPES.Identifier) {
|
|
193
|
+
const typeName = resolvedType.typeName.name;
|
|
194
|
+
if (visitedTypes.has(typeName)) {
|
|
195
|
+
return false;
|
|
196
|
+
}
|
|
197
|
+
visitedTypes.add(typeName);
|
|
198
|
+
const aliasAnnotation = findTypeAliasAnnotation(typeName);
|
|
199
|
+
return checkType(aliasAnnotation, visitedTypes);
|
|
200
|
+
}
|
|
201
|
+
if (resolvedType.type === utils_1.AST_NODE_TYPES.TSIntersectionType) {
|
|
202
|
+
return resolvedType.types.some((part) => checkType(part, new Set(visitedTypes)));
|
|
152
203
|
}
|
|
153
|
-
// For direct type definitions, require extending Identifiable
|
|
154
204
|
return false;
|
|
155
205
|
};
|
|
156
206
|
typeHasIdentifiable = checkType(node.typeAnnotation);
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { TSESLint } from '@typescript-eslint/utils';
|
|
2
|
+
export declare const enforceMemoizeAsync: TSESLint.RuleModule<"requireMemoize", [], TSESLint.RuleListener>;
|