cabloy 5.1.222 → 5.1.224

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 (43) hide show
  1. package/.cabloy-version +1 -1
  2. package/.github/workflows/vona-test-sqlite3.yml +1 -1
  3. package/.github/workflows/vona-tsc.yml +4 -3
  4. package/CHANGELOG.md +23 -0
  5. package/lint-staged.config.mjs +2 -0
  6. package/oxfmt.config.ts +2 -0
  7. package/oxlint.config.ts +2 -0
  8. package/package.json +11 -2
  9. package/repo-docs/reference/repo-scripts.md +31 -0
  10. package/scripts/release.ts +3 -0
  11. package/scripts/runIsolatedTest.test.ts +1 -1
  12. package/scripts/typecheck.test.ts +199 -0
  13. package/scripts/typecheck.ts +20 -0
  14. package/vona/package.original.json +3 -0
  15. package/vona/packages-cli/cli/package.json +1 -1
  16. package/vona/packages-cli/cli-set-api/package.json +2 -2
  17. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.dev.ts +0 -7
  18. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.test.ts +22 -7
  19. package/vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.tsc.ts +34 -5
  20. package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/testCleanupProcess.test.ts +1 -1
  21. package/vona/packages-cli/cli-set-api/src/lib/bean/toolsBin/testCleanupProcess.ts +1 -1
  22. package/vona/packages-cli/cli-set-api/src/lib/command/bin.tsc.ts +11 -1
  23. package/vona/packages-cli/cli-set-api/src/lib/typescriptRunner.ts +61 -0
  24. package/vona/packages-cli/cli-set-api/templates/app/register.js +1 -1
  25. package/vona/packages-cli/cli-set-api/templates/config/_tsconfig_project.json +0 -3
  26. package/vona/packages-cli/cli-set-api/templates/config/_tsconfig_source.json +0 -3
  27. package/vona/packages-cli/cli-set-api/test/binTestPatterns.test.ts +57 -0
  28. package/vona/packages-vona/vona/package.json +1 -1
  29. package/vona/pnpm-lock.yaml +455 -117
  30. package/vona/src/suite-vendor/a-cabloy/modules/a-rbac/package.json +1 -1
  31. package/vona/src/suite-vendor/a-cabloy/package.json +2 -2
  32. package/vona/src/suite-vendor/a-vona/modules/a-core/package.json +3 -3
  33. package/vona/src/suite-vendor/a-vona/modules/a-orm/package.json +1 -1
  34. package/vona/src/suite-vendor/a-vona/modules/a-orm/src/common/utils.ts +2 -1
  35. package/vona/src/suite-vendor/a-vona/modules/a-permission/package.json +1 -1
  36. package/vona/src/suite-vendor/a-vona/modules/a-redis/package.json +1 -1
  37. package/vona/src/suite-vendor/a-vona/modules/a-redis/test/redisCleanup.test.ts +1 -1
  38. package/vona/src/suite-vendor/a-vona/modules/a-startup/package.json +1 -1
  39. package/vona/src/suite-vendor/a-vona/modules/a-startup/test/devSeed.test.ts +1 -1
  40. package/vona/src/suite-vendor/a-vona/package.json +1 -1
  41. package/vona/tsconfig.json +1 -4
  42. package/zova/package.original.json +2 -0
  43. package/zova/pnpm-lock.yaml +47 -11
package/.cabloy-version CHANGED
@@ -1 +1 @@
1
- 5.1.222
1
+ 5.1.224
@@ -93,7 +93,7 @@ jobs:
93
93
  - name: init
94
94
  run: npm run init
95
95
  - name: run isolated test infrastructure gate
96
- run: node --test scripts/testClaimProcesses.test.ts scripts/runIsolatedTest.test.ts scripts/testClaimCleanup.test.ts scripts/testProcessGuardianWindows.test.ts vona/packages-vona/vona-core/src/lib/core/testClaim.test.ts vona/packages-vona/vona-core/src/lib/core/testClaimFilesystem.test.ts vona/packages-vona/vona-core/src/lib/framework/bootstrap.test.ts vona/packages-vona/vona-core/src/lib/framework/useApp.test.ts vona/packages-cli/cli-set-api/test/binBuildEntries.test.ts
96
+ run: node --test scripts/testClaimProcesses.test.ts scripts/runIsolatedTest.test.ts scripts/testClaimCleanup.test.ts scripts/testProcessGuardianWindows.test.ts vona/packages-vona/vona-core/src/lib/core/testClaim.test.ts vona/packages-vona/vona-core/src/lib/core/testClaimFilesystem.test.ts vona/packages-vona/vona-core/src/lib/framework/bootstrap.test.ts vona/packages-vona/vona-core/src/lib/framework/useApp.test.ts vona/packages-cli/cli-set-api/test/binBuildEntries.test.ts vona/packages-cli/cli-set-api/test/binTestPatterns.test.ts
97
97
  - name: run A-Pay focused gate
98
98
  run: npm run test -- test-pay/test/paymentSession.test.ts test-pay/test/payMock.test.ts test-pay/test/paypalProvider.test.ts test-pay/test/paypalLifecycle.test.ts test-pay/test/stripeProvider.test.ts test-pay/test/stripeLifecycle.test.ts test-pay/test/outbox.test.ts test-pay/test/webhook.test.ts
99
99
  working-directory: vona
@@ -22,6 +22,7 @@ jobs:
22
22
  version: '12.14.0'
23
23
  - name: init
24
24
  run: npm run init
25
- - name: tsc
26
- run: npm run tsc
27
- working-directory: vona
25
+ - name: typecheck runner tests
26
+ run: npm run test:typecheck
27
+ - name: legacy typecheck
28
+ run: npm run tsc:legacy
package/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.1.224
4
+
5
+ ### Features
6
+
7
+ - Update functionality.
8
+
9
+ ### Improvements
10
+
11
+ - Update the release script.
12
+
13
+ ## 5.1.223
14
+
15
+ ### Features
16
+
17
+ - Add a CLI test command.
18
+
19
+ ### Improvements
20
+
21
+ - Replace ts-node with swc-core.
22
+ - Refactor TypeScript compilation.
23
+ - Update isolated test coverage.
24
+ - Update dependency lockfile.
25
+
3
26
  ## 5.1.222
4
27
 
5
28
  ### Features
@@ -5,6 +5,8 @@ const OXFMT_IGNORE_PATTERNS = [
5
5
  // root original
6
6
  '**/.claude',
7
7
  '**/.vscode',
8
+ // Preserve retained evidence bytes and hashes.
9
+ 'repo-specs/**/evidence/**',
8
10
  // file type patterns
9
11
  '*.min.js',
10
12
  '*.code-snippets',
package/oxfmt.config.ts CHANGED
@@ -7,6 +7,8 @@ export default defineConfig(
7
7
  // root original
8
8
  '**/.claude',
9
9
  '**/.vscode',
10
+ // Preserve retained evidence bytes and hashes.
11
+ 'repo-specs/**/evidence/**',
10
12
  // file type patterns (from vona & zova)
11
13
  '*.min.js',
12
14
  '*.code-snippets',
package/oxlint.config.ts CHANGED
@@ -7,6 +7,8 @@ export default defineConfig(
7
7
  // root original
8
8
  '**/.claude',
9
9
  '**/.vscode',
10
+ // Preserve retained evidence bytes and hashes.
11
+ 'repo-specs/**/evidence/**',
10
12
  // glob patterns (from vona & zova, already work from root)
11
13
  '**/node_modules',
12
14
  '**/dist',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cabloy",
3
- "version": "5.1.222",
3
+ "version": "5.1.224",
4
4
  "gitHead": "2c5c19284bab738e492856189acb6fad74b8a7b7",
5
5
  "description": "A Node.js fullstack framework",
6
6
  "keywords": [
@@ -50,8 +50,16 @@
50
50
  "contract:generate:isolated": "node scripts/generateOpenapiIsolated.ts",
51
51
  "test:docs:e2e": "npm run docs:build && playwright test --config repo-e2e/docs/playwright.config.ts",
52
52
  "db:reset": "cd vona && npm run db:reset",
53
- "tsc": "npm run tsc:zova && pnpm --dir vona run tsc",
53
+ "tsc": "npm run tsc:native",
54
+ "tsc:force": "npm run tsc:zova:native && npm run tsc:vona:native:force",
54
55
  "tsc:zova": "pnpm --dir zova run tsc",
56
+ "tsc:native": "npm run tsc:zova:native && npm run tsc:vona:native",
57
+ "tsc:legacy": "npm run tsc:zova:legacy && pnpm --dir vona run tsc:legacy",
58
+ "tsc:zova:native": "node scripts/typecheck.ts native zova --noEmit --incremental false --project tsconfig.vue-tsc.json",
59
+ "tsc:zova:legacy": "node scripts/typecheck.ts typescript zova --noEmit --incremental false --project tsconfig.vue-tsc.json",
60
+ "tsc:vona:native": "pnpm --dir vona run tsc:native",
61
+ "tsc:vona:native:force": "pnpm --dir vona run tsc:native:force",
62
+ "test:typecheck": "node --test scripts/typecheck.test.ts",
55
63
  "deps:vona": "pnpm --dir vona run vona :tools:deps",
56
64
  "deps:zova": "pnpm --dir zova run zova :tools:deps",
57
65
  "format": "oxfmt --check",
@@ -91,6 +99,7 @@
91
99
  "@playwright/test": "^1.62.1",
92
100
  "@types/fs-extra": "^11.0.4",
93
101
  "@types/node": "^26.1.2",
102
+ "@typescript/native": "npm:typescript@7.0.2",
94
103
  "husky": "^9.1.7",
95
104
  "lerna": "^10.0.0",
96
105
  "lint-staged": "^17.0.5",
@@ -44,12 +44,43 @@ Cabloy Basic exposes these shared root scripts:
44
44
  - `npm run contract:generate:isolated`
45
45
  - `npm run db:reset`
46
46
  - `npm run tsc`
47
+ - `npm run tsc:force`
48
+ - `npm run tsc:native`
49
+ - `npm run tsc:legacy`
50
+ - `npm run test:typecheck`
47
51
  - `npm run docs:dev`
48
52
  - `npm run docs:build`
49
53
  - `npm run docs:preview`
50
54
 
51
55
  `npm run init` prepares all Cabloy Basic SSR and REST artifacts with `npm run build:zova:all`, which sequentially builds the Basic and Commerce flavor batches before Vona initialization. Use `build:zova` or `build:zova:commerce` for focused artifact refreshes; use `build:zova:all` only when every shipped Basic flavor must be prepared.
52
56
 
57
+ ## TypeScript toolchains in Cabloy Basic
58
+
59
+ Cabloy Basic keeps two TypeScript toolchains: root `@typescript/native` is the exact npm alias `npm:typescript@7.0.2`, while classic `typescript` 5.9.3 remains available for compiler-API consumers and existing tooling. The alias changes the dependency name, not the executable name: its package still declares `bin.tsc`, not a separate `native` or `tsgo` command.
60
+
61
+ Use the explicit root commands to select the verification toolchain:
62
+
63
+ | Root command | Scope |
64
+ | ------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------- |
65
+ | `npm run tsc` / `npm run tsc:native` | Check Zova, then the complete Vona graph, with native TypeScript; reuse Vona incremental results. |
66
+ | `npm run tsc:force` | Check the same scopes with native TypeScript, forcing Vona to rebuild. |
67
+ | `npm run tsc:legacy` | Check the same scopes with classic TypeScript. |
68
+ | `npm run tsc:zova:native` | Check Zova with native TypeScript. |
69
+ | `npm run tsc:zova:legacy` | Check Zova with classic TypeScript. |
70
+ | `npm run tsc:vona:native` | Check the complete Vona graph with native TypeScript, reusing incremental results. |
71
+ | `npm run tsc:vona:native:force` | Force native checking of the complete Vona graph. |
72
+ | `npm run test:typecheck` | Test compiler selection, argument and failure propagation, Vona graph traversal, and installed compiler versions/API availability. |
73
+
74
+ `scripts/typecheck.ts` delegates to the package-resolving runner in `vona/packages-cli/cli-set-api/src/lib/typescriptRunner.ts`. It resolves `@typescript/native` or `typescript` from the target workspace, reads that package's `bin.tsc`, and invokes it directly with Node. Native Vona checks use the same runner. This avoids relying on `PATH` or a shared `.bin/tsc` name to identify the selected compiler.
75
+
76
+ Both explicit Zova checks use `tsconfig.vue-tsc.json` with `--noEmit --incremental false`. Native Vona checks retain build mode (`-b`), visiting the project, every local suite, and every standalone local module, rather than replacing that graph with a root-only no-emit check. The default native check omits `--force`; `tsc:force` adds it without changing the traversal scope. Zova's cache policy is unchanged, so the force distinction applies to Vona. The explicit legacy check continues to force a rebuild. Vona's emitted files and build-info artifacts are shared between compiler versions: run native and legacy checks **serially**, and coordinate them with other operations writing the same artifacts. After switching from TS5 back to native, run `npm run tsc:force` before relying on incremental checks. Forced rebuilding prevents one compiler's incremental state from standing in for verification by the other; it does not isolate their output.
77
+
78
+ Root `npm run tsc` delegates to incremental `tsc:native` for daily development; use `tsc:force` for full forced verification and `tsc:legacy` for comparison or fallback. The nested Vona and Zova `tsc` defaults, frontend `prerun`, build commands, package publish emitters, and REST emitters remain unchanged. Classic TypeScript remains installed for compiler-JavaScript-API consumers, including SWC configuration loading, Rollup integration, and OpenAPI generation; the existing REST native-preview emitter dependency is also retained.
79
+
80
+ The native alias is installed at the repository root, not in either nested workspace. Run `pnpm install` at the root after updating the checkout; a missing alias fails with an installation diagnostic rather than silently selecting the legacy compiler. A standalone Vona project using `--compiler=native` must install that alias in its project or an ancestor. Do not use a bare root `tsc`/`pnpm exec tsc` to choose a compiler, because both packages declare the same binary name.
81
+
82
+ The `vona-tsc` CI workflow runs root `npm run test:typecheck`, then root `npm run tsc:force`, after its existing initialization. The root release workflow also runs `tsc:force` before versioning/publishing (excluding changelog-only and GitHub-release-only runs), and its post-release compensation verification uses the same forced entrypoint. These gates retain forced verification even though daily checking is incremental. Check the active repository before assuming the same aliases or commands exist in Cabloy Start.
83
+
53
84
  ## Test isolation and development data {#test-isolation-and-development-data}
54
85
 
55
86
  <span id="test-isolation-and-development-data-in-cabloy-basic"></span>
@@ -963,6 +963,9 @@ async function release(options: ReleaseOptions): Promise<void> {
963
963
  }
964
964
 
965
965
  runGovernancePreflight(options.dryRun);
966
+ if (!options.changelogOnly && !options.releaseOnly) {
967
+ execInherited('npm run tsc', options.dryRun);
968
+ }
966
969
 
967
970
  // Determine the version to use
968
971
  let version: string;
@@ -641,7 +641,6 @@ test(
641
641
  try {
642
642
  const script = `
643
643
  import { writeFileSync } from 'node:fs';
644
- writeFileSync(process.argv[1], 'ready');
645
644
  process.on('SIGINT', () => {
646
645
  setTimeout(() => {
647
646
  writeFileSync(process.argv[2], 'stopped');
@@ -649,6 +648,7 @@ test(
649
648
  }, 150);
650
649
  });
651
650
  setInterval(() => {}, 1000);
651
+ writeFileSync(process.argv[1], 'ready');
652
652
  `;
653
653
  const pending = runIsolatedProcess(
654
654
  process.execPath,
@@ -0,0 +1,199 @@
1
+ import assert from 'node:assert/strict';
2
+ import { spawnSync } from 'node:child_process';
3
+ import { mkdirSync, mkdtempSync, readFileSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
4
+ import { createRequire } from 'node:module';
5
+ import { tmpdir } from 'node:os';
6
+ import path from 'node:path';
7
+ import test from 'node:test';
8
+ import { fileURLToPath } from 'node:url';
9
+
10
+ import { CliBinTsc } from '../vona/packages-cli/cli-set-api/src/lib/bean/cli.bin.tsc.ts';
11
+ import {
12
+ resolveTypeScriptCompiler,
13
+ runTypeScript,
14
+ } from '../vona/packages-cli/cli-set-api/src/lib/typescriptRunner.ts';
15
+
16
+ const root = fileURLToPath(new URL('../', import.meta.url));
17
+
18
+ function writeCompiler(root: string, packageName: string, report?: string) {
19
+ const dir = path.join(root, 'node_modules', packageName);
20
+ mkdirSync(dir, { recursive: true });
21
+ writeFileSync(
22
+ path.join(dir, 'package.json'),
23
+ JSON.stringify({ name: 'typescript', bin: { tsc: 'compiler.cjs' } }),
24
+ );
25
+ writeFileSync(
26
+ path.join(dir, 'compiler.cjs'),
27
+ `
28
+ const fs = require('node:fs');
29
+ if (process.argv[2] === '--fail') process.exit(3);
30
+ const report = ${JSON.stringify(report)};
31
+ if (report) fs.appendFileSync(report, JSON.stringify({ cwd: process.cwd(), args: process.argv.slice(2), compiler: ${JSON.stringify(packageName)} }) + '\\n');
32
+ `,
33
+ );
34
+ return path.join(dir, 'compiler.cjs');
35
+ }
36
+
37
+ test('selects exact packages, preserving compiler argv, cwd and failures', async () => {
38
+ const dir = realpathSync(mkdtempSync(path.join(tmpdir(), 'cabloy-typecheck-')));
39
+ try {
40
+ const projectPath = path.join(dir, 'project with spaces');
41
+ mkdirSync(projectPath);
42
+ await assert.rejects(
43
+ runTypeScript('native', [], { projectPath }),
44
+ /Cannot resolve @typescript\/native/,
45
+ );
46
+ const report = path.join(dir, 'calls.jsonl');
47
+ const native = writeCompiler(dir, '@typescript/native', report);
48
+ const legacy = writeCompiler(projectPath, 'typescript');
49
+ assert.equal(resolveTypeScriptCompiler('native', projectPath), native);
50
+ assert.equal(resolveTypeScriptCompiler('typescript', projectPath), legacy);
51
+ const args = ['--project', 'file with spaces.json', 'literal;argument', '$unchanged'];
52
+ await runTypeScript('native', args, { projectPath });
53
+ assert.deepEqual(JSON.parse(readFileSync(report, 'utf8')), {
54
+ cwd: projectPath,
55
+ args,
56
+ compiler: '@typescript/native',
57
+ });
58
+ await assert.rejects(runTypeScript('native', ['--fail'], { projectPath }), { exitCode: 3 });
59
+ await assert.rejects(
60
+ runTypeScript('native', [], { projectPath, cwd: path.join(dir, 'missing') }),
61
+ { code: 'ENOENT' },
62
+ );
63
+ } finally {
64
+ rmSync(dir, { recursive: true, force: true });
65
+ }
66
+ });
67
+
68
+ test('Vona keeps its legacy default and visits the same graph with native', async () => {
69
+ const dir = realpathSync(mkdtempSync(path.join(tmpdir(), 'cabloy-check-graph-')));
70
+ try {
71
+ const report = path.join(dir, 'calls.jsonl');
72
+ writeCompiler(dir, '@typescript/native', report);
73
+ const suiteRoot = path.join(dir, 'suite');
74
+ const moduleRoot = path.join(dir, 'standalone');
75
+ mkdirSync(suiteRoot);
76
+ mkdirSync(moduleRoot);
77
+ const calls: unknown[] = [];
78
+ const cli = Object.create(CliBinTsc.prototype);
79
+ Object.defineProperties(cli, {
80
+ modulesMeta: {
81
+ value: {
82
+ suites: {
83
+ local: { root: suiteRoot, info: { originalName: 'local' } },
84
+ external: { info: { node_modules: true } },
85
+ },
86
+ modulesArray: [
87
+ { root: moduleRoot, info: { originalName: 'standalone' } },
88
+ { suite: 'local', info: {} },
89
+ { info: { node_modules: true } },
90
+ ],
91
+ },
92
+ },
93
+ helper: {
94
+ value: {
95
+ processHelper: {
96
+ tsc: async (...args: unknown[]) => {
97
+ calls.push(args);
98
+ },
99
+ },
100
+ },
101
+ },
102
+ });
103
+ await cli._tsc(dir, false);
104
+ assert.deepEqual(
105
+ calls,
106
+ [dir, suiteRoot, moduleRoot].map(cwd => [['-b'], { cwd }]),
107
+ );
108
+ for (const force of [false, true]) {
109
+ for (const builders of [undefined, 1, 2]) {
110
+ writeFileSync(report, '');
111
+ await cli._tsc(dir, force, 'native', builders);
112
+ const nativeCalls = readFileSync(report, 'utf8')
113
+ .trim()
114
+ .split('\n')
115
+ .map(line => JSON.parse(line));
116
+ const args = force ? ['-b', '--force'] : ['-b'];
117
+ if (builders !== undefined) args.push('--builders', String(builders));
118
+ assert.deepEqual(
119
+ nativeCalls,
120
+ [dir, suiteRoot, moduleRoot].map(cwd => ({
121
+ cwd,
122
+ args,
123
+ compiler: '@typescript/native',
124
+ })),
125
+ );
126
+ }
127
+ }
128
+ assert.equal(calls.length, 3, 'native must not use the legacy binary helper');
129
+ } finally {
130
+ rmSync(dir, { recursive: true, force: true });
131
+ }
132
+ });
133
+
134
+ test('Vona rejects invalid or legacy builder limits before starting compilation', async () => {
135
+ const cli = Object.create(CliBinTsc.prototype);
136
+ for (const builders of [0, -1, 1.5, Number.NaN, Infinity, Number.MAX_SAFE_INTEGER + 1]) {
137
+ await assert.rejects(cli._tsc(root, true, 'native', builders), /positive safe integer/);
138
+ }
139
+ await assert.rejects(cli._tsc(root, true, 'typescript', 1), /requires --compiler=native/);
140
+ });
141
+
142
+ test('root commands retain optional native checks and use legacy in CI', () => {
143
+ const scripts = JSON.parse(readFileSync(path.join(root, 'package.json'), 'utf8')).scripts;
144
+ const vonaScripts = JSON.parse(
145
+ readFileSync(path.join(root, 'vona/package.original.json'), 'utf8'),
146
+ ).scripts;
147
+ assert.equal(scripts.tsc, 'npm run tsc:native');
148
+ assert.equal(scripts['tsc:native'], 'npm run tsc:zova:native && npm run tsc:vona:native');
149
+ assert.equal(scripts['tsc:force'], 'npm run tsc:zova:native && npm run tsc:vona:native:force');
150
+ assert.equal(scripts['tsc:vona:native'], 'pnpm --dir vona run tsc:native');
151
+ assert.equal(scripts['tsc:vona:native:force'], 'pnpm --dir vona run tsc:native:force');
152
+ assert.equal(
153
+ vonaScripts['tsc:native'],
154
+ 'npm run prerun && npm run vona :bin:tsc -- --compiler=native',
155
+ );
156
+ assert.equal(vonaScripts['tsc:native:force'], `${vonaScripts['tsc:native']} --force`);
157
+ assert.equal(vonaScripts['tsc:legacy'], 'npm run prerun && npm run vona :bin:tsc -- --force');
158
+ assert.equal(scripts['tsc:legacy'], 'npm run tsc:zova:legacy && pnpm --dir vona run tsc:legacy');
159
+ assert.equal(
160
+ scripts['tsc:zova:legacy'],
161
+ 'node scripts/typecheck.ts typescript zova --noEmit --incremental false --project tsconfig.vue-tsc.json',
162
+ );
163
+ const workflow = readFileSync(path.join(root, '.github/workflows/vona-tsc.yml'), 'utf8');
164
+ assert.match(workflow, /run: npm run tsc:legacy\s*$/m);
165
+ assert.doesNotMatch(workflow, /run:.*tsc(?::[\w-]+)*native|npm run tsc:force/);
166
+ });
167
+
168
+ test('release dry-run keeps forced checks before publishing only', () => {
169
+ for (const [mode, shouldCheck] of [
170
+ ['--publish-only', true],
171
+ ['--changelog-only', false],
172
+ ['--release-only', false],
173
+ ] as const) {
174
+ const result = spawnSync(process.execPath, ['scripts/release.ts', '--dry-run', mode], {
175
+ cwd: root,
176
+ encoding: 'utf8',
177
+ timeout: 30_000,
178
+ });
179
+ assert.equal(result.error, undefined);
180
+ assert.equal(result.status, 0, result.stderr);
181
+ const check = result.stdout.indexOf('[dry-run] npm run tsc:force');
182
+ assert.equal(check !== -1, shouldCheck, mode);
183
+ if (shouldCheck) {
184
+ assert.ok(result.stdout.indexOf('[dry-run] npm publish') > check);
185
+ }
186
+ }
187
+ });
188
+
189
+ test('installation retains TS5 APIs and exact stable native compiler', () => {
190
+ for (const workspace of ['.', 'vona', 'zova']) {
191
+ const require = createRequire(path.join(root, workspace, 'package.json'));
192
+ const ts = require('typescript');
193
+ assert.equal(ts.version, '5.9.3');
194
+ assert.equal(typeof ts.createSourceFile, 'function');
195
+ assert.match(ts.transpileModule('const value: number = 1;', {}).outputText, /value/);
196
+ }
197
+ const require = createRequire(path.join(root, 'package.json'));
198
+ assert.equal(require('@typescript/native/package.json').version, '7.0.2');
199
+ });
@@ -0,0 +1,20 @@
1
+ import path from 'node:path';
2
+ import { fileURLToPath } from 'node:url';
3
+
4
+ import { runTypeScript } from '../vona/packages-cli/cli-set-api/src/lib/typescriptRunner.ts';
5
+
6
+ const [compiler, workspace, ...args] = process.argv.slice(2);
7
+ if ((compiler !== 'native' && compiler !== 'typescript') || !['vona', 'zova'].includes(workspace)) {
8
+ console.error(
9
+ 'Usage: node scripts/typecheck.ts <native|typescript> <vona|zova> [compiler arguments]',
10
+ );
11
+ process.exitCode = 1;
12
+ } else {
13
+ const projectPath = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..', workspace);
14
+ try {
15
+ await runTypeScript(compiler, args, { projectPath });
16
+ } catch (error) {
17
+ console.error(error instanceof Error ? error.message : error);
18
+ process.exitCode = (error as { exitCode?: number }).exitCode ?? 1;
19
+ }
20
+ }
@@ -27,6 +27,9 @@
27
27
  "test": "node ../scripts/runIsolatedTest.ts unit",
28
28
  "cov": "node ../scripts/runIsolatedTest.ts unit --coverage",
29
29
  "tsc": "npm run prerun && npm run vona :bin:tsc",
30
+ "tsc:native": "npm run prerun && npm run vona :bin:tsc -- --compiler=native",
31
+ "tsc:native:force": "npm run prerun && npm run vona :bin:tsc -- --compiler=native --force",
32
+ "tsc:legacy": "npm run prerun && npm run vona :bin:tsc -- --force",
30
33
  "build": "npm run prerun && npm run vona :bin:build -- --flavor=normal",
31
34
  "build:docker": "npm run prerun && npm run vona :bin:build -- --flavor=docker",
32
35
  "start": "pnpm -C ./dist/normal install && node ./dist/normal/bootstrap.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-cli",
3
- "version": "1.1.168",
3
+ "version": "1.1.169",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "vona cli",
6
6
  "keywords": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vona-cli-set-api",
3
- "version": "1.1.166",
3
+ "version": "1.1.167",
4
4
  "gitHead": "a79189b882c17af5911573896a781bbb0046d37d",
5
5
  "description": "vona cli-set-api",
6
6
  "keywords": [
@@ -63,6 +63,7 @@
63
63
  "@rollup/plugin-replace": "^6.0.3",
64
64
  "@rollup/plugin-terser": "^1.0.0",
65
65
  "@rollup/plugin-typescript": "^12.3.0",
66
+ "@swc-node/register": "^1.12.1",
66
67
  "babel-plugin-transform-typescript-metadata": "^0.3.2",
67
68
  "babel-plugin-vona-bean-module": "workspace:^",
68
69
  "chalk": "^3.0.0",
@@ -76,7 +77,6 @@
76
77
  "randomatic": "^3.1.1",
77
78
  "rimraf": "^6.1.3",
78
79
  "rollup": "^4.60.1",
79
- "ts-node-maintained": "^10.9.6",
80
80
  "urllib": "^4.9.0",
81
81
  "uuid": "^11.1.0",
82
82
  "vona-core": "workspace:^",
@@ -165,12 +165,5 @@ export class CliBinDev extends BeanCliBase {
165
165
  console.log('App restarted due to: ', files);
166
166
  });
167
167
  });
168
- // await this.helper.spawnExe({
169
- // cmd: 'node',
170
- // args: ['--experimental-transform-types', '--loader=ts-node/esm', '.vona/bootstrap.ts'],
171
- // options: {
172
- // cwd: projectPath,
173
- // },
174
- // });
175
168
  }
176
169
  }
@@ -4,6 +4,7 @@ import type { VonaConfigMeta, VonaMetaFlavor, VonaMetaMode } from '@cabloy/modul
4
4
  import { BeanCliBase } from '@cabloy/cli';
5
5
  import { catchError } from '@cabloy/utils';
6
6
  import fse from 'fs-extra';
7
+ import { spawn } from 'node:child_process';
7
8
  import path from 'node:path';
8
9
  import { rimraf } from 'rimraf';
9
10
  import { resolveVonaLocalPaths } from 'vona-core';
@@ -20,6 +21,26 @@ declare module '@cabloy/cli' {
20
21
  }
21
22
  }
22
23
 
24
+ export async function runTestChild(args: string[], projectPath: string): Promise<void> {
25
+ const child = spawn(process.execPath, args, { cwd: projectPath, stdio: 'inherit' });
26
+ const onInterrupt = () => child.kill('SIGINT');
27
+ const onTerminate = () => child.kill('SIGTERM');
28
+ process.on('SIGINT', onInterrupt);
29
+ process.on('SIGTERM', onTerminate);
30
+ try {
31
+ await new Promise<void>((resolve, reject) => {
32
+ child.once('error', reject);
33
+ child.once('close', (code, signal) => {
34
+ if (code === 0) resolve();
35
+ else reject(new Error(`Test child exited: ${signal ?? code}`));
36
+ });
37
+ });
38
+ } finally {
39
+ process.off('SIGINT', onInterrupt);
40
+ process.off('SIGTERM', onTerminate);
41
+ }
42
+ }
43
+
23
44
  export class CliBinTest extends BeanCliBase {
24
45
  async execute() {
25
46
  const { argv } = this.context;
@@ -82,13 +103,7 @@ export class CliBinTest extends BeanCliBase {
82
103
  patterns.join(','),
83
104
  ]);
84
105
  // args = args.concat(['--experimental-transform-types', getImportEsm(), testFile, projectPath, (!!argv.coverage).toString(), patterns.join(',')]);
85
- await this.helper.spawnExe({
86
- cmd: 'node',
87
- args,
88
- options: {
89
- cwd: projectPath,
90
- },
91
- });
106
+ await runTestChild(args, projectPath);
92
107
  }
93
108
 
94
109
  async _outputCoverageReportViewer(projectPath: string) {
@@ -1,8 +1,14 @@
1
1
  import { BeanCliBase } from '@cabloy/cli';
2
2
 
3
+ import type { TypeScriptCompiler } from '../typescriptRunner.ts';
4
+
5
+ import { runTypeScript } from '../typescriptRunner.ts';
6
+
3
7
  declare module '@cabloy/cli' {
4
8
  interface ICommandArgv {
5
9
  force: boolean;
10
+ compiler: TypeScriptCompiler;
11
+ builders: number;
6
12
  }
7
13
  }
8
14
 
@@ -13,10 +19,23 @@ export class CliBinTsc extends BeanCliBase {
13
19
  await super.execute();
14
20
  const projectPath = argv.projectPath;
15
21
  const force = argv.force;
16
- await this._tsc(projectPath, force);
22
+ await this._tsc(projectPath, force, argv.compiler ?? 'typescript', argv.builders);
17
23
  }
18
24
 
19
- async _tsc(projectPath: string, force: boolean) {
25
+ async _tsc(
26
+ projectPath: string,
27
+ force: boolean,
28
+ compiler: TypeScriptCompiler = 'typescript',
29
+ builders?: number,
30
+ ) {
31
+ if (builders !== undefined) {
32
+ if (!Number.isSafeInteger(builders) || builders < 1) {
33
+ throw new Error('--builders must be a positive safe integer');
34
+ }
35
+ if (compiler !== 'native') {
36
+ throw new Error('--builders requires --compiler=native');
37
+ }
38
+ }
20
39
  const suiteNames = Object.keys(this.modulesMeta.suites).filter(
21
40
  suiteName => !this.modulesMeta.suites[suiteName].info.node_modules,
22
41
  );
@@ -35,22 +54,32 @@ export class CliBinTsc extends BeanCliBase {
35
54
  if (force) {
36
55
  tscArgs.push('--force');
37
56
  }
57
+ if (builders !== undefined) {
58
+ tscArgs.push('--builders', String(builders));
59
+ }
60
+ const check = async (cwd: string) => {
61
+ if (compiler === 'native') {
62
+ await runTypeScript(compiler, tscArgs, { projectPath, cwd });
63
+ } else {
64
+ await this.helper.processHelper.tsc(tscArgs, { cwd });
65
+ }
66
+ };
38
67
  // tsc: project
39
68
  // eslint-disable-next-line
40
69
  console.log(`===> ${++counter}/${count} project`);
41
- await this.helper.processHelper.tsc(tscArgs, { cwd: projectPath });
70
+ await check(projectPath);
42
71
  // suites
43
72
  for (const key of suiteNames) {
44
73
  const suite = this.modulesMeta.suites[key];
45
74
  // eslint-disable-next-line
46
75
  console.log(`===> ${++counter}/${count} suite: ${suite.info.originalName}`);
47
- await this.helper.processHelper.tsc(tscArgs, { cwd: suite.root });
76
+ await check(suite.root);
48
77
  }
49
78
  // modules
50
79
  for (const module of modulesArray) {
51
80
  // eslint-disable-next-line
52
81
  console.log(`===> ${++counter}/${count} module: ${module.info.originalName}`);
53
- await this.helper.processHelper.tsc(tscArgs, { cwd: module.root });
82
+ await check(module.root);
54
83
  }
55
84
  // end
56
85
  const timeEnd = Date.now();
@@ -17,7 +17,7 @@ test('cleanup helper launches via process.execPath and resolves only fake source
17
17
  await writeFile(path.join(project, 'package.json'), '{"type":"module"}');
18
18
  await writeFile(
19
19
  path.join(project, 'tsconfig.json'),
20
- '{"compilerOptions":{"module":"NodeNext","moduleResolution":"NodeNext","target":"ESNext","allowImportingTsExtensions":true},"ts-node":{"transpileOnly":true}}',
20
+ '{"compilerOptions":{"module":"NodeNext","moduleResolution":"NodeNext","target":"ESNext","allowImportingTsExtensions":true}}',
21
21
  );
22
22
  await writeFile(
23
23
  path.join(configDir, 'config.ts'),
@@ -4,7 +4,7 @@ import { pathToFileURL } from 'node:url';
4
4
 
5
5
  // Register before dynamically importing source config/framework (decorators and
6
6
  // workspace TS exports). Dependencies resolve from this checkout's Vona install.
7
- register(import.meta.resolve('ts-node-maintained/esm'), pathToFileURL(`${process.cwd()}/`));
7
+ register(import.meta.resolve('@swc-node/register/esm'), pathToFileURL(`${process.cwd()}/`));
8
8
  const require = createRequire(pathToFileURL(path.join(process.cwd(), 'package.json')));
9
9
  let queue = Promise.resolve();
10
10
  let claim: import('vona-core').TestClaimManifest | undefined;
@@ -3,9 +3,19 @@ export default {
3
3
  info: {
4
4
  version: '5.0.0',
5
5
  title: 'Cli: Bin: Tsc',
6
- usage: 'npm run vona :bin:tsc -- [--force]',
6
+ usage: 'npm run vona :bin:tsc -- [--force] [--compiler=typescript|native] [--builders=]',
7
7
  },
8
8
  options: {
9
+ compiler: {
10
+ description:
11
+ 'TypeScript compiler (native requires @typescript/native in the project or repository root)',
12
+ type: 'string',
13
+ choices: ['typescript', 'native'],
14
+ },
15
+ builders: {
16
+ description: 'Maximum number of projects to build concurrently (native only)',
17
+ type: 'number',
18
+ },
9
19
  force: {
10
20
  description: 'force',
11
21
  type: 'boolean',