Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .changeset/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
"@openapi-qraft/plugin",
"@openapi-qraft/tanstack-query-react-plugin",
"@openapi-qraft/react",
"@openapi-qraft/tanstack-query-react-types"
"@openapi-qraft/tanstack-query-react-types",
"@openapi-qraft/eslint-plugin-query"
]
],
"linked": [],
Expand Down
7 changes: 7 additions & 0 deletions .changeset/wise-cats-stare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
'@openapi-qraft/eslint-plugin-query': minor
---

Added `@openapi-qraft/eslint-plugin-query`

An ESLint plugin to enforce best practices and prevent common mistakes with Qraft-generated hooks has been added.
15 changes: 9 additions & 6 deletions .github/actions/spelling/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@ amannn
APITS
apps
Batalov
Bcategory
bccc
bnpm
bnpx
bytesin
cbb
cdn
clientapi
codegen
codemod
csr
Expand All @@ -24,17 +24,18 @@ expressjs
fba
fddbf
Firefox
gimuy
gitlab
groupnames
hipchat
htpasswd
ianvs
iat
iddle
idx
ietf
ifm
INADDR
Intelli
iss
JOPT
jscodeshift
Expand All @@ -43,11 +44,12 @@ jwt
kubb
linkcheck
linting
mnot
monite
mozilla
mryechkin
mycdn
myclient
myqraft
nbf
nochange
npmrc
Expand All @@ -61,8 +63,10 @@ petstore
pids
QMethod
qraft
qraftclient
qraftio
radist
reate
redocly
refetched
Refetches
Expand All @@ -75,6 +79,7 @@ somedomain
srv
ssr
swcrc
TAdditional
tagline
tarball
TAsync
Expand All @@ -93,6 +98,7 @@ TRequest
TResult
TSchema
tservice
TSES
TSignal
TValue
TVariables
Expand All @@ -113,6 +119,3 @@ workaround
workflows
workspaces
XMonite
TCallbacks
reate
Intelli
7 changes: 7 additions & 0 deletions knip.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,13 @@
],
"ignore": ["src/**/__snapshots__/**", "eslint.config.js"]
},
"packages/eslint-plugin-query": {
"project": [
"src/**/*.{js,cjs,mjs,jsx,ts,cts,mts,tsx}",
"!src/__tests__/**"
],
"ignore": ["rollup.config.mjs", "eslint.config.js"]
},
"playground": {
"ignoreDependencies": ["dotenv", "dotenv-expand", "eslint-plugin-react", "@tanstack/react-query"]
}
Expand Down
1 change: 1 addition & 0 deletions packages/eslint-config/eslint.vanilla.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export default [
files: [
'**/**.spec.{ts,tsx}',
'**/**.test.{ts,tsx}',
'**/__tests__/**',
'**/setupTests.ts',
'**/vitestFsMock.ts',
],
Expand Down
131 changes: 131 additions & 0 deletions packages/eslint-plugin-query/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# @openapi-qraft/eslint-plugin-query

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.

- Homepage: `https://openapi-qraft.github.io/openapi-qraft/docs/eslint/eslint-plugin-query`
- Repository: `https://github.com/OpenAPI-Qraft/openapi-qraft`

## Requirements

- Node.js >= 18
- ESLint ^8.57.0 or ^9.0.0

## Installation

```bash
npm i -D @openapi-qraft/eslint-plugin-query
# or
pnpm add -D @openapi-qraft/eslint-plugin-query
# or
yarn add -D @openapi-qraft/eslint-plugin-query
# or
bun add -D @openapi-qraft/eslint-plugin-query
```

## Usage (ESLint Flat Config)

Create or update `eslint.config.js`:

```js
import pluginQraftQuery from '@openapi-qraft/eslint-plugin-query'

export default [
// Enable the recommended rules for this plugin
...pluginQraftQuery.configs['flat/recommended'],
// Any other config...
]
```

### Custom setup (Flat Config)

```js
import pluginQraftQuery from '@openapi-qraft/eslint-plugin-query'

export default [
{
plugins: {
'@openapi-qraft/query': pluginQraftQuery,
},
rules: {
'@openapi-qraft/query/no-rest-destructuring': 'warn',
'@openapi-qraft/query/no-unstable-deps': 'error',
},
},
]
```

## Usage (Legacy config)

Add to your `.eslintrc`:

```json
{
"extends": [
"plugin:@openapi-qraft/query/recommended"
]
}
```

### Custom setup (Legacy)

```json
{
"plugins": ["@openapi-qraft/query"],
"rules": {
"@openapi-qraft/query/no-rest-destructuring": "warn",
"@openapi-qraft/query/no-unstable-deps": "error"
}
}
```

## Options

Some rules detect Qraft-generated hooks only when they are called as methods on your client instance (e.g. `qraft.service.operation.useQuery()`).
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`.

Example (Flat Config):

```js
import pluginQraftQuery from '@openapi-qraft/eslint-plugin-query'

export default [
{
plugins: { '@openapi-qraft/query': pluginQraftQuery },
rules: {
'@openapi-qraft/query/no-rest-destructuring': [
'warn',
{ clientNamePattern: '/myQraftClient/i' },
],
'@openapi-qraft/query/no-unstable-deps': [
'error',
{ clientNamePattern: '/myQraftClient/i' },
],
},
},
]
```

## Configurations

This plugin ships with the following shareable configurations:

- `plugin:@openapi-qraft/query/recommended` (Legacy)
- `plugin.configs['flat/recommended']` (Flat)

They enable the rules as follows:

- `@openapi-qraft/query/no-rest-destructuring`: warn
- `@openapi-qraft/query/no-unstable-deps`: error

## Rules

- `@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`
- `@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`

## TypeScript

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.

## License

MIT © OpenAPI Qraft
7 changes: 7 additions & 0 deletions packages/eslint-plugin-query/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import openAPIQraftConfig from '@openapi-qraft/eslint-config/eslint.vanilla.config';
import globals from 'globals';

export default [
{ languageOptions: { globals: globals.node } },
...openAPIQraftConfig,
];
67 changes: 67 additions & 0 deletions packages/eslint-plugin-query/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"name": "@openapi-qraft/eslint-plugin-query",
"version": "2.11.0",
"description": "ESLint plugin for OpenAPI Qraft",
"homepage": "https://openapi-qraft.github.io/openapi-qraft/docs/eslint/eslint-plugin-query",
"packageManager": "yarn@4.0.2",
"license": "MIT",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "git+https://github.com/OpenAPI-Qraft/openapi-qraft.git",
"directory": "packages/eslint-plugin-query"
},
"scripts": {
"build": "yarn clean && NODE_ENV=production rollup --config rollup.config.mjs && tsc --project tsconfig.build.json --emitDeclarationOnly",
"typecheck": "tsc --noEmit",
"lint": "eslint",
"test": "vitest run --coverage",
"clean": "rimraf dist/"
},
"type": "module",
"types": "dist/types/index.d.ts",
"module": "dist/esm/index.js",
"main": "dist/cjs/index.cjs",
"exports": {
".": {
"types": "./dist/types/index.d.ts",
"import": "./dist/esm/index.js",
"require": "./dist/cjs/index.cjs"
},
"./package.json": "./package.json"
},
"typesVersions": {
"*": {
"*": [
"dist/types/*"
]
}
},
"sideEffects": false,
"files": [
"dist",
"src",
"!src/__tests__"
],
"dependencies": {
"@typescript-eslint/utils": "^8.37.0"
},
"devDependencies": {
"@openapi-qraft/eslint-config": "workspace:*",
"@openapi-qraft/rollup-config": "workspace:*",
"@types/node": "^20.16.5",
"@typescript-eslint/rule-tester": "^8.37.0",
"@typescript-eslint/typescript-estree": "^8.39.1",
"@vitest/coverage-v8": "^3.0.5",
"eslint": "^9.24.0",
"rimraf": "^5.0.10",
"rollup": "~4.22.4",
"typescript": "^5.6.2",
"vitest": "^3.0.5"
},
"peerDependencies": {
"eslint": "^8.57.0 || ^9.0.0"
}
}
11 changes: 11 additions & 0 deletions packages/eslint-plugin-query/rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { rollupConfig } from '@openapi-qraft/rollup-config';
import packageJson from './package.json' with { type: 'json' };

const moduleDist = {
import: packageJson['exports']['.']['import'],
require: packageJson['exports']['.']['require'],
};

const config = [rollupConfig(moduleDist, { input: 'src/index.ts' })];

export default config;
Loading
Loading