@tanstack/eslint-plugin-query 5.57.1 → 5.58.1
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/dist/cjs/index.cjs +1 -1
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs +5 -2
- package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs.map +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js +5 -2
- package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/infinite-query-property-order.rule.test.ts +44 -7
- package/src/index.ts +1 -1
- package/src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts +5 -2
package/dist/cjs/index.cjs
CHANGED
|
@@ -9,7 +9,7 @@ const plugin = {
|
|
|
9
9
|
};
|
|
10
10
|
Object.assign(plugin.configs, {
|
|
11
11
|
recommended: {
|
|
12
|
-
plugins: ["@tanstack/
|
|
12
|
+
plugins: ["@tanstack/query"],
|
|
13
13
|
rules: {
|
|
14
14
|
"@tanstack/query/exhaustive-deps": "error",
|
|
15
15
|
"@tanstack/query/no-rest-destructuring": "warn",
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-query',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-query',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/query'],\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n '@tanstack/query/infinite-query-property-order': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/query': plugin,\n },\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n '@tanstack/query/infinite-query-property-order': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"names":["rules"],"mappings":";;AAcA,MAAM,SAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,EACR;AAAA,EACA,SAAS,CAAC;AAAA,EAAA,OACVA,MAAA;AACF;AAGA,OAAO,OAAO,OAAO,SAAS;AAAA,EAC5B,aAAa;AAAA,IACX,SAAS,CAAC,iBAAiB;AAAA,IAC3B,OAAO;AAAA,MACL,mCAAmC;AAAA,MACnC,yCAAyC;AAAA,MACzC,uCAAuC;AAAA,MACvC,oCAAoC;AAAA,MACpC,iDAAiD;AAAA,IACnD;AAAA,EACF;AAAA,EACA,oBAAoB;AAAA,IAClB;AAAA,MACE,SAAS;AAAA,QACP,mBAAmB;AAAA,MACrB;AAAA,MACA,OAAO;AAAA,QACL,mCAAmC;AAAA,QACnC,yCAAyC;AAAA,QACzC,uCAAuC;AAAA,QACvC,oCAAoC;AAAA,QACpC,iDAAiD;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AACF,CAAC;;"}
|
|
@@ -51,9 +51,12 @@ const rule = createRule({
|
|
|
51
51
|
} else if (p.type === utils.AST_NODE_TYPES.SpreadElement) {
|
|
52
52
|
if (p.argument.type === utils.AST_NODE_TYPES.Identifier) {
|
|
53
53
|
return { name: p.argument.name, property: p };
|
|
54
|
-
} else {
|
|
55
|
-
|
|
54
|
+
} else if (p.argument.type === utils.AST_NODE_TYPES.CallExpression) {
|
|
55
|
+
if (p.argument.callee.type === utils.AST_NODE_TYPES.Identifier) {
|
|
56
|
+
return { name: p.argument.callee.name, property: p };
|
|
57
|
+
}
|
|
56
58
|
}
|
|
59
|
+
throw new Error("Unsupported spread element");
|
|
57
60
|
}
|
|
58
61
|
return [];
|
|
59
62
|
});
|
package/dist/cjs/rules/infinite-query-property-order/infinite-query-property-order.rule.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"infinite-query-property-order.rule.cjs","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport { sortDataByOrder } from './infinite-query-property-order.utils'\nimport { infiniteQueryFunctions, sortRules } from './constants'\nimport type { InfiniteQueryFunctions } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions)\nfunction isInfiniteQueryFunction(node: any): node is InfiniteQueryFunctions {\n return infiniteQueryFunctionsSet.has(node)\n}\n\nexport const name = 'infinite-query-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for infinite queries',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const infiniteQueryFunction = node.callee.name\n if (!isInfiniteQueryFunction(infiniteQueryFunction)) {\n return\n }\n const argument = node.arguments[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n
|
|
1
|
+
{"version":3,"file":"infinite-query-property-order.rule.cjs","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport { sortDataByOrder } from './infinite-query-property-order.utils'\nimport { infiniteQueryFunctions, sortRules } from './constants'\nimport type { InfiniteQueryFunctions } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions)\nfunction isInfiniteQueryFunction(node: any): node is InfiniteQueryFunctions {\n return infiniteQueryFunctionsSet.has(node)\n}\n\nexport const name = 'infinite-query-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for infinite queries',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const infiniteQueryFunction = node.callee.name\n if (!isInfiniteQueryFunction(infiniteQueryFunction)) {\n return\n }\n const argument = node.arguments[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else if (p.argument.type === AST_NODE_TYPES.CallExpression) {\n if (p.argument.callee.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.callee.name, property: p }\n }\n }\n throw new Error('Unsupported spread element')\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(properties, sortRules, 'name')\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"names":["ESLintUtils","getDocsUrl","infiniteQueryFunctions","detectTanstackQueryImports","AST_NODE_TYPES","sortDataByOrder","sortRules","text"],"mappings":";;;;;;;AASA,MAAM,aAAaA,MAAY,YAAA,YAA2BC,WAAAA,UAAU;AAEpE,MAAM,4BAA4B,IAAI,IAAIC,UAAAA,sBAAsB;AAChE,SAAS,wBAAwB,MAA2C;AACnE,SAAA,0BAA0B,IAAI,IAAI;AAC3C;AAEO,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,MACF,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,cAAc;AAAA,IAChB;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,gBAAgB;AAAA,IAChB,SAAS;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EAEjB,QAAQC,wBAAAA,2BAA2B,CAAC,YAAY;AACvC,WAAA;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAASC,MAAAA,eAAe,YAAY;AAClD;AAAA,QACF;AACM,cAAA,wBAAwB,KAAK,OAAO;AACtC,YAAA,CAAC,wBAAwB,qBAAqB,GAAG;AACnD;AAAA,QACF;AACM,cAAA,WAAW,KAAK,UAAU,CAAC;AACjC,YAAI,aAAa,UAAa,SAAS,SAAS,oBAAoB;AAClE;AAAA,QACF;AAEA,cAAM,gBAAgB,SAAS;AAG3B,YAAA,cAAc,SAAS,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,QAAQ,CAAC,MAAM;AAE5C,cAAA,EAAE,SAASA,MAAAA,eAAe,YAC1B,EAAE,IAAI,SAASA,qBAAe,YAC9B;AACA,mBAAO,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU;UAC5B,WAAA,EAAE,SAASA,MAAAA,eAAe,eAAe;AAClD,gBAAI,EAAE,SAAS,SAASA,MAAAA,eAAe,YAAY;AACjD,qBAAO,EAAE,MAAM,EAAE,SAAS,MAAM,UAAU;YACjC,WAAA,EAAE,SAAS,SAASA,MAAAA,eAAe,gBAAgB;AAC5D,kBAAI,EAAE,SAAS,OAAO,SAASA,MAAAA,eAAe,YAAY;AACxD,uBAAO,EAAE,MAAM,EAAE,SAAS,OAAO,MAAM,UAAU;cACnD;AAAA,YACF;AACM,kBAAA,IAAI,MAAM,4BAA4B;AAAA,UAC9C;AACA,iBAAO;QAAC,CACT;AAED,cAAM,mBAAmBC,iCAAA,gBAAgB,YAAYC,UAAA,WAAW,MAAM;AACtE,YAAI,qBAAqB,MAAM;AAC7B;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,MAAM,EAAE,UAAU,KAAK,OAAO,KAAK;AAAA,UACnC,WAAW;AAAA,UACX,IAAI,OAAO;AACT,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,OAAO,iBAAiB;AAAA,cAC5B,CAAC,YAAY,WAAW,UAAU;AAChC,oBAAIC,QAAO;AACP,oBAAA,QAAQ,cAAc,SAAS,GAAG;AACpCA,0BAAO,WACJ,QAAA,EACA;AAAA,oBACC,cAAc,KAAK,EAAG,MAAM,CAAC;AAAA,oBAC7B,cAAc,QAAQ,CAAC,EAAG,MAAM,CAAC;AAAA,kBAAA;AAAA,gBAEvC;AACA,uBACE,aAAa,WAAW,QAAQ,UAAU,QAAQ,IAAIA;AAAAA,cAE1D;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,MAAM;AAAA,cACX,CAAC,cAAc,CAAC,EAAG,MAAM,CAAC,GAAG,cAAc,GAAG,EAAE,EAAG,MAAM,CAAC,CAAC;AAAA,cAC3D;AAAA,YAAA;AAAA,UAEJ;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;;;"}
|
package/dist/esm/index.js
CHANGED
|
@@ -8,7 +8,7 @@ const plugin = {
|
|
|
8
8
|
};
|
|
9
9
|
Object.assign(plugin.configs, {
|
|
10
10
|
recommended: {
|
|
11
|
-
plugins: ["@tanstack/
|
|
11
|
+
plugins: ["@tanstack/query"],
|
|
12
12
|
rules: {
|
|
13
13
|
"@tanstack/query/exhaustive-deps": "error",
|
|
14
14
|
"@tanstack/query/no-rest-destructuring": "warn",
|
package/dist/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-query',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import { rules } from './rules'\nimport type { ESLint, Linter } from 'eslint'\nimport type { RuleModule } from '@typescript-eslint/utils/ts-eslint'\n\ntype RuleKey = keyof typeof rules\n\ninterface Plugin extends Omit<ESLint.Plugin, 'rules'> {\n rules: Record<RuleKey, RuleModule<any, any, any>>\n configs: {\n recommended: ESLint.ConfigData\n 'flat/recommended': Array<Linter.FlatConfig>\n }\n}\n\nconst plugin: Plugin = {\n meta: {\n name: '@tanstack/eslint-plugin-query',\n },\n configs: {} as Plugin['configs'],\n rules,\n}\n\n// Assign configs here so we can reference `plugin`\nObject.assign(plugin.configs, {\n recommended: {\n plugins: ['@tanstack/query'],\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n '@tanstack/query/infinite-query-property-order': 'error',\n },\n },\n 'flat/recommended': [\n {\n plugins: {\n '@tanstack/query': plugin,\n },\n rules: {\n '@tanstack/query/exhaustive-deps': 'error',\n '@tanstack/query/no-rest-destructuring': 'warn',\n '@tanstack/query/stable-query-client': 'error',\n '@tanstack/query/no-unstable-deps': 'error',\n '@tanstack/query/infinite-query-property-order': 'error',\n },\n },\n ],\n})\n\nexport default plugin\n"],"names":[],"mappings":";AAcA,MAAM,SAAiB;AAAA,EACrB,MAAM;AAAA,IACJ,MAAM;AAAA,EACR;AAAA,EACA,SAAS,CAAC;AAAA,EACV;AACF;AAGA,OAAO,OAAO,OAAO,SAAS;AAAA,EAC5B,aAAa;AAAA,IACX,SAAS,CAAC,iBAAiB;AAAA,IAC3B,OAAO;AAAA,MACL,mCAAmC;AAAA,MACnC,yCAAyC;AAAA,MACzC,uCAAuC;AAAA,MACvC,oCAAoC;AAAA,MACpC,iDAAiD;AAAA,IACnD;AAAA,EACF;AAAA,EACA,oBAAoB;AAAA,IAClB;AAAA,MACE,SAAS;AAAA,QACP,mBAAmB;AAAA,MACrB;AAAA,MACA,OAAO;AAAA,QACL,mCAAmC;AAAA,QACnC,yCAAyC;AAAA,QACzC,uCAAuC;AAAA,QACvC,oCAAoC;AAAA,QACpC,iDAAiD;AAAA,MACnD;AAAA,IACF;AAAA,EACF;AACF,CAAC;"}
|
|
@@ -49,9 +49,12 @@ const rule = createRule({
|
|
|
49
49
|
} else if (p.type === AST_NODE_TYPES.SpreadElement) {
|
|
50
50
|
if (p.argument.type === AST_NODE_TYPES.Identifier) {
|
|
51
51
|
return { name: p.argument.name, property: p };
|
|
52
|
-
} else {
|
|
53
|
-
|
|
52
|
+
} else if (p.argument.type === AST_NODE_TYPES.CallExpression) {
|
|
53
|
+
if (p.argument.callee.type === AST_NODE_TYPES.Identifier) {
|
|
54
|
+
return { name: p.argument.callee.name, property: p };
|
|
55
|
+
}
|
|
54
56
|
}
|
|
57
|
+
throw new Error("Unsupported spread element");
|
|
55
58
|
}
|
|
56
59
|
return [];
|
|
57
60
|
});
|
package/dist/esm/rules/infinite-query-property-order/infinite-query-property-order.rule.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"infinite-query-property-order.rule.js","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport { sortDataByOrder } from './infinite-query-property-order.utils'\nimport { infiniteQueryFunctions, sortRules } from './constants'\nimport type { InfiniteQueryFunctions } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions)\nfunction isInfiniteQueryFunction(node: any): node is InfiniteQueryFunctions {\n return infiniteQueryFunctionsSet.has(node)\n}\n\nexport const name = 'infinite-query-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for infinite queries',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const infiniteQueryFunction = node.callee.name\n if (!isInfiniteQueryFunction(infiniteQueryFunction)) {\n return\n }\n const argument = node.arguments[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else {\n throw new Error('Unsupported spread element')\n
|
|
1
|
+
{"version":3,"file":"infinite-query-property-order.rule.js","sources":["../../../../src/rules/infinite-query-property-order/infinite-query-property-order.rule.ts"],"sourcesContent":["import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils'\n\nimport { getDocsUrl } from '../../utils/get-docs-url'\nimport { detectTanstackQueryImports } from '../../utils/detect-react-query-imports'\nimport { sortDataByOrder } from './infinite-query-property-order.utils'\nimport { infiniteQueryFunctions, sortRules } from './constants'\nimport type { InfiniteQueryFunctions } from './constants'\nimport type { ExtraRuleDocs } from '../../types'\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl)\n\nconst infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions)\nfunction isInfiniteQueryFunction(node: any): node is InfiniteQueryFunctions {\n return infiniteQueryFunctionsSet.has(node)\n}\n\nexport const name = 'infinite-query-property-order'\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Ensure correct order of inference sensitive properties for infinite queries',\n recommended: 'error',\n },\n messages: {\n invalidOrder: 'Invalid order of properties for `{{function}}`.',\n },\n schema: [],\n hasSuggestions: true,\n fixable: 'code',\n },\n defaultOptions: [],\n\n create: detectTanstackQueryImports((context) => {\n return {\n CallExpression(node) {\n if (node.callee.type !== AST_NODE_TYPES.Identifier) {\n return\n }\n const infiniteQueryFunction = node.callee.name\n if (!isInfiniteQueryFunction(infiniteQueryFunction)) {\n return\n }\n const argument = node.arguments[0]\n if (argument === undefined || argument.type !== 'ObjectExpression') {\n return\n }\n\n const allProperties = argument.properties\n\n // no need to sort if there is at max 1 property\n if (allProperties.length < 2) {\n return\n }\n\n const properties = allProperties.flatMap((p) => {\n if (\n p.type === AST_NODE_TYPES.Property &&\n p.key.type === AST_NODE_TYPES.Identifier\n ) {\n return { name: p.key.name, property: p }\n } else if (p.type === AST_NODE_TYPES.SpreadElement) {\n if (p.argument.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.name, property: p }\n } else if (p.argument.type === AST_NODE_TYPES.CallExpression) {\n if (p.argument.callee.type === AST_NODE_TYPES.Identifier) {\n return { name: p.argument.callee.name, property: p }\n }\n }\n throw new Error('Unsupported spread element')\n }\n return []\n })\n\n const sortedProperties = sortDataByOrder(properties, sortRules, 'name')\n if (sortedProperties === null) {\n return\n }\n context.report({\n node: argument,\n data: { function: node.callee.name },\n messageId: 'invalidOrder',\n fix(fixer) {\n const sourceCode = context.sourceCode\n\n const text = sortedProperties.reduce(\n (sourceText, specifier, index) => {\n let text = ''\n if (index < allProperties.length - 1) {\n text = sourceCode\n .getText()\n .slice(\n allProperties[index]!.range[1],\n allProperties[index + 1]!.range[0],\n )\n }\n return (\n sourceText + sourceCode.getText(specifier.property) + text\n )\n },\n '',\n )\n return fixer.replaceTextRange(\n [allProperties[0]!.range[0], allProperties.at(-1)!.range[1]],\n text,\n )\n },\n })\n },\n }\n }),\n})\n"],"names":["text"],"mappings":";;;;;AASA,MAAM,aAAa,YAAY,YAA2B,UAAU;AAEpE,MAAM,4BAA4B,IAAI,IAAI,sBAAsB;AAChE,SAAS,wBAAwB,MAA2C;AACnE,SAAA,0BAA0B,IAAI,IAAI;AAC3C;AAEO,MAAM,OAAO;AAEb,MAAM,OAAO,WAAW;AAAA,EAC7B;AAAA,EACA,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,MACF,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,cAAc;AAAA,IAChB;AAAA,IACA,QAAQ,CAAC;AAAA,IACT,gBAAgB;AAAA,IAChB,SAAS;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EAEjB,QAAQ,2BAA2B,CAAC,YAAY;AACvC,WAAA;AAAA,MACL,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAAS,eAAe,YAAY;AAClD;AAAA,QACF;AACM,cAAA,wBAAwB,KAAK,OAAO;AACtC,YAAA,CAAC,wBAAwB,qBAAqB,GAAG;AACnD;AAAA,QACF;AACM,cAAA,WAAW,KAAK,UAAU,CAAC;AACjC,YAAI,aAAa,UAAa,SAAS,SAAS,oBAAoB;AAClE;AAAA,QACF;AAEA,cAAM,gBAAgB,SAAS;AAG3B,YAAA,cAAc,SAAS,GAAG;AAC5B;AAAA,QACF;AAEA,cAAM,aAAa,cAAc,QAAQ,CAAC,MAAM;AAE5C,cAAA,EAAE,SAAS,eAAe,YAC1B,EAAE,IAAI,SAAS,eAAe,YAC9B;AACA,mBAAO,EAAE,MAAM,EAAE,IAAI,MAAM,UAAU;UAC5B,WAAA,EAAE,SAAS,eAAe,eAAe;AAClD,gBAAI,EAAE,SAAS,SAAS,eAAe,YAAY;AACjD,qBAAO,EAAE,MAAM,EAAE,SAAS,MAAM,UAAU;YACjC,WAAA,EAAE,SAAS,SAAS,eAAe,gBAAgB;AAC5D,kBAAI,EAAE,SAAS,OAAO,SAAS,eAAe,YAAY;AACxD,uBAAO,EAAE,MAAM,EAAE,SAAS,OAAO,MAAM,UAAU;cACnD;AAAA,YACF;AACM,kBAAA,IAAI,MAAM,4BAA4B;AAAA,UAC9C;AACA,iBAAO;QAAC,CACT;AAED,cAAM,mBAAmB,gBAAgB,YAAY,WAAW,MAAM;AACtE,YAAI,qBAAqB,MAAM;AAC7B;AAAA,QACF;AACA,gBAAQ,OAAO;AAAA,UACb,MAAM;AAAA,UACN,MAAM,EAAE,UAAU,KAAK,OAAO,KAAK;AAAA,UACnC,WAAW;AAAA,UACX,IAAI,OAAO;AACT,kBAAM,aAAa,QAAQ;AAE3B,kBAAM,OAAO,iBAAiB;AAAA,cAC5B,CAAC,YAAY,WAAW,UAAU;AAChC,oBAAIA,QAAO;AACP,oBAAA,QAAQ,cAAc,SAAS,GAAG;AACpCA,0BAAO,WACJ,QAAA,EACA;AAAA,oBACC,cAAc,KAAK,EAAG,MAAM,CAAC;AAAA,oBAC7B,cAAc,QAAQ,CAAC,EAAG,MAAM,CAAC;AAAA,kBAAA;AAAA,gBAEvC;AACA,uBACE,aAAa,WAAW,QAAQ,UAAU,QAAQ,IAAIA;AAAAA,cAE1D;AAAA,cACA;AAAA,YAAA;AAEF,mBAAO,MAAM;AAAA,cACX,CAAC,cAAc,CAAC,EAAG,MAAM,CAAC,GAAG,cAAc,GAAG,EAAE,EAAG,MAAM,CAAC,CAAC;AAAA,cAC3D;AAAA,YAAA;AAAA,UAEJ;AAAA,QAAA,CACD;AAAA,MACH;AAAA,IAAA;AAAA,EACF,CACD;AACH,CAAC;"}
|
package/package.json
CHANGED
|
@@ -13,13 +13,18 @@ import {
|
|
|
13
13
|
generateInterleavedCombinations,
|
|
14
14
|
generatePartialCombinations,
|
|
15
15
|
generatePermutations,
|
|
16
|
+
normalizeIndent,
|
|
16
17
|
} from './test-utils'
|
|
17
18
|
import type { InfiniteQueryFunctions } from '../rules/infinite-query-property-order/constants'
|
|
18
19
|
|
|
19
20
|
const ruleTester = new RuleTester()
|
|
20
21
|
|
|
21
22
|
type CheckedProperties = (typeof checkedProperties)[number]
|
|
22
|
-
const orderIndependentProps = [
|
|
23
|
+
const orderIndependentProps = [
|
|
24
|
+
'queryKey',
|
|
25
|
+
'...objectExpressionSpread',
|
|
26
|
+
'...callExpressionSpread',
|
|
27
|
+
] as const
|
|
23
28
|
type OrderIndependentProps = (typeof orderIndependentProps)[number]
|
|
24
29
|
|
|
25
30
|
interface TestCase {
|
|
@@ -84,7 +89,7 @@ export function generateInvalidPermutations(
|
|
|
84
89
|
Math.abs(
|
|
85
90
|
invalid.indexOf('getNextPageParam') -
|
|
86
91
|
invalid.indexOf('getPreviousPageParam'),
|
|
87
|
-
) !== 1
|
|
92
|
+
) !== 1,
|
|
88
93
|
),
|
|
89
94
|
)
|
|
90
95
|
}
|
|
@@ -122,6 +127,14 @@ const invalidTestMatrix = combinate({
|
|
|
122
127
|
properties: interleavedInvalidPermutations,
|
|
123
128
|
})
|
|
124
129
|
|
|
130
|
+
const callExpressionSpread = normalizeIndent`
|
|
131
|
+
...communitiesQuery({
|
|
132
|
+
filters: {
|
|
133
|
+
...fieldValues,
|
|
134
|
+
placementFormats: [],
|
|
135
|
+
},
|
|
136
|
+
})`
|
|
137
|
+
|
|
125
138
|
function getCode({
|
|
126
139
|
infiniteQueryFunction: infiniteQueryFunction,
|
|
127
140
|
properties,
|
|
@@ -129,10 +142,11 @@ function getCode({
|
|
|
129
142
|
function getPropertyCode(
|
|
130
143
|
property: CheckedProperties | OrderIndependentProps,
|
|
131
144
|
) {
|
|
132
|
-
if (property.startsWith('...')) {
|
|
133
|
-
return property
|
|
134
|
-
}
|
|
135
145
|
switch (property) {
|
|
146
|
+
case '...objectExpressionSpread':
|
|
147
|
+
return `...objectExpressionSpread`
|
|
148
|
+
case '...callExpressionSpread':
|
|
149
|
+
return callExpressionSpread
|
|
136
150
|
case 'queryKey':
|
|
137
151
|
return `queryKey: ['projects']`
|
|
138
152
|
case 'queryFn':
|
|
@@ -142,8 +156,6 @@ function getCode({
|
|
|
142
156
|
case 'getNextPageParam':
|
|
143
157
|
return 'getNextPageParam: (lastPage) => lastPage.nextId ?? undefined'
|
|
144
158
|
}
|
|
145
|
-
|
|
146
|
-
return `${property}: () => null`
|
|
147
159
|
}
|
|
148
160
|
return `
|
|
149
161
|
import { ${infiniteQueryFunction} } from '@tanstack/react-query'
|
|
@@ -180,3 +192,28 @@ ruleTester.run(name, rule, {
|
|
|
180
192
|
valid: validTestCases,
|
|
181
193
|
invalid: invalidTestCases,
|
|
182
194
|
})
|
|
195
|
+
|
|
196
|
+
// regression tests
|
|
197
|
+
|
|
198
|
+
const regressionTestCases = {
|
|
199
|
+
valid: [
|
|
200
|
+
{
|
|
201
|
+
name: 'should pass with call expression spread',
|
|
202
|
+
code: normalizeIndent`
|
|
203
|
+
import { useInfiniteQuery } from '@tanstack/react-query'
|
|
204
|
+
const { data, isFetching, isLoading, hasNextPage, fetchNextPage } =
|
|
205
|
+
useInfiniteQuery({
|
|
206
|
+
...communitiesQuery({
|
|
207
|
+
filters: {
|
|
208
|
+
...fieldValues,
|
|
209
|
+
placementFormats: [],
|
|
210
|
+
},
|
|
211
|
+
}),
|
|
212
|
+
refetchOnMount: false,
|
|
213
|
+
})`,
|
|
214
|
+
},
|
|
215
|
+
],
|
|
216
|
+
invalid: [],
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
ruleTester.run(name, rule, regressionTestCases)
|
package/src/index.ts
CHANGED
|
@@ -23,7 +23,7 @@ const plugin: Plugin = {
|
|
|
23
23
|
// Assign configs here so we can reference `plugin`
|
|
24
24
|
Object.assign(plugin.configs, {
|
|
25
25
|
recommended: {
|
|
26
|
-
plugins: ['@tanstack/
|
|
26
|
+
plugins: ['@tanstack/query'],
|
|
27
27
|
rules: {
|
|
28
28
|
'@tanstack/query/exhaustive-deps': 'error',
|
|
29
29
|
'@tanstack/query/no-rest-destructuring': 'warn',
|
|
@@ -65,9 +65,12 @@ export const rule = createRule({
|
|
|
65
65
|
} else if (p.type === AST_NODE_TYPES.SpreadElement) {
|
|
66
66
|
if (p.argument.type === AST_NODE_TYPES.Identifier) {
|
|
67
67
|
return { name: p.argument.name, property: p }
|
|
68
|
-
} else {
|
|
69
|
-
|
|
68
|
+
} else if (p.argument.type === AST_NODE_TYPES.CallExpression) {
|
|
69
|
+
if (p.argument.callee.type === AST_NODE_TYPES.Identifier) {
|
|
70
|
+
return { name: p.argument.callee.name, property: p }
|
|
71
|
+
}
|
|
70
72
|
}
|
|
73
|
+
throw new Error('Unsupported spread element')
|
|
71
74
|
}
|
|
72
75
|
return []
|
|
73
76
|
})
|