bertui 1.2.0 โ 1.2.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/README.md +152 -197
- package/index.js +16 -8
- package/package.json +1 -1
- package/src/build/compiler/file-transpiler.js +119 -76
- package/src/build/compiler/index.js +23 -15
- package/src/build/compiler/route-discoverer.js +4 -3
- package/src/build/generators/sitemap-generator.js +1 -1
- package/src/build/processors/css-builder.js +45 -41
- package/src/build.js +147 -90
- package/src/client/compiler.js +169 -157
- package/src/config/defaultConfig.js +13 -4
- package/src/config/loadConfig.js +47 -32
- package/src/dev.js +222 -49
- package/src/logger/logger.js +294 -16
- package/src/server/dev-handler.js +11 -0
- package/src/server/dev-server-utils.js +262 -160
- package/src/utils/importhow.js +52 -0
package/src/logger/logger.js
CHANGED
|
@@ -1,18 +1,296 @@
|
|
|
1
|
-
// src/
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
1
|
+
// bertui/src/logger/logger.js
|
|
2
|
+
// Compact, progress-style CLI โ replaces verbose line-by-line logs
|
|
3
|
+
|
|
4
|
+
import { createWriteStream } from 'fs';
|
|
5
|
+
import { join } from 'path';
|
|
6
|
+
|
|
7
|
+
// โโ ANSI helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
8
|
+
const C = {
|
|
9
|
+
reset: '\x1b[0m',
|
|
10
|
+
bold: '\x1b[1m',
|
|
11
|
+
dim: '\x1b[2m',
|
|
12
|
+
red: '\x1b[31m',
|
|
13
|
+
green: '\x1b[32m',
|
|
14
|
+
yellow: '\x1b[33m',
|
|
15
|
+
blue: '\x1b[34m',
|
|
16
|
+
magenta: '\x1b[35m',
|
|
17
|
+
cyan: '\x1b[36m',
|
|
18
|
+
white: '\x1b[37m',
|
|
19
|
+
bgBlack: '\x1b[40m',
|
|
20
|
+
bgRed: '\x1b[41m',
|
|
21
|
+
bgGreen: '\x1b[42m',
|
|
22
|
+
bgBlue: '\x1b[44m',
|
|
23
|
+
bgCyan: '\x1b[46m',
|
|
24
|
+
bgWhite: '\x1b[47m',
|
|
25
|
+
gray: '\x1b[90m',
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const isTTY = process.stdout.isTTY;
|
|
29
|
+
|
|
30
|
+
// โโ Spinner frames โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
31
|
+
const SPINNER = ['โ ','โ ','โ น','โ ธ','โ ผ','โ ด','โ ฆ','โ ง','โ ','โ '];
|
|
32
|
+
let _spinnerFrame = 0;
|
|
33
|
+
let _spinnerTimer = null;
|
|
34
|
+
let _currentSpinnerLine = '';
|
|
35
|
+
|
|
36
|
+
// โโ Internal state โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
37
|
+
let _mode = 'idle'; // 'idle' | 'build' | 'dev'
|
|
38
|
+
let _totalSteps = 10;
|
|
39
|
+
let _stepIndex = 0;
|
|
40
|
+
let _stepLabel = '';
|
|
41
|
+
let _stepDetail = '';
|
|
42
|
+
let _errors = [];
|
|
43
|
+
let _warnings = [];
|
|
44
|
+
let _startTime = null;
|
|
45
|
+
|
|
46
|
+
// โโ Header โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
47
|
+
export function printHeader(mode = 'BUILD') {
|
|
48
|
+
_mode = mode.toLowerCase();
|
|
49
|
+
_startTime = Date.now();
|
|
50
|
+
_errors = [];
|
|
51
|
+
_warnings = [];
|
|
52
|
+
|
|
53
|
+
const W = 46;
|
|
54
|
+
const bar = 'โ'.repeat(W);
|
|
55
|
+
|
|
56
|
+
// Big block-letter BERTUI (6 rows)
|
|
57
|
+
const BIG = [
|
|
58
|
+
' โโโโโโโ โโโโโโโโโโโโโโโ โโโโโโโโโโโโ โโโโโโ',
|
|
59
|
+
' โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ โโโโโโ',
|
|
60
|
+
' โโโโโโโโโโโโโโ โโโโโโโโ โโโ โโโ โโโโโโ',
|
|
61
|
+
' โโโโโโโโโโโโโโ โโโโโโโโ โโโ โโโ โโโโโโ',
|
|
62
|
+
' โโโโโโโโโโโโโโโโโโโ โโโ โโโ โโโโโโโโโโโโ',
|
|
63
|
+
' โโโโโโโ โโโโโโโโโโโ โโโ โโโ โโโโโโโ โโโ',
|
|
64
|
+
];
|
|
65
|
+
|
|
66
|
+
process.stdout.write('\n');
|
|
67
|
+
process.stdout.write(`${C.cyan}${C.bold} ${bar}${C.reset}\n`);
|
|
68
|
+
for (const row of BIG) {
|
|
69
|
+
process.stdout.write(`${C.cyan}${C.bold}${row}${C.reset}\n`);
|
|
70
|
+
}
|
|
71
|
+
process.stdout.write(`${C.gray} by Pease Ernest${C.reset}${C.gray} ยท ${C.reset}${C.white}${C.bold}${mode.toUpperCase()}${C.reset}\n`);
|
|
72
|
+
process.stdout.write(`${C.cyan}${C.bold} ${bar}${C.reset}\n`);
|
|
73
|
+
process.stdout.write('\n');
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// โโ Step progress โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
77
|
+
export function step(index, total, label, detail = '') {
|
|
78
|
+
_stepIndex = index;
|
|
79
|
+
_totalSteps = total;
|
|
80
|
+
_stepLabel = label;
|
|
81
|
+
_stepDetail = detail;
|
|
82
|
+
_stopSpinner();
|
|
83
|
+
_renderStep('running', detail);
|
|
84
|
+
_startSpinner();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function stepDone(label, detail = '') {
|
|
88
|
+
_stopSpinner();
|
|
89
|
+
_clearLine();
|
|
90
|
+
const idx = String(_stepIndex).padStart(2, ' ');
|
|
91
|
+
const lbl = (label || _stepLabel).padEnd(24, ' ');
|
|
92
|
+
const det = detail ? `${C.gray}${_truncate(detail, 38)}${C.reset}` : '';
|
|
93
|
+
process.stdout.write(
|
|
94
|
+
` ${C.gray}[${idx}/${_totalSteps}]${C.reset} ${C.green}โ${C.reset} ${C.white}${lbl}${C.reset} ${det}\n`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
export function stepFail(label, detail = '') {
|
|
99
|
+
_stopSpinner();
|
|
100
|
+
_clearLine();
|
|
101
|
+
const idx = String(_stepIndex).padStart(2, ' ');
|
|
102
|
+
const lbl = (label || _stepLabel).padEnd(24, ' ');
|
|
103
|
+
process.stdout.write(
|
|
104
|
+
` ${C.gray}[${idx}/${_totalSteps}]${C.reset} ${C.red}โ${C.reset} ${C.white}${lbl}${C.reset} ${C.red}${detail}${C.reset}\n`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
// โโ Inline file progress (replaces "Progress: 2/2 (100%)") โโโโโโโโโโโโโโโโโโโ
|
|
109
|
+
export function fileProgress(current, total, filename) {
|
|
110
|
+
if (!isTTY) return;
|
|
111
|
+
_clearLine();
|
|
112
|
+
const pct = Math.round((current / total) * 100);
|
|
113
|
+
const bar = _bar(pct, 16);
|
|
114
|
+
const name = _truncate(filename, 30);
|
|
115
|
+
_currentSpinnerLine =
|
|
116
|
+
` ${C.gray}[${String(_stepIndex).padStart(2,' ')}/${_totalSteps}]${C.reset}` +
|
|
117
|
+
` ${C.cyan}โ ธ${C.reset} ${C.white}${_stepLabel.padEnd(24,' ')}${C.reset}` +
|
|
118
|
+
` ${bar} ${C.gray}${current}/${total}${C.reset} ${C.dim}${name}${C.reset}`;
|
|
119
|
+
process.stdout.write('\r' + _currentSpinnerLine);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// โโ Simple log levels (used internally, suppressed in compact mode) โโโโโโโโโโโ
|
|
123
|
+
export function info(msg) {
|
|
124
|
+
// In compact mode swallow routine info โ only pass through to debug log
|
|
125
|
+
_debugLog('INFO', msg);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export function success(msg) {
|
|
129
|
+
// Swallow โ stepDone() is the visual replacement
|
|
130
|
+
_debugLog('SUCCESS', msg);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export function warn(msg) {
|
|
134
|
+
_warnings.push(msg);
|
|
135
|
+
_stopSpinner();
|
|
136
|
+
_clearLine();
|
|
137
|
+
process.stdout.write(` ${C.yellow}โ ${C.reset} ${C.yellow}${msg}${C.reset}\n`);
|
|
138
|
+
if (_stepLabel) _startSpinner();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export function error(msg) {
|
|
142
|
+
_errors.push(msg);
|
|
143
|
+
_stopSpinner();
|
|
144
|
+
_clearLine();
|
|
145
|
+
process.stdout.write(` ${C.red}โ${C.reset} ${C.red}${msg}${C.reset}\n`);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function debug(msg) {
|
|
149
|
+
_debugLog('DEBUG', msg);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// โโ Table (kept for route/island tables but made compact) โโโโโโโโโโโโโโโโโโโโโ
|
|
153
|
+
export function table(rows) {
|
|
154
|
+
if (!rows || rows.length === 0) return;
|
|
155
|
+
_stopSpinner();
|
|
156
|
+
const keys = Object.keys(rows[0]).filter(k => k !== '');
|
|
157
|
+
const widths = keys.map(k =>
|
|
158
|
+
Math.max(k.length, ...rows.map(r => String(r[k] ?? '').length))
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const hr = ' ' + widths.map(w => 'โ'.repeat(w + 2)).join('โผ') ;
|
|
162
|
+
const header = ' ' + keys.map((k, i) => ` ${C.bold}${k.padEnd(widths[i])}${C.reset} `).join('โ');
|
|
163
|
+
|
|
164
|
+
process.stdout.write(`${C.gray}${hr}${C.reset}\n`);
|
|
165
|
+
process.stdout.write(`${header}\n`);
|
|
166
|
+
process.stdout.write(`${C.gray}${hr}${C.reset}\n`);
|
|
167
|
+
|
|
168
|
+
for (const row of rows) {
|
|
169
|
+
const line = ' ' + keys.map((k, i) => ` ${String(row[k] ?? '').padEnd(widths[i])} `).join(`${C.gray}โ${C.reset}`);
|
|
170
|
+
process.stdout.write(`${line}\n`);
|
|
171
|
+
}
|
|
172
|
+
process.stdout.write(`${C.gray}${hr}${C.reset}\n`);
|
|
173
|
+
|
|
174
|
+
if (_stepLabel) _startSpinner();
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// โโ bigLog โ replaced by section headers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
178
|
+
export function bigLog(title, opts = {}) {
|
|
179
|
+
_stopSpinner();
|
|
180
|
+
_clearLine();
|
|
181
|
+
process.stdout.write(`\n ${C.bold}${C.cyan}โโ ${title} โโ${C.reset}\n\n`);
|
|
182
|
+
if (_stepLabel) _startSpinner();
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// โโ Build/Dev summary โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
186
|
+
export function printSummary(stats = {}) {
|
|
187
|
+
_stopSpinner();
|
|
188
|
+
process.stdout.write('\n');
|
|
189
|
+
|
|
190
|
+
const dur = _startTime ? `${((Date.now() - _startTime) / 1000).toFixed(2)}s` : '';
|
|
191
|
+
|
|
192
|
+
process.stdout.write(`${C.cyan}${C.bold} โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${C.reset}\n`);
|
|
193
|
+
process.stdout.write(`${C.green}${C.bold} โ Done${C.reset}${dur ? ` ${C.gray}${dur}${C.reset}` : ''}\n`);
|
|
194
|
+
|
|
195
|
+
if (stats.routes) _summaryLine('Routes', stats.routes);
|
|
196
|
+
if (stats.serverIslands)_summaryLine('Server Islands', stats.serverIslands);
|
|
197
|
+
if (stats.interactive) _summaryLine('Interactive', stats.interactive);
|
|
198
|
+
if (stats.staticRoutes) _summaryLine('Static', stats.staticRoutes);
|
|
199
|
+
if (stats.jsSize) _summaryLine('JS bundle', stats.jsSize);
|
|
200
|
+
if (stats.cssSize) _summaryLine('CSS bundle', stats.cssSize);
|
|
201
|
+
if (stats.outDir) _summaryLine('Output', stats.outDir);
|
|
202
|
+
|
|
203
|
+
if (_warnings.length > 0) {
|
|
204
|
+
process.stdout.write(`\n ${C.yellow}${_warnings.length} warning(s)${C.reset}\n`);
|
|
205
|
+
}
|
|
206
|
+
if (_errors.length > 0) {
|
|
207
|
+
process.stdout.write(`\n ${C.red}${_errors.length} error(s)${C.reset}\n`);
|
|
208
|
+
_errors.forEach(e => process.stdout.write(` ${C.red} ยท ${e}${C.reset}\n`));
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
process.stdout.write(`${C.cyan}${C.bold} โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ${C.reset}\n\n`);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
function _summaryLine(label, value) {
|
|
215
|
+
process.stdout.write(
|
|
216
|
+
` ${C.gray}${label.padEnd(18)}${C.reset}${C.white}${value}${C.reset}\n`
|
|
217
|
+
);
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
// โโ Spinner internals โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
221
|
+
function _startSpinner() {
|
|
222
|
+
if (!isTTY || _spinnerTimer) return;
|
|
223
|
+
_spinnerTimer = setInterval(() => {
|
|
224
|
+
_spinnerFrame = (_spinnerFrame + 1) % SPINNER.length;
|
|
225
|
+
_renderStep('running', _stepDetail);
|
|
226
|
+
}, 80);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
function _stopSpinner() {
|
|
230
|
+
if (_spinnerTimer) {
|
|
231
|
+
clearInterval(_spinnerTimer);
|
|
232
|
+
_spinnerTimer = null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function _renderStep(state, detail = '') {
|
|
237
|
+
if (!isTTY) return;
|
|
238
|
+
_clearLine();
|
|
239
|
+
const spin = SPINNER[_spinnerFrame];
|
|
240
|
+
const idx = String(_stepIndex).padStart(2, ' ');
|
|
241
|
+
const lbl = _stepLabel.padEnd(24, ' ');
|
|
242
|
+
const det = detail ? `${C.gray}${_truncate(detail, 38)}${C.reset}` : '';
|
|
243
|
+
_currentSpinnerLine =
|
|
244
|
+
` ${C.gray}[${idx}/${_totalSteps}]${C.reset} ${C.cyan}${spin}${C.reset} ${C.white}${lbl}${C.reset} ${det}`;
|
|
245
|
+
process.stdout.write('\r' + _currentSpinnerLine);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function _clearLine() {
|
|
249
|
+
if (!isTTY) return;
|
|
250
|
+
process.stdout.write('\r\x1b[2K');
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
// โโ Helpers โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
|
|
254
|
+
function _bar(pct, width) {
|
|
255
|
+
const filled = Math.round((pct / 100) * width);
|
|
256
|
+
const empty = width - filled;
|
|
257
|
+
return `${C.cyan}${'โ'.repeat(filled)}${C.gray}${'โ'.repeat(empty)}${C.reset}`;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function _truncate(str, max) {
|
|
261
|
+
if (!str) return '';
|
|
262
|
+
str = String(str);
|
|
263
|
+
return str.length > max ? 'โฆ' + str.slice(-(max - 1)) : str;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// โโ Debug file log (always written, never shown in terminal) โโโโโโโโโโโโโโโโโโ
|
|
267
|
+
let _logStream = null;
|
|
268
|
+
function _debugLog(level, msg) {
|
|
269
|
+
if (!_logStream) {
|
|
270
|
+
try {
|
|
271
|
+
_logStream = createWriteStream(
|
|
272
|
+
join(process.cwd(), '.bertui', 'dev.log'),
|
|
273
|
+
{ flags: 'a' }
|
|
274
|
+
);
|
|
275
|
+
} catch { return; }
|
|
14
276
|
}
|
|
15
|
-
|
|
277
|
+
const ts = new Date().toISOString().substring(11, 23);
|
|
278
|
+
_logStream.write(`[${ts}] [${level}] ${msg}\n`);
|
|
279
|
+
}
|
|
16
280
|
|
|
17
|
-
//
|
|
18
|
-
export default
|
|
281
|
+
// โโ Default export (matches existing logger.method() call sites) โโโโโโโโโโโโโโ
|
|
282
|
+
export default {
|
|
283
|
+
printHeader,
|
|
284
|
+
step,
|
|
285
|
+
stepDone,
|
|
286
|
+
stepFail,
|
|
287
|
+
fileProgress,
|
|
288
|
+
info,
|
|
289
|
+
success,
|
|
290
|
+
warn,
|
|
291
|
+
error,
|
|
292
|
+
debug,
|
|
293
|
+
table,
|
|
294
|
+
bigLog,
|
|
295
|
+
printSummary,
|
|
296
|
+
};
|
|
@@ -99,6 +99,17 @@ export async function createDevHandler(options = {}) {
|
|
|
99
99
|
}
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
+
// Error overlay script
|
|
103
|
+
if (url.pathname === '/error-overlay.js') {
|
|
104
|
+
const overlayPath = join(root, 'node_modules/bertui/error-overlay.js');
|
|
105
|
+
const file = Bun.file(overlayPath);
|
|
106
|
+
if (await file.exists()) {
|
|
107
|
+
return new Response(file, {
|
|
108
|
+
headers: { 'Content-Type': 'application/javascript; charset=utf-8', 'Cache-Control': 'no-store' },
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
102
113
|
// bertui-animate CSS
|
|
103
114
|
if (url.pathname === '/bertui-animate.css') {
|
|
104
115
|
const animPath = join(root, 'node_modules/bertui-animate/dist/bertui-animate.min.css');
|