@zenithbuild/cli 0.6.6 → 0.6.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.d.ts +32 -0
- package/dist/build.js +193 -548
- package/dist/compiler-bridge-runner.d.ts +5 -0
- package/dist/compiler-bridge-runner.js +70 -0
- package/dist/component-instance-ir.d.ts +6 -0
- package/dist/component-instance-ir.js +0 -20
- package/dist/component-occurrences.d.ts +6 -0
- package/dist/component-occurrences.js +6 -28
- package/dist/dev-server.d.ts +18 -0
- package/dist/dev-server.js +65 -114
- package/dist/dev-watch.d.ts +1 -0
- package/dist/dev-watch.js +2 -2
- package/dist/index.d.ts +8 -0
- package/dist/index.js +6 -28
- package/dist/manifest.d.ts +23 -0
- package/dist/manifest.js +22 -48
- package/dist/preview.d.ts +100 -0
- package/dist/preview.js +418 -488
- package/dist/resolve-components.d.ts +39 -0
- package/dist/resolve-components.js +30 -104
- package/dist/server/resolve-request-route.d.ts +39 -0
- package/dist/server/resolve-request-route.js +104 -113
- package/dist/server-contract.d.ts +39 -0
- package/dist/server-contract.js +15 -67
- package/dist/toolchain-paths.d.ts +23 -0
- package/dist/toolchain-paths.js +139 -39
- package/dist/toolchain-runner.d.ts +33 -0
- package/dist/toolchain-runner.js +194 -0
- package/dist/types/generate-env-dts.d.ts +5 -0
- package/dist/types/generate-env-dts.js +4 -2
- package/dist/types/generate-routes-dts.d.ts +8 -0
- package/dist/types/generate-routes-dts.js +7 -5
- package/dist/types/index.d.ts +14 -0
- package/dist/types/index.js +16 -7
- package/dist/ui/env.d.ts +18 -0
- package/dist/ui/env.js +0 -12
- package/dist/ui/format.d.ts +33 -0
- package/dist/ui/format.js +8 -46
- package/dist/ui/logger.d.ts +59 -0
- package/dist/ui/logger.js +3 -32
- package/dist/version-check.d.ts +54 -0
- package/dist/version-check.js +41 -98
- package/package.json +6 -4
package/dist/toolchain-paths.js
CHANGED
|
@@ -2,51 +2,115 @@ import { existsSync, readFileSync } from 'node:fs';
|
|
|
2
2
|
import { createRequire } from 'node:module';
|
|
3
3
|
import { dirname, resolve } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
|
|
6
5
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
6
|
const __dirname = dirname(__filename);
|
|
8
7
|
const CLI_ROOT = resolve(__dirname, '..');
|
|
9
8
|
const localRequire = createRequire(import.meta.url);
|
|
10
|
-
|
|
9
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
10
|
+
const COMPILER_BRIDGE_RUNNER = resolve(__dirname, 'compiler-bridge-runner.js');
|
|
11
|
+
const BUNDLER_PLATFORM_PACKAGES = {
|
|
12
|
+
'darwin-arm64': {
|
|
13
|
+
packageName: '@zenithbuild/bundler-darwin-arm64',
|
|
14
|
+
binaryName: 'zenith-bundler'
|
|
15
|
+
},
|
|
16
|
+
'darwin-x64': {
|
|
17
|
+
packageName: '@zenithbuild/bundler-darwin-x64',
|
|
18
|
+
binaryName: 'zenith-bundler'
|
|
19
|
+
},
|
|
20
|
+
'linux-x64': {
|
|
21
|
+
packageName: '@zenithbuild/bundler-linux-x64',
|
|
22
|
+
binaryName: 'zenith-bundler'
|
|
23
|
+
},
|
|
24
|
+
'win32-x64': {
|
|
25
|
+
packageName: '@zenithbuild/bundler-win32-x64',
|
|
26
|
+
binaryName: 'zenith-bundler.exe'
|
|
27
|
+
}
|
|
28
|
+
};
|
|
11
29
|
function safeCreateRequire(projectRoot) {
|
|
12
30
|
if (!projectRoot) {
|
|
13
31
|
return localRequire;
|
|
14
32
|
}
|
|
15
33
|
try {
|
|
16
34
|
return createRequire(resolve(projectRoot, 'package.json'));
|
|
17
|
-
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
18
37
|
return localRequire;
|
|
19
38
|
}
|
|
20
39
|
}
|
|
21
|
-
|
|
22
40
|
function safeResolve(requireFn, specifier) {
|
|
23
41
|
try {
|
|
24
42
|
return requireFn.resolve(specifier);
|
|
25
|
-
}
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function resolveExecutablePath(candidatePath) {
|
|
49
|
+
if (typeof candidatePath !== 'string' || candidatePath.length === 0) {
|
|
50
|
+
return '';
|
|
51
|
+
}
|
|
52
|
+
if (!IS_WINDOWS || candidatePath.toLowerCase().endsWith('.exe')) {
|
|
53
|
+
return candidatePath;
|
|
54
|
+
}
|
|
55
|
+
if (existsSync(candidatePath)) {
|
|
56
|
+
return candidatePath;
|
|
57
|
+
}
|
|
58
|
+
const exePath = `${candidatePath}.exe`;
|
|
59
|
+
return existsSync(exePath) ? exePath : candidatePath;
|
|
60
|
+
}
|
|
61
|
+
function createBinaryCandidate(tool, source, candidatePath) {
|
|
62
|
+
const resolvedPath = resolveExecutablePath(candidatePath);
|
|
63
|
+
return {
|
|
64
|
+
tool,
|
|
65
|
+
mode: 'binary',
|
|
66
|
+
source,
|
|
67
|
+
sourceKey: `${tool}:${source}:${resolvedPath}`,
|
|
68
|
+
label: source,
|
|
69
|
+
path: resolvedPath,
|
|
70
|
+
command: resolvedPath,
|
|
71
|
+
argsPrefix: []
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
function createCompilerBridgeCandidate(modulePath) {
|
|
75
|
+
if (typeof modulePath !== 'string' || modulePath.length === 0) {
|
|
26
76
|
return null;
|
|
27
77
|
}
|
|
78
|
+
return {
|
|
79
|
+
tool: 'compiler',
|
|
80
|
+
mode: 'node-bridge',
|
|
81
|
+
source: 'JS bridge',
|
|
82
|
+
sourceKey: `compiler:js-bridge:${modulePath}`,
|
|
83
|
+
label: 'JS bridge',
|
|
84
|
+
path: modulePath,
|
|
85
|
+
command: process.execPath,
|
|
86
|
+
argsPrefix: [COMPILER_BRIDGE_RUNNER, '--bridge-module', modulePath]
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function currentBundlerPlatformPackage() {
|
|
90
|
+
return BUNDLER_PLATFORM_PACKAGES[`${process.platform}-${process.arch}`] || null;
|
|
28
91
|
}
|
|
29
|
-
|
|
30
92
|
export function resolveBinary(candidates) {
|
|
31
93
|
for (const candidate of candidates) {
|
|
32
|
-
|
|
33
|
-
|
|
94
|
+
const path = typeof candidate === 'string' ? candidate : candidate.path;
|
|
95
|
+
if (path && existsSync(path)) {
|
|
96
|
+
return path;
|
|
34
97
|
}
|
|
35
98
|
}
|
|
36
|
-
|
|
99
|
+
const first = candidates[0];
|
|
100
|
+
if (typeof first === 'string') {
|
|
101
|
+
return first;
|
|
102
|
+
}
|
|
103
|
+
return first?.path || '';
|
|
37
104
|
}
|
|
38
|
-
|
|
39
105
|
export function resolvePackageRoot(packageName, projectRoot = null) {
|
|
40
106
|
const projectRequire = safeCreateRequire(projectRoot);
|
|
41
107
|
const projectPath = safeResolve(projectRequire, `${packageName}/package.json`);
|
|
42
108
|
if (projectPath) {
|
|
43
109
|
return dirname(projectPath);
|
|
44
110
|
}
|
|
45
|
-
|
|
46
111
|
const localPath = safeResolve(localRequire, `${packageName}/package.json`);
|
|
47
112
|
return localPath ? dirname(localPath) : null;
|
|
48
113
|
}
|
|
49
|
-
|
|
50
114
|
export function readInstalledPackageVersion(packageName, projectRoot = null) {
|
|
51
115
|
const packageRoot = resolvePackageRoot(packageName, projectRoot);
|
|
52
116
|
if (!packageRoot) {
|
|
@@ -55,56 +119,92 @@ export function readInstalledPackageVersion(packageName, projectRoot = null) {
|
|
|
55
119
|
try {
|
|
56
120
|
const pkg = JSON.parse(readFileSync(resolve(packageRoot, 'package.json'), 'utf8'));
|
|
57
121
|
return typeof pkg.version === 'string' ? pkg.version : null;
|
|
58
|
-
}
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
59
124
|
return null;
|
|
60
125
|
}
|
|
61
126
|
}
|
|
62
|
-
|
|
63
127
|
export function readCliPackageVersion() {
|
|
64
128
|
try {
|
|
65
129
|
const pkg = JSON.parse(readFileSync(resolve(CLI_ROOT, 'package.json'), 'utf8'));
|
|
66
130
|
return typeof pkg.version === 'string' ? pkg.version : '0.0.0';
|
|
67
|
-
}
|
|
131
|
+
}
|
|
132
|
+
catch {
|
|
68
133
|
return '0.0.0';
|
|
69
134
|
}
|
|
70
135
|
}
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
resolve(CLI_ROOT, '../compiler/target/release/zenith-compiler')
|
|
75
|
-
resolve(CLI_ROOT, '../zenith-compiler/target/release/zenith-compiler')
|
|
136
|
+
function compilerWorkspaceBinaryCandidates() {
|
|
137
|
+
return [
|
|
138
|
+
createBinaryCandidate('compiler', 'workspace binary', resolve(CLI_ROOT, '../compiler/target/release/zenith-compiler')),
|
|
139
|
+
createBinaryCandidate('compiler', 'workspace binary', resolve(CLI_ROOT, '../zenith-compiler/target/release/zenith-compiler'))
|
|
76
140
|
];
|
|
141
|
+
}
|
|
142
|
+
function bundlerWorkspaceBinaryCandidates() {
|
|
143
|
+
return [
|
|
144
|
+
createBinaryCandidate('bundler', 'workspace binary', resolve(CLI_ROOT, '../bundler/target/release/zenith-bundler')),
|
|
145
|
+
createBinaryCandidate('bundler', 'workspace binary', resolve(CLI_ROOT, '../zenith-bundler/target/release/zenith-bundler'))
|
|
146
|
+
];
|
|
147
|
+
}
|
|
148
|
+
export function compilerCommandCandidates(projectRoot = null, env = process.env) {
|
|
149
|
+
const candidates = [];
|
|
150
|
+
const envBin = env.ZENITH_COMPILER_BIN;
|
|
151
|
+
if (typeof envBin === 'string' && envBin.length > 0) {
|
|
152
|
+
candidates.push({
|
|
153
|
+
...createBinaryCandidate('compiler', 'env override (ZENITH_COMPILER_BIN)', envBin),
|
|
154
|
+
explicit: true
|
|
155
|
+
});
|
|
156
|
+
}
|
|
77
157
|
const installedRoot = resolvePackageRoot('@zenithbuild/compiler', projectRoot);
|
|
78
158
|
if (installedRoot) {
|
|
79
|
-
candidates.
|
|
159
|
+
candidates.push(createBinaryCandidate('compiler', 'installed package binary', resolve(installedRoot, 'target/release/zenith-compiler')));
|
|
160
|
+
}
|
|
161
|
+
candidates.push(...compilerWorkspaceBinaryCandidates());
|
|
162
|
+
if (installedRoot) {
|
|
163
|
+
const bridgeCandidate = createCompilerBridgeCandidate(resolve(installedRoot, 'dist/index.js'));
|
|
164
|
+
if (bridgeCandidate) {
|
|
165
|
+
candidates.push(bridgeCandidate);
|
|
166
|
+
}
|
|
80
167
|
}
|
|
81
168
|
return candidates;
|
|
82
169
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
170
|
+
export function compilerBinCandidates(projectRoot = null, env = process.env) {
|
|
171
|
+
return compilerCommandCandidates(projectRoot, env)
|
|
172
|
+
.filter((candidate) => candidate.mode === 'binary')
|
|
173
|
+
.map((candidate) => candidate.path);
|
|
86
174
|
}
|
|
87
|
-
|
|
88
|
-
|
|
175
|
+
export function resolveCompilerBin(projectRoot = null, env = process.env) {
|
|
176
|
+
return resolveBinary(compilerBinCandidates(projectRoot, env));
|
|
177
|
+
}
|
|
178
|
+
export function bundlerCommandCandidates(projectRoot = null, env = process.env) {
|
|
89
179
|
const candidates = [];
|
|
90
|
-
const envBin = env
|
|
180
|
+
const envBin = env.ZENITH_BUNDLER_BIN;
|
|
91
181
|
if (typeof envBin === 'string' && envBin.length > 0) {
|
|
92
|
-
candidates.push(
|
|
182
|
+
candidates.push({
|
|
183
|
+
...createBinaryCandidate('bundler', 'env override (ZENITH_BUNDLER_BIN)', envBin),
|
|
184
|
+
explicit: true
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
const platformPackage = currentBundlerPlatformPackage();
|
|
188
|
+
if (platformPackage) {
|
|
189
|
+
const platformPackageRoot = resolvePackageRoot(platformPackage.packageName, projectRoot);
|
|
190
|
+
if (platformPackageRoot) {
|
|
191
|
+
candidates.push(createBinaryCandidate('bundler', 'installed platform package binary', resolve(platformPackageRoot, 'bin', platformPackage.binaryName)));
|
|
192
|
+
}
|
|
93
193
|
}
|
|
94
|
-
|
|
95
194
|
const installedRoot = resolvePackageRoot('@zenithbuild/bundler', projectRoot);
|
|
96
195
|
if (installedRoot) {
|
|
97
|
-
candidates.push(resolve(installedRoot, 'target/release/zenith-bundler'));
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
candidates.push(
|
|
101
|
-
resolve(CLI_ROOT, '../bundler/target/release/zenith-bundler'),
|
|
102
|
-
resolve(CLI_ROOT, '../zenith-bundler/target/release/zenith-bundler')
|
|
103
|
-
);
|
|
104
|
-
|
|
196
|
+
candidates.push(createBinaryCandidate('bundler', 'installed package binary', resolve(installedRoot, 'target/release/zenith-bundler')));
|
|
197
|
+
}
|
|
198
|
+
candidates.push(...bundlerWorkspaceBinaryCandidates());
|
|
105
199
|
return candidates;
|
|
106
200
|
}
|
|
107
|
-
|
|
108
201
|
export function resolveBundlerBin(projectRoot = null, env = process.env) {
|
|
109
|
-
return resolveBinary(
|
|
202
|
+
return resolveBinary(bundlerCommandCandidates(projectRoot, env)
|
|
203
|
+
.filter((candidate) => candidate.mode === 'binary')
|
|
204
|
+
.map((candidate) => candidate.path));
|
|
205
|
+
}
|
|
206
|
+
export function bundlerBinCandidates(projectRoot = null, env = process.env) {
|
|
207
|
+
return bundlerCommandCandidates(projectRoot, env)
|
|
208
|
+
.filter((candidate) => candidate.mode === 'binary')
|
|
209
|
+
.map((candidate) => candidate.path);
|
|
110
210
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { SpawnSyncOptionsWithStringEncoding, SpawnSyncReturns } from 'node:child_process';
|
|
2
|
+
import { type ToolchainCandidate, type ToolchainTool } from './toolchain-paths.js';
|
|
3
|
+
export interface ToolchainLogger {
|
|
4
|
+
warn?: (message: string, options?: {
|
|
5
|
+
onceKey?: string;
|
|
6
|
+
}) => void;
|
|
7
|
+
}
|
|
8
|
+
export interface ToolchainState {
|
|
9
|
+
tool: ToolchainTool;
|
|
10
|
+
logger: ToolchainLogger | null;
|
|
11
|
+
candidates: ToolchainCandidate[];
|
|
12
|
+
activeIndex: number;
|
|
13
|
+
}
|
|
14
|
+
type SpawnResult = SpawnSyncReturns<string>;
|
|
15
|
+
export declare function createCompilerToolchain({ projectRoot, env, logger }?: {
|
|
16
|
+
projectRoot?: string | null;
|
|
17
|
+
env?: NodeJS.ProcessEnv;
|
|
18
|
+
logger?: ToolchainLogger | null;
|
|
19
|
+
}): ToolchainState;
|
|
20
|
+
export declare function createBundlerToolchain({ projectRoot, env, logger }?: {
|
|
21
|
+
projectRoot?: string | null;
|
|
22
|
+
env?: NodeJS.ProcessEnv;
|
|
23
|
+
logger?: ToolchainLogger | null;
|
|
24
|
+
}): ToolchainState;
|
|
25
|
+
export declare function createToolchainStateForTests(tool: ToolchainTool, candidates: ToolchainCandidate[], logger?: ToolchainLogger | null): ToolchainState;
|
|
26
|
+
export declare function resetToolchainWarningsForTests(): void;
|
|
27
|
+
export declare function getActiveToolchainCandidate(toolchain: ToolchainState): ToolchainCandidate | null;
|
|
28
|
+
export declare function ensureToolchainCompatibility(toolchain: ToolchainState, probeArgs?: string[]): ToolchainCandidate;
|
|
29
|
+
export declare function runToolchainSync(toolchain: ToolchainState, args: string[], spawnOptions?: SpawnSyncOptionsWithStringEncoding): {
|
|
30
|
+
result: SpawnResult;
|
|
31
|
+
candidate: ToolchainCandidate;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { bundlerCommandCandidates, compilerCommandCandidates } from './toolchain-paths.js';
|
|
4
|
+
const FALLBACK_LOG_KEYS = new Set();
|
|
5
|
+
const INCOMPATIBLE_ERROR_CODES = new Set(['ENOEXEC', 'EACCES']);
|
|
6
|
+
const INCOMPATIBLE_STDERR_PATTERNS = [
|
|
7
|
+
/exec format error/i,
|
|
8
|
+
/bad cpu type/i,
|
|
9
|
+
/cannot execute binary file/i,
|
|
10
|
+
/not a valid win32 application/i
|
|
11
|
+
];
|
|
12
|
+
function currentPlatformLabel() {
|
|
13
|
+
return `${process.platform}-${process.arch}`;
|
|
14
|
+
}
|
|
15
|
+
function toolEnvVar(tool) {
|
|
16
|
+
return tool === 'bundler' ? 'ZENITH_BUNDLER_BIN' : 'ZENITH_COMPILER_BIN';
|
|
17
|
+
}
|
|
18
|
+
function candidateExists(candidate) {
|
|
19
|
+
if (!candidate) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
if (candidate.mode === 'node-bridge') {
|
|
23
|
+
const [runnerPath] = candidate.argsPrefix;
|
|
24
|
+
return existsSync(candidate.path) && typeof runnerPath === 'string' && existsSync(runnerPath);
|
|
25
|
+
}
|
|
26
|
+
return typeof candidate.path === 'string' && candidate.path.length > 0 && existsSync(candidate.path);
|
|
27
|
+
}
|
|
28
|
+
function candidateSupportsArgs(candidate, args) {
|
|
29
|
+
if (!candidate || candidate.mode !== 'node-bridge') {
|
|
30
|
+
return true;
|
|
31
|
+
}
|
|
32
|
+
return !args.includes('--embedded-markup-expressions') && !args.includes('--strict-dom-lints');
|
|
33
|
+
}
|
|
34
|
+
function isBinaryIncompatible(result) {
|
|
35
|
+
const error = result?.error;
|
|
36
|
+
const errorCode = error?.code;
|
|
37
|
+
if (typeof errorCode === 'string' && INCOMPATIBLE_ERROR_CODES.has(errorCode)) {
|
|
38
|
+
return true;
|
|
39
|
+
}
|
|
40
|
+
const stderr = `${result?.stderr || ''}\n${error?.message || ''}`;
|
|
41
|
+
return INCOMPATIBLE_STDERR_PATTERNS.some((pattern) => pattern.test(stderr));
|
|
42
|
+
}
|
|
43
|
+
function emitFallbackWarning(toolchain, nextCandidate) {
|
|
44
|
+
const message = `[zenith] ${toolchain.tool} binary incompatible for this platform; falling back to ${nextCandidate.label}`;
|
|
45
|
+
const onceKey = `toolchain-fallback:${toolchain.tool}:${nextCandidate.sourceKey}`;
|
|
46
|
+
if (toolchain.logger && typeof toolchain.logger.warn === 'function') {
|
|
47
|
+
toolchain.logger.warn(message, { onceKey });
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (FALLBACK_LOG_KEYS.has(onceKey)) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
FALLBACK_LOG_KEYS.add(onceKey);
|
|
54
|
+
console.warn(message);
|
|
55
|
+
}
|
|
56
|
+
function missingToolchainError(toolchain) {
|
|
57
|
+
if (toolchain.tool === 'bundler') {
|
|
58
|
+
return new Error(`[zenith] Bundler binary not installed for ${process.platform}/${process.arch}. ` +
|
|
59
|
+
'Reinstall @zenithbuild/bundler or ensure optional dependency installed.');
|
|
60
|
+
}
|
|
61
|
+
return new Error(`[zenith] ${toolchain.tool} binary not installed for ${currentPlatformLabel()}; ` +
|
|
62
|
+
`reinstall or set ${toolEnvVar(toolchain.tool)}=...`);
|
|
63
|
+
}
|
|
64
|
+
function incompatibleBinaryError(toolchain) {
|
|
65
|
+
return new Error(`[zenith] ${toolchain.tool} binary is incompatible for ${currentPlatformLabel()}; ` +
|
|
66
|
+
`reinstall or set ${toolEnvVar(toolchain.tool)}=...`);
|
|
67
|
+
}
|
|
68
|
+
function toolchainProbeError(toolchain, result) {
|
|
69
|
+
const detail = result?.error?.message
|
|
70
|
+
|| String(result?.stderr || '').trim()
|
|
71
|
+
|| `exit code ${result?.status ?? 'unknown'}`;
|
|
72
|
+
return new Error(`[zenith] ${toolchain.tool} probe failed: ${detail}`);
|
|
73
|
+
}
|
|
74
|
+
function buildToolchainState(tool, candidates, logger = null) {
|
|
75
|
+
const explicitIndex = candidates.findIndex((candidate) => candidate.explicit === true);
|
|
76
|
+
const initialIndex = explicitIndex >= 0
|
|
77
|
+
? explicitIndex
|
|
78
|
+
: candidates.findIndex((candidate) => candidateExists(candidate));
|
|
79
|
+
return {
|
|
80
|
+
tool,
|
|
81
|
+
logger,
|
|
82
|
+
candidates,
|
|
83
|
+
activeIndex: initialIndex >= 0 ? initialIndex : 0
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function findNextFallbackIndex(toolchain, args) {
|
|
87
|
+
for (let index = toolchain.activeIndex + 1; index < toolchain.candidates.length; index += 1) {
|
|
88
|
+
const candidate = toolchain.candidates[index];
|
|
89
|
+
if (!candidateExists(candidate)) {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
if (!candidateSupportsArgs(candidate, args)) {
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
return index;
|
|
96
|
+
}
|
|
97
|
+
return -1;
|
|
98
|
+
}
|
|
99
|
+
function activeCandidate(toolchain) {
|
|
100
|
+
return toolchain.candidates[toolchain.activeIndex] || null;
|
|
101
|
+
}
|
|
102
|
+
function runCandidateSync(candidate, args, spawnOptions) {
|
|
103
|
+
return spawnSync(candidate.command, [...candidate.argsPrefix, ...args], spawnOptions);
|
|
104
|
+
}
|
|
105
|
+
export function createCompilerToolchain({ projectRoot = null, env = process.env, logger = null } = {}) {
|
|
106
|
+
return buildToolchainState('compiler', compilerCommandCandidates(projectRoot, env), logger);
|
|
107
|
+
}
|
|
108
|
+
export function createBundlerToolchain({ projectRoot = null, env = process.env, logger = null } = {}) {
|
|
109
|
+
return buildToolchainState('bundler', bundlerCommandCandidates(projectRoot, env), logger);
|
|
110
|
+
}
|
|
111
|
+
export function createToolchainStateForTests(tool, candidates, logger = null) {
|
|
112
|
+
return buildToolchainState(tool, candidates, logger);
|
|
113
|
+
}
|
|
114
|
+
export function resetToolchainWarningsForTests() {
|
|
115
|
+
FALLBACK_LOG_KEYS.clear();
|
|
116
|
+
}
|
|
117
|
+
export function getActiveToolchainCandidate(toolchain) {
|
|
118
|
+
return activeCandidate(toolchain);
|
|
119
|
+
}
|
|
120
|
+
export function ensureToolchainCompatibility(toolchain, probeArgs = ['--version']) {
|
|
121
|
+
while (toolchain.activeIndex < toolchain.candidates.length) {
|
|
122
|
+
const candidate = activeCandidate(toolchain);
|
|
123
|
+
if (!candidate) {
|
|
124
|
+
break;
|
|
125
|
+
}
|
|
126
|
+
if (!candidateExists(candidate)) {
|
|
127
|
+
const nextIndex = findNextFallbackIndex(toolchain, probeArgs);
|
|
128
|
+
if (nextIndex === -1) {
|
|
129
|
+
throw missingToolchainError(toolchain);
|
|
130
|
+
}
|
|
131
|
+
toolchain.activeIndex = nextIndex;
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
if (!candidateSupportsArgs(candidate, probeArgs)) {
|
|
135
|
+
const nextIndex = findNextFallbackIndex(toolchain, probeArgs);
|
|
136
|
+
if (nextIndex === -1) {
|
|
137
|
+
throw incompatibleBinaryError(toolchain);
|
|
138
|
+
}
|
|
139
|
+
toolchain.activeIndex = nextIndex;
|
|
140
|
+
emitFallbackWarning(toolchain, toolchain.candidates[nextIndex]);
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
const result = runCandidateSync(candidate, probeArgs, { encoding: 'utf8' });
|
|
144
|
+
if (!isBinaryIncompatible(result)) {
|
|
145
|
+
if (result.error || result.status !== 0) {
|
|
146
|
+
throw toolchainProbeError(toolchain, result);
|
|
147
|
+
}
|
|
148
|
+
return candidate;
|
|
149
|
+
}
|
|
150
|
+
const nextIndex = findNextFallbackIndex(toolchain, probeArgs);
|
|
151
|
+
if (nextIndex === -1) {
|
|
152
|
+
throw incompatibleBinaryError(toolchain);
|
|
153
|
+
}
|
|
154
|
+
toolchain.activeIndex = nextIndex;
|
|
155
|
+
emitFallbackWarning(toolchain, toolchain.candidates[nextIndex]);
|
|
156
|
+
}
|
|
157
|
+
throw missingToolchainError(toolchain);
|
|
158
|
+
}
|
|
159
|
+
export function runToolchainSync(toolchain, args, spawnOptions = { encoding: 'utf8' }) {
|
|
160
|
+
while (toolchain.activeIndex < toolchain.candidates.length) {
|
|
161
|
+
const candidate = activeCandidate(toolchain);
|
|
162
|
+
if (!candidate) {
|
|
163
|
+
break;
|
|
164
|
+
}
|
|
165
|
+
if (!candidateExists(candidate)) {
|
|
166
|
+
const nextIndex = findNextFallbackIndex(toolchain, args);
|
|
167
|
+
if (nextIndex === -1) {
|
|
168
|
+
throw missingToolchainError(toolchain);
|
|
169
|
+
}
|
|
170
|
+
toolchain.activeIndex = nextIndex;
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
173
|
+
if (!candidateSupportsArgs(candidate, args)) {
|
|
174
|
+
const nextIndex = findNextFallbackIndex(toolchain, args);
|
|
175
|
+
if (nextIndex === -1) {
|
|
176
|
+
throw incompatibleBinaryError(toolchain);
|
|
177
|
+
}
|
|
178
|
+
toolchain.activeIndex = nextIndex;
|
|
179
|
+
emitFallbackWarning(toolchain, toolchain.candidates[nextIndex]);
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
const result = runCandidateSync(candidate, args, spawnOptions);
|
|
183
|
+
if (!isBinaryIncompatible(result)) {
|
|
184
|
+
return { result, candidate };
|
|
185
|
+
}
|
|
186
|
+
const nextIndex = findNextFallbackIndex(toolchain, args);
|
|
187
|
+
if (nextIndex === -1) {
|
|
188
|
+
throw incompatibleBinaryError(toolchain);
|
|
189
|
+
}
|
|
190
|
+
toolchain.activeIndex = nextIndex;
|
|
191
|
+
emitFallbackWarning(toolchain, toolchain.candidates[nextIndex]);
|
|
192
|
+
}
|
|
193
|
+
throw missingToolchainError(toolchain);
|
|
194
|
+
}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { writeFile, mkdir } from 'node:fs/promises';
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} projectRoot
|
|
5
|
+
* @returns {Promise<void>}
|
|
6
|
+
*/
|
|
4
7
|
export async function generateEnvDts(projectRoot) {
|
|
5
8
|
const content = `// .zenith/zenith-env.d.ts
|
|
6
9
|
// Auto-generated by Zenith. Do not edit.
|
|
@@ -45,7 +48,6 @@ declare global {
|
|
|
45
48
|
}
|
|
46
49
|
}
|
|
47
50
|
`;
|
|
48
|
-
|
|
49
51
|
const outPath = join(projectRoot, '.zenith', 'zenith-env.d.ts');
|
|
50
52
|
await mkdir(dirname(outPath), { recursive: true });
|
|
51
53
|
await writeFile(outPath, content, 'utf8');
|
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { writeFile, mkdir } from 'node:fs/promises';
|
|
2
2
|
import { join, dirname } from 'node:path';
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* @param {string} projectRoot
|
|
5
|
+
* @param {Array<{ path?: string | null }>} [manifest]
|
|
6
|
+
* @returns {Promise<void>}
|
|
7
|
+
*/
|
|
4
8
|
export async function generateRoutesDts(projectRoot, manifest) {
|
|
5
|
-
const routes = (manifest || []).map(
|
|
9
|
+
const routes = (manifest || []).map((route) => route.path).filter(Boolean);
|
|
6
10
|
const typeDef = routes.length > 0
|
|
7
|
-
? routes.map(
|
|
11
|
+
? routes.map((route) => `"${route}"`).join(' | ')
|
|
8
12
|
: 'string';
|
|
9
|
-
|
|
10
13
|
const content = '// .zenith/zenith-routes.d.ts\\n' +
|
|
11
14
|
'// Auto-generated by Zenith. Do not edit.\\n\\n' +
|
|
12
15
|
'export {};\\n\\n' +
|
|
@@ -15,7 +18,6 @@ export async function generateRoutesDts(projectRoot, manifest) {
|
|
|
15
18
|
' type RoutePattern = ' + typeDef + ';\\n' +
|
|
16
19
|
' }\\n' +
|
|
17
20
|
'}\\n';
|
|
18
|
-
|
|
19
21
|
const outPath = join(projectRoot, '.zenith', 'zenith-routes.d.ts');
|
|
20
22
|
await mkdir(dirname(outPath), { recursive: true });
|
|
21
23
|
await writeFile(outPath, content, 'utf8');
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @typedef {typeof globalThis & { __zenithTypesWarned?: boolean }} ZenithTypesGlobal
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* @param {string} projectRoot
|
|
6
|
+
* @param {Array<{ path?: string }>} [manifest]
|
|
7
|
+
* @returns {Promise<void>}
|
|
8
|
+
*/
|
|
9
|
+
export function ensureZenithTypes(projectRoot: string, manifest?: Array<{
|
|
10
|
+
path?: string;
|
|
11
|
+
}>): Promise<void>;
|
|
12
|
+
export type ZenithTypesGlobal = typeof globalThis & {
|
|
13
|
+
__zenithTypesWarned?: boolean;
|
|
14
|
+
};
|
package/dist/types/index.js
CHANGED
|
@@ -2,33 +2,42 @@ import { generateEnvDts } from './generate-env-dts.js';
|
|
|
2
2
|
import { generateRoutesDts } from './generate-routes-dts.js';
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { access, constants } from 'node:fs/promises';
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* @typedef {typeof globalThis & { __zenithTypesWarned?: boolean }} ZenithTypesGlobal
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* @param {string} projectRoot
|
|
10
|
+
* @param {Array<{ path?: string }>} [manifest]
|
|
11
|
+
* @returns {Promise<void>}
|
|
12
|
+
*/
|
|
6
13
|
export async function ensureZenithTypes(projectRoot, manifest) {
|
|
7
14
|
try {
|
|
8
15
|
await generateEnvDts(projectRoot);
|
|
9
16
|
if (manifest) {
|
|
10
17
|
await generateRoutesDts(projectRoot, manifest);
|
|
11
18
|
}
|
|
12
|
-
|
|
13
19
|
// Check if tsconfig.json exists, if it does, check if .zenith is included
|
|
14
20
|
const tsconfigPath = join(projectRoot, 'tsconfig.json');
|
|
15
21
|
let hasTsConfig = false;
|
|
16
22
|
try {
|
|
17
23
|
await access(tsconfigPath, constants.F_OK);
|
|
18
24
|
hasTsConfig = true;
|
|
19
|
-
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
20
27
|
hasTsConfig = false;
|
|
21
28
|
}
|
|
22
|
-
|
|
23
29
|
if (hasTsConfig) {
|
|
24
30
|
// In a real implementation this would parse the JSON and check "include".
|
|
25
31
|
// For now, we simply inform the user to include it if they haven't.
|
|
26
|
-
|
|
32
|
+
/** @type {ZenithTypesGlobal} */
|
|
33
|
+
const globalScope = globalThis;
|
|
34
|
+
if (!globalScope.__zenithTypesWarned) {
|
|
27
35
|
console.warn('\\x1b[33m[zenith]\\x1b[0m For the best TypeScript experience, ensure ".zenith/**/*.d.ts" is in your tsconfig.json "include" array.');
|
|
28
|
-
|
|
36
|
+
globalScope.__zenithTypesWarned = true;
|
|
29
37
|
}
|
|
30
38
|
}
|
|
31
|
-
}
|
|
39
|
+
}
|
|
40
|
+
catch (err) {
|
|
32
41
|
console.error('[zenith] Failed to generate type definitions:', err);
|
|
33
42
|
}
|
|
34
43
|
}
|
package/dist/ui/env.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export type UiLogLevel = 'quiet' | 'normal' | 'verbose';
|
|
2
|
+
export interface UiMode {
|
|
3
|
+
plain: boolean;
|
|
4
|
+
color: boolean;
|
|
5
|
+
tty: boolean;
|
|
6
|
+
ci: boolean;
|
|
7
|
+
spinner: boolean;
|
|
8
|
+
debug: boolean;
|
|
9
|
+
logLevel: UiLogLevel;
|
|
10
|
+
}
|
|
11
|
+
export interface UiRuntime {
|
|
12
|
+
env?: Record<string, string | undefined>;
|
|
13
|
+
stdout?: {
|
|
14
|
+
isTTY?: boolean;
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export declare function getUiMode(runtime?: UiRuntime): UiMode;
|
|
18
|
+
export declare function isUiPlain(runtime?: UiRuntime): boolean;
|
package/dist/ui/env.js
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* UI environment mode detection for deterministic CLI output.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
1
|
function flagEnabled(value) {
|
|
6
2
|
if (value === undefined || value === null) {
|
|
7
3
|
return false;
|
|
@@ -9,7 +5,6 @@ function flagEnabled(value) {
|
|
|
9
5
|
const normalized = String(value).trim().toLowerCase();
|
|
10
6
|
return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';
|
|
11
7
|
}
|
|
12
|
-
|
|
13
8
|
function parseLogLevel(value) {
|
|
14
9
|
const normalized = String(value || '').trim().toLowerCase();
|
|
15
10
|
if (normalized === 'quiet' || normalized === 'verbose') {
|
|
@@ -17,10 +12,6 @@ function parseLogLevel(value) {
|
|
|
17
12
|
}
|
|
18
13
|
return 'normal';
|
|
19
14
|
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* @param {{ env?: Record<string, string | undefined>, stdout?: { isTTY?: boolean } }} runtime
|
|
23
|
-
*/
|
|
24
15
|
export function getUiMode(runtime = process) {
|
|
25
16
|
const env = runtime.env || {};
|
|
26
17
|
const tty = Boolean(runtime.stdout?.isTTY);
|
|
@@ -30,7 +21,6 @@ export function getUiMode(runtime = process) {
|
|
|
30
21
|
const forceColor = flagEnabled(env.FORCE_COLOR);
|
|
31
22
|
const debug = flagEnabled(env.ZENITH_DEBUG);
|
|
32
23
|
let logLevel = parseLogLevel(env.ZENITH_LOG_LEVEL);
|
|
33
|
-
|
|
34
24
|
const plain = noUi || ci || !tty;
|
|
35
25
|
const color = !plain && !noColor && (forceColor || tty);
|
|
36
26
|
const spinner = tty && !plain && !ci;
|
|
@@ -40,7 +30,6 @@ export function getUiMode(runtime = process) {
|
|
|
40
30
|
if (debug && logLevel !== 'quiet') {
|
|
41
31
|
logLevel = 'verbose';
|
|
42
32
|
}
|
|
43
|
-
|
|
44
33
|
return {
|
|
45
34
|
plain,
|
|
46
35
|
color,
|
|
@@ -51,7 +40,6 @@ export function getUiMode(runtime = process) {
|
|
|
51
40
|
logLevel
|
|
52
41
|
};
|
|
53
42
|
}
|
|
54
|
-
|
|
55
43
|
export function isUiPlain(runtime = process) {
|
|
56
44
|
return getUiMode(runtime).plain;
|
|
57
45
|
}
|