@zenithbuild/cli 0.5.0-beta.2.6 → 0.6.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/ui/logger.js CHANGED
@@ -1,105 +1,270 @@
1
- import { formatErrorBlock, formatHeading, formatStep, formatSummaryTable } from './format.js';
1
+ import {
2
+ formatErrorBlock,
3
+ formatHeading,
4
+ formatHint,
5
+ formatLine,
6
+ formatSummaryTable
7
+ } from './format.js';
2
8
  import { getUiMode } from './env.js';
3
9
 
4
- const SPINNER_FRAMES = ['-', '\\', '|', '/'];
5
-
6
10
  function write(out, text) {
7
11
  out.write(`${text}\n`);
8
12
  }
9
13
 
10
- function createSpinner(mode, stderr) {
11
- if (!mode.spinner) {
14
+ const SILENT_MODE = {
15
+ plain: true,
16
+ color: false,
17
+ tty: false,
18
+ ci: true,
19
+ spinner: false,
20
+ debug: false,
21
+ logLevel: 'quiet'
22
+ };
23
+
24
+ function createNoopSpinner() {
25
+ return {
26
+ start() { },
27
+ update() { },
28
+ stop() { },
29
+ succeed() { },
30
+ fail() { }
31
+ };
32
+ }
33
+
34
+ function normalizeLevel(level) {
35
+ return level === 'quiet' || level === 'verbose' ? level : 'normal';
36
+ }
37
+
38
+ function shouldEmit(mode, tag) {
39
+ const level = normalizeLevel(mode.logLevel);
40
+ if (level === 'quiet') {
41
+ return tag === 'OK' || tag === 'WARN' || tag === 'ERR';
42
+ }
43
+ return true;
44
+ }
45
+
46
+ function createWriter(runtime, mode, sink = null) {
47
+ if (typeof sink === 'function') {
48
+ return sink;
49
+ }
50
+ return (stream, text) => {
51
+ const out = stream === 'stderr' ? runtime.stderr : runtime.stdout;
52
+ write(out, text);
53
+ };
54
+ }
55
+
56
+ function classifyChildLine(line) {
57
+ const trimmed = String(line || '').trim();
58
+ if (!trimmed) {
59
+ return null;
60
+ }
61
+
62
+ const vendorCache = trimmed.match(/^\[zenith\]\s+Vendor cache (hit|miss):\s+(.+)$/);
63
+ if (vendorCache) {
64
+ return {
65
+ tag: 'BUILD',
66
+ glyph: '•',
67
+ message: `vendor cache ${vendorCache[1]} (${vendorCache[2]})`,
68
+ onceKey: `vendor-cache:${vendorCache[1]}:${vendorCache[2]}`
69
+ };
70
+ }
71
+
72
+ const vendorBundle = trimmed.match(/^\[zenith\]\s+Vendor bundle:\s+(.+)$/);
73
+ if (vendorBundle) {
12
74
  return {
13
- start() { },
14
- update() { },
15
- stop() { },
16
- succeed() { },
17
- fail() { }
75
+ tag: 'BUILD',
76
+ glyph: '•',
77
+ message: `vendor bundle ${vendorBundle[1]}`,
78
+ onceKey: `vendor-bundle:${vendorBundle[1]}`
18
79
  };
19
80
  }
20
81
 
21
- let interval = null;
22
- let frame = 0;
23
- let message = '';
82
+ const bundler = trimmed.match(/^\[zenith-bundler\]\s*(.+)$/);
83
+ if (bundler) {
84
+ const message = bundler[1].trim();
85
+ const lower = message.toLowerCase();
86
+ if (lower.includes('warning')) {
87
+ return {
88
+ tag: 'WARN',
89
+ glyph: '⚠',
90
+ message,
91
+ onceKey: `bundler-warning:${message}`
92
+ };
93
+ }
94
+ if (lower.includes('error') || lower.includes('failed')) {
95
+ return {
96
+ tag: 'ERR',
97
+ glyph: '✖',
98
+ message
99
+ };
100
+ }
101
+ return {
102
+ tag: 'BUILD',
103
+ glyph: '•',
104
+ message
105
+ };
106
+ }
24
107
 
25
- const paint = () => {
26
- const current = SPINNER_FRAMES[frame % SPINNER_FRAMES.length];
27
- stderr.write(`\r[zenith] ${current} ${message}`);
28
- frame += 1;
29
- };
108
+ const zenith = trimmed.match(/^\[zenith\]\s+(.+)$/);
109
+ if (zenith) {
110
+ return {
111
+ tag: 'BUILD',
112
+ glyph: '•',
113
+ message: zenith[1].trim(),
114
+ onceKey: `zenith-child:${zenith[1].trim()}`
115
+ };
116
+ }
30
117
 
31
- const clear = () => {
32
- stderr.write('\r');
33
- stderr.write(' '.repeat(message.length + 12));
34
- stderr.write('\r');
35
- };
118
+ const compilerWarning = trimmed.match(/warning\[[^\]]+\]/i);
119
+ if (compilerWarning) {
120
+ return {
121
+ tag: 'WARN',
122
+ glyph: '⚠',
123
+ message: trimmed,
124
+ onceKey: `compiler-warning:${trimmed}`
125
+ };
126
+ }
36
127
 
37
128
  return {
38
- start(nextMessage) {
39
- message = String(nextMessage || '');
40
- clearInterval(interval);
41
- frame = 0;
42
- paint();
43
- interval = setInterval(paint, 80);
44
- },
45
- update(nextMessage) {
46
- message = String(nextMessage || '');
47
- },
48
- stop() {
49
- clearInterval(interval);
50
- interval = null;
51
- clear();
52
- },
53
- succeed(nextMessage) {
54
- this.stop();
55
- write(stderr, `[zenith] OK: ${nextMessage}`);
56
- },
57
- fail(nextMessage) {
58
- this.stop();
59
- write(stderr, `[zenith] ERROR: ${nextMessage}`);
60
- }
129
+ tag: 'BUILD',
130
+ glyph: '',
131
+ message: trimmed
61
132
  };
62
133
  }
63
134
 
64
- /**
65
- * @param {NodeJS.Process} runtime
66
- */
67
- export function createLogger(runtime = process) {
68
- const mode = getUiMode(runtime);
69
- const stdout = runtime.stdout;
70
- const stderr = runtime.stderr;
71
- const spinner = createSpinner(mode, stderr);
135
+ function createBaseLogger({ runtime = process, mode, sink = null, silent = false } = {}) {
136
+ const resolvedMode = mode || (silent ? SILENT_MODE : getUiMode(runtime));
137
+ const once = new Set();
138
+ const writeLine = createWriter(runtime, resolvedMode, sink);
139
+
140
+ function emit(tag, glyph, message, options = {}) {
141
+ if (options.onceKey) {
142
+ if (once.has(options.onceKey)) {
143
+ return false;
144
+ }
145
+ once.add(options.onceKey);
146
+ }
147
+
148
+ if (!shouldEmit(resolvedMode, tag)) {
149
+ return false;
150
+ }
151
+
152
+ const stream = tag === 'WARN' || tag === 'ERR' ? 'stderr' : 'stdout';
153
+ writeLine(stream, formatLine(resolvedMode, { glyph, tag, text: message }));
154
+ if (options.hint) {
155
+ writeLine(stream, formatHint(resolvedMode, options.hint));
156
+ }
157
+ return true;
158
+ }
72
159
 
73
160
  return {
74
- mode,
75
- spinner,
161
+ mode: resolvedMode,
162
+ spinner: createNoopSpinner(),
76
163
  heading(text) {
77
- write(stdout, formatHeading(mode, text));
164
+ writeLine('stdout', formatHeading(resolvedMode, text));
165
+ },
166
+ print(text) {
167
+ writeLine('stdout', String(text));
78
168
  },
79
- info(text) {
80
- if (mode.plain) {
81
- write(stdout, `[zenith] INFO: ${text}`);
82
- return;
169
+ summary(rows, tag = 'BUILD') {
170
+ const table = formatSummaryTable(resolvedMode, rows, tag);
171
+ if (table) {
172
+ writeLine('stdout', table);
83
173
  }
84
- write(stdout, formatStep(mode, text));
85
174
  },
86
- success(text) {
87
- write(stdout, `[zenith] OK: ${text}`);
175
+ dev(message, options = {}) {
176
+ return emit('DEV', '•', message, options);
88
177
  },
89
- warn(text) {
90
- write(stderr, `[zenith] WARN: ${text}`);
178
+ build(message, options = {}) {
179
+ return emit('BUILD', '•', message, options);
91
180
  },
92
- error(err) {
93
- write(stderr, formatErrorBlock(err, mode));
181
+ hmr(message, options = {}) {
182
+ return emit('HMR', '•', message, options);
94
183
  },
95
- summary(rows) {
96
- const table = formatSummaryTable(mode, rows);
97
- if (table) {
98
- write(stdout, table);
184
+ router(message, options = {}) {
185
+ return emit('ROUTER', '•', message, options);
186
+ },
187
+ css(message, options = {}) {
188
+ return emit('CSS', '•', message, options);
189
+ },
190
+ ok(message, options = {}) {
191
+ return emit('OK', '✓', message, options);
192
+ },
193
+ warn(message, options = {}) {
194
+ return emit('WARN', '⚠', message, options);
195
+ },
196
+ error(messageOrError, options = {}) {
197
+ const hasStructuredError = messageOrError instanceof Error || typeof messageOrError === 'object';
198
+ if (hasStructuredError && !options.hint && !options.onceKey && !options.error) {
199
+ writeLine('stderr', formatErrorBlock(messageOrError, resolvedMode));
200
+ return true;
201
+ }
202
+ const detail = options.error || messageOrError;
203
+ const formatted = detail instanceof Error || typeof detail === 'object'
204
+ ? formatErrorBlock(detail, resolvedMode)
205
+ : null;
206
+ if (formatted && (resolvedMode.logLevel === 'verbose' || resolvedMode.debug)) {
207
+ writeLine('stderr', formatted);
208
+ return true;
99
209
  }
210
+ const text = typeof messageOrError === 'string'
211
+ ? messageOrError
212
+ : (detail instanceof Error ? detail.message : String(detail || 'Command failed'));
213
+ return emit('ERR', '✖', text, options);
100
214
  },
101
- print(text) {
102
- write(stdout, String(text));
215
+ verbose(tag, message, options = {}) {
216
+ if (resolvedMode.logLevel !== 'verbose') {
217
+ return false;
218
+ }
219
+ return emit(tag, '•', message, options);
220
+ },
221
+ childLine(source, line, options = {}) {
222
+ const entry = classifyChildLine(line);
223
+ if (!entry) {
224
+ return false;
225
+ }
226
+ const streamHint = options.stream === 'stderr';
227
+ const isVerbose = resolvedMode.logLevel === 'verbose';
228
+ const isSeverity = entry.tag === 'WARN' || entry.tag === 'ERR';
229
+ if (!isVerbose && !isSeverity && options.showInfo === false) {
230
+ return false;
231
+ }
232
+ const onceKey = options.onceKey || entry.onceKey;
233
+ const message = options.prefix
234
+ ? `${options.prefix}${entry.message}`
235
+ : entry.message;
236
+ return emit(entry.tag, entry.glyph, message, {
237
+ ...options,
238
+ onceKey,
239
+ hint: options.hint,
240
+ stream: streamHint ? 'stderr' : undefined
241
+ });
242
+ },
243
+ info(message) {
244
+ return emit('DEV', '•', message);
245
+ },
246
+ success(message) {
247
+ return emit('OK', '✓', message);
103
248
  }
104
249
  };
105
250
  }
251
+
252
+ export function createZenithLogger(runtime = process, options = {}) {
253
+ const mode = getUiMode(runtime);
254
+ if (options.logLevel) {
255
+ mode.logLevel = normalizeLevel(options.logLevel);
256
+ }
257
+ return createBaseLogger({ runtime, mode });
258
+ }
259
+
260
+ export function createSilentLogger() {
261
+ return createBaseLogger({
262
+ mode: SILENT_MODE,
263
+ sink: () => { },
264
+ silent: true
265
+ });
266
+ }
267
+
268
+ export function createLogger(runtime = process, options = {}) {
269
+ return createZenithLogger(runtime, options);
270
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@zenithbuild/cli",
3
- "version": "0.5.0-beta.2.6",
3
+ "version": "0.6.2",
4
4
  "description": "Deterministic project orchestrator for Zenith framework",
5
5
  "license": "MIT",
6
6
  "type": "module",
@@ -24,7 +24,8 @@
24
24
  "prepublishOnly": "npm run build"
25
25
  },
26
26
  "dependencies": {
27
- "@zenithbuild/compiler": "0.5.0-beta.2.6"
27
+ "@zenithbuild/compiler": "0.6.2",
28
+ "picocolors": "^1.1.1"
28
29
  },
29
30
  "devDependencies": {
30
31
  "@jest/globals": "^30.2.0",
@@ -32,4 +33,4 @@
32
33
  "jest-environment-jsdom": "^30.2.0"
33
34
  },
34
35
  "private": false
35
- }
36
+ }