@tanstack/eslint-plugin-query
Advanced tools
Comparing version 5.57.0 to 5.57.1
export declare const infiniteQueryFunctions: readonly ["infiniteQueryOptions", "useInfiniteQuery", "useSuspenseInfiniteQuery"]; | ||
export type InfiniteQueryFunctions = (typeof infiniteQueryFunctions)[number]; | ||
export declare const checkedProperties: readonly ["queryFn", "getPreviousPageParam", "getNextPageParam"]; | ||
export declare const sortRules: readonly [readonly [readonly ["queryFn"], readonly ["getPreviousPageParam", "getNextPageParam"]]]; |
@@ -6,11 +6,9 @@ const infiniteQueryFunctions = [ | ||
]; | ||
const checkedProperties = [ | ||
"queryFn", | ||
"getPreviousPageParam", | ||
"getNextPageParam" | ||
const sortRules = [ | ||
[["queryFn"], ["getPreviousPageParam", "getNextPageParam"]] | ||
]; | ||
export { | ||
checkedProperties, | ||
infiniteQueryFunctions | ||
infiniteQueryFunctions, | ||
sortRules | ||
}; | ||
//# sourceMappingURL=constants.js.map |
@@ -5,3 +5,3 @@ import { ESLintUtils, AST_NODE_TYPES } from "@typescript-eslint/utils"; | ||
import { sortDataByOrder } from "./infinite-query-property-order.utils.js"; | ||
import { infiniteQueryFunctions, checkedProperties } from "./constants.js"; | ||
import { infiniteQueryFunctions, sortRules } from "./constants.js"; | ||
const createRule = ESLintUtils.RuleCreator(getDocsUrl); | ||
@@ -59,7 +59,3 @@ const infiniteQueryFunctionsSet = new Set(infiniteQueryFunctions); | ||
}); | ||
const sortedProperties = sortDataByOrder( | ||
properties, | ||
checkedProperties, | ||
"name" | ||
); | ||
const sortedProperties = sortDataByOrder(properties, sortRules, "name"); | ||
if (sortedProperties === null) { | ||
@@ -66,0 +62,0 @@ return; |
@@ -1,1 +0,1 @@ | ||
export declare function sortDataByOrder<T, TKey extends keyof T>(data: Array<T> | ReadonlyArray<T>, orderArray: Array<T[TKey]> | ReadonlyArray<T[TKey]>, key: TKey): Array<T> | null; | ||
export declare function sortDataByOrder<T, TKey extends keyof T>(data: Array<T> | ReadonlyArray<T>, orderRules: ReadonlyArray<Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]>>, key: TKey): Array<T> | null; |
@@ -1,12 +0,31 @@ | ||
function sortDataByOrder(data, orderArray, key) { | ||
const orderMap = new Map(orderArray.map((item, index) => [item, index])); | ||
const inOrderArray = data.filter((item) => orderMap.has(item[key])).sort((a, b) => { | ||
const indexA = orderMap.get(a[key]); | ||
const indexB = orderMap.get(b[key]); | ||
return indexA - indexB; | ||
function sortDataByOrder(data, orderRules, key) { | ||
const getSubsetIndex = (item, subsets) => { | ||
var _a; | ||
for (let i = 0; i < subsets.length; i++) { | ||
if ((_a = subsets[i]) == null ? void 0 : _a.includes(item)) { | ||
return i; | ||
} | ||
} | ||
return null; | ||
}; | ||
const orderSets = orderRules.reduce( | ||
(sets, [A, B]) => [...sets, A, B], | ||
[] | ||
); | ||
const inOrderArray = data.filter( | ||
(item) => getSubsetIndex(item[key], orderSets) !== null | ||
); | ||
let wasResorted = false; | ||
const sortedArray = inOrderArray.sort((a, b) => { | ||
const aKey = a[key], bKey = b[key]; | ||
const aSubsetIndex = getSubsetIndex(aKey, orderSets); | ||
const bSubsetIndex = getSubsetIndex(bKey, orderSets); | ||
if (aSubsetIndex !== null && bSubsetIndex !== null && aSubsetIndex !== bSubsetIndex) { | ||
return aSubsetIndex - bSubsetIndex; | ||
} | ||
return 0; | ||
}); | ||
const inOrderIterator = inOrderArray.values(); | ||
let wasResorted = false; | ||
const inOrderIterator = sortedArray.values(); | ||
const result = data.map((item) => { | ||
if (orderMap.has(item[key])) { | ||
if (getSubsetIndex(item[key], orderSets) !== null) { | ||
const sortedItem = inOrderIterator.next().value; | ||
@@ -13,0 +32,0 @@ if (sortedItem[key] !== item[key]) { |
{ | ||
"name": "@tanstack/eslint-plugin-query", | ||
"version": "5.57.0", | ||
"version": "5.57.1", | ||
"description": "ESLint plugin for TanStack Query", | ||
@@ -5,0 +5,0 @@ "author": "Eliya Cohen", |
@@ -35,7 +35,13 @@ import { RuleTester } from '@typescript-eslint/rule-tester' | ||
export function generateInvalidPermutations<T>( | ||
arr: ReadonlyArray<T>, | ||
): Array<{ invalid: Array<T>; valid: Array<T> }> { | ||
export function generateInvalidPermutations( | ||
arr: ReadonlyArray<CheckedProperties>, | ||
): Array<{ | ||
invalid: Array<CheckedProperties> | ||
valid: Array<CheckedProperties> | ||
}> { | ||
const combinations = generatePartialCombinations(arr, 2) | ||
const allPermutations: Array<{ invalid: Array<T>; valid: Array<T> }> = [] | ||
const allPermutations: Array<{ | ||
invalid: Array<CheckedProperties> | ||
valid: Array<CheckedProperties> | ||
}> = [] | ||
@@ -46,4 +52,40 @@ for (const combination of combinations) { | ||
const invalidPermutations = permutations.slice(1) | ||
if ( | ||
combination.includes('getNextPageParam') && | ||
combination.includes('getPreviousPageParam') | ||
) { | ||
if ( | ||
combination.indexOf('getNextPageParam') < | ||
combination.indexOf('getPreviousPageParam') | ||
) { | ||
// since we ignore the relative order of 'getPreviousPageParam' and 'getNextPageParam', we skip this combination (but keep the other one where `getPreviousPageParam` is before `getNextPageParam`) | ||
continue | ||
} | ||
} | ||
allPermutations.push( | ||
...invalidPermutations.map((p) => ({ invalid: p, valid: combination })), | ||
...invalidPermutations | ||
.map((p) => { | ||
// ignore the relative order of 'getPreviousPageParam' and 'getNextPageParam' | ||
const correctedValid = [...combination].sort((a, b) => { | ||
if ( | ||
(a === 'getNextPageParam' && b === 'getPreviousPageParam') || | ||
(a === 'getPreviousPageParam' && b === 'getNextPageParam') | ||
) { | ||
return p.indexOf(a) - p.indexOf(b) | ||
} | ||
return checkedProperties.indexOf(a) - checkedProperties.indexOf(b) | ||
}) | ||
return { invalid: p, valid: correctedValid } | ||
}) | ||
.filter( | ||
({ invalid }) => | ||
// if `getPreviousPageParam` and `getNextPageParam` are next to each other and `queryFn` is not present, we skip this invalid permutation | ||
Math.abs( | ||
invalid.indexOf('getNextPageParam') - | ||
invalid.indexOf('getPreviousPageParam'), | ||
) !== 1 && !invalid.includes('queryFn'), | ||
), | ||
) | ||
@@ -126,3 +168,3 @@ } | ||
({ infiniteQueryFunction, properties }) => ({ | ||
name: `incorrect property order is detected for ${infiniteQueryFunction} with order: ${properties.invalid.join(', ')}`, | ||
name: `incorrect property order is detected for ${infiniteQueryFunction} with invalid order: ${properties.invalid.join(', ')}, valid order: ${properties.valid.join(', ')}`, | ||
code: getCode({ | ||
@@ -129,0 +171,0 @@ infiniteQueryFunction: infiniteQueryFunction, |
@@ -9,3 +9,6 @@ import { describe, expect, test } from 'vitest' | ||
data: [{ key: 'a' }, { key: 'c' }, { key: 'b' }], | ||
orderArray: ['a', 'b', 'c'], | ||
orderArray: [ | ||
[['a'], ['b']], | ||
[['b'], ['c']], | ||
], | ||
key: 'key', | ||
@@ -16,3 +19,6 @@ expected: [{ key: 'a' }, { key: 'b' }, { key: 'c' }], | ||
data: [{ key: 'b' }, { key: 'a' }, { key: 'c' }], | ||
orderArray: ['a', 'b', 'c'], | ||
orderArray: [ | ||
[['a'], ['b']], | ||
[['b'], ['c']], | ||
], | ||
key: 'key', | ||
@@ -23,3 +29,6 @@ expected: [{ key: 'a' }, { key: 'b' }, { key: 'c' }], | ||
data: [{ key: 'a' }, { key: 'b' }, { key: 'c' }], | ||
orderArray: ['a', 'b', 'c'], | ||
orderArray: [ | ||
[['a'], ['b']], | ||
[['b'], ['c']], | ||
], | ||
key: 'key', | ||
@@ -30,3 +39,6 @@ expected: null, | ||
data: [{ key: 'a' }, { key: 'b' }, { key: 'c' }, { key: 'd' }], | ||
orderArray: ['a', 'b', 'c'], | ||
orderArray: [ | ||
[['a'], ['b']], | ||
[['b'], ['c']], | ||
], | ||
key: 'key', | ||
@@ -37,3 +49,6 @@ expected: null, | ||
data: [{ key: 'a' }, { key: 'b' }, { key: 'd' }, { key: 'c' }], | ||
orderArray: ['a', 'b', 'c'], | ||
orderArray: [ | ||
[['a'], ['b']], | ||
[['b'], ['c']], | ||
], | ||
key: 'key', | ||
@@ -44,3 +59,6 @@ expected: null, | ||
data: [{ key: 'd' }, { key: 'a' }, { key: 'b' }, { key: 'c' }], | ||
orderArray: ['a', 'b', 'c'], | ||
orderArray: [ | ||
[['a'], ['b']], | ||
[['b'], ['c']], | ||
], | ||
key: 'key', | ||
@@ -51,3 +69,6 @@ expected: null, | ||
data: [{ key: 'd' }, { key: 'b' }, { key: 'a' }, { key: 'c' }], | ||
orderArray: ['a', 'b', 'c'], | ||
orderArray: [ | ||
[['a'], ['b']], | ||
[['b'], ['c']], | ||
], | ||
key: 'key', | ||
@@ -54,0 +75,0 @@ expected: [{ key: 'd' }, { key: 'a' }, { key: 'b' }, { key: 'c' }], |
@@ -14,1 +14,5 @@ export const infiniteQueryFunctions = [ | ||
] as const | ||
export const sortRules = [ | ||
[['queryFn'], ['getPreviousPageParam', 'getNextPageParam']], | ||
] as const |
@@ -6,3 +6,3 @@ import { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils' | ||
import { sortDataByOrder } from './infinite-query-property-order.utils' | ||
import { checkedProperties, infiniteQueryFunctions } from './constants' | ||
import { infiniteQueryFunctions, sortRules } from './constants' | ||
import type { InfiniteQueryFunctions } from './constants' | ||
@@ -54,2 +54,4 @@ import type { ExtraRuleDocs } from '../../types' | ||
const allProperties = argument.properties | ||
// no need to sort if there is at max 1 property | ||
if (allProperties.length < 2) { | ||
@@ -75,7 +77,3 @@ return | ||
const sortedProperties = sortDataByOrder( | ||
properties, | ||
checkedProperties, | ||
'name', | ||
) | ||
const sortedProperties = sortDataByOrder(properties, sortRules, 'name') | ||
if (sortedProperties === null) { | ||
@@ -82,0 +80,0 @@ return |
export function sortDataByOrder<T, TKey extends keyof T>( | ||
data: Array<T> | ReadonlyArray<T>, | ||
orderArray: Array<T[TKey]> | ReadonlyArray<T[TKey]>, | ||
orderRules: ReadonlyArray< | ||
Readonly<[ReadonlyArray<T[TKey]>, ReadonlyArray<T[TKey]>]> | ||
>, | ||
key: TKey, | ||
): Array<T> | null { | ||
const orderMap = new Map(orderArray.map((item, index) => [item, index])) | ||
const getSubsetIndex = ( | ||
item: T[TKey], | ||
subsets: ReadonlyArray<ReadonlyArray<T[TKey]> | Array<T[TKey]>>, | ||
): number | null => { | ||
for (let i = 0; i < subsets.length; i++) { | ||
if (subsets[i]?.includes(item)) { | ||
return i | ||
} | ||
} | ||
return null | ||
} | ||
// Separate items that are in orderArray from those that are not | ||
const inOrderArray = data | ||
.filter((item) => orderMap.has(item[key])) | ||
.sort((a, b) => { | ||
const indexA = orderMap.get(a[key])! | ||
const indexB = orderMap.get(b[key])! | ||
const orderSets = orderRules.reduce( | ||
(sets, [A, B]) => [...sets, A, B], | ||
[] as Array<ReadonlyArray<T[TKey]> | Array<T[TKey]>>, | ||
) | ||
return indexA - indexB | ||
}) | ||
const inOrderArray = data.filter( | ||
(item) => getSubsetIndex(item[key], orderSets) !== null, | ||
) | ||
const inOrderIterator = inOrderArray.values() | ||
// `as boolean` is needed to avoid TS incorrectly inferring that wasResorted is always `true` | ||
let wasResorted = false as boolean | ||
// Sort by the relative order defined by the rules | ||
const sortedArray = inOrderArray.sort((a, b) => { | ||
const aKey = a[key], | ||
bKey = b[key] | ||
const aSubsetIndex = getSubsetIndex(aKey, orderSets) | ||
const bSubsetIndex = getSubsetIndex(bKey, orderSets) | ||
// If both items belong to different subsets, sort by their subset order | ||
if ( | ||
aSubsetIndex !== null && | ||
bSubsetIndex !== null && | ||
aSubsetIndex !== bSubsetIndex | ||
) { | ||
return aSubsetIndex - bSubsetIndex | ||
} | ||
// If both items belong to the same subset or neither is in the subset, keep their relative order | ||
return 0 | ||
}) | ||
const inOrderIterator = sortedArray.values() | ||
const result = data.map((item) => { | ||
if (orderMap.has(item[key])) { | ||
if (getSubsetIndex(item[key], orderSets) !== null) { | ||
const sortedItem = inOrderIterator.next().value! | ||
@@ -26,0 +55,0 @@ if (sortedItem[key] !== item[key]) { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
295135
4733