@openapi-qraft/eslint-plugin-query 2.12.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/CHANGELOG.md +9 -0
- package/README.md +131 -0
- package/dist/cjs/index.cjs +44 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.rule.cjs +116 -0
- package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.rule.cjs.map +1 -0
- package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.utils.cjs +15 -0
- package/dist/cjs/rules/no-rest-destructuring/no-rest-destructuring.utils.cjs.map +1 -0
- package/dist/cjs/rules/no-unstable-deps/no-unstable-deps.rule.cjs +126 -0
- package/dist/cjs/rules/no-unstable-deps/no-unstable-deps.rule.cjs.map +1 -0
- package/dist/cjs/rules.cjs +12 -0
- package/dist/cjs/rules.cjs.map +1 -0
- package/dist/cjs/utils/create-client-name-regex.cjs +27 -0
- package/dist/cjs/utils/create-client-name-regex.cjs.map +1 -0
- package/dist/cjs/utils/get-docs-url.cjs +6 -0
- package/dist/cjs/utils/get-docs-url.cjs.map +1 -0
- package/dist/cjs/utils/get-root-identifier.cjs +22 -0
- package/dist/cjs/utils/get-root-identifier.cjs.map +1 -0
- package/dist/esm/index.js +37 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.rule.js +113 -0
- package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.rule.js.map +1 -0
- package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.utils.js +13 -0
- package/dist/esm/rules/no-rest-destructuring/no-rest-destructuring.utils.js.map +1 -0
- package/dist/esm/rules/no-unstable-deps/no-unstable-deps.rule.js +121 -0
- package/dist/esm/rules/no-unstable-deps/no-unstable-deps.rule.js.map +1 -0
- package/dist/esm/rules.js +10 -0
- package/dist/esm/rules.js.map +1 -0
- package/dist/esm/utils/create-client-name-regex.js +25 -0
- package/dist/esm/utils/create-client-name-regex.js.map +1 -0
- package/dist/esm/utils/get-docs-url.js +4 -0
- package/dist/esm/utils/get-docs-url.js.map +1 -0
- package/dist/esm/utils/get-root-identifier.js +20 -0
- package/dist/esm/utils/get-root-identifier.js.map +1 -0
- package/dist/types/index.d.ts +23 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/rules/no-rest-destructuring/no-rest-destructuring.rule.d.ts +5 -0
- package/dist/types/rules/no-rest-destructuring/no-rest-destructuring.rule.d.ts.map +1 -0
- package/dist/types/rules/no-rest-destructuring/no-rest-destructuring.utils.d.ts +5 -0
- package/dist/types/rules/no-rest-destructuring/no-rest-destructuring.utils.d.ts.map +1 -0
- package/dist/types/rules/no-unstable-deps/no-unstable-deps.rule.d.ts +7 -0
- package/dist/types/rules/no-unstable-deps/no-unstable-deps.rule.d.ts.map +1 -0
- package/dist/types/rules.d.ts +4 -0
- package/dist/types/rules.d.ts.map +1 -0
- package/dist/types/types.d.ts +4 -0
- package/dist/types/types.d.ts.map +1 -0
- package/dist/types/utils/create-client-name-regex.d.ts +2 -0
- package/dist/types/utils/create-client-name-regex.d.ts.map +1 -0
- package/dist/types/utils/get-docs-url.d.ts +2 -0
- package/dist/types/utils/get-docs-url.d.ts.map +1 -0
- package/dist/types/utils/get-root-identifier.d.ts +3 -0
- package/dist/types/utils/get-root-identifier.d.ts.map +1 -0
- package/package.json +67 -0
- package/src/index.ts +54 -0
- package/src/rules/no-rest-destructuring/no-rest-destructuring.rule.ts +135 -0
- package/src/rules/no-rest-destructuring/no-rest-destructuring.utils.ts +11 -0
- package/src/rules/no-unstable-deps/no-unstable-deps.rule.ts +137 -0
- package/src/rules.ts +17 -0
- package/src/types.ts +3 -0
- package/src/utils/create-client-name-regex.ts +32 -0
- package/src/utils/get-docs-url.ts +2 -0
- package/src/utils/get-root-identifier.ts +25 -0
package/CHANGELOG.md
ADDED
package/README.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# @openapi-qraft/eslint-plugin-query
|
|
2
|
+
|
|
3
|
+
ESLint plugin for projects using `@openapi-qraft/react`. It helps enforce best practices around Qraft-generated hooks (e.g. `qraft.service.operation.useQuery()`, `qraft.useInfiniteQuery()`) and prevents mistakes that cause unnecessary re-renders or unstable dependencies.
|
|
4
|
+
|
|
5
|
+
- Homepage: `https://openapi-qraft.github.io/openapi-qraft/docs/eslint/eslint-plugin-query`
|
|
6
|
+
- Repository: `https://github.com/OpenAPI-Qraft/openapi-qraft`
|
|
7
|
+
|
|
8
|
+
## Requirements
|
|
9
|
+
|
|
10
|
+
- Node.js >= 18
|
|
11
|
+
- ESLint ^8.57.0 or ^9.0.0
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm i -D @openapi-qraft/eslint-plugin-query
|
|
17
|
+
# or
|
|
18
|
+
pnpm add -D @openapi-qraft/eslint-plugin-query
|
|
19
|
+
# or
|
|
20
|
+
yarn add -D @openapi-qraft/eslint-plugin-query
|
|
21
|
+
# or
|
|
22
|
+
bun add -D @openapi-qraft/eslint-plugin-query
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Usage (ESLint Flat Config)
|
|
26
|
+
|
|
27
|
+
Create or update `eslint.config.js`:
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
import pluginQraftQuery from '@openapi-qraft/eslint-plugin-query'
|
|
31
|
+
|
|
32
|
+
export default [
|
|
33
|
+
// Enable the recommended rules for this plugin
|
|
34
|
+
...pluginQraftQuery.configs['flat/recommended'],
|
|
35
|
+
// Any other config...
|
|
36
|
+
]
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
### Custom setup (Flat Config)
|
|
40
|
+
|
|
41
|
+
```js
|
|
42
|
+
import pluginQraftQuery from '@openapi-qraft/eslint-plugin-query'
|
|
43
|
+
|
|
44
|
+
export default [
|
|
45
|
+
{
|
|
46
|
+
plugins: {
|
|
47
|
+
'@openapi-qraft/query': pluginQraftQuery,
|
|
48
|
+
},
|
|
49
|
+
rules: {
|
|
50
|
+
'@openapi-qraft/query/no-rest-destructuring': 'warn',
|
|
51
|
+
'@openapi-qraft/query/no-unstable-deps': 'error',
|
|
52
|
+
},
|
|
53
|
+
},
|
|
54
|
+
]
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Usage (Legacy config)
|
|
58
|
+
|
|
59
|
+
Add to your `.eslintrc`:
|
|
60
|
+
|
|
61
|
+
```json
|
|
62
|
+
{
|
|
63
|
+
"extends": [
|
|
64
|
+
"plugin:@openapi-qraft/query/recommended"
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Custom setup (Legacy)
|
|
70
|
+
|
|
71
|
+
```json
|
|
72
|
+
{
|
|
73
|
+
"plugins": ["@openapi-qraft/query"],
|
|
74
|
+
"rules": {
|
|
75
|
+
"@openapi-qraft/query/no-rest-destructuring": "warn",
|
|
76
|
+
"@openapi-qraft/query/no-unstable-deps": "error"
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## Options
|
|
82
|
+
|
|
83
|
+
Some rules detect Qraft-generated hooks only when they are called as methods on your client instance (e.g. `qraft.service.operation.useQuery()`).
|
|
84
|
+
To support custom client names, each rule accepts an optional `clientNamePattern` (string or regex literal) option. By default, it matches the case-insensitive regex `/qraft|api/i`.
|
|
85
|
+
|
|
86
|
+
Example (Flat Config):
|
|
87
|
+
|
|
88
|
+
```js
|
|
89
|
+
import pluginQraftQuery from '@openapi-qraft/eslint-plugin-query'
|
|
90
|
+
|
|
91
|
+
export default [
|
|
92
|
+
{
|
|
93
|
+
plugins: { '@openapi-qraft/query': pluginQraftQuery },
|
|
94
|
+
rules: {
|
|
95
|
+
'@openapi-qraft/query/no-rest-destructuring': [
|
|
96
|
+
'warn',
|
|
97
|
+
{ clientNamePattern: '/myQraftClient/i' },
|
|
98
|
+
],
|
|
99
|
+
'@openapi-qraft/query/no-unstable-deps': [
|
|
100
|
+
'error',
|
|
101
|
+
{ clientNamePattern: '/myQraftClient/i' },
|
|
102
|
+
],
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
]
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Configurations
|
|
109
|
+
|
|
110
|
+
This plugin ships with the following shareable configurations:
|
|
111
|
+
|
|
112
|
+
- `plugin:@openapi-qraft/query/recommended` (Legacy)
|
|
113
|
+
- `plugin.configs['flat/recommended']` (Flat)
|
|
114
|
+
|
|
115
|
+
They enable the rules as follows:
|
|
116
|
+
|
|
117
|
+
- `@openapi-qraft/query/no-rest-destructuring`: warn
|
|
118
|
+
- `@openapi-qraft/query/no-unstable-deps`: error
|
|
119
|
+
|
|
120
|
+
## Rules
|
|
121
|
+
|
|
122
|
+
- `@openapi-qraft/query/no-rest-destructuring` — Disallow object rest destructuring on query results. Recommended: warn. Docs: `https://openapi-qraft.github.io/openapi-qraft/docs/eslint/no-rest-destructuring`
|
|
123
|
+
- `@openapi-qraft/query/no-unstable-deps` — Disallow putting the result of query hooks directly in a React hook dependency array. Recommended: error. Docs: `https://openapi-qraft.github.io/openapi-qraft/docs/eslint/no-unstable-deps`
|
|
124
|
+
|
|
125
|
+
## TypeScript
|
|
126
|
+
|
|
127
|
+
This plugin is implemented with `@typescript-eslint/utils` and works in both JavaScript and TypeScript projects. No special TypeScript configuration is required beyond your project's usual setup.
|
|
128
|
+
|
|
129
|
+
## License
|
|
130
|
+
|
|
131
|
+
MIT © OpenAPI Qraft
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var rules = require('./rules.cjs');
|
|
6
|
+
|
|
7
|
+
const plugin = {
|
|
8
|
+
meta: {
|
|
9
|
+
name: '@openapi-qraft/eslint-plugin-query'
|
|
10
|
+
},
|
|
11
|
+
configs: {},
|
|
12
|
+
rules: rules.rules
|
|
13
|
+
};
|
|
14
|
+
// Assign configs here so we can reference `plugin`
|
|
15
|
+
Object.assign(plugin.configs, {
|
|
16
|
+
recommended: {
|
|
17
|
+
plugins: [
|
|
18
|
+
'@openapi-qraft/query'
|
|
19
|
+
],
|
|
20
|
+
rules: {
|
|
21
|
+
'@openapi-qraft/query/no-rest-destructuring': 'warn',
|
|
22
|
+
'@openapi-qraft/query/no-unstable-deps': 'error'
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
'flat/recommended': [
|
|
26
|
+
{
|
|
27
|
+
name: 'openapi-qraft/query/flat/recommended',
|
|
28
|
+
plugins: {
|
|
29
|
+
'@openapi-qraft/query': plugin
|
|
30
|
+
},
|
|
31
|
+
rules: {
|
|
32
|
+
'@openapi-qraft/query/no-rest-destructuring': 'warn',
|
|
33
|
+
'@openapi-qraft/query/no-unstable-deps': 'error'
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
]
|
|
37
|
+
});
|
|
38
|
+
const configs = plugin.configs;
|
|
39
|
+
|
|
40
|
+
exports.rules = rules.rules;
|
|
41
|
+
exports.configs = configs;
|
|
42
|
+
exports.default = plugin;
|
|
43
|
+
exports.plugin = plugin;
|
|
44
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.cjs","sources":["../../src/index.ts"],"sourcesContent":["import type { RuleModule } from '@typescript-eslint/utils/ts-eslint';\nimport type { ESLint, Linter } from 'eslint';\nimport { rules } from './rules';\n\ntype RuleKey = keyof typeof rules;\n\nexport interface 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.Config>;\n };\n}\n\nexport const plugin: Plugin = {\n meta: {\n name: '@openapi-qraft/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: ['@openapi-qraft/query'],\n rules: {\n '@openapi-qraft/query/no-rest-destructuring': 'warn',\n '@openapi-qraft/query/no-unstable-deps': 'error',\n },\n },\n 'flat/recommended': [\n {\n name: 'openapi-qraft/query/flat/recommended',\n plugins: {\n '@openapi-qraft/query': plugin,\n },\n rules: {\n '@openapi-qraft/query/no-rest-destructuring': 'warn',\n '@openapi-qraft/query/no-unstable-deps': 'error',\n },\n },\n ],\n});\n\n// Reexport rules & configs for the Legacy config\nexport { rules };\nexport const configs = plugin.configs;\n\n/**\n * @alias\n * @type {Plugin}\n **/\nexport default plugin;\n"],"names":["plugin","meta","name","configs","rules","Object","assign","recommended","plugins"],"mappings":";;;;;;MAcaA,MAAiB,GAAA;IAC5BC,IAAM,EAAA;QACJC,IAAM,EAAA,oCAAA;AACR,KAAA;AACAC,IAAAA,OAAAA,EAAS,EAAC;AACVC,WAAAA,WAAAA;AACF,EAAE;AAEF;AACAC,MAAAA,CAAOC,MAAM,CAACN,MAAOG,CAAAA,OAAO,EAAE;IAC5BI,WAAa,EAAA;QACXC,OAAS,EAAA;AAAC,YAAA,sBAAA;AAAuB,SAAA;QACjCJ,KAAO,EAAA;YACL,4CAA8C,EAAA,MAAA;YAC9C,uCAAyC,EAAA,OAAA;AAC3C,SAAA;AACF,KAAA;IACA,kBAAoB,EAAA;AAClB,QAAA;YACEF,IAAM,EAAA,sCAAA;YACNM,OAAS,EAAA;gBACP,sBAAwBR,EAAAA,MAAAA;AAC1B,aAAA;YACAI,KAAO,EAAA;gBACL,4CAA8C,EAAA,MAAA;gBAC9C,uCAAyC,EAAA,OAAA;AAC3C,aAAA;AACF,SAAA;AACD,KAAA;AACH,CAAA,CAAA,CAAA;AAIaD,MAAAA,OAAAA,GAAUH,MAAOG,CAAAA;;;;;;;"}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('@typescript-eslint/utils');
|
|
4
|
+
var createClientNameRegex = require('../../utils/create-client-name-regex.cjs');
|
|
5
|
+
var getDocsUrl = require('../../utils/get-docs-url.cjs');
|
|
6
|
+
var getRootIdentifier = require('../../utils/get-root-identifier.cjs');
|
|
7
|
+
var noRestDestructuring_utils = require('./no-rest-destructuring.utils.cjs');
|
|
8
|
+
|
|
9
|
+
const name = 'no-rest-destructuring';
|
|
10
|
+
const createRule = utils.ESLintUtils.RuleCreator(getDocsUrl.getDocsUrl);
|
|
11
|
+
const queryHooks = [
|
|
12
|
+
'useQuery',
|
|
13
|
+
'useQueries',
|
|
14
|
+
'useInfiniteQuery',
|
|
15
|
+
'useSuspenseQuery',
|
|
16
|
+
'useSuspenseQueries',
|
|
17
|
+
'useSuspenseInfiniteQuery'
|
|
18
|
+
];
|
|
19
|
+
const rule = createRule({
|
|
20
|
+
name,
|
|
21
|
+
meta: {
|
|
22
|
+
type: 'problem',
|
|
23
|
+
docs: {
|
|
24
|
+
description: 'Disallows rest destructuring in queries',
|
|
25
|
+
recommended: 'warn'
|
|
26
|
+
},
|
|
27
|
+
messages: {
|
|
28
|
+
objectRestDestructure: `Object rest destructuring on a query will observe all changes to the query, leading to excessive re-renders.`
|
|
29
|
+
},
|
|
30
|
+
schema: [
|
|
31
|
+
{
|
|
32
|
+
type: 'object',
|
|
33
|
+
properties: {
|
|
34
|
+
clientNamePattern: {
|
|
35
|
+
type: 'string'
|
|
36
|
+
}
|
|
37
|
+
},
|
|
38
|
+
additionalProperties: false
|
|
39
|
+
}
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
defaultOptions: [
|
|
43
|
+
{}
|
|
44
|
+
],
|
|
45
|
+
create: (context)=>{
|
|
46
|
+
const option = context.options[0] ?? {};
|
|
47
|
+
const clientRegex = createClientNameRegex.createClientNameRegex(option.clientNamePattern);
|
|
48
|
+
const queryResultVariables = new Set();
|
|
49
|
+
return {
|
|
50
|
+
CallExpression: (node)=>{
|
|
51
|
+
if (node.parent.type !== utils.AST_NODE_TYPES.VariableDeclarator) return;
|
|
52
|
+
const callee = node.callee;
|
|
53
|
+
if (callee.type !== utils.AST_NODE_TYPES.MemberExpression) return;
|
|
54
|
+
const hookName = getHookNameIfTargetFromClient(clientRegex, callee);
|
|
55
|
+
if (!hookName) return;
|
|
56
|
+
const returnValue = node.parent.id;
|
|
57
|
+
if (hookName !== 'useQueries' && hookName !== 'useSuspenseQueries') {
|
|
58
|
+
if (noRestDestructuring_utils.NoRestDestructuringUtils.isObjectRestDestructuring(returnValue)) {
|
|
59
|
+
return context.report({
|
|
60
|
+
node: node.parent,
|
|
61
|
+
messageId: 'objectRestDestructure'
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
if (returnValue.type === utils.AST_NODE_TYPES.Identifier) {
|
|
65
|
+
queryResultVariables.add(returnValue.name);
|
|
66
|
+
}
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (returnValue.type !== utils.AST_NODE_TYPES.ArrayPattern) {
|
|
70
|
+
if (returnValue.type === utils.AST_NODE_TYPES.Identifier) {
|
|
71
|
+
queryResultVariables.add(returnValue.name);
|
|
72
|
+
}
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
returnValue.elements.forEach((queryResult)=>{
|
|
76
|
+
if (queryResult === null) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
if (noRestDestructuring_utils.NoRestDestructuringUtils.isObjectRestDestructuring(queryResult)) {
|
|
80
|
+
context.report({
|
|
81
|
+
node: queryResult,
|
|
82
|
+
messageId: 'objectRestDestructure'
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
},
|
|
87
|
+
VariableDeclarator: (node)=>{
|
|
88
|
+
if (node.init?.type === utils.AST_NODE_TYPES.Identifier && queryResultVariables.has(node.init.name) && noRestDestructuring_utils.NoRestDestructuringUtils.isObjectRestDestructuring(node.id)) {
|
|
89
|
+
context.report({
|
|
90
|
+
node,
|
|
91
|
+
messageId: 'objectRestDestructure'
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
},
|
|
95
|
+
SpreadElement: (node)=>{
|
|
96
|
+
if (node.argument.type === utils.AST_NODE_TYPES.Identifier && queryResultVariables.has(node.argument.name)) {
|
|
97
|
+
context.report({
|
|
98
|
+
node,
|
|
99
|
+
messageId: 'objectRestDestructure'
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
function getHookNameIfTargetFromClient(clientRegex, callee) {
|
|
107
|
+
if (callee.property.type !== utils.AST_NODE_TYPES.Identifier) return;
|
|
108
|
+
const name = callee.property.name;
|
|
109
|
+
if (!queryHooks.includes(name)) return;
|
|
110
|
+
const root = getRootIdentifier.getRootIdentifier(callee.object);
|
|
111
|
+
return root && clientRegex.test(root.name) ? name : undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
exports.name = name;
|
|
115
|
+
exports.rule = rule;
|
|
116
|
+
//# sourceMappingURL=no-rest-destructuring.rule.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-rest-destructuring.rule.cjs","sources":["../../../../src/rules/no-rest-destructuring/no-rest-destructuring.rule.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport type { ExtraRuleDocs } from '../../types';\nimport { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';\nimport { createClientNameRegex } from '../../utils/create-client-name-regex';\nimport { getDocsUrl } from '../../utils/get-docs-url';\nimport { getRootIdentifier } from '../../utils/get-root-identifier';\nimport { NoRestDestructuringUtils } from './no-rest-destructuring.utils';\n\nexport const name = 'no-rest-destructuring';\n\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl);\n\nconst queryHooks = [\n 'useQuery',\n 'useQueries',\n 'useInfiniteQuery',\n 'useSuspenseQuery',\n 'useSuspenseQueries',\n 'useSuspenseInfiniteQuery',\n];\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description: 'Disallows rest destructuring in queries',\n recommended: 'warn',\n },\n messages: {\n objectRestDestructure: `Object rest destructuring on a query will observe all changes to the query, leading to excessive re-renders.`,\n },\n schema: [\n {\n type: 'object',\n properties: {\n clientNamePattern: { type: 'string' },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{}],\n\n create: (context) => {\n const option =\n (context.options[0] as { clientNamePattern?: string } | undefined) ?? {};\n\n const clientRegex = createClientNameRegex(option.clientNamePattern);\n\n const queryResultVariables = new Set<string>();\n\n return {\n CallExpression: (node) => {\n if (node.parent.type !== AST_NODE_TYPES.VariableDeclarator) return;\n\n const callee = node.callee;\n if (callee.type !== AST_NODE_TYPES.MemberExpression) return;\n const hookName = getHookNameIfTargetFromClient(clientRegex, callee);\n if (!hookName) return;\n const returnValue = node.parent.id;\n\n if (hookName !== 'useQueries' && hookName !== 'useSuspenseQueries') {\n if (NoRestDestructuringUtils.isObjectRestDestructuring(returnValue)) {\n return context.report({\n node: node.parent,\n messageId: 'objectRestDestructure',\n });\n }\n\n if (returnValue.type === AST_NODE_TYPES.Identifier) {\n queryResultVariables.add(returnValue.name);\n }\n\n return;\n }\n\n if (returnValue.type !== AST_NODE_TYPES.ArrayPattern) {\n if (returnValue.type === AST_NODE_TYPES.Identifier) {\n queryResultVariables.add(returnValue.name);\n }\n return;\n }\n\n returnValue.elements.forEach((queryResult) => {\n if (queryResult === null) {\n return;\n }\n if (NoRestDestructuringUtils.isObjectRestDestructuring(queryResult)) {\n context.report({\n node: queryResult,\n messageId: 'objectRestDestructure',\n });\n }\n });\n },\n\n VariableDeclarator: (node) => {\n if (\n node.init?.type === AST_NODE_TYPES.Identifier &&\n queryResultVariables.has(node.init.name) &&\n NoRestDestructuringUtils.isObjectRestDestructuring(node.id)\n ) {\n context.report({\n node,\n messageId: 'objectRestDestructure',\n });\n }\n },\n\n SpreadElement: (node) => {\n if (\n node.argument.type === AST_NODE_TYPES.Identifier &&\n queryResultVariables.has(node.argument.name)\n ) {\n context.report({\n node,\n messageId: 'objectRestDestructure',\n });\n }\n },\n };\n },\n});\n\nfunction getHookNameIfTargetFromClient(\n clientRegex: RegExp,\n callee: TSESTree.MemberExpression\n): string | undefined {\n if (callee.property.type !== AST_NODE_TYPES.Identifier) return;\n const name = callee.property.name;\n if (!queryHooks.includes(name)) return;\n const root = getRootIdentifier(callee.object);\n return root && clientRegex.test(root.name) ? name : undefined;\n}\n"],"names":["name","createRule","ESLintUtils","RuleCreator","getDocsUrl","queryHooks","rule","meta","type","docs","description","recommended","messages","objectRestDestructure","schema","properties","clientNamePattern","additionalProperties","defaultOptions","create","context","option","options","clientRegex","createClientNameRegex","queryResultVariables","Set","CallExpression","node","parent","AST_NODE_TYPES","VariableDeclarator","callee","MemberExpression","hookName","getHookNameIfTargetFromClient","returnValue","id","NoRestDestructuringUtils","isObjectRestDestructuring","report","messageId","Identifier","add","ArrayPattern","elements","forEach","queryResult","init","has","SpreadElement","argument","property","includes","root","getRootIdentifier","object","test","undefined"],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('@typescript-eslint/utils');
|
|
4
|
+
|
|
5
|
+
const NoRestDestructuringUtils = {
|
|
6
|
+
isObjectRestDestructuring (node) {
|
|
7
|
+
if (node.type !== utils.AST_NODE_TYPES.ObjectPattern) {
|
|
8
|
+
return false;
|
|
9
|
+
}
|
|
10
|
+
return node.properties.some((p)=>p.type === utils.AST_NODE_TYPES.RestElement);
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
exports.NoRestDestructuringUtils = NoRestDestructuringUtils;
|
|
15
|
+
//# sourceMappingURL=no-rest-destructuring.utils.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-rest-destructuring.utils.cjs","sources":["../../../../src/rules/no-rest-destructuring/no-rest-destructuring.utils.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nexport const NoRestDestructuringUtils = {\n isObjectRestDestructuring(node: TSESTree.Node): boolean {\n if (node.type !== AST_NODE_TYPES.ObjectPattern) {\n return false;\n }\n return node.properties.some((p) => p.type === AST_NODE_TYPES.RestElement);\n },\n};\n"],"names":["NoRestDestructuringUtils","isObjectRestDestructuring","node","type","AST_NODE_TYPES","ObjectPattern","properties","some","p","RestElement"],"mappings":";;;;MAGaA,wBAA2B,GAAA;AACtCC,IAAAA,yBAAAA,CAAAA,CAA0BC,IAAmB,EAAA;AAC3C,QAAA,IAAIA,IAAKC,CAAAA,IAAI,KAAKC,oBAAAA,CAAeC,aAAa,EAAE;YAC9C,OAAO,KAAA,CAAA;AACT,SAAA;QACA,OAAOH,IAAAA,CAAKI,UAAU,CAACC,IAAI,CAAC,CAACC,CAAAA,GAAMA,CAAEL,CAAAA,IAAI,KAAKC,oBAAAA,CAAeK,WAAW,CAAA,CAAA;AAC1E,KAAA;AACF;;;;"}
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('@typescript-eslint/utils');
|
|
4
|
+
var createClientNameRegex = require('../../utils/create-client-name-regex.cjs');
|
|
5
|
+
var getDocsUrl = require('../../utils/get-docs-url.cjs');
|
|
6
|
+
var getRootIdentifier = require('../../utils/get-root-identifier.cjs');
|
|
7
|
+
|
|
8
|
+
const name = 'no-unstable-deps';
|
|
9
|
+
const reactHookNames = [
|
|
10
|
+
'useEffect',
|
|
11
|
+
'useCallback',
|
|
12
|
+
'useMemo'
|
|
13
|
+
];
|
|
14
|
+
const useQueryHookNames = [
|
|
15
|
+
'useQuery',
|
|
16
|
+
'useSuspenseQuery',
|
|
17
|
+
'useQueries',
|
|
18
|
+
'useSuspenseQueries',
|
|
19
|
+
'useInfiniteQuery',
|
|
20
|
+
'useSuspenseInfiniteQuery'
|
|
21
|
+
];
|
|
22
|
+
const allHookNames = [
|
|
23
|
+
'useMutation',
|
|
24
|
+
...useQueryHookNames
|
|
25
|
+
];
|
|
26
|
+
const createRule = utils.ESLintUtils.RuleCreator(getDocsUrl.getDocsUrl);
|
|
27
|
+
const rule = createRule({
|
|
28
|
+
name,
|
|
29
|
+
meta: {
|
|
30
|
+
type: 'problem',
|
|
31
|
+
docs: {
|
|
32
|
+
description: 'Disallow putting the result of query hooks directly in a React hook dependency array',
|
|
33
|
+
recommended: 'error'
|
|
34
|
+
},
|
|
35
|
+
messages: {
|
|
36
|
+
noUnstableDeps: `The result of {{queryHook}} is not referentially stable, so don't pass it directly into the dependencies array of {{reactHook}}. Instead, destructure the return value of {{queryHook}} and pass the destructured values into the dependency array of {{reactHook}}.`
|
|
37
|
+
},
|
|
38
|
+
schema: [
|
|
39
|
+
{
|
|
40
|
+
type: 'object',
|
|
41
|
+
properties: {
|
|
42
|
+
clientNamePattern: {
|
|
43
|
+
type: 'string'
|
|
44
|
+
}
|
|
45
|
+
},
|
|
46
|
+
additionalProperties: false
|
|
47
|
+
}
|
|
48
|
+
]
|
|
49
|
+
},
|
|
50
|
+
defaultOptions: [
|
|
51
|
+
{}
|
|
52
|
+
],
|
|
53
|
+
create: (context)=>{
|
|
54
|
+
const option = context.options[0] ?? {};
|
|
55
|
+
const clientRegex = createClientNameRegex.createClientNameRegex(option.clientNamePattern);
|
|
56
|
+
const trackedVariables = {};
|
|
57
|
+
const hookAliasMap = {};
|
|
58
|
+
function getReactHook(node) {
|
|
59
|
+
if (node.callee.type === 'Identifier') {
|
|
60
|
+
const calleeName = node.callee.name;
|
|
61
|
+
if (reactHookNames.includes(calleeName) || calleeName in hookAliasMap) {
|
|
62
|
+
// Return the actually used identifier (could be alias)
|
|
63
|
+
return calleeName;
|
|
64
|
+
}
|
|
65
|
+
} else if (node.callee.type === 'MemberExpression' && node.callee.object.type === 'Identifier' && node.callee.object.name === 'React' && node.callee.property.type === 'Identifier' && reactHookNames.includes(node.callee.property.name)) {
|
|
66
|
+
return node.callee.property.name;
|
|
67
|
+
}
|
|
68
|
+
return undefined;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
ImportDeclaration (node) {
|
|
72
|
+
if (node.specifiers.length > 0 && node.importKind === 'value' && node.source.value === 'React') {
|
|
73
|
+
node.specifiers.forEach((specifier)=>{
|
|
74
|
+
if (specifier.type === utils.AST_NODE_TYPES.ImportSpecifier && specifier.imported.type === utils.AST_NODE_TYPES.Identifier && reactHookNames.includes(specifier.imported.name)) {
|
|
75
|
+
hookAliasMap[specifier.local.name] = specifier.imported.name;
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
VariableDeclarator (node) {
|
|
81
|
+
if (node.init?.type !== utils.AST_NODE_TYPES.CallExpression) return;
|
|
82
|
+
const hook = isQueryHookFromClient(clientRegex, node.init);
|
|
83
|
+
if (!hook) return;
|
|
84
|
+
if (node.id.type === utils.AST_NODE_TYPES.Identifier) {
|
|
85
|
+
trackedVariables[node.id.name] = hook;
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
CallExpression: (node)=>{
|
|
89
|
+
const reactHook = getReactHook(node);
|
|
90
|
+
if (!reactHook) return;
|
|
91
|
+
if (node.arguments.length <= 1) return;
|
|
92
|
+
if (node.arguments[1]?.type !== utils.AST_NODE_TYPES.ArrayExpression) return;
|
|
93
|
+
const depsArray = node.arguments[1].elements;
|
|
94
|
+
depsArray.forEach((dep)=>{
|
|
95
|
+
if (dep?.type !== utils.AST_NODE_TYPES.Identifier) return;
|
|
96
|
+
const queryHook = trackedVariables[dep.name];
|
|
97
|
+
if (!queryHook) return;
|
|
98
|
+
context.report({
|
|
99
|
+
node: dep,
|
|
100
|
+
messageId: 'noUnstableDeps',
|
|
101
|
+
data: {
|
|
102
|
+
queryHook,
|
|
103
|
+
reactHook
|
|
104
|
+
}
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
function isQueryHookFromClient(clientRegex, call) {
|
|
112
|
+
if (call.callee.type !== utils.AST_NODE_TYPES.MemberExpression) return null;
|
|
113
|
+
const member = call.callee;
|
|
114
|
+
if (member.property.type !== utils.AST_NODE_TYPES.Identifier) return null;
|
|
115
|
+
const hook = member.property.name;
|
|
116
|
+
if (!allHookNames.includes(hook)) return null;
|
|
117
|
+
const root = getRootIdentifier.getRootIdentifier(member.object);
|
|
118
|
+
if (!root) return null;
|
|
119
|
+
return clientRegex.test(root.name) ? hook : null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
exports.name = name;
|
|
123
|
+
exports.reactHookNames = reactHookNames;
|
|
124
|
+
exports.rule = rule;
|
|
125
|
+
exports.useQueryHookNames = useQueryHookNames;
|
|
126
|
+
//# sourceMappingURL=no-unstable-deps.rule.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"no-unstable-deps.rule.cjs","sources":["../../../../src/rules/no-unstable-deps/no-unstable-deps.rule.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport type { ExtraRuleDocs } from '../../types';\nimport { AST_NODE_TYPES, ESLintUtils } from '@typescript-eslint/utils';\nimport { createClientNameRegex } from '../../utils/create-client-name-regex';\nimport { getDocsUrl } from '../../utils/get-docs-url';\nimport { getRootIdentifier } from '../../utils/get-root-identifier';\n\nexport const name = 'no-unstable-deps';\n\nexport const reactHookNames = ['useEffect', 'useCallback', 'useMemo'];\nexport const useQueryHookNames = [\n 'useQuery',\n 'useSuspenseQuery',\n 'useQueries',\n 'useSuspenseQueries',\n 'useInfiniteQuery',\n 'useSuspenseInfiniteQuery',\n];\nconst allHookNames = ['useMutation', ...useQueryHookNames];\nconst createRule = ESLintUtils.RuleCreator<ExtraRuleDocs>(getDocsUrl);\n\nexport const rule = createRule({\n name,\n meta: {\n type: 'problem',\n docs: {\n description:\n 'Disallow putting the result of query hooks directly in a React hook dependency array',\n recommended: 'error',\n },\n messages: {\n noUnstableDeps: `The result of {{queryHook}} is not referentially stable, so don't pass it directly into the dependencies array of {{reactHook}}. Instead, destructure the return value of {{queryHook}} and pass the destructured values into the dependency array of {{reactHook}}.`,\n },\n schema: [\n {\n type: 'object',\n properties: {\n clientNamePattern: { type: 'string' },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{}],\n\n create: (context) => {\n const option =\n (context.options[0] as { clientNamePattern?: string } | undefined) ?? {};\n const clientRegex = createClientNameRegex(option.clientNamePattern);\n\n const trackedVariables: Record<string, string> = {};\n const hookAliasMap: Record<string, string> = {};\n\n function getReactHook(node: TSESTree.CallExpression): string | undefined {\n if (node.callee.type === 'Identifier') {\n const calleeName = node.callee.name;\n if (reactHookNames.includes(calleeName) || calleeName in hookAliasMap) {\n // Return the actually used identifier (could be alias)\n return calleeName;\n }\n } else if (\n node.callee.type === 'MemberExpression' &&\n node.callee.object.type === 'Identifier' &&\n node.callee.object.name === 'React' &&\n node.callee.property.type === 'Identifier' &&\n reactHookNames.includes(node.callee.property.name)\n ) {\n return node.callee.property.name;\n }\n return undefined;\n }\n\n return {\n ImportDeclaration(node: TSESTree.ImportDeclaration) {\n if (\n node.specifiers.length > 0 &&\n node.importKind === 'value' &&\n node.source.value === 'React'\n ) {\n node.specifiers.forEach((specifier) => {\n if (\n specifier.type === AST_NODE_TYPES.ImportSpecifier &&\n specifier.imported.type === AST_NODE_TYPES.Identifier &&\n reactHookNames.includes(specifier.imported.name)\n ) {\n hookAliasMap[specifier.local.name] = specifier.imported.name;\n }\n });\n }\n },\n\n VariableDeclarator(node) {\n if (node.init?.type !== AST_NODE_TYPES.CallExpression) return;\n const hook = isQueryHookFromClient(clientRegex, node.init);\n if (!hook) return;\n if (node.id.type === AST_NODE_TYPES.Identifier) {\n trackedVariables[node.id.name] = hook;\n }\n },\n CallExpression: (node) => {\n const reactHook = getReactHook(node);\n if (!reactHook) return;\n if (node.arguments.length <= 1) return;\n if (node.arguments[1]?.type !== AST_NODE_TYPES.ArrayExpression) return;\n\n const depsArray = node.arguments[1].elements;\n depsArray.forEach((dep) => {\n if (dep?.type !== AST_NODE_TYPES.Identifier) return;\n const queryHook = trackedVariables[dep.name];\n if (!queryHook) return;\n context.report({\n node: dep,\n messageId: 'noUnstableDeps',\n data: {\n queryHook,\n reactHook,\n },\n });\n });\n },\n };\n },\n});\n\nfunction isQueryHookFromClient(\n clientRegex: RegExp,\n call: TSESTree.CallExpression\n): string | null {\n if (call.callee.type !== AST_NODE_TYPES.MemberExpression) return null;\n const member = call.callee;\n if (member.property.type !== AST_NODE_TYPES.Identifier) return null;\n const hook = member.property.name;\n if (!allHookNames.includes(hook)) return null;\n const root = getRootIdentifier(member.object);\n if (!root) return null;\n return clientRegex.test(root.name) ? hook : null;\n}\n"],"names":["name","reactHookNames","useQueryHookNames","allHookNames","createRule","ESLintUtils","RuleCreator","getDocsUrl","rule","meta","type","docs","description","recommended","messages","noUnstableDeps","schema","properties","clientNamePattern","additionalProperties","defaultOptions","create","context","option","options","clientRegex","createClientNameRegex","trackedVariables","hookAliasMap","getReactHook","node","callee","calleeName","includes","object","property","undefined","ImportDeclaration","specifiers","length","importKind","source","value","forEach","specifier","AST_NODE_TYPES","ImportSpecifier","imported","Identifier","local","VariableDeclarator","init","CallExpression","hook","isQueryHookFromClient","id","reactHook","arguments","ArrayExpression","depsArray","elements","dep","queryHook","report","messageId","data","call","MemberExpression","member","root","getRootIdentifier","test"],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var noRestDestructuring_rule = require('./rules/no-rest-destructuring/no-rest-destructuring.rule.cjs');
|
|
4
|
+
var noUnstableDeps_rule = require('./rules/no-unstable-deps/no-unstable-deps.rule.cjs');
|
|
5
|
+
|
|
6
|
+
const rules = {
|
|
7
|
+
[noRestDestructuring_rule.name]: noRestDestructuring_rule.rule,
|
|
8
|
+
[noUnstableDeps_rule.name]: noUnstableDeps_rule.rule
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
exports.rules = rules;
|
|
12
|
+
//# sourceMappingURL=rules.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.cjs","sources":["../../src/rules.ts"],"sourcesContent":["import type { ESLintUtils } from '@typescript-eslint/utils';\nimport type { ExtraRuleDocs } from './types';\nimport * as noRestDestructuring from './rules/no-rest-destructuring/no-rest-destructuring.rule';\nimport * as noUnstableDeps from './rules/no-unstable-deps/no-unstable-deps.rule';\n\nexport const rules: Record<\n string,\n ESLintUtils.RuleModule<\n string,\n ReadonlyArray<unknown>,\n ExtraRuleDocs,\n ESLintUtils.RuleListener\n >\n> = {\n [noRestDestructuring.name]: noRestDestructuring.rule,\n [noUnstableDeps.name]: noUnstableDeps.rule,\n};\n"],"names":["rules","noRestDestructuring","noUnstableDeps"],"mappings":";;;;;MAKaA,KAQT,GAAA;AACF,IAAA,CAACC,6BAAwB,GAAGA,6BAAwB;AACpD,IAAA,CAACC,wBAAmB,GAAGA,wBAAmB;AAC5C;;;;"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
function createClientNameRegex(clientNamePattern) {
|
|
4
|
+
clientNamePattern = clientNamePattern?.trim();
|
|
5
|
+
if (clientNamePattern) {
|
|
6
|
+
// Check if pattern is in regex format: /pattern/flags
|
|
7
|
+
const regexMatch = clientNamePattern.match(/^\/(.*)\/([gimuy]*)$/);
|
|
8
|
+
if (regexMatch) {
|
|
9
|
+
const regexPattern = regexMatch[1].trim();
|
|
10
|
+
const flags = regexMatch[2];
|
|
11
|
+
// Validate that regex pattern is not empty or whitespace-only
|
|
12
|
+
if (regexPattern === '') {
|
|
13
|
+
throw new Error('clientNamePattern cannot be empty or contain only whitespace');
|
|
14
|
+
}
|
|
15
|
+
return new RegExp(regexPattern, flags);
|
|
16
|
+
}
|
|
17
|
+
// Fallback to treating as plain string pattern
|
|
18
|
+
return new RegExp(clientNamePattern);
|
|
19
|
+
} else if (clientNamePattern === '') {
|
|
20
|
+
throw new Error('clientNamePattern cannot be empty or contain only whitespace');
|
|
21
|
+
}
|
|
22
|
+
// Default if no pattern provided
|
|
23
|
+
return /qraft|api/i;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
exports.createClientNameRegex = createClientNameRegex;
|
|
27
|
+
//# sourceMappingURL=create-client-name-regex.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-client-name-regex.cjs","sources":["../../../src/utils/create-client-name-regex.ts"],"sourcesContent":["export function createClientNameRegex(clientNamePattern: string | undefined) {\n clientNamePattern = clientNamePattern?.trim();\n\n if (clientNamePattern) {\n // Check if pattern is in regex format: /pattern/flags\n const regexMatch = clientNamePattern.match(/^\\/(.*)\\/([gimuy]*)$/);\n\n if (regexMatch) {\n const regexPattern = regexMatch[1].trim();\n const flags = regexMatch[2];\n\n // Validate that regex pattern is not empty or whitespace-only\n if (regexPattern === '') {\n throw new Error(\n 'clientNamePattern cannot be empty or contain only whitespace'\n );\n }\n\n return new RegExp(regexPattern, flags);\n }\n\n // Fallback to treating as plain string pattern\n return new RegExp(clientNamePattern);\n } else if (clientNamePattern === '') {\n throw new Error(\n 'clientNamePattern cannot be empty or contain only whitespace'\n );\n }\n\n // Default if no pattern provided\n return /qraft|api/i;\n}\n"],"names":["createClientNameRegex","clientNamePattern","trim","regexMatch","match","regexPattern","flags","Error","RegExp"],"mappings":";;AAAO,SAASA,sBAAsBC,iBAAqC,EAAA;AACzEA,IAAAA,iBAAAA,GAAoBA,iBAAmBC,EAAAA,IAAAA,EAAAA,CAAAA;AAEvC,IAAA,IAAID,iBAAmB,EAAA;;QAErB,MAAME,UAAAA,GAAaF,iBAAkBG,CAAAA,KAAK,CAAC,sBAAA,CAAA,CAAA;AAE3C,QAAA,IAAID,UAAY,EAAA;AACd,YAAA,MAAME,YAAeF,GAAAA,UAAU,CAAC,CAAA,CAAE,CAACD,IAAI,EAAA,CAAA;YACvC,MAAMI,KAAAA,GAAQH,UAAU,CAAC,CAAE,CAAA,CAAA;;AAG3B,YAAA,IAAIE,iBAAiB,EAAI,EAAA;AACvB,gBAAA,MAAM,IAAIE,KACR,CAAA,8DAAA,CAAA,CAAA;AAEJ,aAAA;YAEA,OAAO,IAAIC,OAAOH,YAAcC,EAAAA,KAAAA,CAAAA,CAAAA;AAClC,SAAA;;AAGA,QAAA,OAAO,IAAIE,MAAOP,CAAAA,iBAAAA,CAAAA,CAAAA;KACb,MAAA,IAAIA,sBAAsB,EAAI,EAAA;AACnC,QAAA,MAAM,IAAIM,KACR,CAAA,8DAAA,CAAA,CAAA;AAEJ,KAAA;;IAGA,OAAO,YAAA,CAAA;AACT;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-docs-url.cjs","sources":["../../../src/utils/get-docs-url.ts"],"sourcesContent":["export const getDocsUrl = (ruleName: string): string =>\n `https://openapi-qraft.github.io/openapi-qraft/docs/eslint/${ruleName}`;\n"],"names":["getDocsUrl","ruleName"],"mappings":";;AAAO,MAAMA,aAAa,CAACC,QAAAA,GACzB,CAAC,0DAA0D,EAAEA,QAAS,CAAA;;;;"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var utils = require('@typescript-eslint/utils');
|
|
4
|
+
|
|
5
|
+
function getRootIdentifier(node) {
|
|
6
|
+
let current = node;
|
|
7
|
+
while(current.type === utils.AST_NODE_TYPES.MemberExpression || current.type === utils.AST_NODE_TYPES.TSNonNullExpression || current.type === utils.AST_NODE_TYPES.ChainExpression){
|
|
8
|
+
if (current.type === utils.AST_NODE_TYPES.MemberExpression) {
|
|
9
|
+
current = current.object;
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
if (current.type === utils.AST_NODE_TYPES.TSNonNullExpression) {
|
|
13
|
+
current = current.expression;
|
|
14
|
+
continue;
|
|
15
|
+
}
|
|
16
|
+
current = current.expression;
|
|
17
|
+
}
|
|
18
|
+
return current.type === utils.AST_NODE_TYPES.Identifier ? current : undefined;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
exports.getRootIdentifier = getRootIdentifier;
|
|
22
|
+
//# sourceMappingURL=get-root-identifier.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-root-identifier.cjs","sources":["../../../src/utils/get-root-identifier.ts"],"sourcesContent":["import type { TSESTree } from '@typescript-eslint/utils';\nimport { AST_NODE_TYPES } from '@typescript-eslint/utils';\n\nexport function getRootIdentifier(\n node: TSESTree.Node\n): TSESTree.Identifier | undefined {\n let current: TSESTree.Node | undefined = node;\n while (\n current.type === AST_NODE_TYPES.MemberExpression ||\n current.type === AST_NODE_TYPES.TSNonNullExpression ||\n current.type === AST_NODE_TYPES.ChainExpression\n ) {\n if (current.type === AST_NODE_TYPES.MemberExpression) {\n current = current.object;\n continue;\n }\n if (current.type === AST_NODE_TYPES.TSNonNullExpression) {\n current = current.expression;\n continue;\n }\n\n current = current.expression;\n }\n return current.type === AST_NODE_TYPES.Identifier ? current : undefined;\n}\n"],"names":["getRootIdentifier","node","current","type","AST_NODE_TYPES","MemberExpression","TSNonNullExpression","ChainExpression","object","expression","Identifier","undefined"],"mappings":";;;;AAGO,SAASA,kBACdC,IAAmB,EAAA;AAEnB,IAAA,IAAIC,OAAqCD,GAAAA,IAAAA,CAAAA;AACzC,IAAA,MACEC,QAAQC,IAAI,KAAKC,oBAAeC,CAAAA,gBAAgB,IAChDH,OAAQC,CAAAA,IAAI,KAAKC,oBAAAA,CAAeE,mBAAmB,IACnDJ,OAAAA,CAAQC,IAAI,KAAKC,oBAAAA,CAAeG,eAAe,CAC/C;AACA,QAAA,IAAIL,OAAQC,CAAAA,IAAI,KAAKC,oBAAAA,CAAeC,gBAAgB,EAAE;AACpDH,YAAAA,OAAAA,GAAUA,QAAQM,MAAM,CAAA;AACxB,YAAA,SAAA;AACF,SAAA;AACA,QAAA,IAAIN,OAAQC,CAAAA,IAAI,KAAKC,oBAAAA,CAAeE,mBAAmB,EAAE;AACvDJ,YAAAA,OAAAA,GAAUA,QAAQO,UAAU,CAAA;AAC5B,YAAA,SAAA;AACF,SAAA;AAEAP,QAAAA,OAAAA,GAAUA,QAAQO,UAAU,CAAA;AAC9B,KAAA;AACA,IAAA,OAAOP,QAAQC,IAAI,KAAKC,oBAAeM,CAAAA,UAAU,GAAGR,OAAUS,GAAAA,SAAAA,CAAAA;AAChE;;;;"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { rules } from './rules.js';
|
|
2
|
+
|
|
3
|
+
const plugin = {
|
|
4
|
+
meta: {
|
|
5
|
+
name: '@openapi-qraft/eslint-plugin-query'
|
|
6
|
+
},
|
|
7
|
+
configs: {},
|
|
8
|
+
rules
|
|
9
|
+
};
|
|
10
|
+
// Assign configs here so we can reference `plugin`
|
|
11
|
+
Object.assign(plugin.configs, {
|
|
12
|
+
recommended: {
|
|
13
|
+
plugins: [
|
|
14
|
+
'@openapi-qraft/query'
|
|
15
|
+
],
|
|
16
|
+
rules: {
|
|
17
|
+
'@openapi-qraft/query/no-rest-destructuring': 'warn',
|
|
18
|
+
'@openapi-qraft/query/no-unstable-deps': 'error'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
'flat/recommended': [
|
|
22
|
+
{
|
|
23
|
+
name: 'openapi-qraft/query/flat/recommended',
|
|
24
|
+
plugins: {
|
|
25
|
+
'@openapi-qraft/query': plugin
|
|
26
|
+
},
|
|
27
|
+
rules: {
|
|
28
|
+
'@openapi-qraft/query/no-rest-destructuring': 'warn',
|
|
29
|
+
'@openapi-qraft/query/no-unstable-deps': 'error'
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
]
|
|
33
|
+
});
|
|
34
|
+
const configs = plugin.configs;
|
|
35
|
+
|
|
36
|
+
export { configs, plugin as default, plugin, rules };
|
|
37
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../src/index.ts"],"sourcesContent":["import type { RuleModule } from '@typescript-eslint/utils/ts-eslint';\nimport type { ESLint, Linter } from 'eslint';\nimport { rules } from './rules';\n\ntype RuleKey = keyof typeof rules;\n\nexport interface 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.Config>;\n };\n}\n\nexport const plugin: Plugin = {\n meta: {\n name: '@openapi-qraft/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: ['@openapi-qraft/query'],\n rules: {\n '@openapi-qraft/query/no-rest-destructuring': 'warn',\n '@openapi-qraft/query/no-unstable-deps': 'error',\n },\n },\n 'flat/recommended': [\n {\n name: 'openapi-qraft/query/flat/recommended',\n plugins: {\n '@openapi-qraft/query': plugin,\n },\n rules: {\n '@openapi-qraft/query/no-rest-destructuring': 'warn',\n '@openapi-qraft/query/no-unstable-deps': 'error',\n },\n },\n ],\n});\n\n// Reexport rules & configs for the Legacy config\nexport { rules };\nexport const configs = plugin.configs;\n\n/**\n * @alias\n * @type {Plugin}\n **/\nexport default plugin;\n"],"names":["plugin","meta","name","configs","rules","Object","assign","recommended","plugins"],"mappings":";;MAcaA,MAAiB,GAAA;IAC5BC,IAAM,EAAA;QACJC,IAAM,EAAA,oCAAA;AACR,KAAA;AACAC,IAAAA,OAAAA,EAAS,EAAC;AACVC,IAAAA,KAAAA;AACF,EAAE;AAEF;AACAC,MAAAA,CAAOC,MAAM,CAACN,MAAOG,CAAAA,OAAO,EAAE;IAC5BI,WAAa,EAAA;QACXC,OAAS,EAAA;AAAC,YAAA,sBAAA;AAAuB,SAAA;QACjCJ,KAAO,EAAA;YACL,4CAA8C,EAAA,MAAA;YAC9C,uCAAyC,EAAA,OAAA;AAC3C,SAAA;AACF,KAAA;IACA,kBAAoB,EAAA;AAClB,QAAA;YACEF,IAAM,EAAA,sCAAA;YACNM,OAAS,EAAA;gBACP,sBAAwBR,EAAAA,MAAAA;AAC1B,aAAA;YACAI,KAAO,EAAA;gBACL,4CAA8C,EAAA,MAAA;gBAC9C,uCAAyC,EAAA,OAAA;AAC3C,aAAA;AACF,SAAA;AACD,KAAA;AACH,CAAA,CAAA,CAAA;AAIaD,MAAAA,OAAAA,GAAUH,MAAOG,CAAAA;;;;"}
|