lintmax 0.0.11 → 0.0.13

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 CHANGED
@@ -1,105 +1,49 @@
1
1
  # lintmax
2
2
 
3
- Maximum strictness linting, formatting, and type-checking in one package.
3
+ Opinionated max-strict lint/format/typecheck with a minimal config surface.
4
4
 
5
- Wraps **6 tools** into a single CLI: [Biome](https://biomejs.dev), [oxlint](https://oxc.rs), [ESLint](https://eslint.org), [Prettier](https://prettier.io) (markdown), [sort-package-json](https://github.com/keithamus/sort-package-json), and [Flowmark](https://github.com/jlevy/flowmark) (optional).
5
+ ## Quick start
6
6
 
7
- All rules enabled at `error` by default. You only disable what you don’t need.
8
-
9
- ## Install
7
+ Install and initialize:
10
8
 
11
9
  ```bash
12
10
  bun add -d lintmax
13
11
  bunx lintmax init
14
12
  ```
15
13
 
16
- `lintmax init` scaffolds:
17
-
18
- - `tsconfig.json` extending `lintmax/tsconfig`
19
- - `package.json` scripts (`fix`, `check`)
20
- - `.gitignore` entries
21
- - `.vscode/settings.json` (biome formatter, eslint, codeActionsOnSave)
22
- - `.vscode/extensions.json`
23
-
24
- ## Usage
14
+ Run checks:
25
15
 
26
16
  ```bash
27
- bun fix # auto-fix and format everything
28
- bun check # check without modifying
17
+ bun fix
18
+ bun check
29
19
  ```
30
20
 
31
- ## Customization
21
+ `lintmax` works without configuration. Add `lintmax.config.ts` only when you need to tune behavior.
22
+
23
+ ## Canonical knobs
32
24
 
33
- ### Biome and oxlint overrides
25
+ - `off`: disable rules
26
+ - `ignores`: ignore file globs
27
+ - `overrides`: map file globs to per-linter `off` arrays
34
28
 
35
- Create `lintmax.config.ts`:
29
+ Example:
36
30
 
37
31
  ```ts
38
32
  import { defineConfig } from 'lintmax'
39
33
 
40
34
  export default defineConfig({
41
- compact: true,
42
- globalIgnorePatterns: ['packages/ui/**', '.intlayer/cache/**'],
43
- biome: {
44
- rules: { noBarrelFile: 'off' },
45
- overrides: [{ disableLinter: true, includes: ['packages/ui/**'] }]
46
- },
47
- oxlint: {
48
- ignorePatterns: ['_generated/'],
49
- rules: { 'unicorn/filename-case': 'off' }
50
- }
51
- })
52
- ```
53
-
54
- - `globalIgnorePatterns` appends patterns to Biome, ESLint, and oxlint ignore sets.
55
- - `compact` runs a whitespace compaction pass before linting (`false` by default).
56
- - `lintmax fix`: rewrites tracked/untracked text files by collapsing 2+ blank lines to 1.
57
- - `lintmax check`: verifies compaction state without modifying files.
58
-
59
- ### ESLint overrides
60
-
61
- Create `eslint.config.ts`:
62
-
63
- ```ts
64
- import { eslint } from 'lintmax/eslint'
65
-
66
- export default eslint({
67
- rules: { '@typescript-eslint/no-magic-numbers': 'off' },
68
35
  ignores: ['vendor/**'],
69
- tailwind: 'src/styles/globals.css',
70
- append: [{ files: ['tests/**'], rules: { 'no-magic-numbers': 'off' } }]
36
+ eslint: { off: ['@typescript-eslint/no-magic-numbers'] },
37
+ overrides: {
38
+ '**/*.test.ts': {
39
+ eslint: ['no-console'],
40
+ oxlint: ['no-console'],
41
+ biome: ['noConsole']
42
+ }
43
+ }
71
44
  })
72
45
  ```
73
46
 
74
- Without `eslint.config.ts`, lintmax generates a default config automatically.
75
-
76
- ### TypeScript
77
-
78
- `tsconfig.json`:
79
-
80
- ```json
81
- { "extends": "lintmax/tsconfig" }
82
- ```
83
-
84
- Strict mode, bundler resolution, ESNext target, JSX preserve. One preset for all.
85
-
86
- ## How it stays up to date
87
-
88
- Biome config is built **dynamically** from the installed `@biomejs/biome` schema at runtime. New rules, category changes, and nursery promotions are picked up automatically.
89
-
90
- ESLint plugins and oxlint are dependencies with auto-updating versions. Run `bun update` to get the latest rules without waiting for a lintmax release.
91
-
92
- ## What each tool handles
93
-
94
- | Tool | Scope |
95
- | ----------------- | ------------------------------------------------------------------------------- |
96
- | Biome | Formatting (JS/TS/JSX/TSX/CSS/JSON) + linting |
97
- | oxlint | Fast linting (correctness, perf, style, pedantic) |
98
- | ESLint | Type-aware linting (typescript-eslint, React, Next.js, Tailwind, Perfectionist) |
99
- | Prettier | Markdown formatting |
100
- | sort-package-json | package.json field ordering |
101
- | Flowmark | Markdown prose wrapping (optional, uses system install) |
102
-
103
- ## License
47
+ Advanced options: `doc/advanced-configuration.md`.
104
48
 
105
- MIT
49
+ License: MIT
package/dist/cli.js CHANGED
@@ -1,499 +1,24 @@
1
1
  #!/usr/bin/env bun
2
- import { env as bunEnv, file, spawnSync, write } from 'bun';
3
- import { cacheDir, sync } from './index.js';
4
- import { dirnamePath, fromFileUrl, joinPath } from './path.js';
5
- class CliExitError extends Error {
6
- code;
7
- constructor({ code, message }) {
8
- super(message ?? '');
9
- this.code = code;
10
- }
11
- }
12
- const COMPACT_REGEX = /(?:\r?\n){2,}/gu, compactBasenames = new Set(['.env.example', '.gitignore', '.npmrc', '.prettierignore', 'Dockerfile', 'Makefile']), compactExtensions = new Set([
13
- '.cjs',
14
- '.css',
15
- '.gql',
16
- '.graphql',
17
- '.html',
18
- '.js',
19
- '.json',
20
- '.jsonc',
21
- '.jsx',
22
- '.md',
23
- '.mjs',
24
- '.mts',
25
- '.scss',
26
- '.sql',
27
- '.ts',
28
- '.tsx',
29
- '.txt',
30
- '.yaml',
31
- '.yml'
32
- ]), decoder = new TextDecoder(), cwd = process.cwd(), cmd = process.argv[2], ignoreEntries = ['.cache/', '.eslintcache'], lintmaxRoot = dirnamePath(dirnamePath(fromFileUrl(import.meta.url))), decodeText = (bytes) => decoder.decode(bytes ?? new Uint8Array()), pathExists = async ({ path }) => file(path).exists(), readJson = async ({ path }) => {
33
- if (!(await pathExists({ path })))
34
- return {};
35
- try {
36
- const text = await file(path).text();
37
- return JSON.parse(text);
38
- }
39
- catch {
40
- return {};
41
- }
42
- }, readRequiredJson = async ({ path }) => {
43
- const text = await file(path).text();
44
- return JSON.parse(text);
45
- }, writeJson = async ({ data, path }) => write(path, `${JSON.stringify(data, null, 2)}\n`), basename = ({ path }) => {
46
- const index = path.lastIndexOf('/');
47
- if (index === -1)
48
- return path;
49
- return path.slice(index + 1);
50
- }, extension = ({ path }) => {
51
- const slashIndex = path.lastIndexOf('/'), dotIndex = path.lastIndexOf('.');
52
- return dotIndex > slashIndex ? path.slice(dotIndex) : '';
53
- }, compactContent = ({ content }) => content.replace(COMPACT_REGEX, '\n'), isCompactCandidate = ({ relativePath }) => {
54
- const fileName = basename({ path: relativePath });
55
- if (compactBasenames.has(fileName))
56
- return true;
57
- return compactExtensions.has(extension({ path: relativePath }));
58
- }, isBinary = ({ bytes }) => {
59
- for (const byte of bytes)
60
- if (byte === 0)
61
- return true;
62
- return false;
63
- }, listCompactFiles = ({ env, root }) => {
64
- const result = spawnSync({
65
- cmd: ['git', '-C', root, 'ls-files', '-z', '--cached', '--others', '--exclude-standard'],
66
- env,
67
- stderr: 'pipe',
68
- stdout: 'pipe'
69
- });
70
- if (result.exitCode !== 0) {
71
- const stderr = decodeText(result.stderr).trim();
72
- throw new CliExitError({
73
- code: result.exitCode,
74
- message: stderr.length > 0 ? stderr : 'Failed to list files for compact step'
75
- });
76
- }
77
- const entries = decodeText(result.stdout).split('\0'), files = [];
78
- for (const entry of entries)
79
- if (entry.length > 0 && entry !== 'bun.lock')
80
- files.push(entry);
81
- return files;
82
- }, runCompact = async ({ env, mode, root }) => {
83
- const files = listCompactFiles({ env, root }), results = await Promise.all(files.map(async (relativePath) => {
84
- if (!isCompactCandidate({ relativePath }))
85
- return { changed: false, relativePath, scanned: false };
86
- const absolutePath = joinPath(root, relativePath), source = file(absolutePath);
87
- if (!(await source.exists()))
88
- return { changed: false, relativePath, scanned: false };
89
- const bytes = new Uint8Array(await source.arrayBuffer());
90
- if (isBinary({ bytes }))
91
- return { changed: false, relativePath, scanned: true };
92
- const content = decodeText(bytes), compacted = compactContent({ content });
93
- if (content === compacted)
94
- return { changed: false, relativePath, scanned: true };
95
- if (mode === 'fix')
96
- await write(absolutePath, compacted);
97
- return { changed: true, relativePath, scanned: true };
98
- })), changed = [];
99
- let scanned = 0;
100
- for (const result of results) {
101
- if (result.scanned)
102
- scanned += 1;
103
- if (result.changed)
104
- changed.push(result.relativePath);
105
- }
106
- if (mode === 'fix') {
107
- process.stdout.write(`[compact] Scanned ${scanned} files\n`);
108
- process.stdout.write(`[compact] Updated ${changed.length} files\n`);
109
- return;
110
- }
111
- if (changed.length === 0)
112
- return;
113
- const shown = changed.slice(0, 10), suffix = changed.length > shown.length ? `\n...and ${changed.length - shown.length} more` : '';
114
- throw new CliExitError({
115
- code: 1,
116
- message: `[compact]\nFiles requiring compaction:\n${shown.join('\n')}${suffix}\nRun: lintmax fix`
117
- });
118
- }, ensureDirectory = ({ directory }) => {
119
- const result = spawnSync({
120
- cmd: ['mkdir', '-p', directory],
121
- stderr: 'pipe',
122
- stdout: 'pipe'
123
- });
124
- if (result.exitCode === 0)
125
- return;
126
- const stderr = decodeText(result.stderr).trim();
127
- throw new CliExitError({
128
- code: result.exitCode,
129
- message: stderr.length > 0 ? stderr : `Failed to create directory: ${directory}`
130
- });
131
- }, sortKeys = (obj) => {
132
- const sorted = {}, keys = Object.keys(obj).toSorted();
133
- for (const key of keys)
134
- sorted[key] = obj[key];
135
- return sorted;
136
- }, initScripts = async ({ pkg, pkgPath }) => {
137
- const scripts = pkg.scripts ?? {};
138
- let changed = false;
139
- if (!scripts.fix) {
140
- scripts.fix = 'lintmax fix';
141
- changed = true;
142
- }
143
- if (!scripts.check) {
144
- scripts.check = 'lintmax check';
145
- changed = true;
146
- }
147
- if (!changed)
148
- return;
149
- pkg.scripts = scripts;
150
- await writeJson({ data: pkg, path: pkgPath });
151
- }, initTsconfig = async ({ configFiles }) => {
152
- const tsconfigPath = joinPath(cwd, 'tsconfig.json');
153
- if (!(await pathExists({ path: tsconfigPath }))) {
154
- const tsconfig = { extends: 'lintmax/tsconfig' };
155
- if (configFiles.length > 0)
156
- tsconfig.include = configFiles;
157
- await writeJson({ data: tsconfig, path: tsconfigPath });
158
- return;
159
- }
160
- try {
161
- const tsconfig = await readRequiredJson({ path: tsconfigPath });
162
- let changed = false;
163
- if (tsconfig.extends !== 'lintmax/tsconfig') {
164
- tsconfig.extends = 'lintmax/tsconfig';
165
- changed = true;
166
- }
167
- const toAdd = configFiles.filter(f => !(tsconfig.include ?? []).includes(f));
168
- if (toAdd.length > 0) {
169
- tsconfig.include = [...(tsconfig.include ?? []), ...toAdd];
170
- changed = true;
171
- }
172
- if (changed)
173
- await writeJson({ data: tsconfig, path: tsconfigPath });
174
- }
175
- catch {
176
- process.stderr.write('tsconfig.json: could not parse, add "extends": "lintmax/tsconfig" manually\n');
177
- }
178
- }, initGitignore = async () => {
179
- const gitignorePath = joinPath(cwd, '.gitignore');
180
- if (await pathExists({ path: gitignorePath })) {
181
- const content = await file(gitignorePath).text(), toAdd = [];
182
- for (const entry of ignoreEntries)
183
- if (!content.includes(entry))
184
- toAdd.push(entry);
185
- if (toAdd.length > 0)
186
- await write(gitignorePath, `${content.trimEnd()}\n${toAdd.join('\n')}\n`);
187
- return;
188
- }
189
- await write(gitignorePath, `${ignoreEntries.join('\n')}\n`);
190
- }, initVscodeSettings = async ({ pkg }) => {
191
- const vscodePath = joinPath(cwd, '.vscode');
192
- ensureDirectory({ directory: vscodePath });
193
- const settingsPath = joinPath(vscodePath, 'settings.json'), settings = await readJson({ path: settingsPath });
194
- settings['biome.configPath'] = 'node_modules/.cache/lintmax/biome.json';
195
- const formatterLangs = [
196
- 'css',
197
- 'graphql',
198
- 'javascript',
199
- 'javascriptreact',
200
- 'json',
201
- 'jsonc',
202
- 'typescript',
203
- 'typescriptreact'
204
- ];
205
- for (const lang of formatterLangs) {
206
- const key = `[${lang}]`, existing = (settings[key] ?? {});
207
- settings[key] = {
208
- ...existing,
209
- 'editor.defaultFormatter': 'biomejs.biome'
210
- };
211
- }
212
- const existingActions = (settings['editor.codeActionsOnSave'] ?? {});
213
- settings['editor.codeActionsOnSave'] = {
214
- ...existingActions,
215
- 'source.fixAll.biome': 'always',
216
- 'source.fixAll.eslint': 'always',
217
- 'source.organizeImports.biome': 'always'
218
- };
219
- settings['editor.formatOnSave'] = true;
220
- settings['eslint.rules.customizations'] = [{ rule: '*', severity: 'warn' }];
221
- if (pkg.workspaces && !settings['eslint.workingDirectories']) {
222
- const dirs = [];
223
- for (const ws of pkg.workspaces) {
224
- const pattern = ws.endsWith('/') ? ws : `${ws}/`;
225
- dirs.push({ pattern });
226
- }
227
- if (dirs.length > 0)
228
- settings['eslint.workingDirectories'] = dirs;
229
- }
230
- await writeJson({ data: sortKeys(settings), path: settingsPath });
231
- }, initVscodeExtensions = async () => {
232
- const extensionsPath = joinPath(cwd, '.vscode', 'extensions.json'), extJson = (await readJson({ path: extensionsPath })), recommendations = ['biomejs.biome', 'dbaeumer.vscode-eslint'], currentRecs = extJson.recommendations ?? [], recsToAdd = [];
233
- for (const rec of recommendations)
234
- if (!currentRecs.includes(rec))
235
- recsToAdd.push(rec);
236
- if (recsToAdd.length > 0 || !extJson.recommendations) {
237
- extJson.recommendations = [...currentRecs, ...recsToAdd];
238
- await writeJson({ data: extJson, path: extensionsPath });
239
- }
240
- }, findLegacyConfigs = async () => {
241
- const legacyConfigs = [
242
- '.eslintrc',
243
- '.eslintrc.json',
244
- '.eslintrc.js',
245
- '.eslintrc.cjs',
246
- '.eslintrc.yml',
247
- '.eslintrc.yaml',
248
- '.prettierrc',
249
- '.prettierrc.json',
250
- '.prettierrc.js',
251
- '.prettierrc.yml',
252
- '.prettierrc.yaml',
253
- '.prettierrc.toml',
254
- 'biome.json',
255
- 'biome.jsonc',
256
- '.oxlintrc.json'
257
- ], checks = legacyConfigs.map(async (configFile) => ({
258
- configFile,
259
- exists: await pathExists({ path: joinPath(cwd, configFile) })
260
- })), resolved = await Promise.all(checks), found = [];
261
- for (const item of resolved)
262
- if (item.exists)
263
- found.push(item.configFile);
264
- return found;
265
- }, readVersion = async () => {
266
- const pkg = await readRequiredJson({
267
- path: joinPath(lintmaxRoot, 'package.json')
268
- });
269
- return pkg.version;
270
- }, usage = ({ version }) => {
271
- process.stdout.write(`lintmax v${version}\n\n`);
272
- process.stdout.write('Usage: lintmax <command>\n\n');
273
- process.stdout.write('Commands:\n');
274
- process.stdout.write(' init Scaffold config files for a new project\n');
275
- process.stdout.write(' fix Auto-fix and format all files\n');
276
- process.stdout.write(' check Check all files without modifying\n');
277
- process.stdout.write(' --version Show version\n');
278
- }, resolvePackageJsonPath = async ({ pkg }) => {
279
- try {
280
- return fromFileUrl(import.meta.resolve(`${pkg}/package.json`));
281
- }
282
- catch {
283
- const consumerCandidate = joinPath(cwd, 'node_modules', pkg, 'package.json');
284
- if (await pathExists({ path: consumerCandidate }))
285
- return consumerCandidate;
286
- return null;
287
- }
288
- }, resolveBin = async ({ bin, pkg }) => {
289
- const packageJsonPath = await resolvePackageJsonPath({ pkg });
290
- if (!packageJsonPath)
291
- throw new CliExitError({
292
- code: 1,
293
- message: `Cannot find ${pkg} — run: bun add -d lintmax`
294
- });
295
- const pkgJson = await readRequiredJson({ path: packageJsonPath }), pkgDir = dirnamePath(packageJsonPath), binPath = typeof pkgJson.bin === 'string' ? pkgJson.bin : (pkgJson.bin?.[bin] ?? '');
296
- return joinPath(pkgDir, binPath);
297
- }, run = ({ args, command, env, label, silent = false }) => {
298
- const result = spawnSync({
299
- cmd: [command, ...args],
300
- cwd,
301
- env,
302
- stderr: silent ? 'pipe' : 'inherit',
303
- stdout: silent ? 'pipe' : 'inherit'
304
- });
305
- if (result.exitCode === 0)
306
- return;
307
- if (silent) {
308
- process.stderr.write(`[${label}]\n`);
309
- const stdout = decodeText(result.stdout);
310
- if (stdout.length > 0)
311
- process.stderr.write(stdout);
312
- const stderr = decodeText(result.stderr);
313
- if (stderr.length > 0)
314
- process.stderr.write(stderr);
315
- }
316
- throw new CliExitError({ code: result.exitCode });
317
- }, runInit = async () => {
318
- const pkgPath = joinPath(cwd, 'package.json');
319
- if (!(await pathExists({ path: pkgPath })))
320
- throw new CliExitError({ code: 1, message: 'No package.json found' });
321
- const pkg = await readRequiredJson({ path: pkgPath }), configFiles = [];
322
- if (await pathExists({ path: joinPath(cwd, 'eslint.config.ts') }))
323
- configFiles.push('eslint.config.ts');
324
- if (await pathExists({ path: joinPath(cwd, 'lintmax.config.ts') }))
325
- configFiles.push('lintmax.config.ts');
326
- await initScripts({ pkg, pkgPath });
327
- await initTsconfig({ configFiles });
328
- await initGitignore();
329
- await initVscodeSettings({ pkg });
330
- await initVscodeExtensions();
331
- const foundLegacy = await findLegacyConfigs();
332
- process.stdout.write('tsconfig.json extends lintmax/tsconfig');
333
- if (configFiles.length > 0)
334
- process.stdout.write(`, include: ${configFiles.join(', ')}`);
335
- process.stdout.write('\n');
336
- process.stdout.write('package.json "fix": "lintmax fix", "check": "lintmax check"\n');
337
- process.stdout.write(`.gitignore ${ignoreEntries.join(', ')}\n`);
338
- process.stdout.write('.vscode/settings biome formatter, codeActionsOnSave, eslint\n');
339
- process.stdout.write('.vscode/ext biomejs.biome, dbaeumer.vscode-eslint\n');
340
- if (foundLegacy.length > 0)
341
- process.stdout.write(`\nLegacy configs found (can be removed): ${foundLegacy.join(', ')}\n`);
342
- process.stdout.write('\nRun: bun fix\n');
343
- }, runLint = async () => {
344
- const dir = joinPath(cwd, cacheDir);
345
- ensureDirectory({ directory: dir });
346
- const configPath = joinPath(cwd, 'lintmax.config.ts'), hasConfig = await pathExists({ path: configPath }), bundledBinA = joinPath(lintmaxRoot, 'node_modules', '.bin'), bundledBinB = joinPath(dirnamePath(lintmaxRoot), '.bin'), cwdBinDir = joinPath(cwd, 'node_modules', '.bin'), runtimePath = joinPath(dir, 'lintmax.json'), env = {
347
- ...bunEnv,
348
- PATH: `${bundledBinA}:${bundledBinB}:${cwdBinDir}:${bunEnv.PATH ?? ''}`
349
- };
350
- if (hasConfig)
351
- run({
352
- args: [
353
- '-e',
354
- `const m = await import('${configPath}'); const { sync: s } = await import('lintmax'); await s(m.default);`
355
- ],
356
- command: 'bun',
357
- env,
358
- label: 'config',
359
- silent: true
360
- });
361
- else
362
- await sync();
363
- const runtime = (await readJson({ path: runtimePath }));
364
- if (runtime.compact === true)
365
- await runCompact({
366
- env,
367
- mode: cmd === 'fix' ? 'fix' : 'check',
368
- root: cwd
369
- });
370
- const hasEslintConfig = (await pathExists({ path: joinPath(cwd, 'eslint.config.ts') })) ||
371
- (await pathExists({ path: joinPath(cwd, 'eslint.config.js') })) ||
372
- (await pathExists({ path: joinPath(cwd, 'eslint.config.mjs') })), eslintArgs = hasEslintConfig ? [] : ['--config', joinPath(dir, 'eslint.config.mjs')], [sortPkgJson, biomeBin, oxlintBin, eslintBin, prettierBin] = await Promise.all([
373
- resolveBin({ bin: 'sort-package-json', pkg: 'sort-package-json' }),
374
- resolveBin({ bin: 'biome', pkg: '@biomejs/biome' }),
375
- resolveBin({ bin: 'oxlint', pkg: 'oxlint' }),
376
- resolveBin({ bin: 'eslint', pkg: 'eslint' }),
377
- resolveBin({ bin: 'prettier', pkg: 'prettier' })
378
- ]), prettierMd = [
379
- '--single-quote',
380
- '--no-semi',
381
- '--trailing-comma',
382
- 'none',
383
- '--print-width',
384
- '80',
385
- '--arrow-parens',
386
- 'avoid',
387
- '--tab-width',
388
- '2',
389
- '--prose-wrap',
390
- 'preserve'
391
- ], hasFlowmark = spawnSync({
392
- cmd: ['which', 'flowmark'],
393
- env,
394
- stderr: 'pipe',
395
- stdout: 'pipe'
396
- }).exitCode === 0;
397
- if (cmd === 'fix') {
398
- run({
399
- args: [sortPkgJson, '**/package.json', '--ignore', '**/node_modules/**'],
400
- command: 'bun',
401
- env,
402
- label: 'sort-package-json',
403
- silent: true
404
- });
405
- run({
406
- args: [biomeBin, 'check', '--config-path', dir, '--fix', '--diagnostic-level=error'],
407
- command: 'bun',
408
- env,
409
- label: 'biome',
410
- silent: true
411
- });
412
- run({
413
- args: [oxlintBin, '-c', joinPath(dir, '.oxlintrc.json'), '--fix', '--fix-suggestions', '--quiet'],
414
- command: 'bun',
415
- env,
416
- label: 'oxlint',
417
- silent: true
418
- });
419
- run({
420
- args: [eslintBin, ...eslintArgs, '--fix', '--cache', '--cache-location', joinPath(cwd, '.cache', '.eslintcache')],
421
- command: 'bun',
422
- env,
423
- label: 'eslint',
424
- silent: true
425
- });
426
- run({
427
- args: [biomeBin, 'check', '--config-path', dir, '--fix', '--diagnostic-level=error'],
428
- command: 'bun',
429
- env,
430
- label: 'biome',
431
- silent: true
432
- });
433
- if (hasFlowmark)
434
- run({
435
- args: ['-w', '0', '--auto', '.'],
436
- command: 'flowmark',
437
- env,
438
- label: 'flowmark',
439
- silent: true
440
- });
441
- run({
442
- args: [prettierBin, ...prettierMd, '--write', '--no-error-on-unmatched-pattern', '**/*.md'],
443
- command: 'bun',
444
- env,
445
- label: 'prettier',
446
- silent: true
447
- });
448
- return;
449
- }
450
- run({
451
- args: [sortPkgJson, '--check', '**/package.json', '--ignore', '**/node_modules/**'],
452
- command: 'bun',
453
- env,
454
- label: 'sort-package-json'
455
- });
456
- run({
457
- args: [biomeBin, 'ci', '--config-path', dir, '--diagnostic-level=error'],
458
- command: 'bun',
459
- env,
460
- label: 'biome'
461
- });
462
- run({
463
- args: [oxlintBin, '-c', joinPath(dir, '.oxlintrc.json'), '--quiet'],
464
- command: 'bun',
465
- env,
466
- label: 'oxlint'
467
- });
468
- run({
469
- args: [eslintBin, ...eslintArgs, '--cache', '--cache-location', joinPath(cwd, '.cache', '.eslintcache')],
470
- command: 'bun',
471
- env,
472
- label: 'eslint'
473
- });
474
- run({
475
- args: [prettierBin, ...prettierMd, '--check', '--no-error-on-unmatched-pattern', '**/*.md'],
476
- command: 'bun',
477
- env,
478
- label: 'prettier'
479
- });
480
- }, main = async () => {
2
+ import { CliExitError, readVersion, usage } from './core.js';
3
+ import { runInit } from './init.js';
4
+ import { runLint } from './pipeline.js';
5
+ const command = process.argv[2], main = async () => {
481
6
  const version = await readVersion();
482
- if (cmd === 'init') {
7
+ if (command === 'init') {
483
8
  await runInit();
484
9
  return;
485
10
  }
486
- if (cmd === '--version' || cmd === '-v') {
11
+ if (command === '--version' || command === '-v') {
487
12
  process.stdout.write(`${version}\n`);
488
13
  return;
489
14
  }
490
- if (cmd !== 'fix' && cmd !== 'check') {
15
+ if (command !== 'fix' && command !== 'check') {
491
16
  usage({ version });
492
- if (cmd === '--help' || cmd === '-h')
17
+ if (command === '--help' || command === '-h')
493
18
  return;
494
19
  throw new CliExitError({ code: 1 });
495
20
  }
496
- await runLint();
21
+ await runLint({ command });
497
22
  };
498
23
  try {
499
24
  await main();