@letstri/oxc-config 0.5.0 → 0.6.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 CHANGED
@@ -32,44 +32,6 @@ all four run. Config files are skipped if they already exist (`--force` to
32
32
  overwrite); editor settings are deep-merged into any existing files. See
33
33
  [Editor setup](#editor-setup).
34
34
 
35
- ## AI setup prompt
36
-
37
- Paste this into Claude Code, Cursor, or any coding agent to wire everything up:
38
-
39
- <details>
40
- <summary>Show prompt</summary>
41
-
42
- ````text
43
- Set up @letstri/oxc-config (oxlint + oxfmt) in this project:
44
-
45
- 1. Install dev deps: `@letstri/oxc-config oxlint oxfmt`.
46
- 2. Remove ESLint and Prettier: their configs, deps, and scripts.
47
- 3. Create `oxlint.config.ts`:
48
- ```ts
49
- import { oxlintConfig } from '@letstri/oxc-config'
50
-
51
- export default oxlintConfig()
52
- ```
53
- 4. Create `oxfmt.config.ts`:
54
- ```ts
55
- import { oxfmtConfig } from '@letstri/oxc-config'
56
-
57
- export default oxfmtConfig()
58
- ```
59
- 5. Add package.json scripts:
60
- - "lint": "oxlint"
61
- - "lint:fix": "oxlint --fix"
62
- - "format": "oxfmt"
63
- - "format:check": "oxfmt --check"
64
- 6. Framework plugins auto-enable from the nearest package.json. If a framework
65
- dep (react/vue/next/vitest/jest/typescript) lives in a nested workspace,
66
- enable it manually, e.g. `oxlintConfig({ plugins: ['vue'] })`.
67
- 7. Add the VS Code and Zed editor settings from the @letstri/oxc-config README.
68
- 8. Run `pnpm lint` and `pnpm format` and fix anything reported.
69
- ````
70
-
71
- </details>
72
-
73
35
  ## Usage
74
36
 
75
37
  `oxlint.config.ts`:
@@ -126,16 +88,16 @@ export default oxlintConfig({ rules: { 'no-console': 'off' } }, { plugins: ['vue
126
88
 
127
89
  ### Tailwind
128
90
 
129
- `tailwind({ entryPoint })` returns a config chunk for
91
+ `tailwindPlugin({ entryPoint })` returns a config chunk for
130
92
  [`eslint-plugin-better-tailwindcss`](https://github.com/schoero/eslint-plugin-better-tailwindcss).
131
93
  Pass it as an argument to `oxlintConfig`:
132
94
 
133
95
  ```ts
134
- import { oxlintConfig, tailwind } from '@letstri/oxc-config'
96
+ import { oxlintConfig, tailwindPlugin } from '@letstri/oxc-config'
135
97
 
136
98
  export default oxlintConfig(
137
99
  { plugins: ['react', 'jsx-a11y'] },
138
- tailwind({ entryPoint: 'app/globals.css' }),
100
+ tailwindPlugin({ entryPoint: 'app/globals.css' }),
139
101
  )
140
102
  ```
141
103
 
@@ -150,7 +112,7 @@ Options:
150
112
  a component library generates that the plugin can't resolve):
151
113
 
152
114
  ```ts
153
- tailwind({ entryPoint: 'app/globals.css', ignoreClasses: ['toaster'] })
115
+ tailwindPlugin({ entryPoint: 'app/globals.css', ignoreClasses: ['toaster'] })
154
116
  ```
155
117
 
156
118
  The plugin is an **optional peer dependency** — install it yourself:
@@ -159,7 +121,7 @@ The plugin is an **optional peer dependency** — install it yourself:
159
121
  pnpm add -D eslint-plugin-better-tailwindcss
160
122
  ```
161
123
 
162
- If the plugin is missing, `tailwind()` throws with an install hint.
124
+ If the plugin is missing, `tailwindPlugin()` throws with an install hint.
163
125
 
164
126
  ## Editor setup
165
127
 
package/dist/index.d.mts CHANGED
@@ -1,7 +1,21 @@
1
1
  import { defineConfig } from "oxlint";
2
2
  import { defineConfig as defineConfig$1 } from "oxfmt";
3
3
  //#region src/oxlint.d.ts
4
- type OxlintOptions$1 = Parameters<typeof defineConfig>[0];
4
+ type OxlintOptions = Parameters<typeof defineConfig>[0];
5
+ type OxlintPlugin = NonNullable<NonNullable<OxlintOptions>['plugins']>[number];
6
+ declare const basePlugins: readonly ["import", "unicorn", "jsdoc", "node", "promise", "oxc"];
7
+ /**
8
+ * Plugins always enabled by the base config — excluded from the `plugins` you
9
+ * can add, since listing them again is redundant.
10
+ */
11
+ type BasePlugin = (typeof basePlugins)[number];
12
+ /**
13
+ * Oxlint config accepted by {@link oxlintConfig}. Same as oxlint's own config,
14
+ * but `plugins` can't include the always-on base plugins.
15
+ */
16
+ type OxlintConfig = Omit<NonNullable<OxlintOptions>, 'plugins'> & {
17
+ plugins?: Exclude<OxlintPlugin, BasePlugin>[];
18
+ };
5
19
  /**
6
20
  * Build an oxlint config.
7
21
  *
@@ -10,8 +24,9 @@ type OxlintOptions$1 = Parameters<typeof defineConfig>[0];
10
24
  * plugin whose dependency lives elsewhere — e.g. a nested workspace like
11
25
  * `apps/web/package.json` — add it through `plugins`.
12
26
  *
13
- * Pass any number of config objects; they are deep-merged (arrays concatenated),
14
- * so pieces like {@link tailwind} compose without clobbering each other.
27
+ * Pass any number of config objects; they are deep-merged (arrays concatenated,
28
+ * with `plugins` de-duplicated), so pieces like {@link tailwindPlugin} compose
29
+ * without clobbering each other.
15
30
  *
16
31
  * @example
17
32
  * ```ts
@@ -28,11 +43,11 @@ type OxlintOptions$1 = Parameters<typeof defineConfig>[0];
28
43
  * // compose Tailwind — its plugins merge with the ones above, not overwrite
29
44
  * export default oxlintConfig(
30
45
  * { plugins: ['react', 'jsx-a11y'] },
31
- * tailwind({ entryPoint: 'app/globals.css' }),
46
+ * tailwindPlugin({ entryPoint: 'app/globals.css' }),
32
47
  * )
33
48
  * ```
34
49
  */
35
- declare function oxlintConfig(...overrides: OxlintOptions$1[]): OxlintOptions$1;
50
+ declare function oxlintConfig(...overrides: OxlintConfig[]): OxlintOptions;
36
51
  //#endregion
37
52
  //#region src/oxfmt.d.ts
38
53
  type OxfmtOptions = Parameters<typeof defineConfig$1>[0];
@@ -43,7 +58,6 @@ type OxfmtOptions = Parameters<typeof defineConfig$1>[0];
43
58
  declare function oxfmtConfig(...overrides: OxfmtOptions[]): OxfmtOptions;
44
59
  //#endregion
45
60
  //#region src/tailwind.d.ts
46
- type OxlintOptions = Parameters<typeof defineConfig>[0];
47
61
  interface TailwindOptions {
48
62
  /**
49
63
  * Path to the Tailwind entry CSS. Required — the plugin needs it to resolve
@@ -67,7 +81,7 @@ interface TailwindOptions {
67
81
  * Pass the result as an argument to `oxlintConfig`:
68
82
  *
69
83
  * ```ts
70
- * export default oxlintConfig(tailwind({
84
+ * export default oxlintConfig(tailwindPlugin({
71
85
  * entryPoint: 'app/globals.css',
72
86
  * ignoreClasses: ['toaster'],
73
87
  * }))
@@ -77,6 +91,6 @@ interface TailwindOptions {
77
91
  * (`pnpm add -D eslint-plugin-better-tailwindcss`). If it is missing, an error
78
92
  * is thrown.
79
93
  */
80
- declare function tailwind({ entryPoint, ignoreClasses, cwd }: TailwindOptions): OxlintOptions;
94
+ declare function tailwindPlugin({ entryPoint, ignoreClasses, cwd }: TailwindOptions): OxlintConfig;
81
95
  //#endregion
82
- export { oxfmtConfig, oxlintConfig, tailwind };
96
+ export { oxfmtConfig, oxlintConfig, tailwindPlugin };
package/dist/index.mjs CHANGED
@@ -536,8 +536,9 @@ function resolvePlugins(cwd) {
536
536
  * plugin whose dependency lives elsewhere — e.g. a nested workspace like
537
537
  * `apps/web/package.json` — add it through `plugins`.
538
538
  *
539
- * Pass any number of config objects; they are deep-merged (arrays concatenated),
540
- * so pieces like {@link tailwind} compose without clobbering each other.
539
+ * Pass any number of config objects; they are deep-merged (arrays concatenated,
540
+ * with `plugins` de-duplicated), so pieces like {@link tailwindPlugin} compose
541
+ * without clobbering each other.
541
542
  *
542
543
  * @example
543
544
  * ```ts
@@ -554,12 +555,14 @@ function resolvePlugins(cwd) {
554
555
  * // compose Tailwind — its plugins merge with the ones above, not overwrite
555
556
  * export default oxlintConfig(
556
557
  * { plugins: ['react', 'jsx-a11y'] },
557
- * tailwind({ entryPoint: 'app/globals.css' }),
558
+ * tailwindPlugin({ entryPoint: 'app/globals.css' }),
558
559
  * )
559
560
  * ```
560
561
  */
561
562
  function oxlintConfig(...overrides) {
562
- return defu({}, ...overrides, { plugins: resolvePlugins(process.cwd()) }, baseOxlintConfig);
563
+ const merged = defu({}, ...overrides, { plugins: resolvePlugins(process.cwd()) }, baseOxlintConfig);
564
+ if (merged?.plugins) merged.plugins = [...new Set(merged.plugins)];
565
+ return merged;
563
566
  }
564
567
  //#endregion
565
568
  //#region src/oxfmt.ts
@@ -586,7 +589,7 @@ const TAILWIND_PLUGIN = "eslint-plugin-better-tailwindcss";
586
589
  * Pass the result as an argument to `oxlintConfig`:
587
590
  *
588
591
  * ```ts
589
- * export default oxlintConfig(tailwind({
592
+ * export default oxlintConfig(tailwindPlugin({
590
593
  * entryPoint: 'app/globals.css',
591
594
  * ignoreClasses: ['toaster'],
592
595
  * }))
@@ -596,7 +599,7 @@ const TAILWIND_PLUGIN = "eslint-plugin-better-tailwindcss";
596
599
  * (`pnpm add -D eslint-plugin-better-tailwindcss`). If it is missing, an error
597
600
  * is thrown.
598
601
  */
599
- function tailwind({ entryPoint, ignoreClasses = [], cwd = process.cwd() }) {
602
+ function tailwindPlugin({ entryPoint, ignoreClasses = [], cwd = process.cwd() }) {
600
603
  if (!getInstalledPackages(cwd).has(TAILWIND_PLUGIN)) throw new Error(`[@letstri/oxc-config] Tailwind linting needs "${TAILWIND_PLUGIN}". Install it: pnpm add -D ${TAILWIND_PLUGIN}`);
601
604
  return defineConfig({
602
605
  jsPlugins: [TAILWIND_PLUGIN],
@@ -614,4 +617,4 @@ function tailwind({ entryPoint, ignoreClasses = [], cwd = process.cwd() }) {
614
617
  });
615
618
  }
616
619
  //#endregion
617
- export { oxfmtConfig, oxlintConfig, tailwind };
620
+ export { oxfmtConfig, oxlintConfig, tailwindPlugin };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@letstri/oxc-config",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Opinionated Oxlint and Oxfmt configs",
5
5
  "homepage": "https://github.com/letstri/oxc-config#readme",
6
6
  "bugs": {