@kitql/eslint-config 0.8.4 → 0.9.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/.oxfmtrc.json ADDED
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "./node_modules/oxfmt/configuration_schema.json",
3
+ "tabWidth": 1,
4
+ "useTabs": true,
5
+ "singleQuote": true,
6
+ "trailingComma": "all",
7
+ "semi": false,
8
+ "arrowParens": "always",
9
+ "printWidth": 100,
10
+ "sortPackageJson": false,
11
+ "sortImports": {
12
+ "groups": [
13
+ "builtin",
14
+ { "newlinesBetween": false },
15
+ "external",
16
+ "kitql",
17
+ "sveltekit",
18
+ "aliases",
19
+ ["parent", "sibling", "index"],
20
+ "unknown"
21
+ ],
22
+ "customGroups": [
23
+ { "groupName": "kitql", "elementNamePattern": ["@kitql/**"] },
24
+ {
25
+ "groupName": "sveltekit",
26
+ "elementNamePattern": ["$env", "$env/**", "$app", "$app/**"]
27
+ },
28
+ { "groupName": "aliases", "elementNamePattern": ["$*", "$*/**"] }
29
+ ],
30
+ "newlinesBetween": true
31
+ },
32
+ "ignorePatterns": []
33
+ }
package/.oxlintrc.json CHANGED
@@ -1,19 +1,62 @@
1
1
  {
2
2
  "$schema": "./node_modules/oxlint/configuration_schema.json",
3
3
  "plugins": ["unicorn", "typescript", "oxc"],
4
- "jsPlugins": ["eslint-plugin-svelte"],
4
+ "jsPlugins": ["@e18e/eslint-plugin", "eslint-plugin-svelte"],
5
+ "ignorePatterns": ["**/test/fixtures/**"],
6
+ "categories": {
7
+ "correctness": "error"
8
+ },
5
9
  "rules": {
6
- // "no-unused-vars": [
7
- // "error",
8
- // { "caughtErrors": "none", "argsIgnorePattern": "^_", "varsIgnorePattern": "^_" }
9
- // ],
10
10
  "no-console": [
11
11
  "error",
12
12
  {
13
13
  "allow": ["info", "warn", "error", "time", "timeEnd", "dir"]
14
14
  }
15
15
  ],
16
+ "no-unused-vars": ["error", { "args": "none", "caughtErrors": "none" }],
17
+ "@typescript-eslint/no-unused-vars": ["error", { "args": "none", "caughtErrors": "none" }],
16
18
  "@typescript-eslint/no-redundant-type-constituents": "off",
17
- "no-base-to-string": "off"
18
- }
19
+ "@typescript-eslint/no-unused-expressions": "off",
20
+ "no-unused-expressions": "off",
21
+ "no-base-to-string": "off",
22
+
23
+ "e18e/prefer-array-at": "error",
24
+ "e18e/prefer-array-fill": "error",
25
+ "e18e/prefer-includes": "error",
26
+ "e18e/prefer-array-to-reversed": "error",
27
+ "e18e/prefer-array-to-sorted": "error",
28
+ "e18e/prefer-array-to-spliced": "error",
29
+ "e18e/prefer-nullish-coalescing": "error",
30
+ "e18e/prefer-object-has-own": "error",
31
+ "e18e/prefer-spread-syntax": "error",
32
+ "e18e/prefer-url-canparse": "error",
33
+ "e18e/ban-dependencies": "error",
34
+ "e18e/prefer-array-from-map": "error",
35
+ "e18e/prefer-timer-args": "error",
36
+ "e18e/prefer-date-now": "error",
37
+ "e18e/prefer-regex-test": "error",
38
+ "e18e/prefer-array-some": "error",
39
+ "e18e/prefer-static-regex": "error",
40
+
41
+ "@typescript-eslint/prefer-find": "error",
42
+ "@typescript-eslint/prefer-readonly": "error",
43
+ "@typescript-eslint/prefer-regexp-exec": "error"
44
+ },
45
+ "overrides": [
46
+ {
47
+ "files": ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"],
48
+ "rules": {
49
+ "no-var": "error",
50
+ "prefer-const": "error",
51
+ "prefer-rest-params": "error",
52
+ "prefer-spread": "error"
53
+ }
54
+ },
55
+ {
56
+ "files": ["**/*.test.ts", "**/*.test.js", "**/*.spec.ts", "**/*.spec.js"],
57
+ "rules": {
58
+ "e18e/prefer-static-regex": "off"
59
+ }
60
+ }
61
+ ]
19
62
  }
package/README.md CHANGED
@@ -13,9 +13,41 @@
13
13
  npm install @kitql/eslint-config --D
14
14
  ```
15
15
 
16
+ ### tools
17
+
18
+ `kitql-lint` orchestrates four optional tools - install only what you want to use:
19
+
20
+ | Tool | What it does |
21
+ | --------- | --------------------------------------------------------- |
22
+ | eslint | Linter (svelte rules, pnpm catalog rules, custom rules) |
23
+ | prettier | Formatter (every file type, incl. `.svelte`) |
24
+ | oxlint | Faster linter (Rust); covers most JS/TS rules |
25
+ | oxfmt | Faster formatter (Rust); doesn't speak `.svelte` yet |
26
+
27
+ By default `kitql-lint` runs `eslint` + `prettier`. Pick others with `-t`:
28
+
29
+ ```bash
30
+ kitql-lint # eslint + prettier (default)
31
+ kitql-lint -t eslint,prettier,oxlint,tsgolint # add oxlint + type-aware
32
+ kitql-lint -t oxlint,tsgolint,oxfmt,eslint,prettier # 🦀 svelte + full oxc (recommended)
33
+ kitql-lint -t oxlint,tsgolint,oxfmt # 🦀 pure oxc (no .svelte support)
34
+ ```
35
+
36
+ For the svelte combo, enable oxlint integration in eslint to avoid duplicate work on `.ts/.js`:
37
+
38
+ ```js
39
+ // eslint.config.js
40
+ import { kitql } from '@kitql/eslint-config'
41
+
42
+ export default [...kitql({ oxlint: { enable: true } })]
43
+ ```
44
+
45
+ When `oxfmt` is in the tool set, `prettier` auto-restricts to `**/*.svelte` (oxfmt can't parse
46
+ svelte yet); `oxfmt` handles every other file type.
47
+
16
48
  ### eslint config
17
49
 
18
- `.eslint.config.js`
50
+ `eslint.config.js`
19
51
 
20
52
  ```js
21
53
  import { kitql } from '@kitql/eslint-config'
@@ -25,10 +57,10 @@ export default [...kitql()]
25
57
 
26
58
  ### prettier config
27
59
 
28
- `.prettierrc.cjs`
60
+ `.prettierrc.js`
29
61
 
30
62
  ```js
31
- import { kitql } from './packages/eslint-config/.prettierrc.cjs'
63
+ import { kitql } from '@kitql/eslint-config/.prettierrc.js'
32
64
 
33
65
  export default {
34
66
  ...kitql(),
@@ -36,6 +68,23 @@ export default {
36
68
  }
37
69
  ```
38
70
 
71
+ ### oxlint config
72
+
73
+ `.oxlintrc.json`
74
+
75
+ ```jsonc
76
+ {
77
+ "$schema": "./node_modules/oxlint/configuration_schema.json",
78
+ "extends": ["./node_modules/@kitql/eslint-config/.oxlintrc.json"],
79
+ "rules": {}
80
+ }
81
+ ```
82
+
83
+ ### oxfmt config
84
+
85
+ `.oxfmtrc.json` - copy from
86
+ [`@kitql/eslint-config/.oxfmtrc.json`](./.oxfmtrc.json) (oxfmt has no `extends` yet).
87
+
39
88
  ### ignore things with
40
89
 
41
90
  `.prettierignore`
package/cmd.js CHANGED
@@ -7,10 +7,16 @@ import { gray, green, Log } from '@kitql/helpers'
7
7
  import { parseCli } from '@kitql/helpers/server'
8
8
 
9
9
  import { findFileOrUp } from './helper/findFileOrUp.js'
10
+ import {
11
+ buildEslintCmd,
12
+ buildOxfmtCmd,
13
+ buildOxlintCmd,
14
+ buildPrettierCmd,
15
+ } from './src/buildCommands.js'
10
16
 
11
- /** @type {('eslint' | 'prettier' | 'oxlint' | 'tsgolint')[]} */
12
- const TOOLS_ALL = ['eslint', 'prettier', 'oxlint', 'tsgolint']
13
- const TOOLS_DEFAULT = TOOLS_ALL.slice(0, 2)
17
+ /** @type {('eslint' | 'prettier' | 'oxlint' | 'tsgolint' | 'oxfmt')[]} */
18
+ const TOOLS_ALL = ['eslint', 'prettier', 'oxlint', 'tsgolint', 'oxfmt']
19
+ const TOOLS_DEFAULT = ['eslint', 'prettier']
14
20
 
15
21
  const { values: options_cli, help } = parseCli({
16
22
  name: 'kitql-lint',
@@ -21,7 +27,7 @@ const { values: options_cli, help } = parseCli({
21
27
  type: 'string',
22
28
  short: 't',
23
29
  default: TOOLS_DEFAULT.join(','),
24
- description: 'tools to use (eslint, prettier, oxlint, tsgolint)',
30
+ description: 'tools to use (eslint, prettier, oxlint, tsgolint, oxfmt)',
25
31
  },
26
32
  verbose: { type: 'boolean', short: 'v', default: false, description: 'add more logs' },
27
33
  'diff-only': {
@@ -52,6 +58,7 @@ if (options_cli.help) {
52
58
 
53
59
  const pathPrettierIgnore = findFileOrUp('.prettierignore')
54
60
  const pathPrettier_js = findFileOrUp('.prettierrc.js')
61
+ const pathOxfmtrc = findFileOrUp('.oxfmtrc.json')
55
62
 
56
63
  const format = /** @type {boolean} */ (options_cli.format ?? false)
57
64
  let glob = /** @type {string} */ (options_cli.glob ?? '.')
@@ -60,6 +67,11 @@ const pre = /** @type {string} */ (options_cli.prefix ?? 'none')
60
67
  const tools = /** @type {typeof TOOLS_ALL} */ (
61
68
  String(options_cli.tools ?? TOOLS_DEFAULT.join(',')).split(',')
62
69
  )
70
+ const unknown = tools.filter((t) => !TOOLS_ALL.includes(t))
71
+ if (unknown.length > 0) {
72
+ console.error(`Unknown tool(s): ${unknown.join(', ')}. Supported: ${TOOLS_ALL.join(', ')}`)
73
+ process.exit(2)
74
+ }
63
75
  const diffOnly = /** @type {boolean} */ (options_cli['diff-only'] ?? false)
64
76
  const baseBranch = /** @type {string} */ (options_cli['base-branch'] ?? 'main')
65
77
 
@@ -289,55 +301,41 @@ async function getDiffFiles() {
289
301
  }
290
302
  }
291
303
 
292
- async function runOxc(/** @type {string} */ name) {
293
- const cmdLint =
294
- `oxlint` +
295
- `${tools.includes('tsgolint') ? ' --type-aware' : ''}` +
296
- // format or not
297
- `${format ? ' --fix' : ''}` +
298
- ` ${glob}`
304
+ function buildOpts() {
305
+ return {
306
+ tools,
307
+ format,
308
+ glob,
309
+ pre: preToUse,
310
+ pathPrettierIgnore,
311
+ pathPrettier_js,
312
+ pathOxfmtrc,
313
+ }
314
+ }
299
315
 
316
+ async function runOxc(/** @type {string} */ name) {
317
+ const cmdLint = buildOxlintCmd(buildOpts())
300
318
  log.info(gray(`${verbose ? cmdLint : name} `))
301
-
302
- const result_lint = await customSpawn(cmdLint)
303
-
304
- return result_lint
319
+ return customSpawn(cmdLint)
305
320
  }
306
321
 
307
322
  async function runEslint() {
308
- const cmd =
309
- preToUse +
310
- `eslint --no-warn-ignored` +
311
- // format or not
312
- `${format ? ' --fix' : ''}` +
313
- // exec
314
- ` ${glob}`
315
-
323
+ const cmd = buildEslintCmd(buildOpts())
316
324
  log.info(gray(`${verbose ? cmd : 'eslint'} `))
317
- const result_lint = await customSpawn(cmd)
318
-
319
- return result_lint
325
+ return customSpawn(cmd)
320
326
  }
321
327
 
322
328
  async function runPrettier() {
323
- const cmdFormat =
324
- preToUse +
325
- `prettier` +
326
- ` --list-different` +
327
- // ignore?
328
- ` --ignore-path ${pathPrettierIgnore}` +
329
- // config
330
- ` --config ${pathPrettier_js}` +
331
- // format or not
332
- `${format ? ' --write' : ''}` +
333
- // exec
334
- ` ${glob}`
335
-
336
- log.info(gray(`${verbose ? cmdFormat : 'prettier'} `))
337
-
338
- const result_format = await customSpawn(cmdFormat)
339
-
340
- return result_format
329
+ const cmd = buildPrettierCmd(buildOpts())
330
+ const svelteOnly = tools.includes('oxfmt')
331
+ log.info(gray(`${verbose ? cmd : svelteOnly ? 'prettier (svelte)' : 'prettier'} `))
332
+ return customSpawn(cmd)
333
+ }
334
+
335
+ async function runOxfmt() {
336
+ const cmd = buildOxfmtCmd(buildOpts())
337
+ log.info(gray(`${verbose ? cmd : 'oxfmt'} `))
338
+ return customSpawn(cmd)
341
339
  }
342
340
 
343
341
  /** @type {string[]} */
@@ -390,11 +388,22 @@ if (tools.includes('eslint') && glob) {
390
388
  }
391
389
  }
392
390
 
391
+ if (tools.includes('oxfmt') && glob) {
392
+ const start = performance.now()
393
+ const code = await runOxfmt()
394
+ const stepTook = performance.now() - start
395
+ took.push(display('oxfmt', stepTook))
396
+ if (typeof code === 'object' && 'status' in code && code.status) {
397
+ log.error(`format failed, check logs above. ${displayTook()}`)
398
+ process.exit(Number(code.status))
399
+ }
400
+ }
401
+
393
402
  if (tools.includes('prettier') && glob) {
394
403
  const start = performance.now()
395
404
  const code = await runPrettier()
396
405
  const stepTook = performance.now() - start
397
- took.push(display('prettier', stepTook))
406
+ took.push(display(tools.includes('oxfmt') ? 'prettier (svelte)' : 'prettier', stepTook))
398
407
  if (typeof code === 'object' && 'status' in code && code.status) {
399
408
  log.error(`format failed, check logs above. ${displayTook()}`)
400
409
  process.exit(Number(code.status))
package/eslint.config.js CHANGED
@@ -119,7 +119,15 @@ const othersRules = ({ svelteConfig } = {}) => {
119
119
  },
120
120
  {
121
121
  name: '@kitql:ignores',
122
- ignores: ['build/', '.svelte-kit/', 'dist/', '**/build/', '**/.svelte-kit/', '**/dist/'],
122
+ ignores: [
123
+ 'build/',
124
+ '.svelte-kit/',
125
+ 'dist/',
126
+ '**/build/',
127
+ '**/.svelte-kit/',
128
+ '**/dist/',
129
+ '**/test/fixtures/**',
130
+ ],
123
131
  },
124
132
  {
125
133
  name: '@kitql:tests',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitql/eslint-config",
3
- "version": "0.8.4",
3
+ "version": "0.9.0",
4
4
  "type": "module",
5
5
  "description": "opinionated linting and formatting for projects",
6
6
  "repository": {
@@ -18,12 +18,14 @@
18
18
  "main": "eslint.config.js",
19
19
  "types": "eslint.config.d.ts",
20
20
  "files": [
21
+ ".oxfmtrc.json",
21
22
  ".oxlintrc.json",
22
23
  ".prettierrc.js",
23
24
  "cmd.js",
24
25
  "eslint.config.js",
25
26
  "eslint.config.d.ts",
26
- "helper/findFileOrUp.js"
27
+ "helper/findFileOrUp.js",
28
+ "src/buildCommands.js"
27
29
  ],
28
30
  "keywords": [
29
31
  "cli",
@@ -35,6 +37,7 @@
35
37
  ],
36
38
  "peerDependencies": {
37
39
  "eslint": "10.4.0",
40
+ "oxfmt": "0.51.0",
38
41
  "oxlint": "1.66.0",
39
42
  "oxlint-tsgolint": "0.23.0",
40
43
  "prettier": "^3.8.3"
@@ -43,6 +46,9 @@
43
46
  "eslint": {
44
47
  "optional": true
45
48
  },
49
+ "oxfmt": {
50
+ "optional": true
51
+ },
46
52
  "oxlint": {
47
53
  "optional": true
48
54
  },
@@ -53,6 +59,10 @@
53
59
  "optional": true
54
60
  }
55
61
  },
62
+ "devDependencies": {
63
+ "@vitest/coverage-v8": "4.1.4",
64
+ "vitest": "4.1.4"
65
+ },
56
66
  "dependencies": {
57
67
  "@e18e/eslint-plugin": "^0.5.0",
58
68
  "@eslint/compat": "2.1.0",
@@ -82,6 +92,9 @@
82
92
  "format:example": "kitql-lint --format",
83
93
  "inspector": "npx @eslint/config-inspector",
84
94
  "lint": "node ./cmd.js --verbose -p none",
85
- "lint:example": "kitql-lint"
95
+ "lint:oxc": "node ./cmd.js -p none -t oxlint,oxfmt,prettier",
96
+ "lint:example": "kitql-lint",
97
+ "test": "vitest",
98
+ "test:ci": "vitest run --coverage"
86
99
  }
87
100
  }
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Pure helpers that build the shell commands `kitql-lint` runs.
3
+ * Extracted so they can be unit-tested without spawning processes.
4
+ */
5
+
6
+ /**
7
+ * @typedef {Object} BuildOptions
8
+ * @property {string[]} tools - selected tools
9
+ * @property {boolean} format - format vs lint
10
+ * @property {string} glob - target glob/files
11
+ * @property {string} [pre] - prefix to prepend to commands ('', 'pnpm ', 'npm exec ')
12
+ * @property {string} [pathPrettierIgnore]
13
+ * @property {string} [pathPrettier_js]
14
+ * @property {string} [pathOxfmtrc]
15
+ */
16
+
17
+ /**
18
+ * @param {BuildOptions} opts
19
+ */
20
+ export function buildOxlintCmd(opts) {
21
+ const { tools, format, glob, pre = '' } = opts
22
+ return (
23
+ pre +
24
+ `oxlint` +
25
+ `${tools.includes('tsgolint') ? ' --type-aware' : ''}` +
26
+ `${format ? ' --fix' : ''}` +
27
+ ` ${glob}`
28
+ )
29
+ }
30
+
31
+ /**
32
+ * @param {BuildOptions} opts
33
+ */
34
+ export function buildEslintCmd(opts) {
35
+ const { format, glob, pre = '' } = opts
36
+ return pre + `eslint --no-warn-ignored` + `${format ? ' --fix' : ''}` + ` ${glob}`
37
+ }
38
+
39
+ /**
40
+ * @param {BuildOptions} opts
41
+ */
42
+ export function buildPrettierCmd(opts) {
43
+ const { tools, format, glob, pre = '', pathPrettierIgnore, pathPrettier_js } = opts
44
+ // When oxfmt is in the tool set, oxfmt formats every file type it supports
45
+ // and prettier only handles .svelte (oxfmt can't parse it yet) - regardless of mode.
46
+ const svelteOnly = tools.includes('oxfmt')
47
+ const target = svelteOnly ? `'**/*.svelte'` : glob
48
+
49
+ return (
50
+ pre +
51
+ `prettier` +
52
+ ` --list-different` +
53
+ ` --ignore-path ${pathPrettierIgnore}` +
54
+ ` --config ${pathPrettier_js}` +
55
+ `${svelteOnly ? ' --no-error-on-unmatched-pattern' : ''}` +
56
+ `${format ? ' --write' : ''}` +
57
+ ` ${target}`
58
+ )
59
+ }
60
+
61
+ /**
62
+ * @param {BuildOptions} opts
63
+ */
64
+ export function buildOxfmtCmd(opts) {
65
+ const { format, glob, pre = '', pathPrettierIgnore, pathOxfmtrc } = opts
66
+ return (
67
+ pre +
68
+ `oxfmt` +
69
+ (pathPrettierIgnore ? ` --ignore-path ${pathPrettierIgnore}` : '') +
70
+ (pathOxfmtrc ? ` --config ${pathOxfmtrc}` : '') +
71
+ `${format ? ' --write' : ' --check'}` +
72
+ ` --no-error-on-unmatched-pattern` +
73
+ ` ${glob}`
74
+ )
75
+ }