@st1ggy/linter-config 7.3.1 → 7.4.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/README.md +88 -8
- package/data/oxlint-config-inventory.json +2091 -0
- package/data/oxlint-rule-map.json +91859 -0
- package/data/oxlint-source-inventory.json +107728 -0
- package/docs/OXLINT_RULE_MAPPING.md +2968 -0
- package/docs/RULE_MAPPING.md +15 -0
- package/package.json +54 -2
- package/scripts/README.md +33 -1
- package/scripts/init-astro-ox.sh +4 -0
- package/scripts/init-common-ox.sh +4 -0
- package/scripts/init-next-ox.sh +4 -0
- package/scripts/init-react-ox.sh +4 -0
- package/scripts/init-solid-ox.sh +4 -0
- package/scripts/init-svelte-ox.sh +4 -0
- package/scripts/linter-init-core.mjs +80 -20
- package/scripts/linter-init.mjs +24 -32
- package/src/oxlint/configs/config.astro.js +4092 -0
- package/src/oxlint/configs/config.common.js +3209 -0
- package/src/oxlint/configs/config.next.js +3592 -0
- package/src/oxlint/configs/config.react.js +3503 -0
- package/src/oxlint/configs/config.solid.js +4986 -0
- package/src/oxlint/configs/config.svelte.js +3301 -0
- package/src/oxlint/create-config.js +40 -0
- package/src/oxlint/index.d.ts +49 -0
- package/src/oxlint/oxlint.config.astro.js +4 -0
- package/src/oxlint/oxlint.config.common.js +4 -0
- package/src/oxlint/oxlint.config.next.js +4 -0
- package/src/oxlint/oxlint.config.react.js +4 -0
- package/src/oxlint/oxlint.config.solid.js +4 -0
- package/src/oxlint/oxlint.config.svelte.js +4 -0
- package/src/oxlint/plugins/astro.js +41 -0
- package/src/oxlint/plugins/eslint-core.js +5 -0
- package/src/oxlint/plugins/fresh-source-code.js +30 -0
- package/src/oxlint/plugins/import-x.js +38 -0
- package/src/oxlint/plugins/next.js +1 -0
- package/src/oxlint/plugins/prettier.js +1 -0
- package/src/oxlint/plugins/react-hooks.js +1 -0
- package/src/oxlint/plugins/react.js +1 -0
- package/src/oxlint/plugins/solid.js +1 -0
- package/src/oxlint/plugins/sonarjs.js +5 -0
- package/src/oxlint/plugins/stylistic.js +1 -0
- package/src/oxlint/plugins/svelte.js +42 -0
- package/src/oxlint/plugins/typescript.js +1 -0
- package/src/oxlint/plugins/unicorn.js +5 -0
- package/src/oxlint/stacks.js +11 -0
- package/scripts/package-smoke.mjs +0 -56
- package/scripts/solid-config.test.mjs +0 -134
package/docs/RULE_MAPPING.md
CHANGED
|
@@ -33,6 +33,21 @@ Inventory rule counts (sample files in this repository):
|
|
|
33
33
|
- `eslint-svelte`: effective rules on `src/examples/example.svelte`
|
|
34
34
|
- `eslint-astro`: effective rules on `src/examples/example.astro`
|
|
35
35
|
|
|
36
|
+
## Oxlint counterparts
|
|
37
|
+
|
|
38
|
+
The package also exports `common-ox`, `react-ox`, `solid-ox`, `next-ox`, `svelte-ox` and `astro-ox`. Each is one `OxlintConfig` object, used through `oxlint.config.ts`, with `options.typeAware: true` and the native TS7 tsgolint engine. The original ESLint presets remain available.
|
|
39
|
+
|
|
40
|
+
The new variants use explicit migrated rules plus compatible JS adapters, and keep each stack's existing Prettier and Stylelint selections. See [OXLINT_RULE_MAPPING.md](OXLINT_RULE_MAPPING.md) for source/target correspondence, per-scope counts, partial mappings and unsupported rules. Native script extraction does not provide Svelte/Astro template linting.
|
|
41
|
+
|
|
42
|
+
Regenerate and verify the Oxlint inventory with:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npm run generate:ox
|
|
46
|
+
npm run inventory:ox
|
|
47
|
+
npm run generate:ox:check
|
|
48
|
+
npm run inventory:ox:check
|
|
49
|
+
```
|
|
50
|
+
|
|
36
51
|
## Stylelint (SCSS preset)
|
|
37
52
|
|
|
38
53
|
| Layer | `@st1ggy/linter-config` | Notes |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@st1ggy/linter-config",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.4.0",
|
|
4
4
|
"description": "ESLint, Prettier, and Stylelint shareable configs (sources under src/).",
|
|
5
5
|
"private": false,
|
|
6
6
|
"repository": {
|
|
@@ -93,6 +93,36 @@
|
|
|
93
93
|
"import": "./src/eslint/eslint.config.common.js",
|
|
94
94
|
"default": "./src/eslint/eslint.config.common.js"
|
|
95
95
|
},
|
|
96
|
+
"./common-ox": {
|
|
97
|
+
"types": "./src/oxlint/index.d.ts",
|
|
98
|
+
"import": "./src/oxlint/oxlint.config.common.js",
|
|
99
|
+
"default": "./src/oxlint/oxlint.config.common.js"
|
|
100
|
+
},
|
|
101
|
+
"./react-ox": {
|
|
102
|
+
"types": "./src/oxlint/index.d.ts",
|
|
103
|
+
"import": "./src/oxlint/oxlint.config.react.js",
|
|
104
|
+
"default": "./src/oxlint/oxlint.config.react.js"
|
|
105
|
+
},
|
|
106
|
+
"./solid-ox": {
|
|
107
|
+
"types": "./src/oxlint/index.d.ts",
|
|
108
|
+
"import": "./src/oxlint/oxlint.config.solid.js",
|
|
109
|
+
"default": "./src/oxlint/oxlint.config.solid.js"
|
|
110
|
+
},
|
|
111
|
+
"./next-ox": {
|
|
112
|
+
"types": "./src/oxlint/index.d.ts",
|
|
113
|
+
"import": "./src/oxlint/oxlint.config.next.js",
|
|
114
|
+
"default": "./src/oxlint/oxlint.config.next.js"
|
|
115
|
+
},
|
|
116
|
+
"./svelte-ox": {
|
|
117
|
+
"types": "./src/oxlint/index.d.ts",
|
|
118
|
+
"import": "./src/oxlint/oxlint.config.svelte.js",
|
|
119
|
+
"default": "./src/oxlint/oxlint.config.svelte.js"
|
|
120
|
+
},
|
|
121
|
+
"./astro-ox": {
|
|
122
|
+
"types": "./src/oxlint/index.d.ts",
|
|
123
|
+
"import": "./src/oxlint/oxlint.config.astro.js",
|
|
124
|
+
"default": "./src/oxlint/oxlint.config.astro.js"
|
|
125
|
+
},
|
|
96
126
|
"./prettier-common": {
|
|
97
127
|
"types": "./index.d.ts",
|
|
98
128
|
"import": "./src/prettier/prettier.config.common.js",
|
|
@@ -119,7 +149,11 @@
|
|
|
119
149
|
"src",
|
|
120
150
|
"scripts",
|
|
121
151
|
"data",
|
|
122
|
-
"docs"
|
|
152
|
+
"docs",
|
|
153
|
+
"!scripts/fixtures",
|
|
154
|
+
"!scripts/*.test.mjs",
|
|
155
|
+
"!scripts/oxlint-*.mjs",
|
|
156
|
+
"!scripts/package-smoke.mjs"
|
|
123
157
|
],
|
|
124
158
|
"scripts": {
|
|
125
159
|
"lint": "eslint . && stylelint \"src/**/*.{css,scss}\" --config ./src/stylelint/stylelint.config.scss.js --allow-empty-input && prettier --check .",
|
|
@@ -132,6 +166,12 @@
|
|
|
132
166
|
"changelog:dry": "conventional-changelog -p conventionalcommits",
|
|
133
167
|
"publish:npm": "npm publish --access public",
|
|
134
168
|
"inventory": "node ./scripts/inventory.mjs",
|
|
169
|
+
"typecheck:ox": "node ./node_modules/@typescript/native/bin/tsc --noEmit",
|
|
170
|
+
"generate:ox": "node scripts/oxlint-generate.mjs",
|
|
171
|
+
"generate:ox:check": "node scripts/oxlint-generate.mjs --check",
|
|
172
|
+
"inventory:ox": "node scripts/oxlint-inventory.mjs --write",
|
|
173
|
+
"inventory:ox:check": "node scripts/oxlint-inventory.mjs --source-only --check && node scripts/oxlint-inventory.mjs --check",
|
|
174
|
+
"test:ox": "node --test --test-concurrency=2 scripts/oxlint-*.test.mjs",
|
|
135
175
|
"config:init": "node ./scripts/linter-init.mjs init --common --dir ./examples/init-smoke",
|
|
136
176
|
"config:migrate": "node ./scripts/linter-init.mjs migrate --common --dir ./examples/init-smoke",
|
|
137
177
|
"config:reinit": "node ./scripts/linter-init.mjs reinit --common --dir ./examples/init-smoke",
|
|
@@ -148,6 +188,8 @@
|
|
|
148
188
|
"eslint-plugin-solid": "^0.18.0",
|
|
149
189
|
"eslint-plugin-svelte": "^3.22.0",
|
|
150
190
|
"next": "^16.3.0",
|
|
191
|
+
"oxlint": "1.86.0",
|
|
192
|
+
"oxlint-tsgolint": "7.0.2003",
|
|
151
193
|
"prettier": "^3.9.6",
|
|
152
194
|
"prettier-plugin-astro": "^0.14.1",
|
|
153
195
|
"prettier-plugin-svelte": "^4.1.1",
|
|
@@ -180,6 +222,12 @@
|
|
|
180
222
|
"next": {
|
|
181
223
|
"optional": true
|
|
182
224
|
},
|
|
225
|
+
"oxlint": {
|
|
226
|
+
"optional": true
|
|
227
|
+
},
|
|
228
|
+
"oxlint-tsgolint": {
|
|
229
|
+
"optional": true
|
|
230
|
+
},
|
|
183
231
|
"astro": {
|
|
184
232
|
"optional": true
|
|
185
233
|
},
|
|
@@ -203,6 +251,8 @@
|
|
|
203
251
|
}
|
|
204
252
|
},
|
|
205
253
|
"devDependencies": {
|
|
254
|
+
"@typescript/native": "npm:typescript@7.0.2",
|
|
255
|
+
"pnpm": "10.32.1",
|
|
206
256
|
"@next/eslint-plugin-next": "^16.3.0",
|
|
207
257
|
"@stylistic/eslint-plugin-migrate": "^4.4.1",
|
|
208
258
|
"conventional-changelog": "^8.1.0",
|
|
@@ -213,6 +263,8 @@
|
|
|
213
263
|
"eslint-plugin-react-hooks": "^7.1.1",
|
|
214
264
|
"eslint-plugin-solid": "^0.18.0",
|
|
215
265
|
"eslint-plugin-svelte": "^3.22.0",
|
|
266
|
+
"oxlint": "1.86.0",
|
|
267
|
+
"oxlint-tsgolint": "7.0.2003",
|
|
216
268
|
"prettier-plugin-astro": "^0.14.1",
|
|
217
269
|
"prettier-plugin-svelte": "^4.1.1",
|
|
218
270
|
"solid-js": "^1.9.15",
|
package/scripts/README.md
CHANGED
|
@@ -41,10 +41,42 @@ npm exec @st1ggy/linter-config -- migrate --svelte
|
|
|
41
41
|
npx --yes @st1ggy/linter-config init --astro
|
|
42
42
|
```
|
|
43
43
|
|
|
44
|
-
- **
|
|
44
|
+
- **ESLint stacks:** `--common` | `--react` | `--solid` | `--next` | `--svelte` | `--astro`.
|
|
45
|
+
- **Oxlint stacks:** `--common-ox` | `--react-ox` | `--solid-ox` | `--next-ox` | `--svelte-ox` | `--astro-ox`.
|
|
46
|
+
- Select at most one stack; the default is `common`.
|
|
45
47
|
- **`--skip-install`:** only write wrapper files; do not run npm/pnpm/yarn/bun.
|
|
46
48
|
- Every CLI command opens an interactive wizard. `init` creates missing wrappers; `migrate` can remove selected legacy configs and replaces wrappers.
|
|
47
49
|
|
|
48
50
|
Shell shortcuts in this folder (`init-common.sh`, etc.) call **`node …/linter-init.mjs`** (same script as the published **`@st1ggy/linter-config`** CLI) with the matching stack; pass **`--skip-install`** through when needed.
|
|
49
51
|
|
|
50
52
|
For SolidJS, `init-solid.sh` selects `eslint-solid`, `prettier-common`, and `stylelint-scss`, and installs `eslint-plugin-solid` alongside `@st1ggy/linter-config`.
|
|
53
|
+
|
|
54
|
+
## Oxlint wrappers
|
|
55
|
+
|
|
56
|
+
The six `init-*-ox.sh` shortcuts select the corresponding `*-ox` stack. They write `oxlint.config.ts`, `prettier.config.js` and `stylelint.config.js`. The wizard pins `oxlint@1.86.0` and `oxlint-tsgolint@7.0.2003` and installs only the framework integrations used by that preset. Svelte projects provide their Svelte runtime; their formatter and ESLint-compatible script rules use it.
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
npx @st1ggy/linter-config init --react-ox
|
|
60
|
+
npx @st1ggy/linter-config migrate --astro-ox
|
|
61
|
+
node ./scripts/linter-init.mjs init --solid-ox --dir ./my-app --skip-install
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
`init` preserves existing wrappers, including the other engine's config. `migrate` offers the opposite engine config and old `.oxlintrc.*` files for removal before generating the selected wrappers. It never deletes them without confirmation.
|
|
65
|
+
|
|
66
|
+
Oxlint uses native TS7 for typed linting. The consumer tsconfig must be TS7-compatible; the generator does not modify it. Read the [usage guide](../README.md#oxlint-variants) and [coverage report](../docs/OXLINT_RULE_MAPPING.md) before switching a project with Svelte/Astro templates or TS parser-service-dependent JS rules.
|
|
67
|
+
|
|
68
|
+
## Oxlint development checks
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
node scripts/oxlint-inventory.mjs --source-only
|
|
72
|
+
npm run generate:ox
|
|
73
|
+
npm run inventory:ox
|
|
74
|
+
npm run generate:ox:check
|
|
75
|
+
npm run inventory:ox:check
|
|
76
|
+
npm run test:ox
|
|
77
|
+
npm run typecheck:ox
|
|
78
|
+
node scripts/package-smoke.mjs
|
|
79
|
+
node scripts/package-smoke.mjs --pm pnpm
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The parity corpus asserts source and target diagnostics; guardrails reject missing mappings, option/severity drift, absent fixtures and unverified claims of complete SFC coverage. Inventory regeneration is deterministic and does not silently adopt new upstream rules: generated artifacts and fixtures must be reviewed together after dependency updates.
|
|
@@ -4,9 +4,13 @@ import { spawnSync } from 'node:child_process'
|
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs'
|
|
5
5
|
import path from 'node:path'
|
|
6
6
|
|
|
7
|
+
import { OX_FRAMEWORK_PACKAGES, OX_VERSIONS } from '../src/oxlint/stacks.js'
|
|
8
|
+
|
|
7
9
|
export const PACKAGE = '@st1ggy/linter-config'
|
|
8
10
|
|
|
9
|
-
|
|
11
|
+
const BASE_STACK_KEYS = ['common', 'react', 'solid', 'next', 'svelte', 'astro']
|
|
12
|
+
|
|
13
|
+
export const STACK_KEYS = [...BASE_STACK_KEYS, ...BASE_STACK_KEYS.map((key) => `${key}-ox`)]
|
|
10
14
|
|
|
11
15
|
export const STACKS = {
|
|
12
16
|
common: {
|
|
@@ -74,6 +78,21 @@ export const STACK_CHOICES = [
|
|
|
74
78
|
},
|
|
75
79
|
]
|
|
76
80
|
|
|
81
|
+
for (const key of BASE_STACK_KEYS) {
|
|
82
|
+
const base = STACKS[key]
|
|
83
|
+
|
|
84
|
+
base.linterFile = 'eslint.config.js'
|
|
85
|
+
base.linterPreset = base.eslint
|
|
86
|
+
STACKS[`${key}-ox`] = {
|
|
87
|
+
linterFile: 'oxlint.config.ts',
|
|
88
|
+
linterPreset: `${key}-ox`,
|
|
89
|
+
prettier: base.prettier,
|
|
90
|
+
stylelint: base.stylelint,
|
|
91
|
+
packages: [...Object.keys(OX_VERSIONS), ...OX_FRAMEWORK_PACKAGES[key]],
|
|
92
|
+
}
|
|
93
|
+
STACK_CHOICES.push({ value: `${key}-ox`, name: `${key}-ox — Oxlint + native TypeScript 7` })
|
|
94
|
+
}
|
|
95
|
+
|
|
77
96
|
export function readPackageJson(directory) {
|
|
78
97
|
const filePath = path.join(directory, 'package.json')
|
|
79
98
|
|
|
@@ -103,7 +122,7 @@ export function isSelfPackageRoot(directory) {
|
|
|
103
122
|
return packageJson?.name === PACKAGE
|
|
104
123
|
}
|
|
105
124
|
|
|
106
|
-
|
|
125
|
+
function packageManifestPath(startDirectory, packageName) {
|
|
107
126
|
let currentDirectory = path.resolve(startDirectory)
|
|
108
127
|
const packageParts = packageName.split('/')
|
|
109
128
|
|
|
@@ -111,7 +130,7 @@ export function hasResolvablePackage(startDirectory, packageName = PACKAGE) {
|
|
|
111
130
|
const marker = path.join(currentDirectory, 'node_modules', ...packageParts, 'package.json')
|
|
112
131
|
|
|
113
132
|
if (existsSync(marker)) {
|
|
114
|
-
return
|
|
133
|
+
return marker
|
|
115
134
|
}
|
|
116
135
|
|
|
117
136
|
const parentDirectory = path.dirname(currentDirectory)
|
|
@@ -123,7 +142,25 @@ export function hasResolvablePackage(startDirectory, packageName = PACKAGE) {
|
|
|
123
142
|
currentDirectory = parentDirectory
|
|
124
143
|
}
|
|
125
144
|
|
|
126
|
-
return
|
|
145
|
+
return null
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function hasResolvablePackage(startDirectory, packageName = PACKAGE) {
|
|
149
|
+
return packageManifestPath(startDirectory, packageName) !== null
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
function hasRequestedVersion(directory, packageName, spec) {
|
|
153
|
+
const marker = packageManifestPath(directory, packageName)
|
|
154
|
+
|
|
155
|
+
if (!marker) {
|
|
156
|
+
return false
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
try {
|
|
160
|
+
return JSON.parse(readFileSync(marker, 'utf8')).version === spec.split('@').at(-1)
|
|
161
|
+
} catch {
|
|
162
|
+
return false
|
|
163
|
+
}
|
|
127
164
|
}
|
|
128
165
|
|
|
129
166
|
export function detectPackageManager(startDirectory) {
|
|
@@ -170,7 +207,7 @@ export function runPmSync(command, args, cwd) {
|
|
|
170
207
|
|
|
171
208
|
// skipInstall: skip npm install; options.quiet: suppress stderr warnings
|
|
172
209
|
export function ensureDevDependencies(targetDirectory, packages, shouldSkipInstall, options = {}) {
|
|
173
|
-
const { quiet = false } = options
|
|
210
|
+
const { quiet = false, specs = {} } = options
|
|
174
211
|
|
|
175
212
|
if (shouldSkipInstall) {
|
|
176
213
|
return
|
|
@@ -197,7 +234,11 @@ export function ensureDevDependencies(targetDirectory, packages, shouldSkipInsta
|
|
|
197
234
|
}
|
|
198
235
|
|
|
199
236
|
const dependencies = mergedDependencies(packageJson)
|
|
200
|
-
const packagesToAdd = packages.filter(
|
|
237
|
+
const packagesToAdd = packages.filter(
|
|
238
|
+
(packageName) =>
|
|
239
|
+
!Object.hasOwn(dependencies, packageName) ||
|
|
240
|
+
(specs[packageName] && !hasRequestedVersion(directory, packageName, specs[packageName])),
|
|
241
|
+
)
|
|
201
242
|
const hasUnresolvedPackage = packages.some((packageName) => !hasResolvablePackage(directory, packageName))
|
|
202
243
|
|
|
203
244
|
if (!hasUnresolvedPackage && packagesToAdd.length === 0) {
|
|
@@ -223,15 +264,18 @@ export function ensureDevDependencies(targetDirectory, packages, shouldSkipInsta
|
|
|
223
264
|
return
|
|
224
265
|
}
|
|
225
266
|
|
|
267
|
+
const requested = packagesToAdd.map((name) => specs[name] ?? name)
|
|
268
|
+
const shouldPin = requested.some((name, index) => name !== packagesToAdd[index])
|
|
269
|
+
|
|
226
270
|
if (!quiet) {
|
|
227
|
-
process.stdout.write(`install: ${pm} add -D ${
|
|
271
|
+
process.stdout.write(`install: ${pm} add -D ${requested.join(' ')} (${directory})\n`)
|
|
228
272
|
}
|
|
229
273
|
|
|
230
274
|
const add = {
|
|
231
|
-
npm: () => runPmSync('npm', ['install', '-D', ...
|
|
232
|
-
pnpm: () => runPmSync('pnpm', ['add', '-D', ...
|
|
233
|
-
yarn: () => runPmSync('yarn', ['add', '-D', ...
|
|
234
|
-
bun: () => runPmSync('bun', ['add', '-d', ...
|
|
275
|
+
npm: () => runPmSync('npm', ['install', '-D', ...(shouldPin ? ['--save-exact'] : []), ...requested], directory),
|
|
276
|
+
pnpm: () => runPmSync('pnpm', ['add', '-D', ...(shouldPin ? ['--save-exact'] : []), ...requested], directory),
|
|
277
|
+
yarn: () => runPmSync('yarn', ['add', '-D', ...(shouldPin ? ['--exact'] : []), ...requested], directory),
|
|
278
|
+
bun: () => runPmSync('bun', ['add', '-d', ...(shouldPin ? ['--exact'] : []), ...requested], directory),
|
|
235
279
|
}
|
|
236
280
|
|
|
237
281
|
add[pm]()
|
|
@@ -251,6 +295,14 @@ export function stackPackages(stackKey) {
|
|
|
251
295
|
return [PACKAGE, ...stack.packages]
|
|
252
296
|
}
|
|
253
297
|
|
|
298
|
+
export function stackPackageSpecs(stackKey) {
|
|
299
|
+
stackPackages(stackKey)
|
|
300
|
+
|
|
301
|
+
return stackKey.endsWith('-ox')
|
|
302
|
+
? Object.fromEntries(Object.entries(OX_VERSIONS).map(([name, version]) => [name, `${name}@${version}`]))
|
|
303
|
+
: {}
|
|
304
|
+
}
|
|
305
|
+
|
|
254
306
|
export function printHelp() {
|
|
255
307
|
process.stdout.write(`\
|
|
256
308
|
${PACKAGE} — generate local wrapper configs in a consumer project.
|
|
@@ -264,13 +316,15 @@ Commands:
|
|
|
264
316
|
create Alias for init.
|
|
265
317
|
|
|
266
318
|
Writes (each command):
|
|
267
|
-
eslint.config.js, prettier.config.js, stylelint.config.js
|
|
319
|
+
ESLint stacks: eslint.config.js, prettier.config.js, stylelint.config.js.
|
|
320
|
+
Oxlint stacks: oxlint.config.ts, prettier.config.js, stylelint.config.js.
|
|
268
321
|
|
|
269
322
|
Unless --skip-install: if package.json exists, runs the detected package manager to add or sync
|
|
270
323
|
${PACKAGE} and the selected stack's integration plugins.
|
|
271
324
|
|
|
272
325
|
Stack (at most one; default: common):
|
|
273
326
|
--common | --react | --solid | --next | --svelte | --astro
|
|
327
|
+
--common-ox | --react-ox | --solid-ox | --next-ox | --svelte-ox | --astro-ox
|
|
274
328
|
|
|
275
329
|
Options:
|
|
276
330
|
--dir, -d Target directory (default: current working directory).
|
|
@@ -282,6 +336,7 @@ Examples (after: npm i -D ${PACKAGE}):
|
|
|
282
336
|
npx ${PACKAGE} init
|
|
283
337
|
npx ${PACKAGE} init --react
|
|
284
338
|
npx ${PACKAGE} init --solid
|
|
339
|
+
npx ${PACKAGE} init --solid-ox
|
|
285
340
|
npx ${PACKAGE} migrate --svelte --dir ./apps/web
|
|
286
341
|
npx ${PACKAGE} init --astro
|
|
287
342
|
npm exec ${PACKAGE} -- init --common
|
|
@@ -324,23 +379,28 @@ export function writeFile(targetDirectory, name, content, overwrite, options = {
|
|
|
324
379
|
return true
|
|
325
380
|
}
|
|
326
381
|
|
|
327
|
-
export function wrapperFileNames() {
|
|
328
|
-
|
|
382
|
+
export function wrapperFileNames(stackKey = 'common') {
|
|
383
|
+
stackPackages(stackKey)
|
|
384
|
+
|
|
385
|
+
return [STACKS[stackKey].linterFile, 'prettier.config.js', 'stylelint.config.js']
|
|
329
386
|
}
|
|
330
387
|
|
|
331
|
-
export function existingWrapperFiles(targetDirectory) {
|
|
332
|
-
return wrapperFileNames().filter((name) => existsSync(path.join(targetDirectory, name)))
|
|
388
|
+
export function existingWrapperFiles(targetDirectory, stackKey = 'common') {
|
|
389
|
+
return wrapperFileNames(stackKey).filter((name) => existsSync(path.join(targetDirectory, name)))
|
|
333
390
|
}
|
|
334
391
|
|
|
335
|
-
export function legacyConfigFiles(targetDirectory) {
|
|
392
|
+
export function legacyConfigFiles(targetDirectory, stackKey = 'common') {
|
|
336
393
|
if (!existsSync(targetDirectory)) {
|
|
337
394
|
return []
|
|
338
395
|
}
|
|
339
396
|
|
|
340
|
-
const wrappers = new Set(wrapperFileNames())
|
|
397
|
+
const wrappers = new Set(wrapperFileNames(stackKey))
|
|
341
398
|
|
|
342
399
|
return readdirSync(targetDirectory, { withFileTypes: true })
|
|
343
|
-
.filter(
|
|
400
|
+
.filter(
|
|
401
|
+
(entry) =>
|
|
402
|
+
entry.isFile() && /(?:eslint|oxlint|prettier|stylelint)/i.test(entry.name) && !wrappers.has(entry.name),
|
|
403
|
+
)
|
|
344
404
|
.map((entry) => entry.name)
|
|
345
405
|
.toSorted((left, right) => left.localeCompare(right))
|
|
346
406
|
}
|
|
@@ -383,7 +443,7 @@ export function run(mode, targetDirectory, stackKey, options = {}) {
|
|
|
383
443
|
|
|
384
444
|
const shouldOverwrite = mode === 'migrate' || mode === 'reinit'
|
|
385
445
|
|
|
386
|
-
writeFile(targetDirectory,
|
|
446
|
+
writeFile(targetDirectory, stack.linterFile, jsReExport(stack.linterPreset), shouldOverwrite, { quiet })
|
|
387
447
|
writeFile(targetDirectory, 'prettier.config.js', jsReExport(stack.prettier), shouldOverwrite, { quiet })
|
|
388
448
|
writeFile(targetDirectory, 'stylelint.config.js', jsReExport(stack.stylelint), shouldOverwrite, { quiet })
|
|
389
449
|
}
|
package/scripts/linter-init.mjs
CHANGED
|
@@ -20,27 +20,15 @@ import {
|
|
|
20
20
|
resolveStackKey,
|
|
21
21
|
resolveTargetDirectory,
|
|
22
22
|
run,
|
|
23
|
+
stackPackageSpecs,
|
|
23
24
|
stackPackages,
|
|
25
|
+
wrapperFileNames,
|
|
24
26
|
} from './linter-init-core.mjs'
|
|
25
27
|
|
|
26
28
|
function parseArgv(argv) {
|
|
27
29
|
return minimist(argv, {
|
|
28
30
|
string: ['dir', 'd'],
|
|
29
|
-
boolean: [
|
|
30
|
-
'help',
|
|
31
|
-
'h',
|
|
32
|
-
'skip-install',
|
|
33
|
-
'eslint',
|
|
34
|
-
'biome',
|
|
35
|
-
'common',
|
|
36
|
-
'react',
|
|
37
|
-
'solid',
|
|
38
|
-
'next',
|
|
39
|
-
'svelte',
|
|
40
|
-
'astro',
|
|
41
|
-
'interactive',
|
|
42
|
-
'i',
|
|
43
|
-
],
|
|
31
|
+
boolean: ['help', 'h', 'skip-install', 'eslint', 'biome', ...STACK_KEYS, 'interactive', 'i'],
|
|
44
32
|
alias: {
|
|
45
33
|
h: 'help',
|
|
46
34
|
d: 'dir',
|
|
@@ -58,12 +46,7 @@ function argvToValues(argv) {
|
|
|
58
46
|
'skip-install': Boolean(argv['skip-install']),
|
|
59
47
|
eslint: Boolean(argv.eslint),
|
|
60
48
|
biome: Boolean(argv.biome),
|
|
61
|
-
|
|
62
|
-
react: Boolean(argv.react),
|
|
63
|
-
solid: Boolean(argv.solid),
|
|
64
|
-
next: Boolean(argv.next),
|
|
65
|
-
svelte: Boolean(argv.svelte),
|
|
66
|
-
astro: Boolean(argv.astro),
|
|
49
|
+
...Object.fromEntries(STACK_KEYS.map((key) => [key, argv[key] === true])),
|
|
67
50
|
}
|
|
68
51
|
}
|
|
69
52
|
|
|
@@ -77,7 +60,7 @@ async function selectCommand(command) {
|
|
|
77
60
|
choices: [
|
|
78
61
|
{
|
|
79
62
|
value: 'init',
|
|
80
|
-
name: 'init — create missing
|
|
63
|
+
name: 'init — create missing linter, Prettier and Stylelint wrappers',
|
|
81
64
|
},
|
|
82
65
|
{
|
|
83
66
|
value: 'migrate',
|
|
@@ -102,14 +85,14 @@ async function selectStack(values) {
|
|
|
102
85
|
})
|
|
103
86
|
}
|
|
104
87
|
|
|
105
|
-
async function selectLegacyFiles(command, directory) {
|
|
88
|
+
async function selectLegacyFiles(command, directory, stack) {
|
|
106
89
|
if (command !== 'migrate') {
|
|
107
90
|
return []
|
|
108
91
|
}
|
|
109
92
|
|
|
110
93
|
const selected = []
|
|
111
94
|
|
|
112
|
-
for (const file of legacyConfigFiles(directory)) {
|
|
95
|
+
for (const file of legacyConfigFiles(directory, stack)) {
|
|
113
96
|
if (await confirm({ message: `Remove legacy config ${file}?`, default: false })) {
|
|
114
97
|
selected.push(file)
|
|
115
98
|
}
|
|
@@ -122,7 +105,7 @@ function printSummary(command, stack, directory, shouldSkipInstall, existing, fi
|
|
|
122
105
|
const wrapperFiles =
|
|
123
106
|
command === 'init' && existing.length > 0
|
|
124
107
|
? `create missing; keep ${existing.join(', ')}`
|
|
125
|
-
:
|
|
108
|
+
: `write ${wrapperFileNames(stack).join(', ')}`
|
|
126
109
|
|
|
127
110
|
process.stdout.write('\n')
|
|
128
111
|
process.stdout.write(` Action: ${command}\n`)
|
|
@@ -148,11 +131,20 @@ async function runInteractive(command, values) {
|
|
|
148
131
|
}
|
|
149
132
|
|
|
150
133
|
const shouldSkipInstall = values['skip-install'] === true
|
|
151
|
-
const existing = existingWrapperFiles(resolved)
|
|
152
|
-
const filesToRemove = await selectLegacyFiles(selectedCommand, resolved)
|
|
134
|
+
const existing = existingWrapperFiles(resolved, selectedStack)
|
|
135
|
+
const filesToRemove = await selectLegacyFiles(selectedCommand, resolved, selectedStack)
|
|
153
136
|
const packages = stackPackages(selectedStack)
|
|
154
|
-
|
|
155
|
-
|
|
137
|
+
const specs = stackPackageSpecs(selectedStack)
|
|
138
|
+
|
|
139
|
+
printSummary(
|
|
140
|
+
selectedCommand,
|
|
141
|
+
selectedStack,
|
|
142
|
+
resolved,
|
|
143
|
+
shouldSkipInstall,
|
|
144
|
+
existing,
|
|
145
|
+
filesToRemove,
|
|
146
|
+
packages.map((name) => specs[name] ?? name),
|
|
147
|
+
)
|
|
156
148
|
|
|
157
149
|
const shouldProceed = await confirm({
|
|
158
150
|
message: 'Proceed?',
|
|
@@ -175,7 +167,7 @@ async function runInteractive(command, values) {
|
|
|
175
167
|
}).start()
|
|
176
168
|
|
|
177
169
|
try {
|
|
178
|
-
ensureDevDependencies(resolved, packages, false, { quiet: true })
|
|
170
|
+
ensureDevDependencies(resolved, packages, false, { quiet: true, specs })
|
|
179
171
|
spinner.succeed(`${selectedStack} linting packages are available`)
|
|
180
172
|
} catch (error) {
|
|
181
173
|
spinner.fail('Dependency step failed')
|
|
@@ -185,7 +177,7 @@ async function runInteractive(command, values) {
|
|
|
185
177
|
|
|
186
178
|
const writeSpinner = ora({
|
|
187
179
|
color: 'green',
|
|
188
|
-
text:
|
|
180
|
+
text: `Writing ${wrapperFileNames(selectedStack).join(', ')}…`,
|
|
189
181
|
}).start()
|
|
190
182
|
|
|
191
183
|
try {
|
|
@@ -213,7 +205,7 @@ function normalizeCommand(command) {
|
|
|
213
205
|
function warnLegacyFlags(values) {
|
|
214
206
|
if (values.biome === true) {
|
|
215
207
|
process.stderr.write(
|
|
216
|
-
`warning: --biome is ignored; Biome presets were removed from ${PACKAGE}.
|
|
208
|
+
`warning: --biome is ignored; Biome presets were removed from ${PACKAGE}. Select an ESLint or Oxlint stack.\n`,
|
|
217
209
|
)
|
|
218
210
|
}
|
|
219
211
|
}
|