@zenithbuild/cli 0.5.0-beta.2.5 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -0
- package/dist/build.js +154 -119
- package/dist/dev-server.js +558 -53
- package/dist/index.js +75 -14
- package/dist/preview.js +323 -40
- package/dist/resolve-components.js +108 -0
- package/dist/server-contract.js +150 -11
- package/dist/ui/format.js +56 -17
- package/package.json +2 -2
|
@@ -245,6 +245,9 @@ function findNextKnownTag(source, registry, startIndex) {
|
|
|
245
245
|
if (!registry.has(name)) {
|
|
246
246
|
continue;
|
|
247
247
|
}
|
|
248
|
+
if (isInsideExpressionScope(source, match.index)) {
|
|
249
|
+
continue;
|
|
250
|
+
}
|
|
248
251
|
return {
|
|
249
252
|
name,
|
|
250
253
|
start: match.index,
|
|
@@ -256,6 +259,111 @@ function findNextKnownTag(source, registry, startIndex) {
|
|
|
256
259
|
return null;
|
|
257
260
|
}
|
|
258
261
|
|
|
262
|
+
/**
|
|
263
|
+
* Detect whether `index` is inside a `{ ... }` expression scope.
|
|
264
|
+
*
|
|
265
|
+
* This prevents component macro expansion inside embedded markup expressions,
|
|
266
|
+
* which must remain expression-local so the compiler can lower them safely.
|
|
267
|
+
*
|
|
268
|
+
* @param {string} source
|
|
269
|
+
* @param {number} index
|
|
270
|
+
* @returns {boolean}
|
|
271
|
+
*/
|
|
272
|
+
function isInsideExpressionScope(source, index) {
|
|
273
|
+
let depth = 0;
|
|
274
|
+
let mode = 'code';
|
|
275
|
+
let escaped = false;
|
|
276
|
+
const lower = source.toLowerCase();
|
|
277
|
+
|
|
278
|
+
for (let i = 0; i < index; i++) {
|
|
279
|
+
if (mode === 'code') {
|
|
280
|
+
if (lower.startsWith('<script', i)) {
|
|
281
|
+
const close = lower.indexOf('</script>', i + 7);
|
|
282
|
+
if (close < 0 || close >= index) {
|
|
283
|
+
return false;
|
|
284
|
+
}
|
|
285
|
+
i = close + '</script>'.length - 1;
|
|
286
|
+
continue;
|
|
287
|
+
}
|
|
288
|
+
if (lower.startsWith('<style', i)) {
|
|
289
|
+
const close = lower.indexOf('</style>', i + 6);
|
|
290
|
+
if (close < 0 || close >= index) {
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
i = close + '</style>'.length - 1;
|
|
294
|
+
continue;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
const ch = source[i];
|
|
299
|
+
const next = i + 1 < index ? source[i + 1] : '';
|
|
300
|
+
|
|
301
|
+
if (mode === 'line-comment') {
|
|
302
|
+
if (ch === '\n') {
|
|
303
|
+
mode = 'code';
|
|
304
|
+
}
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (mode === 'block-comment') {
|
|
308
|
+
if (ch === '*' && next === '/') {
|
|
309
|
+
mode = 'code';
|
|
310
|
+
i += 1;
|
|
311
|
+
}
|
|
312
|
+
continue;
|
|
313
|
+
}
|
|
314
|
+
if (mode === 'single-quote' || mode === 'double-quote' || mode === 'template') {
|
|
315
|
+
if (escaped) {
|
|
316
|
+
escaped = false;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (ch === '\\') {
|
|
320
|
+
escaped = true;
|
|
321
|
+
continue;
|
|
322
|
+
}
|
|
323
|
+
if (
|
|
324
|
+
(mode === 'single-quote' && ch === "'") ||
|
|
325
|
+
(mode === 'double-quote' && ch === '"') ||
|
|
326
|
+
(mode === 'template' && ch === '`')
|
|
327
|
+
) {
|
|
328
|
+
mode = 'code';
|
|
329
|
+
}
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
if (ch === '/' && next === '/') {
|
|
334
|
+
mode = 'line-comment';
|
|
335
|
+
i += 1;
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
if (ch === '/' && next === '*') {
|
|
339
|
+
mode = 'block-comment';
|
|
340
|
+
i += 1;
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
343
|
+
if (ch === "'") {
|
|
344
|
+
mode = 'single-quote';
|
|
345
|
+
continue;
|
|
346
|
+
}
|
|
347
|
+
if (ch === '"') {
|
|
348
|
+
mode = 'double-quote';
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (ch === '`') {
|
|
352
|
+
mode = 'template';
|
|
353
|
+
continue;
|
|
354
|
+
}
|
|
355
|
+
if (ch === '{') {
|
|
356
|
+
depth += 1;
|
|
357
|
+
continue;
|
|
358
|
+
}
|
|
359
|
+
if (ch === '}') {
|
|
360
|
+
depth = Math.max(0, depth - 1);
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
return depth > 0;
|
|
365
|
+
}
|
|
366
|
+
|
|
259
367
|
/**
|
|
260
368
|
* Find the matching </Name> for an opening tag, accounting for nested
|
|
261
369
|
* tags with the same name.
|
package/dist/server-contract.js
CHANGED
|
@@ -2,9 +2,73 @@
|
|
|
2
2
|
// ---------------------------------------------------------------------------
|
|
3
3
|
// Shared validation and payload resolution logic for <script server> blocks.
|
|
4
4
|
|
|
5
|
-
const NEW_KEYS = new Set(['data', 'load', 'prerender']);
|
|
5
|
+
const NEW_KEYS = new Set(['data', 'load', 'guard', 'prerender']);
|
|
6
6
|
const LEGACY_KEYS = new Set(['ssr_data', 'props', 'ssr', 'prerender']);
|
|
7
|
-
const ALLOWED_KEYS = new Set(['data', 'load', 'prerender', 'ssr_data', 'props', 'ssr']);
|
|
7
|
+
const ALLOWED_KEYS = new Set(['data', 'load', 'guard', 'prerender', 'ssr_data', 'props', 'ssr']);
|
|
8
|
+
|
|
9
|
+
const ROUTE_RESULT_KINDS = new Set(['allow', 'redirect', 'deny', 'data']);
|
|
10
|
+
|
|
11
|
+
export function allow() {
|
|
12
|
+
return { kind: 'allow' };
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function redirect(location, status = 302) {
|
|
16
|
+
return {
|
|
17
|
+
kind: 'redirect',
|
|
18
|
+
location: String(location || ''),
|
|
19
|
+
status: Number.isInteger(status) ? status : 302
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function deny(status = 403, message = undefined) {
|
|
24
|
+
return {
|
|
25
|
+
kind: 'deny',
|
|
26
|
+
status: Number.isInteger(status) ? status : 403,
|
|
27
|
+
message: typeof message === 'string' ? message : undefined
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function data(payload) {
|
|
32
|
+
return { kind: 'data', data: payload };
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
function isRouteResultLike(value) {
|
|
36
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
const kind = value.kind;
|
|
40
|
+
return typeof kind === 'string' && ROUTE_RESULT_KINDS.has(kind);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function assertValidRouteResultShape(value, where, allowedKinds) {
|
|
44
|
+
if (!isRouteResultLike(value)) {
|
|
45
|
+
throw new Error(`[Zenith] ${where}: invalid route result. Expected object with kind.`);
|
|
46
|
+
}
|
|
47
|
+
const kind = value.kind;
|
|
48
|
+
if (!allowedKinds.has(kind)) {
|
|
49
|
+
throw new Error(
|
|
50
|
+
`[Zenith] ${where}: kind "${kind}" is not allowed here (allowed: ${Array.from(allowedKinds).join(', ')}).`
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
if (kind === 'redirect') {
|
|
55
|
+
if (typeof value.location !== 'string' || value.location.length === 0) {
|
|
56
|
+
throw new Error(`[Zenith] ${where}: redirect requires non-empty string location.`);
|
|
57
|
+
}
|
|
58
|
+
if (value.status !== undefined && (!Number.isInteger(value.status) || value.status < 300 || value.status > 399)) {
|
|
59
|
+
throw new Error(`[Zenith] ${where}: redirect status must be an integer 3xx.`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (kind === 'deny') {
|
|
64
|
+
if (!Number.isInteger(value.status) || (value.status !== 401 && value.status !== 403)) {
|
|
65
|
+
throw new Error(`[Zenith] ${where}: deny status must be 401 or 403.`);
|
|
66
|
+
}
|
|
67
|
+
if (value.message !== undefined && typeof value.message !== 'string') {
|
|
68
|
+
throw new Error(`[Zenith] ${where}: deny message must be a string when provided.`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
8
72
|
|
|
9
73
|
export function validateServerExports({ exports, filePath }) {
|
|
10
74
|
const exportKeys = Object.keys(exports);
|
|
@@ -16,6 +80,7 @@ export function validateServerExports({ exports, filePath }) {
|
|
|
16
80
|
|
|
17
81
|
const hasData = 'data' in exports;
|
|
18
82
|
const hasLoad = 'load' in exports;
|
|
83
|
+
const hasGuard = 'guard' in exports;
|
|
19
84
|
|
|
20
85
|
const hasNew = hasData || hasLoad;
|
|
21
86
|
const hasLegacy = ('ssr_data' in exports) || ('props' in exports) || ('ssr' in exports);
|
|
@@ -47,6 +112,20 @@ export function validateServerExports({ exports, filePath }) {
|
|
|
47
112
|
throw new Error(`[Zenith] ${filePath}: "load(ctx)" must not contain rest parameters.`);
|
|
48
113
|
}
|
|
49
114
|
}
|
|
115
|
+
|
|
116
|
+
if (hasGuard && typeof exports.guard !== 'function') {
|
|
117
|
+
throw new Error(`[Zenith] ${filePath}: "guard" must be a function.`);
|
|
118
|
+
}
|
|
119
|
+
if (hasGuard) {
|
|
120
|
+
if (exports.guard.length !== 1) {
|
|
121
|
+
throw new Error(`[Zenith] ${filePath}: "guard(ctx)" must take exactly 1 argument.`);
|
|
122
|
+
}
|
|
123
|
+
const fnStr = exports.guard.toString();
|
|
124
|
+
const paramsMatch = fnStr.match(/^[^{=]+\(([^)]*)\)/);
|
|
125
|
+
if (paramsMatch && paramsMatch[1].includes('...')) {
|
|
126
|
+
throw new Error(`[Zenith] ${filePath}: "guard(ctx)" must not contain rest parameters.`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
50
129
|
}
|
|
51
130
|
|
|
52
131
|
export function assertJsonSerializable(value, where = 'payload') {
|
|
@@ -110,37 +189,97 @@ export function assertJsonSerializable(value, where = 'payload') {
|
|
|
110
189
|
walk(value, '$');
|
|
111
190
|
}
|
|
112
191
|
|
|
113
|
-
export async function
|
|
192
|
+
export async function resolveRouteResult({ exports, ctx, filePath, guardOnly = false }) {
|
|
114
193
|
validateServerExports({ exports, filePath });
|
|
115
194
|
|
|
195
|
+
const trace = {
|
|
196
|
+
guard: 'none',
|
|
197
|
+
load: 'none'
|
|
198
|
+
};
|
|
199
|
+
|
|
200
|
+
if ('guard' in exports) {
|
|
201
|
+
const guardRaw = await exports.guard(ctx);
|
|
202
|
+
const guardResult = guardRaw == null ? allow() : guardRaw;
|
|
203
|
+
if (guardResult.kind === 'data') {
|
|
204
|
+
throw new Error(`[Zenith] ${filePath}: guard(ctx) returned data(payload) which is a critical invariant violation. guard() can only return allow(), redirect(), or deny(). Use load(ctx) for data injection.`);
|
|
205
|
+
}
|
|
206
|
+
assertValidRouteResultShape(
|
|
207
|
+
guardResult,
|
|
208
|
+
`${filePath}: guard(ctx) return`,
|
|
209
|
+
new Set(['allow', 'redirect', 'deny'])
|
|
210
|
+
);
|
|
211
|
+
trace.guard = guardResult.kind;
|
|
212
|
+
if (guardResult.kind === 'redirect' || guardResult.kind === 'deny') {
|
|
213
|
+
return { result: guardResult, trace };
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (guardOnly) {
|
|
218
|
+
return { result: allow(), trace };
|
|
219
|
+
}
|
|
220
|
+
|
|
116
221
|
let payload;
|
|
117
222
|
if ('load' in exports) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
223
|
+
const loadRaw = await exports.load(ctx);
|
|
224
|
+
let loadResult = null;
|
|
225
|
+
if (isRouteResultLike(loadRaw)) {
|
|
226
|
+
loadResult = loadRaw;
|
|
227
|
+
assertValidRouteResultShape(
|
|
228
|
+
loadResult,
|
|
229
|
+
`${filePath}: load(ctx) return`,
|
|
230
|
+
new Set(['data', 'redirect', 'deny'])
|
|
231
|
+
);
|
|
232
|
+
} else {
|
|
233
|
+
assertJsonSerializable(loadRaw, `${filePath}: load(ctx) return`);
|
|
234
|
+
loadResult = data(loadRaw);
|
|
235
|
+
}
|
|
236
|
+
trace.load = loadResult.kind;
|
|
237
|
+
return { result: loadResult, trace };
|
|
121
238
|
}
|
|
122
239
|
if ('data' in exports) {
|
|
123
240
|
payload = exports.data;
|
|
124
241
|
assertJsonSerializable(payload, `${filePath}: data export`);
|
|
125
|
-
|
|
242
|
+
trace.load = 'data';
|
|
243
|
+
return { result: data(payload), trace };
|
|
126
244
|
}
|
|
127
245
|
|
|
128
246
|
// legacy fallback
|
|
129
247
|
if ('ssr_data' in exports) {
|
|
130
248
|
payload = exports.ssr_data;
|
|
131
249
|
assertJsonSerializable(payload, `${filePath}: ssr_data export`);
|
|
132
|
-
|
|
250
|
+
trace.load = 'data';
|
|
251
|
+
return { result: data(payload), trace };
|
|
133
252
|
}
|
|
134
253
|
if ('props' in exports) {
|
|
135
254
|
payload = exports.props;
|
|
136
255
|
assertJsonSerializable(payload, `${filePath}: props export`);
|
|
137
|
-
|
|
256
|
+
trace.load = 'data';
|
|
257
|
+
return { result: data(payload), trace };
|
|
138
258
|
}
|
|
139
259
|
if ('ssr' in exports) {
|
|
140
260
|
payload = exports.ssr;
|
|
141
261
|
assertJsonSerializable(payload, `${filePath}: ssr export`);
|
|
142
|
-
|
|
262
|
+
trace.load = 'data';
|
|
263
|
+
return { result: data(payload), trace };
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
return { result: data({}), trace };
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export async function resolveServerPayload({ exports, ctx, filePath }) {
|
|
270
|
+
const resolved = await resolveRouteResult({ exports, ctx, filePath });
|
|
271
|
+
if (!resolved || !resolved.result || typeof resolved.result !== 'object') {
|
|
272
|
+
return {};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
if (resolved.result.kind === 'data') {
|
|
276
|
+
return resolved.result.data;
|
|
277
|
+
}
|
|
278
|
+
if (resolved.result.kind === 'allow') {
|
|
279
|
+
return {};
|
|
143
280
|
}
|
|
144
281
|
|
|
145
|
-
|
|
282
|
+
throw new Error(
|
|
283
|
+
`[Zenith] ${filePath}: resolveServerPayload() expected data but received ${resolved.result.kind}. Use resolveRouteResult() for guard/load flows.`
|
|
284
|
+
);
|
|
146
285
|
}
|
package/dist/ui/format.js
CHANGED
|
@@ -13,6 +13,9 @@ const ANSI = {
|
|
|
13
13
|
green: '\x1b[32m',
|
|
14
14
|
cyan: '\x1b[36m'
|
|
15
15
|
};
|
|
16
|
+
const DEFAULT_PHASE = 'cli';
|
|
17
|
+
const DEFAULT_FILE = '.';
|
|
18
|
+
const DEFAULT_HINT_BASE = 'https://github.com/zenithbuild/zenith/blob/main/zenith-cli/CLI_CONTRACT.md';
|
|
16
19
|
|
|
17
20
|
function colorize(mode, token, text) {
|
|
18
21
|
if (!mode.color) {
|
|
@@ -62,21 +65,53 @@ function normalizeFileLinePath(line) {
|
|
|
62
65
|
|
|
63
66
|
const prefix = match[1];
|
|
64
67
|
const filePath = match[2].trim();
|
|
65
|
-
|
|
66
|
-
|
|
68
|
+
const normalized = normalizePathForDisplay(filePath);
|
|
69
|
+
return `${prefix}${normalized}`;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function normalizePathForDisplay(filePath) {
|
|
73
|
+
const value = String(filePath || '').trim();
|
|
74
|
+
if (!value) {
|
|
75
|
+
return DEFAULT_FILE;
|
|
76
|
+
}
|
|
77
|
+
if (!value.startsWith('/') && !/^[A-Za-z]:\\/.test(value)) {
|
|
78
|
+
return value;
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
const cwd = process.cwd();
|
|
70
82
|
const cwdWithSep = cwd.endsWith(sep) ? cwd : `${cwd}${sep}`;
|
|
71
|
-
if (
|
|
72
|
-
return
|
|
83
|
+
if (value === cwd) {
|
|
84
|
+
return DEFAULT_FILE;
|
|
73
85
|
}
|
|
74
|
-
if (
|
|
75
|
-
const relativePath = relative(cwd,
|
|
76
|
-
return
|
|
86
|
+
if (value.startsWith(cwdWithSep)) {
|
|
87
|
+
const relativePath = relative(cwd, value).replaceAll('\\', '/');
|
|
88
|
+
return relativePath || DEFAULT_FILE;
|
|
77
89
|
}
|
|
78
90
|
|
|
79
|
-
return
|
|
91
|
+
return value;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function inferPhaseFromArgv() {
|
|
95
|
+
const knownPhases = new Set(['build', 'dev', 'preview']);
|
|
96
|
+
for (const arg of process.argv.slice(2)) {
|
|
97
|
+
if (knownPhases.has(arg)) {
|
|
98
|
+
return arg;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return DEFAULT_PHASE;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function extractFileFromMessage(message) {
|
|
105
|
+
const match = String(message || '').match(/\bFile:\s+([^\n]+)/);
|
|
106
|
+
return match ? match[1].trim() : '';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function formatHintUrl(code) {
|
|
110
|
+
const slug = String(code || 'CLI_ERROR')
|
|
111
|
+
.toLowerCase()
|
|
112
|
+
.replace(/[^a-z0-9]+/g, '-')
|
|
113
|
+
.replace(/^-+|-+$/g, '');
|
|
114
|
+
return `${DEFAULT_HINT_BASE}#${slug || 'cli-error'}`;
|
|
80
115
|
}
|
|
81
116
|
|
|
82
117
|
export function normalizeErrorMessagePaths(message) {
|
|
@@ -102,22 +137,26 @@ export function normalizeError(err) {
|
|
|
102
137
|
*/
|
|
103
138
|
export function formatErrorBlock(err, mode) {
|
|
104
139
|
const normalized = normalizeError(err);
|
|
105
|
-
const maybe = /** @type {{ code?: unknown, phase?: unknown, kind?: unknown }} */ (normalized);
|
|
140
|
+
const maybe = /** @type {{ code?: unknown, phase?: unknown, kind?: unknown, file?: unknown, hint?: unknown }} */ (normalized);
|
|
106
141
|
const kind = sanitizeErrorMessage(maybe.kind || maybe.code || 'CLI_ERROR');
|
|
107
|
-
const phase = maybe.phase ? sanitizeErrorMessage(maybe.phase) :
|
|
108
|
-
const code = maybe.code
|
|
142
|
+
const phase = maybe.phase ? sanitizeErrorMessage(maybe.phase) : inferPhaseFromArgv();
|
|
143
|
+
const code = maybe.code
|
|
144
|
+
? sanitizeErrorMessage(maybe.code)
|
|
145
|
+
: `${phase.toUpperCase().replace(/[^A-Z0-9]+/g, '_') || 'CLI'}_FAILED`;
|
|
109
146
|
const rawMessage = sanitizeErrorMessage(normalized.message || String(normalized));
|
|
110
147
|
const message = normalizeErrorMessagePaths(rawMessage);
|
|
148
|
+
const file = normalizePathForDisplay(
|
|
149
|
+
sanitizeErrorMessage(maybe.file || extractFileFromMessage(message) || DEFAULT_FILE)
|
|
150
|
+
);
|
|
151
|
+
const hint = sanitizeErrorMessage(maybe.hint || formatHintUrl(code));
|
|
111
152
|
|
|
112
153
|
const lines = [];
|
|
113
154
|
lines.push('[zenith] ERROR: Command failed');
|
|
114
155
|
lines.push(`[zenith] Error Kind: ${kind}`);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
lines.push(`[zenith] Code: ${code}`);
|
|
120
|
-
}
|
|
156
|
+
lines.push(`[zenith] Phase: ${phase || DEFAULT_PHASE}`);
|
|
157
|
+
lines.push(`[zenith] Code: ${code || 'CLI_FAILED'}`);
|
|
158
|
+
lines.push(`[zenith] File: ${file || DEFAULT_FILE}`);
|
|
159
|
+
lines.push(`[zenith] Hint: ${hint || formatHintUrl(code)}`);
|
|
121
160
|
lines.push(`[zenith] Message: ${message}`);
|
|
122
161
|
|
|
123
162
|
if (mode.debug && normalized.stack) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zenithbuild/cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Deterministic project orchestrator for Zenith framework",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"prepublishOnly": "npm run build"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@zenithbuild/compiler": "0.
|
|
27
|
+
"@zenithbuild/compiler": "0.6.0"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@jest/globals": "^30.2.0",
|