@tanstack/eslint-plugin-query 5.94.5 → 5.95.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/build/legacy/_tsup-dts-rollup.d.cts +57 -3
- package/build/legacy/_tsup-dts-rollup.d.ts +57 -3
- package/build/legacy/{chunk-HD2KSEKJ.js → chunk-T44AUBX4.js} +289 -90
- package/build/legacy/chunk-T44AUBX4.js.map +1 -0
- package/build/legacy/index.cjs +288 -89
- package/build/legacy/index.cjs.map +1 -1
- package/build/legacy/index.js +1 -1
- package/build/legacy/rules.cjs +288 -89
- package/build/legacy/rules.cjs.map +1 -1
- package/build/legacy/rules.js +1 -1
- package/build/modern/_tsup-dts-rollup.d.cts +57 -3
- package/build/modern/_tsup-dts-rollup.d.ts +57 -3
- package/build/modern/{chunk-XO2SGL7P.js → chunk-XH4ABCYA.js} +288 -90
- package/build/modern/chunk-XH4ABCYA.js.map +1 -0
- package/build/modern/index.cjs +287 -89
- package/build/modern/index.cjs.map +1 -1
- package/build/modern/index.js +1 -1
- package/build/modern/rules.cjs +287 -89
- package/build/modern/rules.cjs.map +1 -1
- package/build/modern/rules.js +1 -1
- package/package.json +1 -1
- package/src/rules/exhaustive-deps/exhaustive-deps.rule.ts +136 -90
- package/src/rules/exhaustive-deps/exhaustive-deps.utils.ts +248 -22
- package/src/utils/ast-utils.ts +2 -25
- package/build/legacy/chunk-HD2KSEKJ.js.map +0 -1
- package/build/modern/chunk-XO2SGL7P.js.map +0 -1
package/build/legacy/rules.cjs
CHANGED
|
@@ -130,21 +130,6 @@ var ASTUtils = {
|
|
|
130
130
|
}
|
|
131
131
|
return identifiers;
|
|
132
132
|
},
|
|
133
|
-
isAncestorIsCallee(identifier) {
|
|
134
|
-
let previousNode = identifier;
|
|
135
|
-
let currentNode = identifier.parent;
|
|
136
|
-
while (currentNode !== void 0) {
|
|
137
|
-
if (currentNode.type === import_utils.AST_NODE_TYPES.CallExpression && currentNode.callee === previousNode) {
|
|
138
|
-
return true;
|
|
139
|
-
}
|
|
140
|
-
if (currentNode.type !== import_utils.AST_NODE_TYPES.MemberExpression) {
|
|
141
|
-
return false;
|
|
142
|
-
}
|
|
143
|
-
previousNode = currentNode;
|
|
144
|
-
currentNode = currentNode.parent;
|
|
145
|
-
}
|
|
146
|
-
return false;
|
|
147
|
-
},
|
|
148
133
|
traverseUpOnly(identifier, allowedNodeTypes) {
|
|
149
134
|
const parent = identifier.parent;
|
|
150
135
|
if (parent !== void 0 && allowedNodeTypes.includes(parent.type)) {
|
|
@@ -369,7 +354,7 @@ var ExhaustiveDepsUtils = {
|
|
|
369
354
|
const { sourceCode, reference, scopeManager, node, filename } = params;
|
|
370
355
|
const component = ASTUtils.getFunctionAncestor(sourceCode, node);
|
|
371
356
|
const queryFnScope = scopeManager.acquire(node);
|
|
372
|
-
if (queryFnScope === null) {
|
|
357
|
+
if (queryFnScope === null || reference.isValueReference === false) {
|
|
373
358
|
return false;
|
|
374
359
|
}
|
|
375
360
|
let currentScope = ((_a = reference.resolved) == null ? void 0 : _a.scope) ?? null;
|
|
@@ -401,15 +386,57 @@ var ExhaustiveDepsUtils = {
|
|
|
401
386
|
}
|
|
402
387
|
return reference.identifier.name !== "undefined" && reference.identifier.parent.type !== import_utils3.AST_NODE_TYPES.NewExpression && !ExhaustiveDepsUtils.isInstanceOfKind(reference.identifier.parent);
|
|
403
388
|
},
|
|
404
|
-
|
|
405
|
-
|
|
389
|
+
/**
|
|
390
|
+
* Given required refs and existing queryKey entries, compute missing dependency paths
|
|
391
|
+
* respecting allowlisted variables and types.
|
|
392
|
+
*/
|
|
393
|
+
computeFilteredMissingPaths(params) {
|
|
394
|
+
const {
|
|
395
|
+
requiredRefs,
|
|
396
|
+
allowlistedVariables,
|
|
397
|
+
existingRootIdentifiers,
|
|
398
|
+
existingFullPaths
|
|
399
|
+
} = params;
|
|
400
|
+
const missingPaths = /* @__PURE__ */ new Set();
|
|
401
|
+
for (const { root, path, allowlistedByType } of requiredRefs) {
|
|
402
|
+
if (existingRootIdentifiers.has(root)) continue;
|
|
403
|
+
if (allowlistedVariables.has(root)) continue;
|
|
404
|
+
if (existingFullPaths.has(path)) continue;
|
|
405
|
+
if (allowlistedByType) continue;
|
|
406
|
+
missingPaths.add(path);
|
|
407
|
+
}
|
|
408
|
+
for (const path of missingPaths) {
|
|
409
|
+
const root = path.split(".")[0];
|
|
410
|
+
if (root !== path && root !== void 0 && missingPaths.has(root)) {
|
|
411
|
+
missingPaths.delete(path);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return Array.from(missingPaths);
|
|
406
415
|
},
|
|
416
|
+
/**
|
|
417
|
+
* Extract existing queryKey deps as root identifiers and full member paths.
|
|
418
|
+
*/
|
|
407
419
|
collectQueryKeyDeps(params) {
|
|
408
420
|
const { sourceCode, scopeManager, queryKeyNode } = params;
|
|
409
|
-
const
|
|
421
|
+
const roots = /* @__PURE__ */ new Set();
|
|
422
|
+
const paths = /* @__PURE__ */ new Set();
|
|
410
423
|
const visitorKeys = sourceCode.visitorKeys;
|
|
411
|
-
function
|
|
412
|
-
|
|
424
|
+
function addRoot(name8) {
|
|
425
|
+
const cleaned = ExhaustiveDepsUtils.normalizeChain(name8);
|
|
426
|
+
roots.add(cleaned);
|
|
427
|
+
paths.add(cleaned);
|
|
428
|
+
}
|
|
429
|
+
function addFull(text) {
|
|
430
|
+
const cleaned = ExhaustiveDepsUtils.normalizeChain(text);
|
|
431
|
+
paths.add(cleaned);
|
|
432
|
+
}
|
|
433
|
+
function addRefPath(refPath) {
|
|
434
|
+
if (!refPath) return;
|
|
435
|
+
if (refPath.coversRootMembers) {
|
|
436
|
+
addRoot(refPath.root);
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
addFull(refPath.path);
|
|
413
440
|
}
|
|
414
441
|
function visitChildren(node) {
|
|
415
442
|
const keys = visitorKeys[node.type] ?? [];
|
|
@@ -431,9 +458,15 @@ var ExhaustiveDepsUtils = {
|
|
|
431
458
|
function visit(node) {
|
|
432
459
|
if (!node) return;
|
|
433
460
|
switch (node.type) {
|
|
434
|
-
case import_utils3.AST_NODE_TYPES.Identifier:
|
|
435
|
-
|
|
461
|
+
case import_utils3.AST_NODE_TYPES.Identifier: {
|
|
462
|
+
addRefPath(
|
|
463
|
+
ExhaustiveDepsUtils.computeRefPath({
|
|
464
|
+
identifier: node,
|
|
465
|
+
sourceCode
|
|
466
|
+
})
|
|
467
|
+
);
|
|
436
468
|
return;
|
|
469
|
+
}
|
|
437
470
|
case import_utils3.AST_NODE_TYPES.ArrowFunctionExpression:
|
|
438
471
|
case import_utils3.AST_NODE_TYPES.FunctionExpression:
|
|
439
472
|
for (const reference of ExhaustiveDepsUtils.collectExternalRefsInFunction(
|
|
@@ -442,9 +475,15 @@ var ExhaustiveDepsUtils = {
|
|
|
442
475
|
scopeManager
|
|
443
476
|
}
|
|
444
477
|
)) {
|
|
445
|
-
if (reference.identifier.type
|
|
446
|
-
|
|
478
|
+
if (reference.identifier.type !== import_utils3.AST_NODE_TYPES.Identifier) {
|
|
479
|
+
continue;
|
|
447
480
|
}
|
|
481
|
+
addRefPath(
|
|
482
|
+
ExhaustiveDepsUtils.computeRefPath({
|
|
483
|
+
identifier: reference.identifier,
|
|
484
|
+
sourceCode
|
|
485
|
+
})
|
|
486
|
+
);
|
|
448
487
|
}
|
|
449
488
|
return;
|
|
450
489
|
case import_utils3.AST_NODE_TYPES.Property:
|
|
@@ -452,26 +491,96 @@ var ExhaustiveDepsUtils = {
|
|
|
452
491
|
return;
|
|
453
492
|
case import_utils3.AST_NODE_TYPES.MemberExpression:
|
|
454
493
|
if (node.parent.type === import_utils3.AST_NODE_TYPES.CallExpression && node.parent.callee === node && node.object.type === import_utils3.AST_NODE_TYPES.Identifier) {
|
|
455
|
-
|
|
494
|
+
addRoot(node.object.name);
|
|
456
495
|
} else {
|
|
457
496
|
visit(node.object);
|
|
458
497
|
}
|
|
459
498
|
return;
|
|
460
499
|
case import_utils3.AST_NODE_TYPES.CallExpression:
|
|
461
500
|
node.arguments.forEach((argument) => visit(argument));
|
|
462
|
-
|
|
463
|
-
|
|
501
|
+
switch (node.callee.type) {
|
|
502
|
+
case import_utils3.AST_NODE_TYPES.Identifier:
|
|
503
|
+
case import_utils3.AST_NODE_TYPES.MemberExpression:
|
|
504
|
+
case import_utils3.AST_NODE_TYPES.ChainExpression:
|
|
505
|
+
case import_utils3.AST_NODE_TYPES.TSNonNullExpression:
|
|
506
|
+
visit(node.callee);
|
|
507
|
+
break;
|
|
464
508
|
}
|
|
465
509
|
return;
|
|
466
510
|
}
|
|
467
511
|
visitChildren(node);
|
|
468
512
|
}
|
|
469
513
|
visit(queryKeyNode);
|
|
470
|
-
return
|
|
514
|
+
return { roots, paths };
|
|
471
515
|
},
|
|
472
516
|
isNode(value) {
|
|
473
517
|
return typeof value === "object" && value !== null && "type" in value && typeof value.type === "string";
|
|
474
518
|
},
|
|
519
|
+
/**
|
|
520
|
+
* Checks whether the resolved variable is allowlisted by its type annotation
|
|
521
|
+
*/
|
|
522
|
+
variableIsAllowlistedByType(params) {
|
|
523
|
+
const { allowlistedTypes, variable } = params;
|
|
524
|
+
if (allowlistedTypes.size === 0) return false;
|
|
525
|
+
if (!variable) return false;
|
|
526
|
+
for (const id of variable.identifiers) {
|
|
527
|
+
if (id.typeAnnotation) {
|
|
528
|
+
const typeIdentifiers = /* @__PURE__ */ new Set();
|
|
529
|
+
ExhaustiveDepsUtils.collectTypeIdentifiers(
|
|
530
|
+
id.typeAnnotation.typeAnnotation,
|
|
531
|
+
typeIdentifiers
|
|
532
|
+
);
|
|
533
|
+
for (const typeIdentifier of typeIdentifiers) {
|
|
534
|
+
if (allowlistedTypes.has(typeIdentifier)) return true;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
}
|
|
538
|
+
return false;
|
|
539
|
+
},
|
|
540
|
+
isInstanceOfKind(node) {
|
|
541
|
+
return node.type === import_utils3.AST_NODE_TYPES.BinaryExpression && node.operator === "instanceof";
|
|
542
|
+
},
|
|
543
|
+
/**
|
|
544
|
+
* Normalizes a chain by removing optional chaining operators
|
|
545
|
+
*
|
|
546
|
+
* Example: `a?.b.c!` -> `a.b.c`
|
|
547
|
+
*/
|
|
548
|
+
normalizeChain(text) {
|
|
549
|
+
return text.replace(/(?:\?(\.)|!)/g, "$1");
|
|
550
|
+
},
|
|
551
|
+
/**
|
|
552
|
+
* Computes the reference path for an identifier
|
|
553
|
+
*
|
|
554
|
+
* Example: `a.b.c!` -> `{ path: 'a.b.c', root: 'a' }`
|
|
555
|
+
*/
|
|
556
|
+
computeRefPath(params) {
|
|
557
|
+
const { identifier, sourceCode } = params;
|
|
558
|
+
const fullChainNode = ASTUtils.traverseUpOnly(identifier, [
|
|
559
|
+
import_utils3.AST_NODE_TYPES.MemberExpression,
|
|
560
|
+
import_utils3.AST_NODE_TYPES.TSNonNullExpression,
|
|
561
|
+
import_utils3.AST_NODE_TYPES.Identifier
|
|
562
|
+
]);
|
|
563
|
+
const fullText = ExhaustiveDepsUtils.normalizeChain(
|
|
564
|
+
sourceCode.getText(fullChainNode)
|
|
565
|
+
);
|
|
566
|
+
const parent = fullChainNode.parent;
|
|
567
|
+
let dependencyPath = fullText;
|
|
568
|
+
let coversRootMembers = fullText === identifier.name;
|
|
569
|
+
if (parent && parent.type === import_utils3.AST_NODE_TYPES.CallExpression && parent.callee === fullChainNode) {
|
|
570
|
+
const segments = fullText.split(".");
|
|
571
|
+
if (segments.length > 1) {
|
|
572
|
+
dependencyPath = segments.slice(0, -1).join(".");
|
|
573
|
+
}
|
|
574
|
+
coversRootMembers = false;
|
|
575
|
+
}
|
|
576
|
+
dependencyPath = dependencyPath.split(".")[0] === "" ? identifier.name : dependencyPath;
|
|
577
|
+
const root = dependencyPath.split(".")[0];
|
|
578
|
+
return {
|
|
579
|
+
path: dependencyPath,
|
|
580
|
+
root: root ?? identifier.name,
|
|
581
|
+
coversRootMembers: coversRootMembers && dependencyPath === root
|
|
582
|
+
};
|
|
583
|
+
},
|
|
475
584
|
collectExternalRefsInFunction(params) {
|
|
476
585
|
const { functionNode, scopeManager } = params;
|
|
477
586
|
const functionScope = scopeManager.acquire(functionNode);
|
|
@@ -503,6 +612,52 @@ var ExhaustiveDepsUtils = {
|
|
|
503
612
|
}
|
|
504
613
|
collect(functionScope);
|
|
505
614
|
return externalRefs;
|
|
615
|
+
},
|
|
616
|
+
/**
|
|
617
|
+
* Recursively collects type identifiers from a type annotation
|
|
618
|
+
*/
|
|
619
|
+
collectTypeIdentifiers(typeNode, out) {
|
|
620
|
+
switch (typeNode.type) {
|
|
621
|
+
case import_utils3.AST_NODE_TYPES.TSTypeReference: {
|
|
622
|
+
if (typeNode.typeName.type === import_utils3.AST_NODE_TYPES.Identifier) {
|
|
623
|
+
out.add(typeNode.typeName.name);
|
|
624
|
+
}
|
|
625
|
+
break;
|
|
626
|
+
}
|
|
627
|
+
case import_utils3.AST_NODE_TYPES.TSUnionType:
|
|
628
|
+
case import_utils3.AST_NODE_TYPES.TSIntersectionType: {
|
|
629
|
+
typeNode.types.forEach(
|
|
630
|
+
(t) => ExhaustiveDepsUtils.collectTypeIdentifiers(t, out)
|
|
631
|
+
);
|
|
632
|
+
break;
|
|
633
|
+
}
|
|
634
|
+
case import_utils3.AST_NODE_TYPES.TSArrayType: {
|
|
635
|
+
ExhaustiveDepsUtils.collectTypeIdentifiers(typeNode.elementType, out);
|
|
636
|
+
break;
|
|
637
|
+
}
|
|
638
|
+
case import_utils3.AST_NODE_TYPES.TSTupleType: {
|
|
639
|
+
typeNode.elementTypes.forEach(
|
|
640
|
+
(et) => ExhaustiveDepsUtils.collectTypeIdentifiers(et, out)
|
|
641
|
+
);
|
|
642
|
+
break;
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
},
|
|
646
|
+
/**
|
|
647
|
+
* Gets the function expression nodes from a queryFn property, handling conditional expressions.
|
|
648
|
+
* When neither branch is skipToken, returns both branches so all deps are scanned.
|
|
649
|
+
*/
|
|
650
|
+
getQueryFnNodes(queryFn) {
|
|
651
|
+
if (queryFn.value.type !== import_utils3.AST_NODE_TYPES.ConditionalExpression) {
|
|
652
|
+
return [queryFn.value];
|
|
653
|
+
}
|
|
654
|
+
if (queryFn.value.consequent.type === import_utils3.AST_NODE_TYPES.Identifier && queryFn.value.consequent.name === "skipToken") {
|
|
655
|
+
return [queryFn.value.alternate];
|
|
656
|
+
}
|
|
657
|
+
if (queryFn.value.alternate.type === import_utils3.AST_NODE_TYPES.Identifier && queryFn.value.alternate.name === "skipToken") {
|
|
658
|
+
return [queryFn.value.consequent];
|
|
659
|
+
}
|
|
660
|
+
return [queryFn.value.consequent, queryFn.value.alternate];
|
|
506
661
|
}
|
|
507
662
|
};
|
|
508
663
|
|
|
@@ -525,22 +680,35 @@ var rule = createRule({
|
|
|
525
680
|
},
|
|
526
681
|
hasSuggestions: true,
|
|
527
682
|
fixable: "code",
|
|
528
|
-
schema: [
|
|
683
|
+
schema: [
|
|
684
|
+
{
|
|
685
|
+
type: "object",
|
|
686
|
+
properties: {
|
|
687
|
+
allowlist: {
|
|
688
|
+
type: "object",
|
|
689
|
+
properties: {
|
|
690
|
+
variables: { type: "array", items: { type: "string" } },
|
|
691
|
+
types: { type: "array", items: { type: "string" } }
|
|
692
|
+
},
|
|
693
|
+
additionalProperties: false
|
|
694
|
+
}
|
|
695
|
+
},
|
|
696
|
+
additionalProperties: false
|
|
697
|
+
}
|
|
698
|
+
]
|
|
529
699
|
},
|
|
530
700
|
defaultOptions: [],
|
|
531
701
|
create: detectTanstackQueryImports((context) => {
|
|
532
702
|
return {
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
return;
|
|
536
|
-
}
|
|
703
|
+
ObjectExpression: (node) => {
|
|
704
|
+
var _a, _b;
|
|
537
705
|
const scopeManager = context.sourceCode.scopeManager;
|
|
538
706
|
const queryKey = ASTUtils.findPropertyWithIdentifierKey(
|
|
539
|
-
node.
|
|
707
|
+
node.properties,
|
|
540
708
|
QUERY_KEY
|
|
541
709
|
);
|
|
542
710
|
const queryFn = ASTUtils.findPropertyWithIdentifierKey(
|
|
543
|
-
node.
|
|
711
|
+
node.properties,
|
|
544
712
|
QUERY_FN
|
|
545
713
|
);
|
|
546
714
|
if (scopeManager === null || queryKey === void 0 || queryFn === void 0 || !ASTUtils.isNodeOfOneOf(queryFn.value, [
|
|
@@ -554,73 +722,104 @@ var rule = createRule({
|
|
|
554
722
|
queryKey.value,
|
|
555
723
|
context
|
|
556
724
|
);
|
|
557
|
-
const
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
node: getQueryFnRelevantNode(queryFn)
|
|
561
|
-
});
|
|
562
|
-
const relevantRefs = externalRefs.filter(
|
|
563
|
-
(reference) => ExhaustiveDepsUtils.isRelevantReference({
|
|
564
|
-
sourceCode: context.sourceCode,
|
|
565
|
-
reference,
|
|
725
|
+
const queryFnNodes = ExhaustiveDepsUtils.getQueryFnNodes(queryFn);
|
|
726
|
+
const externalRefs = queryFnNodes.flatMap(
|
|
727
|
+
(fnNode) => ASTUtils.getExternalRefs({
|
|
566
728
|
scopeManager,
|
|
567
|
-
|
|
568
|
-
|
|
729
|
+
sourceCode: context.sourceCode,
|
|
730
|
+
node: fnNode
|
|
569
731
|
})
|
|
570
732
|
);
|
|
733
|
+
const relevantRefs = externalRefs.filter(
|
|
734
|
+
(reference) => queryFnNodes.some(
|
|
735
|
+
(fnNode) => ExhaustiveDepsUtils.isRelevantReference({
|
|
736
|
+
sourceCode: context.sourceCode,
|
|
737
|
+
reference,
|
|
738
|
+
scopeManager,
|
|
739
|
+
node: fnNode,
|
|
740
|
+
filename: context.filename
|
|
741
|
+
})
|
|
742
|
+
)
|
|
743
|
+
);
|
|
744
|
+
const ruleOptions = context.options.at(0);
|
|
745
|
+
const allowlistedVariables = new Set(
|
|
746
|
+
((_a = ruleOptions == null ? void 0 : ruleOptions.allowlist) == null ? void 0 : _a.variables) ?? []
|
|
747
|
+
);
|
|
748
|
+
const allowlistedTypes = new Set(((_b = ruleOptions == null ? void 0 : ruleOptions.allowlist) == null ? void 0 : _b.types) ?? []);
|
|
749
|
+
const requiredRefs = relevantRefs.flatMap((ref) => {
|
|
750
|
+
if (ref.identifier.type !== import_utils4.AST_NODE_TYPES.Identifier) return [];
|
|
751
|
+
const refPath = ExhaustiveDepsUtils.computeRefPath({
|
|
752
|
+
identifier: ref.identifier,
|
|
753
|
+
sourceCode: context.sourceCode
|
|
754
|
+
});
|
|
755
|
+
if (refPath === null) return [];
|
|
756
|
+
return [
|
|
757
|
+
{
|
|
758
|
+
...refPath,
|
|
759
|
+
allowlistedByType: ExhaustiveDepsUtils.variableIsAllowlistedByType({
|
|
760
|
+
allowlistedTypes,
|
|
761
|
+
variable: ref.resolved ?? null
|
|
762
|
+
})
|
|
763
|
+
}
|
|
764
|
+
];
|
|
765
|
+
});
|
|
766
|
+
if (requiredRefs.length === 0) return;
|
|
571
767
|
const queryKeyDeps = ExhaustiveDepsUtils.collectQueryKeyDeps({
|
|
572
768
|
sourceCode: context.sourceCode,
|
|
573
769
|
scopeManager,
|
|
574
770
|
queryKeyNode
|
|
575
771
|
});
|
|
576
|
-
const
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
messageId: "fixTo",
|
|
597
|
-
data: { result: existingWithMissing },
|
|
598
|
-
fix(fixer) {
|
|
599
|
-
return fixer.replaceText(queryKeyNode, existingWithMissing);
|
|
600
|
-
}
|
|
601
|
-
});
|
|
602
|
-
}
|
|
603
|
-
context.report({
|
|
604
|
-
node,
|
|
605
|
-
messageId: "missingDeps",
|
|
606
|
-
data: {
|
|
607
|
-
deps: uniqueMissingRefs.map((ref) => ref.text).join(", ")
|
|
608
|
-
},
|
|
609
|
-
suggest: suggestions
|
|
610
|
-
});
|
|
611
|
-
}
|
|
772
|
+
const missingPaths = ExhaustiveDepsUtils.computeFilteredMissingPaths({
|
|
773
|
+
requiredRefs,
|
|
774
|
+
allowlistedVariables,
|
|
775
|
+
existingRootIdentifiers: queryKeyDeps.roots,
|
|
776
|
+
existingFullPaths: queryKeyDeps.paths
|
|
777
|
+
});
|
|
778
|
+
if (missingPaths.length === 0) return;
|
|
779
|
+
const missingAsText = missingPaths.join(", ");
|
|
780
|
+
const suggestions = buildSuggestions({
|
|
781
|
+
queryKeyNode,
|
|
782
|
+
missingPaths,
|
|
783
|
+
missingAsText,
|
|
784
|
+
sourceCode: context.sourceCode
|
|
785
|
+
});
|
|
786
|
+
context.report({
|
|
787
|
+
node,
|
|
788
|
+
messageId: "missingDeps",
|
|
789
|
+
data: { deps: missingAsText },
|
|
790
|
+
suggest: suggestions
|
|
791
|
+
});
|
|
612
792
|
}
|
|
613
793
|
};
|
|
614
794
|
})
|
|
615
795
|
});
|
|
616
|
-
function
|
|
617
|
-
|
|
618
|
-
|
|
796
|
+
function buildSuggestions(params) {
|
|
797
|
+
const { queryKeyNode, missingPaths, missingAsText, sourceCode } = params;
|
|
798
|
+
if (queryKeyNode.type !== import_utils4.AST_NODE_TYPES.ArrayExpression) {
|
|
799
|
+
return [];
|
|
619
800
|
}
|
|
620
|
-
|
|
621
|
-
|
|
801
|
+
const closingBracket = sourceCode.getLastToken(queryKeyNode);
|
|
802
|
+
if (!closingBracket) return [];
|
|
803
|
+
const existingElements = queryKeyNode.elements.filter((el) => el !== null).map((el) => sourceCode.getText(el));
|
|
804
|
+
const resultText = `[${[...existingElements, ...missingPaths].join(", ")}]`;
|
|
805
|
+
if (queryKeyNode.elements.length === 0) {
|
|
806
|
+
return [
|
|
807
|
+
{
|
|
808
|
+
messageId: "fixTo",
|
|
809
|
+
data: { result: resultText },
|
|
810
|
+
fix: (fixer) => fixer.replaceText(queryKeyNode, resultText)
|
|
811
|
+
}
|
|
812
|
+
];
|
|
622
813
|
}
|
|
623
|
-
|
|
814
|
+
const tokenBefore = sourceCode.getTokenBefore(closingBracket);
|
|
815
|
+
const separator = (tokenBefore == null ? void 0 : tokenBefore.value) === "," ? " " : ", ";
|
|
816
|
+
return [
|
|
817
|
+
{
|
|
818
|
+
messageId: "fixTo",
|
|
819
|
+
data: { result: resultText },
|
|
820
|
+
fix: (fixer) => fixer.insertTextBefore(closingBracket, `${separator}${missingAsText}`)
|
|
821
|
+
}
|
|
822
|
+
];
|
|
624
823
|
}
|
|
625
824
|
function dereferenceVariablesAndTypeAssertions(queryKeyNode, context) {
|
|
626
825
|
const visitedNodes = /* @__PURE__ */ new Set();
|