@venizia/dev-configs 0.4.8-1 → 0.4.8-2

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 (2) hide show
  1. package/README.md +60 -13
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -9,7 +9,7 @@ it as a dev dependency in an application that wants the same rules.
9
9
  bun add -d @venizia/dev-configs oxlint oxlint-tsgolint eslint typescript
10
10
  ```
11
11
 
12
- `oxlint` (>=1.88.0), `oxlint-tsgolint` (>=7.0.2004), `eslint` (9 or 10),
12
+ `oxlint` (>=1.89.0), `oxlint-tsgolint` (>=7.0.2004), `eslint` (9 or 10),
13
13
  `typescript` (5 or 6) are optional peers. Install only the tools you use. Formatting is `bun fmt` (Bun 1.4.4 or newer), set in `bunfig.toml`: see [Formatting](#formatting). Keep the
14
14
  ESLint config `.mjs`: a TypeScript one (`.mts`) makes ESLint require `jiti`, one more dependency. A
15
15
  project that only wants the full ESLint preset installs `eslint` and skips the oxc tools.
@@ -95,19 +95,21 @@ Every IGNIS package and example does.
95
95
  | Flag | Base value | Why |
96
96
  | :--- | :--- | :--- |
97
97
  | `experimentalDecorators` | `true` | `@inject`, `@controller`, `@repository` and the other decorators need it |
98
- | `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 (`Export named 'X' not found`), so import such names with `import type`; `tsc --noEmit --isolatedModules` (TS1272) finds most of them, loading `src/index.ts` under Bun the rest |
98
+ | `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 (`Export named 'X' not found`), so import such names with `import type`; `bun check` (TS1272; the base tsconfig sets `isolatedModules`) finds most of them, loading `src/index.ts` under Bun the rest |
99
99
  | `useDefineForClassFields` | `false` | Class fields are assigned, not defined, so a subclass field initializer does not shadow a value the base constructor set |
100
100
 
101
101
  ## Entry points
102
102
 
103
103
  | Entry point | What it gives |
104
104
  | :--- | :--- |
105
- | `@venizia/dev-configs` | Everything below, re-exported |
105
+ | `@venizia/dev-configs` | `/compilers` and `/linters`, re-exported. Not `/checks` or `/testing` |
106
106
  | `@venizia/dev-configs/compilers` | `BunCompiler` |
107
107
  | `@venizia/dev-configs/testing` | `RejectionHelper` (`rejectionOf`, `expectRejection`), `SpawnHelper` (`spawnSyncBounded`), `RepoTmp` (`findRoot`, `apply`) - test helpers (imports `bun:test`; tests only) |
108
- | `@venizia/dev-configs/linters` | `oxlintConfigs`, `OxlintConfigs`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `LintIgnore`, `namingConventionConfigs`, `reactNamingConventionConfigs`, `houseConfigs`, `reactHouseConfigs`, `eslintConfigs`, the rule classes and their types |
108
+ | `@venizia/dev-configs/testing/tmpdir-preload` | A bunfig test preload: a bare `bun test` keeps its temp folders in the repository (calls `RepoTmp.apply()`) |
109
+ | `@venizia/dev-configs/checks` | The engines behind `devz check <name>`: catalog, module cycles, purity, split report and the test-trimming checks. Bun-only tooling, never import it from browser code |
110
+ | `@venizia/dev-configs/linters` | `oxlintConfigs`, `OxlintConfigs`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `LintIgnore`, `namingConventionConfigs`, `reactNamingConventionConfigs`, `houseConfigs`, `reactHouseConfigs`, `eslintConfigs`, `paddingConfigs`, the rule classes and their types |
109
111
  | `@venizia/dev-configs/linters/oxlint` | `oxlintConfigs`, `OxlintConfigs`, `IOxlintPresetOptions`, `BrowserOxlintConfigs`, `ReactOxlintConfigs`, `LintIgnore`, the rule classes and their types: everything an oxlint config needs, and nothing that loads ESLint. Loads in milliseconds: `/linters` also loads ESLint and its plugins, which an oxlint config never uses |
110
- | `@venizia/dev-configs/tsconfig.base.json` | Target and lib ES2025, `module` Node16, strict mode (`noImplicitAny` and `useUnknownInCatchVariables` on) with `strictPropertyInitialization` off (DI-injected properties have no initializer), `noEmitOnError`, tests excluded |
112
+ | `@venizia/dev-configs/tsconfig.base.json` | Target and lib ES2025, `module` esnext with `moduleResolution` bundler, strict mode (`noImplicitAny` and `useUnknownInCatchVariables` on) with `strictPropertyInitialization` off (DI-injected properties have no initializer), `noEmitOnError`, tests excluded |
111
113
  | `@venizia/dev-configs/tsconfig.common.json` | Extends the base and restates `module` as `esnext` and `moduleResolution` as `bundler` |
112
114
  | `@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` |
113
115
  | `@venizia/dev-configs/tsconfig.react.json` | Extends `tsconfig.browser.json` and sets `jsx: react-jsx` |
@@ -123,7 +125,7 @@ Every IGNIS package and example does.
123
125
  becomes a runtime import when Bun runs a decorated class's source, and loading fails with
124
126
  `Export named 'X' not found`. `oxlint --fix` rewrites them.
125
127
 
126
- oxlint (1.88) does not read decorator metadata, so it also rewrites the import of a decorated
128
+ oxlint does not read decorator metadata, so it also rewrites the import of a decorated
127
129
  constructor parameter's class to `import { type X }`. tsc then emits `Function` (or `Object` under Bun)
128
130
  as that parameter's `design:paramtypes` entry. IGNIS never injects by that entry - `@inject` names its
129
131
  key, and `@repository` skips `Object` and `Function` - so nothing breaks. Code that does read
@@ -160,8 +162,9 @@ booleans. `BrowserOxlintConfigs.create()` and `ReactOxlintConfigs.create()` take
160
162
 
161
163
  ### houseConfigs and the house rules
162
164
 
163
- `houseConfigs` is `namingConventionConfigs` plus the house rules oxlint cannot express and the four async style rules;
164
- `reactHouseConfigs` is the same over `reactNamingConventionConfigs`. The rules ship as the ESLint plugin
165
+ `houseConfigs` is `namingConventionConfigs` plus the house rules oxlint cannot express, the four async style rules
166
+ and the blank-line padding rules (`paddingConfigs`, below); `reactHouseConfigs` is the same over
167
+ `reactNamingConventionConfigs`, plus the React rules. The house rules ship as the ESLint plugin
165
168
  `houseEslintPlugin`, registered as `venizia`:
166
169
 
167
170
  | Class | Rule | Default | What it enforces |
@@ -176,10 +179,25 @@ booleans. `BrowserOxlintConfigs.create()` and `ReactOxlintConfigs.create()` take
176
179
  with `[ConstClassValuesRule.NAME]: ConstClassValuesRule.build({ severity: 'error' })`. The 5-parameter
177
180
  limit (V-C-02) is `venizia/max-params-own`, an error.
178
181
 
182
+ #### Blank-line padding
183
+
184
+ `paddingConfigs` holds two `@stylistic` rules, both `error`, on `.ts`, `.tsx`, `.mts` and `.cts` files.
185
+ `houseConfigs`, `reactHouseConfigs` and `eslintConfigs` carry it. It has no parser of its own: it rides on the
186
+ TypeScript parser of `namingConventionConfigs` or `eslintConfigs`. oxlint has none of these rules, so a
187
+ project that lints with oxlint alone gets no padding check. `devz lint --fix` writes the blank lines.
188
+
189
+ | Rule | What it enforces |
190
+ | :--- | :--- |
191
+ | `@stylistic/padding-line-between-statements` | A blank line after the imports (none needed between two imports), before a `return`, and around a block-like statement (a statement that ends in a block, such as `if`, `for`, `while`, `switch`, `try`, a function declaration or a bare block). Stacked `case` and `default` labels stay together |
192
+ | `@stylistic/lines-between-class-members` | A blank line between class members, except after a one-line member, so a run of one-line properties stays together |
193
+
194
+ Turn one off after the preset with `'off'`. See the
195
+ [changelog](https://ignis.venizia.ai/changelogs/2026-11-04-blank-line-padding-rules).
196
+
179
197
  ### namingConventionConfigs
180
198
 
181
199
  `namingConventionConfigs` (type `Linter.Config[]`) sets only `@typescript-eslint/naming-convention`, with
182
- its 15 selectors. It targets `.ts`, `.tsx`, `.mts` and `.cts`, and ignores `dist`, `build`,
200
+ its 16 selectors. It targets `.ts`, `.tsx`, `.mts` and `.cts`, and ignores `dist`, `build`,
183
201
  `coverage`, `*.d.ts` and plain JavaScript. ESLint does not report unused disable comments in this
184
202
  config, because oxlint owns the other rules.
185
203
 
@@ -239,9 +257,8 @@ flavor = "oxfmt"
239
257
 
240
258
  ### eslintConfigs
241
259
 
242
- `eslintConfigs` keeps its shape and resolves to the same rules as before, but is now owned here instead
243
- of wrapping `@minimaltech/eslint-node`: ESLint recommended, typescript-eslint, naming
244
- conventions, `curly`, plus these IGNIS rules (the node-protocol check runs in `oxlintConfigs` only):
260
+ `eslintConfigs` is the full ESLint preset: ESLint recommended, typescript-eslint, naming
261
+ conventions, `curly`, the padding rules, plus these IGNIS rules (the node-protocol check runs in `oxlintConfigs` only):
245
262
 
246
263
  | Rule | Setting |
247
264
  | :--- | :--- |
@@ -289,7 +306,13 @@ table above, as strict as the base. `react/no-deprecated` is left out: oxlint ha
289
306
  Both React presets run the same fifteen `jsx-a11y` rules, including the six that need a human
290
307
  decision (`click-events-have-key-events`, `no-static-element-interactions`,
291
308
  `no-noninteractive-element-interactions`, `label-has-associated-control`, `heading-has-content`,
292
- `anchor-is-valid`). `reactHouseConfigs` adds `venizia/no-leaked-render`, which oxlint has no port of.
309
+ `anchor-is-valid`). `reactHouseConfigs` adds three house rules oxlint has no port of:
310
+
311
+ | Rule | What it enforces |
312
+ | :--- | :--- |
313
+ | `venizia/no-leaked-render` | See the table above. On JSX files |
314
+ | `venizia/no-async-hook-callback` | A hook never gets an async function. On all source files |
315
+ | `venizia/effect-cleanup-consistency` | An effect callback returns a cleanup on every path or on none. On all source files |
293
316
 
294
317
  The presets start strict. An application that wants less overrides the rule after the preset:
295
318
 
@@ -360,6 +383,30 @@ await BunCompiler.compile({
360
383
  });
361
384
  ```
362
385
 
386
+ ## The devz command
387
+
388
+ The package installs a `devz` binary. Run `devz --help` for the list, and `devz clean --help`,
389
+ `devz check --help` or `devz codemod --help` for the options of one command. A usage error in a command exits 2.
390
+
391
+ | Command | What it does |
392
+ | :--- | :--- |
393
+ | `devz lint [--fix] [files]` | Runs oxlint, ESLint and `bun fmt` from `.configs/lints/` and `.configs/formatters/.ignore`, and stops at the first tool that fails. With no file it checks the project; with files it handles only those, as a pre-commit hook passes them. `--fix` writes |
394
+ | `devz check purity --claims <file> [package] [--json]` | Probes every entry claimed browser-pure. Needs a build |
395
+ | `devz check module-cycles <dir> [--max <n>]` | Lists the import cycles of a built ESM folder; exits 1 when there are more than `--max` |
396
+ | `devz check split-report [--dist <dir>] [folder...]` | Reports hub files, stray types, missing barrels, long files and cycles. Never a gate |
397
+ | `devz check catalog [--glob <pattern>]... [--pinned <file>]... [--preset-prefix <prefix>]` | Guards dependency ranges against the root `workspaces.catalog` |
398
+ | `devz clean` | Removes `dist`, `node_modules/.cache` and the `*.tsbuildinfo` files next to the tsconfig. It takes no argument |
399
+ | `devz codemod <name> [paths...]` | Rewrites source files. A dry run unless `--write`; `--check` exits 1 while a rewrite remains |
400
+
401
+ `devz check` also runs the four tools of the test-trimming method: `test-weight`, `test-dead-code`,
402
+ `test-mutate` and `test-controls`.
403
+
404
+ The codemods are `drop-redundant-casts` (removes `as X` casts the compiler no longer needs),
405
+ `const-classes` (turns a string-literal union into a const class), `async-style` (applies the async style
406
+ fixers and lists the rest), `namespace-functions` (moves calls of a function that moved into a class to the
407
+ class form) and `connector-imports` (moves `@venizia/ignis/<connector sub-path>` imports to
408
+ `@venizia/ignis-connectors`).
409
+
363
410
  ## Where it sits
364
411
 
365
412
  The root of the chain, with no IGNIS dependency: **dev-configs** -> inversion -> {filter, helpers}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@venizia/dev-configs",
3
- "version": "0.4.8-1",
3
+ "version": "0.4.8-2",
4
4
  "description": "Shareable development configurations for TypeScript projects: oxlint presets with per-rule builders, the ESLint naming-convention rule, the legacy ESLint flat config, and TypeScript compiler options with critical decorator support (experimentalDecorators, emitDecoratorMetadata, useDefineForClassFields). Single source of truth for consistent code style, type checking, and build settings across monorepo packages.",
5
5
  "keywords": [
6
6
  "build-tools",