@evanpurkhiser/oxc-config 0.2.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.
@@ -0,0 +1,16 @@
1
+ name: ci
2
+
3
+ on:
4
+ pull_request:
5
+ workflow_dispatch:
6
+
7
+ jobs:
8
+ check:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-node@v4
13
+ with:
14
+ node-version: '24'
15
+ - run: npm ci
16
+ - run: npm run check
@@ -0,0 +1,37 @@
1
+ name: publish
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+
7
+ jobs:
8
+ check:
9
+ runs-on: ubuntu-latest
10
+ steps:
11
+ - uses: actions/checkout@v4
12
+ - uses: actions/setup-node@v4
13
+ with:
14
+ node-version: '24'
15
+ - run: npm ci
16
+ - run: npm run check
17
+
18
+ publish:
19
+ runs-on: ubuntu-latest
20
+ needs: check
21
+ permissions:
22
+ contents: write
23
+ id-token: write
24
+ steps:
25
+ - uses: actions/checkout@v4
26
+ - uses: actions/setup-node@v4
27
+ with:
28
+ node-version: '24'
29
+ registry-url: 'https://registry.npmjs.org'
30
+ - run: npm ci
31
+ - name: bump version
32
+ run: |
33
+ git config user.name "GitHub Actions"
34
+ git config user.email "<>"
35
+ npm version minor
36
+ git push
37
+ - run: npm publish --provenance --access=public
package/README.md ADDED
@@ -0,0 +1,49 @@
1
+ ## Evan Purkhiser's Personal Oxc config
2
+
3
+ [![publish](https://github.com/evanpurkhiser/oxc-config/workflows/publish/badge.svg)](https://github.com/evanpurkhiser/oxc-config/actions?query=workflow%3Apublish)
4
+ [![NPM](https://img.shields.io/npm/v/@evanpurkhiser/oxc-config)](https://www.npmjs.com/package/@evanpurkhiser/oxc-config)
5
+
6
+ These are my Oxc linting and formatting configurations that I use across my
7
+ various personal
8
+ projects.
9
+
10
+ ```bash
11
+ npm install -D oxlint oxfmt @evanpurkhiser/oxc-config
12
+ ```
13
+
14
+ Create an `oxlint.config.ts` file with the contents:
15
+
16
+ ```ts
17
+ import {defineConfig} from 'oxlint';
18
+ import {all} from '@evanpurkhiser/oxc-config';
19
+
20
+ export default defineConfig({
21
+ extends: all,
22
+ });
23
+ ```
24
+
25
+ The default configuration is for React apps, but you can select from the
26
+ following configurations:
27
+
28
+ - `common` - ES6 and Typescript rules
29
+ - `react` - React specific rules
30
+
31
+ For example:
32
+
33
+ ```ts
34
+ import {defineConfig} from 'oxlint';
35
+ import {common} from '@evanpurkhiser/oxc-config';
36
+
37
+ export default defineConfig({
38
+ extends: [common],
39
+ });
40
+ ```
41
+
42
+ For Oxfmt, create an `oxfmt.config.ts` file:
43
+
44
+ ```ts
45
+ import {defineConfig} from 'oxfmt';
46
+ import {oxfmt} from '@evanpurkhiser/oxc-config/oxfmt';
47
+
48
+ export default defineConfig(oxfmt);
49
+ ```
@@ -0,0 +1,45 @@
1
+ # ESLint to Oxlint migration analysis
2
+
3
+ ## Scope reviewed
4
+
5
+ - `/home/evan/coding/recovery`
6
+ - `/home/evan/coding/instagram-saver`
7
+ - `/home/evan/coding/meal-log`
8
+ - `/home/evan/coding/atuin-abacus`
9
+ - `/home/evan/coding/prolink-connect`
10
+ - `/home/evan/coding/waitress`
11
+ - `/home/evan/coding/transmission-helper`
12
+ - `/home/evan/coding/email-to-lunchmoney`
13
+ - `/home/evan/coding/tooling-personal`
14
+ - `/home/evan/coding/rekordbox-parser`
15
+ - `/home/evan/coding/tune-manager`
16
+ - `/home/evan/coding/doppovich-bot`
17
+ - `/home/evan/coding/keyway-twilio`
18
+ - `/home/evan/coding/prolink-tools`
19
+
20
+ ## Findings by repository
21
+
22
+ | Repository | Current ESLint setup | Recommended Oxlint preset | Special handling |
23
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------------------------- | ------------------------------------------------------------------------------------ |
24
+ | `recovery` | Flat config: `common` + `prettier/prettier: off` | `common` | No custom lint rules needed. |
25
+ | `instagram-saver` | Flat config: `all` + `prettier/prettier: off` | `all` | No custom lint rules needed. |
26
+ | `meal-log` | Flat config: `common` + `prettier/prettier: off` | `common` | No custom lint rules needed. |
27
+ | `atuin-abacus` | Flat config: `common` + `prettier/prettier: off` | `common` | Deno repo; validate JS/TS file globs for CLI usage. |
28
+ | `prolink-connect` | Flat config: `common` + `prettier/prettier: off` | `common` | Keep test-specific overrides local if needed later. |
29
+ | `waitress` | Flat config: `all` + `prettier/prettier: off` | `all` | Browser React app. |
30
+ | `transmission-helper` | Flat config: `common` + `prettier/prettier: off` | `common` | No custom lint rules needed. |
31
+ | `email-to-lunchmoney` | Flat config: `common` + `prettier/prettier: off` | `common` | Cloudflare Worker; add env/global overrides only if diagnostics require it. |
32
+ | `tooling-personal` | Flat config: `all` + `prettier/prettier: off` | `all` | Tooling repo likely to become migration templates. |
33
+ | `rekordbox-parser` | Legacy `.eslintrc.js`: extends `common`, node env, prettier off | `common` | Add `env.node: true` in local config. |
34
+ | `tune-manager` | Legacy `.eslintrc.js`: extends default (`all`), browser env, prettier off | `all` | Add `env.browser: true` explicitly if needed. |
35
+ | `doppovich-bot` | Legacy `.eslintrc.js`: extends `common`, node env, prettier off | `common` | Add `env.node: true` in local config. |
36
+ | `keyway-twilio` | Legacy `.eslintrc.js`: extends `common`, node env, prettier off | `common` | Add `env.node: true` in local config. |
37
+ | `prolink-tools` | Legacy `.eslintrc.js`: extends default (`all`) with custom import groups and `typescript/no-unused-vars` ignore patterns | `all` | Keep repo-local overrides for import sorting groups and unused-vars ignore patterns. |
38
+
39
+ ## Cross-repo migration notes
40
+
41
+ 1. Every repo disables `prettier/prettier`; this is naturally removed in Oxlint.
42
+ 2. Most repos can use only one line of config via `extends: [common]` or `extends: all`.
43
+ 3. Legacy repos that currently set `env.node` should keep that as repo-local override.
44
+ 4. `prolink-tools` should keep local customizations because the internal import groups differ from the shared default.
45
+ 5. Run dual lint (`oxlint` + `eslint`) temporarily only for repos where any unsupported rule must be retained.
@@ -0,0 +1,5 @@
1
+ import {defineConfig} from 'oxfmt';
2
+
3
+ import {oxfmt} from './src/oxfmt.mjs';
4
+
5
+ export default defineConfig(oxfmt);
@@ -0,0 +1,7 @@
1
+ import {defineConfig} from 'oxlint';
2
+
3
+ import {common} from './src/index.mjs';
4
+
5
+ export default defineConfig({
6
+ extends: [common],
7
+ });
package/package.json ADDED
@@ -0,0 +1,37 @@
1
+ {
2
+ "$schema": "https://json.schemastore.org/package.json",
3
+ "name": "@evanpurkhiser/oxc-config",
4
+ "version": "0.2.0",
5
+ "description": "Evan Purkhiser's personal Oxc configuration",
6
+ "license": "MIT",
7
+ "author": "Evan Purkhiser",
8
+ "repository": "https://github.com/evanpurkhiser/oxc-config",
9
+ "type": "module",
10
+ "main": "src/index.mjs",
11
+ "exports": {
12
+ ".": "./src/index.mjs",
13
+ "./common": "./src/common.mjs",
14
+ "./react": "./src/react.mjs",
15
+ "./oxfmt": "./src/oxfmt.mjs"
16
+ },
17
+ "scripts": {
18
+ "lint": "oxlint src oxlint.config.ts profiles/all/oxlint.config.ts",
19
+ "format": "oxfmt .",
20
+ "format:check": "oxfmt --check .",
21
+ "check": "npm run lint && npm run format:check"
22
+ },
23
+ "dependencies": {
24
+ "eslint-plugin-simple-import-sort": "^12.1.1"
25
+ },
26
+ "devDependencies": {
27
+ "oxfmt": "^0.41.0",
28
+ "oxlint": "^1.56.0",
29
+ "typescript": "^5.9.2"
30
+ },
31
+ "peerDependencies": {
32
+ "oxlint": ">=1.56.0"
33
+ },
34
+ "volta": {
35
+ "node": "24.3.0"
36
+ }
37
+ }
@@ -0,0 +1,7 @@
1
+ import {defineConfig} from 'oxlint';
2
+
3
+ import {all} from '../../src/index.mjs';
4
+
5
+ export default defineConfig({
6
+ extends: all,
7
+ });
package/src/common.mjs ADDED
@@ -0,0 +1,81 @@
1
+ import {builtinModules} from 'node:module';
2
+
3
+ const common = {
4
+ plugins: ['eslint', 'typescript', 'unicorn', 'oxc', 'import', 'react'],
5
+
6
+ jsPlugins: ['eslint-plugin-simple-import-sort'],
7
+
8
+ rules: {
9
+ // Best practices
10
+ 'array-callback-return': ['warn'],
11
+ 'consistent-return': ['warn'],
12
+ 'no-caller': ['warn'],
13
+ 'no-else-return': ['error', {allowElseIf: false}],
14
+ 'no-extra-label': ['error'],
15
+ 'no-floating-decimal': ['error'],
16
+ 'no-implied-eval': ['error'],
17
+ 'no-lone-blocks': ['error'],
18
+ 'no-return-await': ['error'],
19
+ 'no-self-compare': ['error'],
20
+ 'no-sequences': ['error'],
21
+ 'no-useless-call': ['warn'],
22
+ 'no-useless-concat': ['warn'],
23
+ 'no-useless-return': ['warn'],
24
+ 'require-await': ['warn'],
25
+ curly: ['error'],
26
+ eqeqeq: ['error'],
27
+ radix: ['warn'],
28
+
29
+ // Variables
30
+ 'no-undef-init': ['warn'],
31
+
32
+ // Style (mostly handled by prettier/oxfmt)
33
+ 'eol-last': ['error', 'always'],
34
+ 'new-parens': ['error'],
35
+ 'padded-blocks': ['warn', 'never'],
36
+ 'spaced-comment': ['warn', 'always'],
37
+
38
+ // ECMAScript
39
+ 'no-var': ['error'],
40
+ 'prefer-arrow-callback': ['warn'],
41
+ 'prefer-const': ['error'],
42
+ 'prefer-destructuring': ['off'],
43
+ 'prefer-numeric-literals': ['warn'],
44
+ 'prefer-rest-params': ['warn'],
45
+ 'prefer-spread': ['warn'],
46
+ 'prefer-template': ['warn'],
47
+ 'arrow-body-style': ['error', 'as-needed'],
48
+
49
+ // Disabled for TypeScript
50
+ 'no-unused-expressions': ['off'],
51
+
52
+ // TypeScript
53
+ 'typescript/explicit-function-return-type': ['off'],
54
+ 'typescript/no-use-before-define': ['off'],
55
+ 'typescript/no-explicit-any': ['off'],
56
+ 'typescript/no-non-null-assertion': ['off'],
57
+ 'typescript/explicit-module-boundary-types': ['off'],
58
+ 'typescript/no-unused-vars': ['error', {argsIgnorePattern: '^_'}],
59
+ 'typescript/no-unused-expressions': ['error'],
60
+ 'typescript/no-useless-constructor': ['error'],
61
+ 'typescript/array-type': ['error', {default: 'array-simple'}],
62
+
63
+ // Sort imports
64
+ 'simple-import-sort/exports': 'error',
65
+ 'simple-import-sort/imports': [
66
+ 'error',
67
+ {
68
+ groups: [
69
+ ['^\\u0000'],
70
+ ['^react', '^@?\\w'],
71
+ [`^(${builtinModules.join('|')})(/|$)`],
72
+ ['^(src|app)(/.*|$)'],
73
+ ['^\\.\\.(?!/?$)', '^\\.\\./?$'],
74
+ ['^\\./(?=.*/)(?!/?$)', '^\\.(?!/?$)', '^\\./?$'],
75
+ ],
76
+ },
77
+ ],
78
+ },
79
+ };
80
+
81
+ export {common};
package/src/index.mjs ADDED
@@ -0,0 +1,6 @@
1
+ import {common} from './common.mjs';
2
+ import {react} from './react.mjs';
3
+
4
+ const all = [common, react];
5
+
6
+ export {all, common, react};
package/src/oxfmt.mjs ADDED
@@ -0,0 +1,33 @@
1
+ const oxfmt = {
2
+ bracketSpacing: false,
3
+ printWidth: 90,
4
+ singleQuote: true,
5
+ arrowParens: 'avoid',
6
+ sortImports: {
7
+ sortSideEffects: true,
8
+ customGroups: [
9
+ {
10
+ groupName: 'react-libs',
11
+ selector: 'external',
12
+ elementNamePattern: ['react', 'react-**'],
13
+ },
14
+ {
15
+ groupName: 'project-internal',
16
+ selector: 'import',
17
+ elementNamePattern: ['src', 'src/**', 'app', 'app/**'],
18
+ },
19
+ ],
20
+ groups: [
21
+ 'side_effect',
22
+ 'react-libs',
23
+ 'external',
24
+ 'builtin',
25
+ 'project-internal',
26
+ 'parent',
27
+ ['sibling', 'index'],
28
+ 'unknown',
29
+ ],
30
+ },
31
+ };
32
+
33
+ export {oxfmt};
package/src/react.mjs ADDED
@@ -0,0 +1,19 @@
1
+ const react = {
2
+ env: {
3
+ browser: true,
4
+ },
5
+
6
+ rules: {
7
+ 'react-hooks/rules-of-hooks': ['error'],
8
+ 'react-hooks/exhaustive-deps': ['warn'],
9
+ 'react/prop-types': ['off'],
10
+ 'react/display-name': ['off'],
11
+ 'react/no-access-state-in-setstate': ['warn'],
12
+ 'react/no-this-in-sfc': ['warn'],
13
+ 'react/prefer-stateless-function': ['warn'],
14
+ 'react/jsx-boolean-value': ['warn'],
15
+ 'react/jsx-pascal-case': ['warn'],
16
+ },
17
+ };
18
+
19
+ export {react};