@venizia/dev-configs 0.2.1 → 0.3.1-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.
Files changed (99) hide show
  1. package/README.md +224 -41
  2. package/dist/{compile.d.ts → compilers/bun.d.ts} +1 -1
  3. package/dist/compilers/bun.d.ts.map +1 -0
  4. package/dist/{compile.js → compilers/bun.js} +8 -9
  5. package/dist/compilers/bun.js.map +1 -0
  6. package/dist/compilers/index.d.ts +2 -0
  7. package/dist/compilers/index.d.ts.map +1 -0
  8. package/dist/compilers/index.js +18 -0
  9. package/dist/compilers/index.js.map +1 -0
  10. package/dist/formatters/index.d.ts +3 -0
  11. package/dist/formatters/index.d.ts.map +1 -0
  12. package/dist/formatters/index.js +19 -0
  13. package/dist/formatters/index.js.map +1 -0
  14. package/dist/formatters/oxfmt.d.ts +28 -0
  15. package/dist/formatters/oxfmt.d.ts.map +1 -0
  16. package/dist/formatters/oxfmt.js +42 -0
  17. package/dist/formatters/oxfmt.js.map +1 -0
  18. package/dist/formatters/prettier.d.ts +3 -0
  19. package/dist/formatters/prettier.d.ts.map +1 -0
  20. package/dist/{prettier.js → formatters/prettier.js} +2 -2
  21. package/dist/formatters/prettier.js.map +1 -0
  22. package/dist/index.d.ts +3 -4
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +3 -4
  25. package/dist/index.js.map +1 -1
  26. package/dist/linters/browser.d.ts +18 -0
  27. package/dist/linters/browser.d.ts.map +1 -0
  28. package/dist/linters/browser.js +31 -0
  29. package/dist/linters/browser.js.map +1 -0
  30. package/dist/linters/eslint.d.ts +20 -0
  31. package/dist/linters/eslint.d.ts.map +1 -0
  32. package/dist/linters/eslint.js +152 -0
  33. package/dist/linters/eslint.js.map +1 -0
  34. package/dist/linters/index.d.ts +6 -0
  35. package/dist/linters/index.d.ts.map +1 -0
  36. package/dist/linters/index.js +22 -0
  37. package/dist/linters/index.js.map +1 -0
  38. package/dist/linters/oxlint.d.ts +19 -0
  39. package/dist/linters/oxlint.d.ts.map +1 -0
  40. package/dist/linters/oxlint.js +166 -0
  41. package/dist/linters/oxlint.js.map +1 -0
  42. package/dist/linters/react.d.ts +59 -0
  43. package/dist/linters/react.d.ts.map +1 -0
  44. package/dist/linters/react.js +178 -0
  45. package/dist/linters/react.js.map +1 -0
  46. package/dist/linters/rules/common.d.ts +6 -0
  47. package/dist/linters/rules/common.d.ts.map +1 -0
  48. package/dist/linters/rules/common.js +3 -0
  49. package/dist/linters/rules/common.js.map +1 -0
  50. package/dist/linters/rules/eqeqeq.rule.d.ts +10 -0
  51. package/dist/linters/rules/eqeqeq.rule.d.ts.map +1 -0
  52. package/dist/linters/rules/eqeqeq.rule.js +13 -0
  53. package/dist/linters/rules/eqeqeq.rule.js.map +1 -0
  54. package/dist/linters/rules/index.d.ts +9 -0
  55. package/dist/linters/rules/index.d.ts.map +1 -0
  56. package/dist/linters/rules/index.js +25 -0
  57. package/dist/linters/rules/index.js.map +1 -0
  58. package/dist/linters/rules/naming-convention.rule.d.ts +20 -0
  59. package/dist/linters/rules/naming-convention.rule.d.ts.map +1 -0
  60. package/dist/linters/rules/naming-convention.rule.js +64 -0
  61. package/dist/linters/rules/naming-convention.rule.js.map +1 -0
  62. package/dist/linters/rules/no-restricted-imports.rule.d.ts +17 -0
  63. package/dist/linters/rules/no-restricted-imports.rule.d.ts.map +1 -0
  64. package/dist/linters/rules/no-restricted-imports.rule.js +19 -0
  65. package/dist/linters/rules/no-restricted-imports.rule.js.map +1 -0
  66. package/dist/linters/rules/no-restricted-properties.rule.d.ts +22 -0
  67. package/dist/linters/rules/no-restricted-properties.rule.d.ts.map +1 -0
  68. package/dist/linters/rules/no-restricted-properties.rule.js +24 -0
  69. package/dist/linters/rules/no-restricted-properties.rule.js.map +1 -0
  70. package/dist/linters/rules/no-unused-vars.rule.d.ts +12 -0
  71. package/dist/linters/rules/no-unused-vars.rule.d.ts.map +1 -0
  72. package/dist/linters/rules/no-unused-vars.rule.js +13 -0
  73. package/dist/linters/rules/no-unused-vars.rule.js.map +1 -0
  74. package/dist/linters/rules/prefer-nullish-coalescing.rule.d.ts +12 -0
  75. package/dist/linters/rules/prefer-nullish-coalescing.rule.d.ts.map +1 -0
  76. package/dist/linters/rules/prefer-nullish-coalescing.rule.js +13 -0
  77. package/dist/linters/rules/prefer-nullish-coalescing.rule.js.map +1 -0
  78. package/dist/linters/rules/switch-case-braces.rule.d.ts +10 -0
  79. package/dist/linters/rules/switch-case-braces.rule.d.ts.map +1 -0
  80. package/dist/linters/rules/switch-case-braces.rule.js +13 -0
  81. package/dist/linters/rules/switch-case-braces.rule.js.map +1 -0
  82. package/package.json +43 -16
  83. package/{tsconfig → src/tsconfig}/tsconfig.base.json +2 -2
  84. package/src/tsconfig/tsconfig.browser.json +11 -0
  85. package/{tsconfig → src/tsconfig}/tsconfig.common.json +1 -1
  86. package/src/tsconfig/tsconfig.react.json +7 -0
  87. package/dist/compile.d.ts.map +0 -1
  88. package/dist/compile.js.map +0 -1
  89. package/dist/eslint.d.ts +0 -3
  90. package/dist/eslint.d.ts.map +0 -1
  91. package/dist/eslint.js +0 -25
  92. package/dist/eslint.js.map +0 -1
  93. package/dist/prettier.d.ts +0 -3
  94. package/dist/prettier.d.ts.map +0 -1
  95. package/dist/prettier.js.map +0 -1
  96. package/dist/react.d.ts +0 -32
  97. package/dist/react.d.ts.map +0 -1
  98. package/dist/react.js +0 -111
  99. package/dist/react.js.map +0 -1
package/README.md CHANGED
@@ -1,35 +1,55 @@
1
1
  # @venizia/dev-configs
2
2
 
3
- The ESLint, Prettier and TypeScript settings every IGNIS package is built with. Install it as a dev
4
- dependency in an application that wants the same rules.
3
+ The oxlint, oxfmt, ESLint, Prettier and TypeScript settings every IGNIS package is built with. Install
4
+ it as a dev dependency in an application that wants the same rules.
5
5
 
6
6
  ## Install
7
7
 
8
8
  ```bash
9
- bun add -d @venizia/dev-configs eslint prettier typescript
9
+ bun add -d @venizia/dev-configs oxlint oxlint-tsgolint oxfmt eslint typescript
10
10
  ```
11
11
 
12
- `eslint` (9 or 10), `prettier` (3) and `typescript` (5 or 6) are optional peers. Install only the
13
- tools you use.
12
+ `oxlint` (>=1.88.0), `oxlint-tsgolint` (>=7.0.2004), `oxfmt` (>=0.73.0), `eslint` (9 or 10),
13
+ `prettier` (3) and `typescript` (5 or 6) are optional peers. Install only the tools you use. Keep the
14
+ ESLint config `.mjs`: a TypeScript one (`.mts`) makes ESLint require `jiti`, one more dependency. A
15
+ project that still runs ESLint and Prettier installs `eslint prettier` and skips the oxc tools.
14
16
 
15
17
  ## Use it
16
18
 
17
- Each tool takes one file.
19
+ Each tool takes one file. IGNIS keeps them in a `.configs/` folder and passes `-c` to each tool.
18
20
 
19
- ```javascript
20
- // eslint.config.mjs
21
- import { eslintConfigs } from '@venizia/dev-configs';
21
+ ```typescript
22
+ // .configs/oxlint.config.mts
23
+ import { defineConfig } from 'oxlint';
24
+ import { oxlintConfigs } from '@venizia/dev-configs/linters';
22
25
 
23
- export default [{ ignores: ['dist/'] }, ...eslintConfigs];
26
+ export default defineConfig(oxlintConfigs);
24
27
  ```
25
28
 
26
- ```javascript
27
- // .prettierrc.mjs
28
- import { prettierConfigs } from '@venizia/dev-configs';
29
+ ```typescript
30
+ // .configs/oxfmt.config.mts
31
+ import { defineConfig } from 'oxfmt';
32
+ import { oxfmtConfigs } from '@venizia/dev-configs/formatters';
29
33
 
30
- export default prettierConfigs;
34
+ export default defineConfig(oxfmtConfigs);
31
35
  ```
32
36
 
37
+ ```typescript
38
+ // .configs/eslint.config.mjs - the one rule oxlint cannot run yet
39
+ import { namingConventionConfigs } from '@venizia/dev-configs/linters';
40
+
41
+ export default namingConventionConfigs;
42
+ ```
43
+
44
+ ```bash
45
+ oxlint -c .configs/oxlint.config.mts --deny-warnings
46
+ eslint -c .configs/eslint.config.mjs .
47
+ oxfmt -c .configs/oxfmt.config.mts --check "**/*.{ts,tsx,mts,js,mjs}"
48
+ ```
49
+
50
+ `tsconfig.json` stays at the project root. Bun, the editor and oxlint's type-aware engine only find it
51
+ there.
52
+
33
53
  ```json
34
54
  // tsconfig.json
35
55
  {
@@ -38,39 +58,159 @@ export default prettierConfigs;
38
58
  "outDir": "dist",
39
59
  "rootDir": "src",
40
60
  "experimentalDecorators": true,
41
- "emitDecoratorMetadata": true
61
+ "useDefineForClassFields": false
42
62
  },
43
63
  "include": ["src"]
44
64
  }
45
65
  ```
46
66
 
47
- ## Declare the decorator flag in your own tsconfig
67
+ The two options in `compilerOptions` repeat the base on purpose - see
68
+ [Restate the runtime options](#restate-the-runtime-options-in-your-own-tsconfig).
48
69
 
49
- The base config sets `experimentalDecorators`. But Bun can miss a flag inherited through `extends`
50
- when it runs your source. Parameter decorators are then dropped with no error, and an `@inject`
51
- value is `undefined` at run time.
70
+ ### Browser and React projects
52
71
 
53
- Declare `experimentalDecorators: true` in your application's own `tsconfig.json`, as in the example
54
- earlier. Every IGNIS example does.
72
+ The presets above target a Bun or Node backend. Code that runs in a browser swaps each one for its
73
+ browser version. A React project swaps it for the React version, which builds on the browser one.
74
+
75
+ | Tool | Backend | Browser | React |
76
+ | :--- | :--- | :--- | :--- |
77
+ | oxlint | `oxlintConfigs` | `BrowserOxlintConfigs.create()` | `ReactOxlintConfigs.create()` |
78
+ | oxfmt | `oxfmtConfigs` | `browserOxfmtConfigs` | `browserOxfmtConfigs` |
79
+ | ESLint | `namingConventionConfigs` | `namingConventionConfigs` | `reactNamingConventionConfigs` |
80
+ | tsconfig | `tsconfig.common.json` | `tsconfig.browser.json` | `tsconfig.react.json` |
81
+
82
+ ## Restate the runtime options in your own tsconfig
83
+
84
+ Bun ignores an `extends` that names a package. With `"extends": "@venizia/dev-configs/tsconfig.common.json"`,
85
+ `bun run` and `bun test` see none of the preset's options - even one level deep (measured on Bun 1.4.2).
86
+ Bun then compiles TC39 decorators: a parameter decorator such as `@inject` is dropped with no error,
87
+ and a method decorator such as `@provide` receives the wrong arguments. Class fields get define
88
+ semantics, while the `tsc` build uses assign semantics.
89
+
90
+ `tsc` follows the whole chain, so typecheck and build stay green. Only what Bun runs diverges, which
91
+ is why nothing reports it.
92
+
93
+ In every `tsconfig.json` that Bun runs - an application, a package whose tests run under
94
+ `bun test`, a browser or React project tested with Bun - restate the options that change the emitted
95
+ code:
96
+
97
+ ```json
98
+ "experimentalDecorators": true,
99
+ "useDefineForClassFields": false
100
+ ```
101
+
102
+ Every IGNIS package and example does.
55
103
 
56
104
  | Flag | Base value | Why |
57
105
  | :--- | :--- | :--- |
58
106
  | `experimentalDecorators` | `true` | `@inject`, `@controller`, `@repository` and the other decorators need it |
59
- | `emitDecoratorMetadata` | `true` | Optional. IGNIS reads `design:paramtypes` once, to validate a `@repository` constructor, and skips the check when the metadata is absent |
107
+ | `emitDecoratorMetadata` | `true` | Optional - restate it only if your code reads `design:*` metadata. IGNIS reads `design:paramtypes` once, to validate a `@repository` constructor, and skips the check when the metadata is absent. Under Bun it turns an interface-typed constructor parameter into a runtime import, so import such names with `import type` |
60
108
  | `useDefineForClassFields` | `false` | Class fields are assigned, not defined, so a subclass field initializer does not shadow a value the base constructor set |
61
109
 
62
110
  ## Entry points
63
111
 
64
112
  | Entry point | What it gives |
65
113
  | :--- | :--- |
66
- | `@venizia/dev-configs` | `eslintConfigs` (flat config array), `ReactEslintConfigs`, `prettierConfigs`, `BunCompiler` |
67
- | `@venizia/dev-configs/tsconfig.base.json` | Target and lib ES2024, `module` Node16, strict mode with `noImplicitAny`, `strictPropertyInitialization` and `useUnknownInCatchVariables` off, `noEmitOnError`, tests excluded |
114
+ | `@venizia/dev-configs` | Everything below, re-exported |
115
+ | `@venizia/dev-configs/compilers` | `BunCompiler` |
116
+ | `@venizia/dev-configs/formatters` | `oxfmtConfigs`, `browserOxfmtConfigs`, `prettierConfigs` |
117
+ | `@venizia/dev-configs/linters` | `oxlintConfigs`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `namingConventionConfigs`, `reactNamingConventionConfigs`, `eslintConfigs`, `ReactEslintConfigs`, the rule classes and their types |
118
+ | `@venizia/dev-configs/tsconfig.base.json` | Target and lib ES2025, `module` Node16, strict mode with `noImplicitAny`, `strictPropertyInitialization` and `useUnknownInCatchVariables` off, `noEmitOnError`, tests excluded |
68
119
  | `@venizia/dev-configs/tsconfig.common.json` | Extends the base and switches `module` and `moduleResolution` to `nodenext` |
120
+ | `@venizia/dev-configs/tsconfig.browser.json` | Extends the base for a browser library built with a bundler: `module` ESNext, `moduleResolution` bundler, lib ES2025 + `DOM` + `DOM.Iterable`, `types: []` so no Bun types reach `dist` |
121
+ | `@venizia/dev-configs/tsconfig.react.json` | Extends `tsconfig.browser.json` and sets `jsx: react-jsx` |
69
122
 
70
123
  ## What each config sets
71
124
 
72
- `eslintConfigs` is `@minimaltech/eslint-node` (ESLint recommended, typescript-eslint, Prettier as a
73
- lint rule, naming conventions, `curly`, `eslint-plugin-n`) plus these IGNIS rules:
125
+ ### oxlintConfigs
126
+
127
+ `oxlintConfigs` (type `OxlintConfig`) is a static port of the `eslintConfigs` rules, generated with
128
+ `@oxlint/migrate`. It enables the `typescript` and `unicorn` plugins and type-aware linting, so it needs
129
+ `oxlint-tsgolint`.
130
+
131
+ Not ported:
132
+
133
+ | Rule | Why |
134
+ | :--- | :--- |
135
+ | `@typescript-eslint/naming-convention` | oxlint has no equivalent yet - `namingConventionConfigs` runs it in ESLint |
136
+ | `@typescript-eslint/prefer-optional-chain` | In oxlint's nursery |
137
+ | `no-invalid-this` | `noImplicitThis` in `tsconfig.base.json` covers it |
138
+ | `n/prefer-node-protocol` | Maps to `unicorn/prefer-node-protocol` |
139
+
140
+ ### namingConventionConfigs
141
+
142
+ `namingConventionConfigs` (type `Linter.Config[]`) sets only `@typescript-eslint/naming-convention`, with
143
+ the 15 LoopBack 4 selectors. It targets `.ts`, `.tsx`, `.mts` and `.cts`, and ignores `dist`, `build`,
144
+ `coverage`, `*.d.ts` and plain JavaScript. ESLint does not report unused disable comments in this
145
+ config, because oxlint owns the other rules.
146
+
147
+ ### Rule classes
148
+
149
+ Each rule has a class with `static readonly NAME` and `static build(options)`. `build` returns the rule
150
+ entry with the IGNIS defaults. Every `severity` defaults to `'error'`.
151
+
152
+ | Class | Rule name | `build` options (default) |
153
+ | :--- | :--- | :--- |
154
+ | `EqeqeqRule` | `eqeqeq` | `mode`: `'always' \| 'smart'` (`'smart'`) |
155
+ | `NoUnusedVarsRule` | `no-unused-vars` | `vars` (`'all'`), `args` (`'none'`), `ignoreRestSiblings` (`false`) |
156
+ | `SwitchCaseBracesRule` | `unicorn/switch-case-braces` | `mode`: `'always' \| 'avoid'` (`'always'`) |
157
+ | `NoRestrictedImportsRule` | `no-restricted-imports` | `extraPaths`: `IRestrictedImportPath[]` (none), added to `PATHS` (lodash) |
158
+ | `NoRestrictedPropertiesRule` | `no-restricted-properties` | `extraProperties`: `IRestrictedProperty[]` (none), added to `SECURE_CONTEXT` (`crypto.randomUUID`) |
159
+ | `PreferNullishCoalescingRule` | `typescript/prefer-nullish-coalescing` | `ignoreConditionalTests`, `ignoreMixedLogicalExpressions`, `ignoreTernaryTests` (oxlint's own defaults) |
160
+ | `NamingConventionRule` | `@typescript-eslint/naming-convention` | `extraSelectors`: `TNamingSelector[]` (none), added after `SELECTORS` |
161
+
162
+ Types: `TRuleSeverity`, `TOxlintRuleEntry`, `TNamingSelector`, `IRestrictedImportPath`.
163
+
164
+ Replace a rule by key. This makes `==` an error everywhere and bans one more import:
165
+
166
+ ```typescript
167
+ // .configs/oxlint.config.mts
168
+ import { defineConfig } from 'oxlint';
169
+ import {
170
+ EqeqeqRule,
171
+ NoRestrictedImportsRule,
172
+ oxlintConfigs,
173
+ } from '@venizia/dev-configs/linters';
174
+
175
+ export default defineConfig({
176
+ ...oxlintConfigs,
177
+ rules: {
178
+ ...oxlintConfigs.rules,
179
+ [EqeqeqRule.NAME]: EqeqeqRule.build({ mode: 'always' }),
180
+ [NoRestrictedImportsRule.NAME]: NoRestrictedImportsRule.build({
181
+ extraPaths: [{ name: 'moment', message: 'Use TemporalHelper instead.' }],
182
+ }),
183
+ },
184
+ });
185
+ ```
186
+
187
+ ### oxfmtConfigs and prettierConfigs
188
+
189
+ `oxfmtConfigs` (type `OxfmtConfig`) and `prettierConfigs` hold the same seven options, so the output
190
+ matches. oxfmt differs from Prettier on long union types, which it breaks with a leading `|` per line.
191
+
192
+ | Setting | Value |
193
+ | :--- | :--- |
194
+ | `printWidth` | `100` |
195
+ | `tabWidth` | `2` |
196
+ | `singleQuote` | `true` |
197
+ | `semi` | `true` |
198
+ | `trailingComma` | `'all'` |
199
+ | `bracketSpacing` | `true` |
200
+ | `arrowParens` | `'avoid'` |
201
+
202
+ `browserOxfmtConfigs` is `oxfmtConfigs` with two changes for browser and React code:
203
+
204
+ | Setting | Value | Effect |
205
+ | :--- | :--- | :--- |
206
+ | `arrowParens` | `'always'` | `(x) => x` instead of `x => x` |
207
+ | `bracketSameLine` | `true` | The closing `>` of a multi-line JSX element stays on its last attribute line, which keeps JSX diffs small |
208
+
209
+ ### eslintConfigs
210
+
211
+ `eslintConfigs` keeps its shape and resolves to the same rules as before, but is now owned here instead
212
+ of wrapping `@minimaltech/eslint-node`: ESLint recommended, typescript-eslint, Prettier as a lint
213
+ rule, naming conventions, `curly`, `eslint-plugin-n`, plus these IGNIS rules:
74
214
 
75
215
  | Rule | Setting |
76
216
  | :--- | :--- |
@@ -79,6 +219,8 @@ lint rule, naming conventions, `curly`, `eslint-plugin-n`) plus these IGNIS rule
79
219
  | `@typescript-eslint/no-namespace` | `error` |
80
220
  | `unicorn/switch-case-braces` | `['error', 'always']` |
81
221
 
222
+ ### ReactEslintConfigs
223
+
82
224
  `ReactEslintConfigs.create({ plugins })` is `eslintConfigs` plus what a React frontend needs. The
83
225
  plugins come in as options, so a backend installs none of them:
84
226
 
@@ -99,13 +241,13 @@ export default [
99
241
  | :--- | :--- |
100
242
  | React correctness (`jsx-key`, `no-children-prop`, `no-deprecated`, ... - 14 rules) | `error`, `.jsx`/`.tsx` |
101
243
  | `jsx-a11y` basics (`alt-text`, `aria-props`, `aria-role`, ... - 9 rules) | `error`, `.jsx`/`.tsx` |
102
- | `react-hooks/rules-of-hooks` / `exhaustive-deps` | `error` / `warn`, every source file |
244
+ | `react-hooks/rules-of-hooks` / `exhaustive-deps` | `error`, every source file |
103
245
  | `@typescript-eslint/consistent-type-imports` | `['error', { prefer: 'type-imports' }]` |
104
246
  | `naming-convention` | the base rule, plus PascalCase functions (`function App()`), `.jsx`/`.tsx` |
105
- | `no-floating-promises`, `no-void`, `no-invalid-this`, `no-use-before-define` | `off` - a UI fires promises from handlers and uses components above their declaration |
106
- | `no-explicit-any` | `warn` (the base has it `off`) |
107
- | `no-shadow` | `warn` |
108
- | `no-unused-vars` | `warn`, `_`-prefixed names ignored |
247
+ | `no-restricted-properties` | `NoRestrictedPropertiesRule.build()` - bans `crypto.randomUUID` |
248
+
249
+ Nothing in the base is relaxed: frontend code meets the backend's standard, so a floating promise, a
250
+ `void`, a use before declaration or a shadowed name fails the lint as it does in a service.
109
251
 
110
252
  Rules the automatic JSX runtime or `tsc` already enforce (`react-in-jsx-scope`, `prop-types`,
111
253
  `jsx-no-undef`, ...) are left out.
@@ -116,17 +258,57 @@ Rules the automatic JSX runtime or `tsc` already enforce (`react-in-jsx-scope`,
116
258
  - `consistent-type-imports` keeps the default `fixStyle`; a codebase that prefers
117
259
  `inline-type-imports` sets it on top.
118
260
 
119
- `prettierConfigs`:
261
+ ### BrowserOxlintConfigs
120
262
 
121
- | Setting | Value |
122
- | :--- | :--- |
123
- | `printWidth` | `100` |
124
- | `tabWidth` | `2` |
125
- | `singleQuote` | `true` |
126
- | `semi` | `true` |
127
- | `trailingComma` | `'all'` |
128
- | `bracketSpacing` | `true` |
129
- | `arrowParens` | `'avoid'` |
263
+ `BrowserOxlintConfigs.create()` is `oxlintConfigs` plus `NoRestrictedPropertiesRule.build()`. That
264
+ rule bans `crypto.randomUUID`, which exists only in a secure context (https, localhost). On a
265
+ plain-http origin or in a WebView, the method is `undefined`. Use this preset for browser code that
266
+ does not use React.
267
+
268
+ ```ts
269
+ // .configs/oxlint.config.mts
270
+ import { defineConfig } from 'oxlint';
271
+ import { BrowserOxlintConfigs } from '@venizia/dev-configs/linters';
272
+
273
+ export default defineConfig(BrowserOxlintConfigs.create());
274
+ ```
275
+
276
+ ### ReactOxlintConfigs and reactNamingConventionConfigs
277
+
278
+ The oxlint version of the React preset. oxlint runs the React, hooks and `jsx-a11y` rules natively, so
279
+ nothing is passed in. Pair it with `reactNamingConventionConfigs` on the ESLint side:
280
+
281
+ ```ts
282
+ // .configs/oxlint.config.mts
283
+ import { defineConfig } from 'oxlint';
284
+ import { ReactOxlintConfigs } from '@venizia/dev-configs/linters';
285
+
286
+ export default defineConfig(ReactOxlintConfigs.create());
287
+
288
+ // .configs/eslint.config.mjs
289
+ import { reactNamingConventionConfigs } from '@venizia/dev-configs/linters';
290
+
291
+ export default reactNamingConventionConfigs;
292
+ ```
293
+
294
+ `ReactOxlintConfigs.create()` is `BrowserOxlintConfigs.create()` plus the same rules as the ESLint
295
+ table above, as strict as the base. `react/no-deprecated` is left out: oxlint has no port of it.
296
+
297
+ The presets start strict. An application that wants less overrides the rule after the preset:
298
+
299
+ ```ts
300
+ const base = ReactOxlintConfigs.create();
301
+
302
+ export default defineConfig({
303
+ ...base,
304
+ rules: { ...base.rules, 'typescript/no-floating-promises': 'warn' },
305
+ });
306
+ ```
307
+
308
+ `reactNamingConventionConfigs` is `namingConventionConfigs` plus PascalCase functions in `.jsx` and
309
+ `.tsx` files.
310
+
311
+ ### BunCompiler
130
312
 
131
313
  `BunCompiler.compile()` builds one Bun executable: minified, with a linked source map. The
132
314
  compile target comes from `BUN_TARGET` and defaults to `bun-linux-x64`.
@@ -146,6 +328,7 @@ The root of the chain, with no IGNIS dependency: **dev-configs** -> inversion ->
146
328
 
147
329
  - [Tooling configuration](https://ignis.venizia.ai/best-practices/code-style-standards/tooling)
148
330
  - [TypeScript 6 and toolchain changelog](https://ignis.venizia.ai/changelogs/2026-03-31-typescript-6-and-toolchain)
331
+ - [oxlint and oxfmt changelog](https://ignis.venizia.ai/changelogs/2026-10-16-oxlint-oxfmt-migration)
149
332
  - [Changelog](https://ignis.venizia.ai/changelogs/)
150
333
  - [Source](https://github.com/VENIZIA-AI/ignis/blob/main/packages/dev-configs)
151
334
 
@@ -12,4 +12,4 @@ export declare class BunCompiler {
12
12
  plugins?: Bun.BunPlugin[];
13
13
  }): Promise<void>;
14
14
  }
15
- //# sourceMappingURL=compile.d.ts.map
15
+ //# sourceMappingURL=bun.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun.d.ts","sourceRoot":"","sources":["../../src/compilers/bun.ts"],"names":[],"mappings":"AAIA,gHAAgH;AAChH,qBAAa,WAAW;IACtB;;;;OAIG;WACU,OAAO,CAClB,IAAI,GAAE;QACJ,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,GAAG,CAAC,SAAS,EAAE,CAAC;KACtB,GACL,OAAO,CAAC,IAAI,CAAC;CAgCjB"}
@@ -1,9 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.BunCompiler = void 0;
4
- const DEFAULT_ENTRYPOINT = "./dist/index.js";
5
- const DEFAULT_OUTFILE = "./dist/bin";
6
- const DEFAULT_COMPILE_TARGET = "bun-linux-x64";
4
+ const DEFAULT_ENTRYPOINT = './dist/index.js';
5
+ const DEFAULT_OUTFILE = './dist/bin';
6
+ const DEFAULT_COMPILE_TARGET = 'bun-linux-x64';
7
7
  /** Bundles and compiles a single Bun executable: minified, linked sourcemaps, target read from `BUN_TARGET`. */
8
8
  class BunCompiler {
9
9
  /**
@@ -15,12 +15,11 @@ class BunCompiler {
15
15
  const { entrypoint = DEFAULT_ENTRYPOINT, outfile = DEFAULT_OUTFILE, target = Bun.env.BUN_TARGET ?? DEFAULT_COMPILE_TARGET, plugins = [], } = opts;
16
16
  const built = await Bun.build({
17
17
  entrypoints: [entrypoint],
18
- target: "bun",
18
+ target: 'bun',
19
19
  minify: { whitespace: true, syntax: true },
20
- sourcemap: "linked",
20
+ sourcemap: 'linked',
21
21
  throw: false,
22
22
  compile: {
23
- // `target` is read from an environment variable at runtime, so it cannot be checked against Bun's literal union at compile time.
24
23
  target: target,
25
24
  outfile,
26
25
  },
@@ -31,10 +30,10 @@ class BunCompiler {
31
30
  // create a circular workspace dependency, so a failed compile throws a plain `Error` instead.
32
31
  throw new Error([
33
32
  `[BunCompiler] compile failed for entrypoint "${entrypoint}":`,
34
- ...built.logs.map((log) => `[${log.level}] ${log.message}`),
35
- ].join("\n"));
33
+ ...built.logs.map(log => `[${log.level}] ${log.message}`),
34
+ ].join('\n'));
36
35
  }
37
36
  }
38
37
  }
39
38
  exports.BunCompiler = BunCompiler;
40
- //# sourceMappingURL=compile.js.map
39
+ //# sourceMappingURL=bun.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bun.js","sourceRoot":"","sources":["../../src/compilers/bun.ts"],"names":[],"mappings":";;;AAAA,MAAM,kBAAkB,GAAG,iBAAiB,CAAC;AAC7C,MAAM,eAAe,GAAG,YAAY,CAAC;AACrC,MAAM,sBAAsB,GAAG,eAAe,CAAC;AAE/C,gHAAgH;AAChH,MAAa,WAAW;IACtB;;;;OAIG;IACH,MAAM,CAAC,KAAK,CAAC,OAAO,CAClB,OAKI,EAAE;QAEN,MAAM,EACJ,UAAU,GAAG,kBAAkB,EAC/B,OAAO,GAAG,eAAe,EACzB,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,UAAU,IAAI,sBAAsB,EACrD,OAAO,GAAG,EAAE,GACb,GAAG,IAAI,CAAC;QAET,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,KAAK,CAAC;YAC5B,WAAW,EAAE,CAAC,UAAU,CAAC;YACzB,MAAM,EAAE,KAAK;YACb,MAAM,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE;YAC1C,SAAS,EAAE,QAAQ;YACnB,KAAK,EAAE,KAAK;YACZ,OAAO,EAAE;gBACP,MAAM,EAAE,MAAiC;gBACzC,OAAO;aACR;YACD,OAAO;SACR,CAAC,CAAC;QAEH,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;YACnB,4FAA4F;YAC5F,8FAA8F;YAC9F,MAAM,IAAI,KAAK,CACb;gBACE,gDAAgD,UAAU,IAAI;gBAC9D,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,GAAG,CAAC,KAAK,KAAK,GAAG,CAAC,OAAO,EAAE,CAAC;aAC1D,CAAC,IAAI,CAAC,IAAI,CAAC,CACb,CAAC;QACJ,CAAC;IACH,CAAC;CACF;AA7CD,kCA6CC"}
@@ -0,0 +1,2 @@
1
+ export * from './bun';
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/compilers/index.ts"],"names":[],"mappings":"AAAA,cAAc,OAAO,CAAC"}
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./bun"), exports);
18
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/compilers/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,wCAAsB"}
@@ -0,0 +1,3 @@
1
+ export * from './oxfmt';
2
+ export * from './prettier';
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":"AAAA,cAAc,SAAS,CAAC;AACxB,cAAc,YAAY,CAAC"}
@@ -0,0 +1,19 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./oxfmt"), exports);
18
+ __exportStar(require("./prettier"), exports);
19
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/formatters/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,6CAA2B"}
@@ -0,0 +1,28 @@
1
+ import type { OxfmtConfig } from 'oxfmt';
2
+ /**
3
+ * The oxfmt port of `prettierConfigs` - the same seven options, so the output matches Prettier's.
4
+ *
5
+ * ```ts
6
+ * // .configs/oxfmt.config.mts
7
+ * import { defineConfig } from 'oxfmt';
8
+ * import { oxfmtConfigs } from '@venizia/dev-configs/formatters';
9
+ *
10
+ * export default defineConfig(oxfmtConfigs);
11
+ * ```
12
+ */
13
+ export declare const oxfmtConfigs: OxfmtConfig;
14
+ /**
15
+ * `oxfmtConfigs` for browser and React code: arrow parameters always in parentheses (`(x) => x`),
16
+ * and the closing `>` of a multi-line JSX element on its last attribute line, which keeps JSX diffs
17
+ * small. `bracketSameLine` changes nothing outside JSX.
18
+ *
19
+ * ```ts
20
+ * // .configs/oxfmt.config.mts
21
+ * import { defineConfig } from 'oxfmt';
22
+ * import { browserOxfmtConfigs } from '@venizia/dev-configs/formatters';
23
+ *
24
+ * export default defineConfig(browserOxfmtConfigs);
25
+ * ```
26
+ */
27
+ export declare const browserOxfmtConfigs: OxfmtConfig;
28
+ //# sourceMappingURL=oxfmt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oxfmt.d.ts","sourceRoot":"","sources":["../../src/formatters/oxfmt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,OAAO,CAAC;AAEzC;;;;;;;;;;GAUG;AACH,eAAO,MAAM,YAAY,EAAE,WAQ1B,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,mBAAmB,EAAE,WAIjC,CAAC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.browserOxfmtConfigs = exports.oxfmtConfigs = void 0;
4
+ /**
5
+ * The oxfmt port of `prettierConfigs` - the same seven options, so the output matches Prettier's.
6
+ *
7
+ * ```ts
8
+ * // .configs/oxfmt.config.mts
9
+ * import { defineConfig } from 'oxfmt';
10
+ * import { oxfmtConfigs } from '@venizia/dev-configs/formatters';
11
+ *
12
+ * export default defineConfig(oxfmtConfigs);
13
+ * ```
14
+ */
15
+ exports.oxfmtConfigs = {
16
+ bracketSpacing: true,
17
+ singleQuote: true,
18
+ printWidth: 100,
19
+ tabWidth: 2,
20
+ trailingComma: 'all',
21
+ arrowParens: 'avoid',
22
+ semi: true,
23
+ };
24
+ /**
25
+ * `oxfmtConfigs` for browser and React code: arrow parameters always in parentheses (`(x) => x`),
26
+ * and the closing `>` of a multi-line JSX element on its last attribute line, which keeps JSX diffs
27
+ * small. `bracketSameLine` changes nothing outside JSX.
28
+ *
29
+ * ```ts
30
+ * // .configs/oxfmt.config.mts
31
+ * import { defineConfig } from 'oxfmt';
32
+ * import { browserOxfmtConfigs } from '@venizia/dev-configs/formatters';
33
+ *
34
+ * export default defineConfig(browserOxfmtConfigs);
35
+ * ```
36
+ */
37
+ exports.browserOxfmtConfigs = {
38
+ ...exports.oxfmtConfigs,
39
+ arrowParens: 'always',
40
+ bracketSameLine: true,
41
+ };
42
+ //# sourceMappingURL=oxfmt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"oxfmt.js","sourceRoot":"","sources":["../../src/formatters/oxfmt.ts"],"names":[],"mappings":";;;AAEA;;;;;;;;;;GAUG;AACU,QAAA,YAAY,GAAgB;IACvC,cAAc,EAAE,IAAI;IACpB,WAAW,EAAE,IAAI;IACjB,UAAU,EAAE,GAAG;IACf,QAAQ,EAAE,CAAC;IACX,aAAa,EAAE,KAAK;IACpB,WAAW,EAAE,OAAO;IACpB,IAAI,EAAE,IAAI;CACX,CAAC;AAEF;;;;;;;;;;;;GAYG;AACU,QAAA,mBAAmB,GAAgB;IAC9C,GAAG,oBAAY;IACf,WAAW,EAAE,QAAQ;IACrB,eAAe,EAAE,IAAI;CACtB,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { Config } from 'prettier';
2
+ export declare const prettierConfigs: Config;
3
+ //# sourceMappingURL=prettier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prettier.d.ts","sourceRoot":"","sources":["../../src/formatters/prettier.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,eAAO,MAAM,eAAe,EAAE,MAQ7B,CAAC"}
@@ -6,8 +6,8 @@ exports.prettierConfigs = {
6
6
  singleQuote: true,
7
7
  printWidth: 100,
8
8
  tabWidth: 2,
9
- trailingComma: "all",
10
- arrowParens: "avoid",
9
+ trailingComma: 'all',
10
+ arrowParens: 'avoid',
11
11
  semi: true,
12
12
  };
13
13
  //# sourceMappingURL=prettier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prettier.js","sourceRoot":"","sources":["../../src/formatters/prettier.ts"],"names":[],"mappings":";;;AAEa,QAAA,eAAe,GAAW;IACrC,cAAc,EAAE,IAAI;IACpB,WAAW,EAAE,IAAI;IACjB,UAAU,EAAE,GAAG;IACf,QAAQ,EAAE,CAAC;IACX,aAAa,EAAE,KAAK;IACpB,WAAW,EAAE,OAAO;IACpB,IAAI,EAAE,IAAI;CACX,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,5 +1,4 @@
1
- export * from "./compile";
2
- export * from "./eslint";
3
- export * from "./prettier";
4
- export * from "./react";
1
+ export * from './compilers';
2
+ export * from './formatters';
3
+ export * from './linters';
5
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,YAAY,CAAC;AAC3B,cAAc,SAAS,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAC;AAC5B,cAAc,cAAc,CAAC;AAC7B,cAAc,WAAW,CAAC"}
package/dist/index.js CHANGED
@@ -14,8 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./compile"), exports);
18
- __exportStar(require("./eslint"), exports);
19
- __exportStar(require("./prettier"), exports);
20
- __exportStar(require("./react"), exports);
17
+ __exportStar(require("./compilers"), exports);
18
+ __exportStar(require("./formatters"), exports);
19
+ __exportStar(require("./linters"), exports);
21
20
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,2CAAyB;AACzB,6CAA2B;AAC3B,0CAAwB"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,8CAA4B;AAC5B,+CAA6B;AAC7B,4CAA0B"}
@@ -0,0 +1,18 @@
1
+ import type { OxlintConfig } from 'oxlint';
2
+ /**
3
+ * `oxlintConfigs` for code that runs in a browser, React or not: the base rules plus the
4
+ * secure-context ban (`crypto.randomUUID` is `undefined` on a plain-http origin). Nothing in the base
5
+ * is relaxed. `ReactOxlintConfigs` builds on this preset.
6
+ *
7
+ * ```ts
8
+ * // .configs/oxlint.config.mts
9
+ * import { defineConfig } from 'oxlint';
10
+ * import { BrowserOxlintConfigs } from '@venizia/dev-configs/linters';
11
+ *
12
+ * export default defineConfig(BrowserOxlintConfigs.create());
13
+ * ```
14
+ */
15
+ export declare class BrowserOxlintConfigs {
16
+ static create(): OxlintConfig;
17
+ }
18
+ //# sourceMappingURL=browser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../../src/linters/browser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAI3C;;;;;;;;;;;;GAYG;AACH,qBAAa,oBAAoB;IAC/B,MAAM,CAAC,MAAM,IAAI,YAAY;CAS9B"}