@regardio/dev 2.3.0 → 2.4.1

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.
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as git, c as runScript, i as getWorkspacePackages, n as chooseForEach, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-VktE94Vs.mjs";
2
+ import { a as git, c as runScript, i as getWorkspacePackages, n as chooseForEach, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-rnvdLrkF.mjs";
3
3
  //#region src/bin/ship/hotfix.ts
4
4
  /**
5
5
  * ship-hotfix: Manage hotfix branches based on production code.
@@ -72,7 +72,14 @@ function runShipHotfix(subcommand, subArgs, cwd = process.cwd()) {
72
72
  process.exit(0);
73
73
  }
74
74
  console.log("\nBumping versions and updating CHANGELOGs...");
75
- for (const { package: pkg, bump } of bumps) runScript(`--filter ${pkg.name} release:${bump}`);
75
+ const hasMajor = bumps.some((b) => b.bump === "major");
76
+ const hasMinor = bumps.some((b) => b.bump === "minor");
77
+ const highestBump = hasMajor ? "major" : hasMinor ? "minor" : "patch";
78
+ try {
79
+ runScript(`release:${highestBump}`);
80
+ } catch {
81
+ console.log("No release script found - skipping versioning (non-publishing repo)");
82
+ }
76
83
  console.log("\nFetching latest state from origin...");
77
84
  git("fetch", "origin");
78
85
  console.log("\nMerging hotfix into production...");
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as git, c as runScript, i as getWorkspacePackages, n as chooseForEach, o as gitRead, r as confirm, s as runQualityChecks, t as branchExists } from "./utils-VktE94Vs.mjs";
2
+ import { a as git, c as runScript, i as getWorkspacePackages, n as chooseForEach, o as gitRead, r as confirm, s as runQualityChecks, t as branchExists } from "./utils-rnvdLrkF.mjs";
3
3
  //#region src/bin/ship/production.ts
4
4
  /**
5
5
  * ship-production: Promote main to production following the GitLab workflow.
@@ -42,6 +42,14 @@ function runShipProduction(cwd = process.cwd()) {
42
42
  }
43
43
  console.log("\nCommits to be shipped to production:");
44
44
  console.log(ahead);
45
+ console.log("\nRunning quality checks on main...");
46
+ try {
47
+ runQualityChecks();
48
+ } catch {
49
+ console.error("\nQuality checks failed on main. Fix issues before shipping.");
50
+ process.exit(1);
51
+ }
52
+ console.log("✅ Quality checks passed");
45
53
  const packages = getWorkspacePackages(cwd);
46
54
  if (packages.length === 0) {
47
55
  console.error("No publishable workspace packages found.");
@@ -57,16 +65,15 @@ function runShipProduction(cwd = process.cwd()) {
57
65
  console.log("Aborted.");
58
66
  process.exit(0);
59
67
  }
60
- console.log("\nRunning quality checks on main...");
68
+ console.log("\nBumping versions and updating CHANGELOGs...");
69
+ const hasMajor = bumps.some((b) => b.bump === "major");
70
+ const hasMinor = bumps.some((b) => b.bump === "minor");
71
+ const highestBump = hasMajor ? "major" : hasMinor ? "minor" : "patch";
61
72
  try {
62
- runQualityChecks();
73
+ runScript(`release:${highestBump}`);
63
74
  } catch {
64
- console.error("\nQuality checks failed on main. Fix issues before shipping.");
65
- process.exit(1);
75
+ console.log("No release script found - skipping versioning (non-publishing repo)");
66
76
  }
67
- console.log("✅ Quality checks passed");
68
- console.log("\nBumping versions and updating CHANGELOGs...");
69
- for (const { package: pkg, bump } of bumps) runScript(`--filter ${pkg.name} release:${bump}`);
70
77
  console.log("\nMerging main into production...");
71
78
  git("checkout", "production");
72
79
  git("pull", "--ff-only", "origin", "production");
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { a as git, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-VktE94Vs.mjs";
2
+ import { a as git, o as gitRead, s as runQualityChecks, t as branchExists } from "./utils-rnvdLrkF.mjs";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  import { join } from "node:path";
5
5
  //#region src/bin/ship/staging.ts
@@ -20,7 +20,7 @@ const runScript = (script) => {
20
20
  execSync(`pnpm ${script}`, { stdio: "inherit" });
21
21
  };
22
22
  const runQualityChecks = () => {
23
- runScript("build");
23
+ runScript("lint");
24
24
  runScript("typecheck");
25
25
  runScript("test");
26
26
  };
@@ -44,26 +44,34 @@ const chooseForEach = (packages, ttyPath = "/dev/tty") => {
44
44
  const bumps = [];
45
45
  const options = [
46
46
  {
47
- label: "skip",
48
- value: "skip"
47
+ label: "0) skip",
48
+ value: "0"
49
49
  },
50
50
  {
51
- label: "patch — bug fixes",
52
- value: "patch"
51
+ label: "1) patch — bug fixes",
52
+ value: "1"
53
53
  },
54
54
  {
55
- label: "minor — new features",
56
- value: "minor"
55
+ label: "2) minor — new features",
56
+ value: "2"
57
57
  },
58
58
  {
59
- label: "major — breaking changes",
60
- value: "major"
59
+ label: "3) major — breaking changes",
60
+ value: "3"
61
61
  }
62
62
  ];
63
63
  for (const pkg of packages) {
64
64
  const answer = choose(`\n${pkg.name}:`, [...options], ttyPath);
65
- if (answer !== "skip") bumps.push({
66
- bump: answer,
65
+ if (answer === "1") bumps.push({
66
+ bump: "patch",
67
+ package: pkg
68
+ });
69
+ else if (answer === "2") bumps.push({
70
+ bump: "minor",
71
+ package: pkg
72
+ });
73
+ else if (answer === "3") bumps.push({
74
+ bump: "major",
67
75
  package: pkg
68
76
  });
69
77
  }
@@ -87,8 +95,8 @@ const confirm = (prompt, ttyPath = "/dev/tty") => {
87
95
  return answer === "y" || answer === "Y";
88
96
  };
89
97
  const choose = (prompt, options, ttyPath = "/dev/tty") => {
90
- const keys = options.map((_, i) => String(i + 1));
91
- const optionList = options.map((o, i) => ` ${i + 1}) ${o.label}`).join("\n");
98
+ const keys = options.map((o) => o.value);
99
+ const optionList = options.map((o) => ` ${o.label}`).join("\n");
92
100
  process.stdout.write(`${prompt}\n${optionList}\nChoice [${keys.join("/")}]: `);
93
101
  const buf = Buffer.alloc(1024);
94
102
  let fd;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  declare const vitestNodeConfig: {
7
7
  coverage: {
8
- provider: "v8";
8
+ provider: 'v8';
9
9
  thresholds: {
10
10
  branches: number;
11
11
  functions: number;
@@ -5,7 +5,7 @@
5
5
  */
6
6
  declare const vitestReactConfig: {
7
7
  coverage: {
8
- provider: "v8";
8
+ provider: 'v8';
9
9
  thresholds: {
10
10
  branches: number;
11
11
  functions: number;
@@ -25,17 +25,17 @@ main → staging (optional) → production
25
25
  - **`staging`** — optional validation environment. No versioning happens here.
26
26
  - **`production`** — versioned, published code only.
27
27
 
28
- When `ship-production` runs, it discovers all publishable workspace packages and asks you to assign a bump type — `skip`, `patch`, `minor`, or `major` — to each one individually. Packages you skip are left untouched. For each package with a bump, it calls `pnpm --filter <package> release:<type>`, which bumps that package's version, rewrites its `CHANGELOG.md` using commits since its last scoped tag, and commits on `main`. The branches merge once after all bumps are applied. CI on `production` publishes only the packages whose version changed.
28
+ When `ship-production` runs, it discovers all publishable workspace packages and asks you to assign a bump type — `0` (skip), `1` (patch), `2` (minor), or `3` (major) — to each one individually. Packages you skip are left untouched. It determines the highest bump type across all selected packages and runs `pnpm release:<type>` at the root, which bumps versions, rewrites `CHANGELOG.md`, and commits on `main`. If no release script exists (non-publishing repos like channels), versioning is skipped entirely and only the git merges happen. The branches merge once after all bumps are applied. CI on `production` publishes only the packages whose version changed.
29
29
 
30
30
  ## How It Works
31
31
 
32
32
  ### Design principles
33
33
 
34
34
  1. **Branches mirror environments.** `staging` reflects what is deployed to the staging server (when used); `production` always reflects what is published to npm. There is never ambiguity about what is running where.
35
- 2. **You choose the bump per package at ship time.** When running `ship-production` or `ship-hotfix finish`, every publishable package is listed and you assign it `skip`, `patch`, `minor`, or `major`. Packages you skip are untouched. The conventional commits in the log inform each choice; the decisions are always explicit.
35
+ 2. **You choose the bump per package at ship time.** When running `ship-production` or `ship-hotfix finish`, every publishable package is listed and you assign it `0` (skip), `1` (patch), `2` (minor), or `3` (major). Packages you skip are untouched. The conventional commits in the log inform each choice; the decisions are always explicit.
36
36
  3. **Version numbers are a production guarantee.** Bumps are applied only at `ship-production` time. Every version tag in git and every release on npm corresponds to code that has been validated and shipped.
37
37
  4. **Staging is optional.** You can ship directly from `main` to `production`. Use `ship-staging` when you want to test changes in a staging environment first.
38
- 5. **Tests are a local gate, not a CI gate.** Quality checks (`build`, `typecheck`, `test`) run on your machine before any commit is made. Broken code cannot enter the repository.
38
+ 5. **Tests are a local gate, not a CI gate.** Quality checks (`lint`, `typecheck`, `test`) run on your machine before any commit is made. Broken code cannot enter the repository.
39
39
  6. **You always land back on `main`.** Every command returns you to `main` when it finishes.
40
40
 
41
41
  ### Full flow diagram
@@ -53,7 +53,8 @@ main ───────────┤ quality checks pass ├──►
53
53
  ship-production
54
54
  ┌──────────────────────────┐
55
55
  │ quality checks on main │
56
- pnpm release
56
+ select packages/bumps
57
+ │ pnpm release:<type>* │
57
58
  main ───────────┤ bumps version + ├──► production
58
59
  │ rewrites CHANGELOG.md │
59
60
  │ ff-merge main → prod │
@@ -76,7 +77,7 @@ production ─────┤ create hotfix/fix-name ├──► hotfix/fix-n
76
77
  ship-hotfix finish
77
78
  ┌──────────────────────────┐
78
79
  │ quality checks │
79
- │ pnpm release
80
+ │ pnpm release:<type>*
80
81
  hotfix/fix-name ┤ bumps version + ├──► production → staging → main
81
82
  │ rewrites CHANGELOG.md │
82
83
  │ merge to production │
@@ -137,10 +138,10 @@ This will:
137
138
  1. Guard: must be on `main`, working tree clean
138
139
  2. Fetch and verify `staging` + `production` branches exist
139
140
  3. Show commits to be shipped
140
- 4. For each publishable package: choose `skip / patch / minor / major`
141
- 5. Confirm the planned bumps abort if declined or all skipped
142
- 6. Run full quality suite on `main` aborts on failure
143
- 7. For each non-skipped package: run `pnpm --filter <pkg> release:<type>` — bumps version, rewrites `CHANGELOG.md`, commits
141
+ 4. Run full quality suite on `main` aborts on failure
142
+ 5. For each publishable package: choose `0 (skip) / 1 (patch) / 2 (minor) / 3 (major)`
143
+ 6. Confirm the planned bumps abort if declined or all skipped
144
+ 7. Run `pnpm release:<type>` at the root (highest bump type) — bumps versions, rewrites `CHANGELOG.md`, commits. If no release script exists, skip versioning.
144
145
  8. Fast-forward merge `main` into `production` and push
145
146
  9. Sync `staging` with `production`
146
147
  10. Push `main` with `--follow-tags` to push all new version tags
@@ -167,13 +168,15 @@ git add . && git commit -m "fix: ..."
167
168
  pnpm ship:hotfix finish
168
169
  ```
169
170
 
170
- `finish` asks you to assign a bump type (`skip`, `patch`, `minor`, or `major`) to each publishable package, runs `pnpm --filter <pkg> release:<type>` for each non-skipped one to bump versions and update `CHANGELOG.md`, then merges `hotfix → production → staging → main` and deletes the hotfix branch. CI publishes from `production`.
171
+ `finish` asks you to assign a bump type (`0` (skip), `1` (patch), `2` (minor), or `3` (major)) to each publishable package, runs `pnpm release:<type>` at the root (highest bump type) to bump versions and update `CHANGELOG.md`. If no release script exists, versioning is skipped. Then it merges `hotfix → production → staging → main` and deletes the hotfix branch. CI publishes from `production`.
171
172
 
172
173
  ## Adoption
173
174
 
174
175
  Install `@regardio/dev` and:
175
176
 
176
- 1. **Add the scripts to `package.json`**:
177
+ 1. **Add the scripts to `package.json`** (optional, for publishing repos):
178
+
179
+ For repos that publish to npm, add release scripts to the root `package.json`:
177
180
 
178
181
  ```json
179
182
  {
@@ -189,6 +192,8 @@ Install `@regardio/dev` and:
189
192
  }
190
193
  ```
191
194
 
195
+ For non-publishing repos (e.g., channels that deploy to servers), omit the release scripts — the ship commands will skip versioning and only perform the git merges. This makes the tools reusable across both publishing and non-publishing repositories.
196
+
192
197
  2. **Add a `.versionrc.json` to each publishable package** with a scoped `tagPrefix` so tags and changelogs stay isolated per package:
193
198
 
194
199
  ```bash
@@ -234,9 +239,11 @@ pnpm typecheck # Must succeed
234
239
  pnpm test # Must succeed
235
240
  ```
236
241
 
237
- ## Private Packages
242
+ ## Private Packages and Non-Publishing Repos
243
+
244
+ Packages that should never be published to npm must set `"private": true` in `package.json`. `pnpm -r publish` skips them automatically.
238
245
 
239
- Packages that should never be published to npm must set `"private": true` in `package.json`. `pnpm -r publish` skips them automatically. The git flow (`ship-staging`, `ship-production`, `ship-hotfix`) works identically version bumps and branch promotion continue as normal; only the npm publish step is skipped.
246
+ For non-publishing repos (e.g., channels that deploy directly to servers instead of npm), omit the `release:*` scripts from `package.json`. The ship tools will skip versioning entirely and only perform the git merges. CI can then handle deployment to servers based on the `production` branch.
240
247
 
241
248
  ## Related
242
249
 
@@ -17,33 +17,62 @@ Strict, shared TypeScript presets for Regardio projects. Extending from `@regard
17
17
 
18
18
  | Preset | Use case |
19
19
  |--------|----------|
20
- | `@regardio/dev/typescript/base` | Node.js packages, libraries |
21
- | `@regardio/dev/typescript/react` | React applications and components |
22
- | `@regardio/dev/typescript/build` | Build-specific settings (extends base) |
20
+ | `@regardio/dev/typescript/base` | Non-publishing packages and meta-configs (e.g. the workspace root) |
21
+ | `@regardio/dev/typescript/library` | Published Node.js packages adds declaration enforcement |
22
+ | `@regardio/dev/typescript/react` | React apps and channels — adds JSX and DOM libs |
23
+ | `@regardio/dev/typescript/react-library` | Published React packages — JSX, DOM libs, and declaration enforcement |
24
+ | `@regardio/dev/typescript/build` | Build-time emission settings (pair with any of the above) |
25
+
26
+ ### Choosing a preset
27
+
28
+ The guiding question is whether the package **publishes type declarations** to consumers.
29
+
30
+ - **App or channel** (`private: true`) → `react` (or `base` for non-React)
31
+ - **Published library without React** → `library`
32
+ - **Published library with React** → `react-library`
33
+
34
+ The `library` and `react-library` presets add two settings on top of the base:
35
+
36
+ - `declaration: true` — validates that `.d.ts` files can be generated (even when `noEmit: true` during typecheck)
37
+ - `isolatedDeclarations: true` — enforces that every exported declaration carries an explicit type annotation, enabling per-file parallel declaration generation
38
+
39
+ `isolatedDeclarations` is a library-authoring constraint. It requires explicit return types on exported functions and explicit annotations on exported variables. Applying it to app code is unnecessarily strict — especially with frameworks like TanStack Router whose `Route` objects carry deeply inferred generics that cannot be spelled out without extraordinary verbosity.
23
40
 
24
41
  ## Configuration
25
42
 
26
- ### `tsconfig.json`
43
+ ### App or channel
27
44
 
28
45
  ```json
29
46
  {
30
- "extends": "@regardio/dev/typescript/base",
47
+ "compilerOptions": {
48
+ "paths": { "#/*": ["./src/*"] }
49
+ },
50
+ "extends": "@regardio/dev/typescript/react",
51
+ "include": ["**/*.ts", "**/*.tsx", "**/*.d.ts"]
52
+ }
53
+ ```
54
+
55
+ ### Published Node.js library
56
+
57
+ ```json
58
+ {
59
+ "extends": "@regardio/dev/typescript/library",
31
60
  "include": ["src/**/*.ts"]
32
61
  }
33
62
  ```
34
63
 
35
- For React projects:
64
+ ### Published React library
36
65
 
37
66
  ```json
38
67
  {
39
- "extends": "@regardio/dev/typescript/react",
68
+ "extends": "@regardio/dev/typescript/react-library",
40
69
  "include": ["src/**/*.ts", "src/**/*.tsx"]
41
70
  }
42
71
  ```
43
72
 
44
73
  ### `tsconfig.build.json`
45
74
 
46
- A separate build config for production output:
75
+ Pair any preset with `build` for production output:
47
76
 
48
77
  ```json
49
78
  {
@@ -51,28 +80,26 @@ A separate build config for production output:
51
80
  "outDir": "./dist",
52
81
  "rootDir": "./src"
53
82
  },
54
- "extends": ["./tsconfig.json", "@regardio/dev/typescript/build"],
55
- "include": ["src/**/*.ts"]
83
+ "extends": ["./tsconfig.json", "@regardio/dev/typescript/build"]
56
84
  }
57
85
  ```
58
86
 
59
87
  ## Strict settings
60
88
 
61
- The base config turns on strict type-checking across the board:
89
+ All presets share the same strict type-checking baseline:
62
90
 
63
91
  - `strict: true` — every strict type-checking option
64
92
  - `noUncheckedIndexedAccess: true` — adds `undefined` to index signatures
65
- - `exactOptionalPropertyTypes: true` — distinguishes `undefined` from missing
66
93
  - `noImplicitReturns: true` — every code path returns a value
67
94
  - `noFallthroughCasesInSwitch: true` — prevents switch-fallthrough surprises
95
+ - `verbatimModuleSyntax: true` — `import type` vs. `import` must be explicit
68
96
 
69
97
  ## Scripts
70
98
 
71
99
  ```json
72
100
  {
73
101
  "scripts": {
74
- "build": "exec-tsc --project tsconfig.build.json",
75
- "typecheck": "exec-tsc --noEmit"
102
+ "typecheck": "tsc --noEmit"
76
103
  }
77
104
  }
78
105
  ```
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://www.schemastore.org/package.json",
3
3
  "name": "@regardio/dev",
4
- "version": "2.3.0",
4
+ "version": "2.4.1",
5
5
  "private": false,
6
6
  "description": "Regardio development presets: biome, typescript, commitlint, markdownlint, vitest, playwright, sqlfluff, husky, and GitLab-flow ship tooling",
7
7
  "keywords": [
@@ -44,7 +44,9 @@
44
44
  },
45
45
  "./typescript/base": "./src/typescript/base.json",
46
46
  "./typescript/build": "./src/typescript/build.json",
47
+ "./typescript/library": "./src/typescript/library.json",
47
48
  "./typescript/react": "./src/typescript/react.json",
49
+ "./typescript/react-library": "./src/typescript/react-library.json",
48
50
  "./vitest/node": {
49
51
  "import": "./dist/vitest/node.mjs",
50
52
  "types": "./dist/vitest/node.d.mts"
@@ -61,6 +63,7 @@
61
63
  },
62
64
  "files": [
63
65
  "dist",
66
+ "LICENSE",
64
67
  "src/biome",
65
68
  "src/commitlint",
66
69
  "src/markdownlint",
@@ -73,7 +76,7 @@
73
76
  "@total-typescript/ts-reset": "0.6.1",
74
77
  "@types/node": "25.6.0",
75
78
  "@vitest/coverage-v8": "4.1.5",
76
- "tsdown": "0.21.10",
79
+ "tsdown": "0.22.0",
77
80
  "vitest": "4.1.5"
78
81
  },
79
82
  "peerDependencies": {
@@ -90,18 +93,11 @@
90
93
  "typescript": ">=6",
91
94
  "vitest": ">=4"
92
95
  },
93
- "engines": {
94
- "node": ">=24"
95
- },
96
96
  "scripts": {
97
97
  "build": "tsdown",
98
98
  "clean": "rimraf .turbo dist",
99
99
  "dev": "tsdown --watch",
100
100
  "fix": "run-s fix:pkg fix:md fix:biome",
101
- "release": "commit-and-tag-version",
102
- "release:major": "commit-and-tag-version --release-as major",
103
- "release:minor": "commit-and-tag-version --release-as minor",
104
- "release:patch": "commit-and-tag-version --release-as patch",
105
101
  "fix:biome": "biome check --write --unsafe .",
106
102
  "fix:md": "markdownlint-cli2 --config ../../.markdownlint-cli2.jsonc --fix",
107
103
  "fix:pkg": "sort-package-json",
@@ -12,7 +12,6 @@
12
12
  "forceConsistentCasingInFileNames": true,
13
13
  "incremental": false,
14
14
  "inlineSources": false,
15
- "isolatedDeclarations": false,
16
15
  "isolatedModules": true,
17
16
  "module": "ESNext",
18
17
  "moduleDetection": "force",
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://www.schemastore.org/tsconfig.json",
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "isolatedDeclarations": true
6
+ },
7
+ "extends": "./base.json"
8
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "$schema": "https://www.schemastore.org/tsconfig.json",
3
+ "compilerOptions": {
4
+ "declaration": true,
5
+ "isolatedDeclarations": true
6
+ },
7
+ "extends": "./react.json"
8
+ }