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