@crab-dev/wake 0.1.3 → 0.1.5
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/CHANGELOG.md +11 -0
- package/bin/terminal.mjs +408 -26
- package/bin/wake.mjs +210 -56
- package/index.d.ts +26 -1
- package/package.json +6 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.5
|
|
4
|
+
|
|
5
|
+
- Stabilized Windows incremental rebuild events by coalescing delayed file notifications.
|
|
6
|
+
|
|
7
|
+
## 0.1.4
|
|
8
|
+
|
|
9
|
+
- Added the opt-in Storybook-like documentation component workbench.
|
|
10
|
+
- Fixed Yarn PnP packages that expose entries and subpaths through `package.json#exports`.
|
|
11
|
+
- Expanded TypeScript and TSX parsing for optional arrow parameters, generic JSX, generic async arrows, and indexed type queries.
|
|
12
|
+
- Added source module paths to build diagnostics and corrected `wake parse` source-type selection.
|
|
13
|
+
|
|
3
14
|
## 0.1.3
|
|
4
15
|
|
|
5
16
|
- Improved the npm development-server terminal panel with Rust CLI-aligned styling, startup timing, rebuild progress, diagnostics, and color controls.
|
package/bin/terminal.mjs
CHANGED
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
const RESET = '\x1b[0m'
|
|
2
2
|
const BOLD = '\x1b[1m'
|
|
3
3
|
const DIM = '\x1b[2m'
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const YELLOW = '\x1b[33m'
|
|
7
|
-
const CYAN = '\x1b[36m'
|
|
8
|
-
const MAGENTA_BOLD = '\x1b[1;35m'
|
|
4
|
+
const MAX_ACTIVITY = 200
|
|
5
|
+
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧']
|
|
9
6
|
|
|
10
7
|
export function supportsColor(stream = process.stderr, env = process.env) {
|
|
11
8
|
return stream.isTTY === true && !Object.hasOwn(env, 'NO_COLOR')
|
|
12
9
|
}
|
|
13
10
|
|
|
14
|
-
export function
|
|
15
|
-
|
|
11
|
+
export function supportsTui(input = process.stdin, output = process.stderr, env = process.env) {
|
|
12
|
+
return input.isTTY === true
|
|
13
|
+
&& output.isTTY === true
|
|
14
|
+
&& String(env.TERM || '').toLowerCase() !== 'dumb'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function createUi(color = supportsColor(), env = process.env) {
|
|
18
|
+
const trueColor = color && /^(truecolor|24bit)$/i.test(env.COLORTERM || '')
|
|
19
|
+
const wrap = (indexed, rgb, text) => {
|
|
20
|
+
if (!color) return String(text)
|
|
21
|
+
const code = trueColor
|
|
22
|
+
? `\x1b[38;2;${rgb.join(';')}m`
|
|
23
|
+
: `\x1b[38;5;${indexed}m`
|
|
24
|
+
return `${code}${text}${RESET}`
|
|
25
|
+
}
|
|
16
26
|
return {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
27
|
+
color,
|
|
28
|
+
accent: (text) => wrap(81, [34, 211, 238], text),
|
|
29
|
+
bold: (text) => color ? `${BOLD}${text}${RESET}` : String(text),
|
|
30
|
+
brand: (text) => color ? `${BOLD}${wrap(213, [217, 70, 239], text)}${RESET}` : String(text),
|
|
31
|
+
dim: (text) => color ? `${DIM}${text}${RESET}` : String(text),
|
|
32
|
+
error: (text) => wrap(204, [251, 113, 133], text),
|
|
33
|
+
ok: (text) => wrap(114, [74, 222, 128], text),
|
|
34
|
+
warn: (text) => wrap(214, [251, 191, 36], text),
|
|
24
35
|
}
|
|
25
36
|
}
|
|
26
37
|
|
|
@@ -32,38 +43,116 @@ export function humanDuration(durationMs) {
|
|
|
32
43
|
return `${Math.floor(seconds / 60)}m${(seconds % 60).toFixed(1)}s`
|
|
33
44
|
}
|
|
34
45
|
|
|
46
|
+
function moduleCount(count) {
|
|
47
|
+
return `${count} module${count === 1 ? '' : 's'}`
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function cacheHitCount(count) {
|
|
51
|
+
return `${count} cache hit${count === 1 ? '' : 's'}`
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function humanRuntime(durationMs) {
|
|
55
|
+
const seconds = Math.max(0, Math.floor(durationMs / 1_000))
|
|
56
|
+
if (seconds < 60) return `${seconds}s`
|
|
57
|
+
if (seconds < 3_600) return `${Math.floor(seconds / 60)}m${String(seconds % 60).padStart(2, '0')}s`
|
|
58
|
+
return `${Math.floor(seconds / 3_600)}h${String(Math.floor((seconds % 3_600) / 60)).padStart(2, '0')}m`
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
export function humanBytes(bytes) {
|
|
62
|
+
const value = Number(bytes) || 0
|
|
63
|
+
if (value >= 1024 * 1024) return `${(value / 1024 / 1024).toFixed(2)} MB`
|
|
64
|
+
if (value >= 1024) return `${(value / 1024).toFixed(1)} KB`
|
|
65
|
+
return `${value} B`
|
|
66
|
+
}
|
|
67
|
+
|
|
35
68
|
export function formatBanner(ui, command, currentVersion) {
|
|
36
69
|
return [
|
|
37
70
|
'',
|
|
38
|
-
` ${ui.warn('⚡')} ${ui.brand('
|
|
71
|
+
` ${ui.warn('⚡')} ${ui.brand('WAKE')} ${ui.dim('/')} ${ui.bold(command.toUpperCase())} ${ui.dim(`v${currentVersion}`)}`,
|
|
39
72
|
'',
|
|
40
73
|
]
|
|
41
74
|
}
|
|
42
75
|
|
|
43
|
-
export function
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
''
|
|
47
|
-
`
|
|
48
|
-
|
|
76
|
+
export function formatBuildResult(ui, result, label = 'Built', extra = '') {
|
|
77
|
+
const bytes = (result.files || []).reduce((sum, file) => sum + Number(file.bytes || 0), 0)
|
|
78
|
+
const lines = [
|
|
79
|
+
` ${ui.ok('✓')} ${ui.bold(label)} ${ui.accent(`in ${humanDuration(result.durationMs)}`)}`,
|
|
80
|
+
` ${ui.accent(`${result.moduleCount} modules`)} ${ui.dim('·')} ${(result.files || []).length} ${ui.dim('files')} ${ui.dim('·')} ${ui.accent(humanBytes(bytes))}${extra}`,
|
|
81
|
+
]
|
|
82
|
+
if (result.outputDir) lines.push(` ${ui.dim('Output')} ${ui.accent(result.outputDir)}`)
|
|
83
|
+
for (const diagnostic of result.diagnostics || []) {
|
|
84
|
+
lines.push(` ${ui.warn(String(diagnostic.severity || 'warning').toUpperCase())} ${diagnostic.message}`)
|
|
85
|
+
}
|
|
86
|
+
lines.push('')
|
|
87
|
+
return lines
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export function formatServerReady(ui, url, metrics) {
|
|
91
|
+
const lines = [
|
|
92
|
+
` ${ui.ok('✓')} ${ui.bold('Development server ready')}`,
|
|
93
|
+
` ${ui.dim('Local')} ${ui.accent(url)}`,
|
|
94
|
+
]
|
|
95
|
+
if (metrics) {
|
|
96
|
+
lines.push(
|
|
97
|
+
` ${ui.accent(`${metrics.modules} modules`)} ${ui.dim('·')} ${metrics.chunks} ${ui.dim('chunks')} ${ui.dim('·')} ${metrics.assets} ${ui.dim('assets')}`,
|
|
98
|
+
)
|
|
99
|
+
}
|
|
100
|
+
lines.push(` ${ui.dim('Press Ctrl-C to stop')}`, '')
|
|
101
|
+
return lines
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
export function formatError(ui, error) {
|
|
105
|
+
const code = error?.code ? `[${error.code}]` : '[WAKE_INTERNAL]'
|
|
106
|
+
const lines = [
|
|
107
|
+
` ${ui.error('✗')} ${ui.bold('Wake failed')} ${ui.error(code)}`,
|
|
108
|
+
` ${error?.message || error}`,
|
|
109
|
+
]
|
|
110
|
+
if (error?.path) lines.push(` ${ui.dim('Path')} ${ui.accent(error.path)}`)
|
|
111
|
+
for (const diagnostic of error?.diagnostics || []) {
|
|
112
|
+
const diagnosticCode = diagnostic.code ? `[${diagnostic.code}] ` : ''
|
|
113
|
+
lines.push(
|
|
114
|
+
` ${ui.warn(String(diagnostic.severity || 'error').toUpperCase())} ${diagnosticCode}${diagnostic.message}`,
|
|
115
|
+
)
|
|
116
|
+
for (const note of diagnostic.notes || []) lines.push(` ${ui.dim('·')} ${note}`)
|
|
117
|
+
}
|
|
118
|
+
lines.push('')
|
|
119
|
+
return lines
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function formatFinalSummary(ui, state, reason, label = 'Server stopped') {
|
|
123
|
+
const lines = [
|
|
49
124
|
'',
|
|
125
|
+
` ${ui.dim('■')} ${ui.bold(label)} ${ui.dim(`(${reason})`)}`,
|
|
50
126
|
]
|
|
127
|
+
if (state.endpoint) {
|
|
128
|
+
lines.push(` ${ui.dim(state.endpointLabel)} ${ui.accent(state.endpoint)}`)
|
|
129
|
+
}
|
|
130
|
+
lines.push(
|
|
131
|
+
` ${state.rebuilds} rebuilds ${ui.dim('·')} runtime ${ui.accent(humanRuntime(Date.now() - state.startedAt))}`,
|
|
132
|
+
'',
|
|
133
|
+
)
|
|
134
|
+
return lines
|
|
51
135
|
}
|
|
52
136
|
|
|
53
137
|
export function observeServer(server, ui, output = console) {
|
|
54
138
|
const onRebuildStart = (event) => {
|
|
55
139
|
const count = event.changedPaths?.length || 0
|
|
56
|
-
const detail = count
|
|
57
|
-
|
|
140
|
+
const detail = count === 1
|
|
141
|
+
? 'Rebuilding after 1 file change…'
|
|
142
|
+
: count > 1
|
|
143
|
+
? `Rebuilding after ${count} file changes…`
|
|
144
|
+
: 'Rebuilding…'
|
|
145
|
+
output.error(` ${ui.warn('↻')} ${ui.dim(detail)}`)
|
|
58
146
|
}
|
|
59
147
|
const onRebuilt = (event) => {
|
|
60
|
-
|
|
61
|
-
|
|
148
|
+
if (event.initial) return
|
|
149
|
+
output.error(
|
|
150
|
+
` ${ui.ok('✓')} ${ui.bold('Updated')} ${ui.dim('·')} ${ui.accent(moduleCount(event.updatedModules))} ${ui.dim('·')} ${ui.accent(cacheHitCount(event.cachedModules))} ${ui.accent(humanDuration(event.durationMs))}`,
|
|
62
151
|
)
|
|
63
152
|
}
|
|
64
153
|
const onDiagnostic = (diagnostic) => {
|
|
65
154
|
const code = diagnostic.code ? `[${diagnostic.code}] ` : ''
|
|
66
|
-
output.error(` ${ui.error('✗')} ${ui.bold('
|
|
155
|
+
output.error(` ${ui.error('✗')} ${ui.bold('Build failed')} ${code}${diagnostic.message}`)
|
|
67
156
|
}
|
|
68
157
|
|
|
69
158
|
server.on('rebuildStart', onRebuildStart)
|
|
@@ -75,3 +164,296 @@ export function observeServer(server, ui, output = console) {
|
|
|
75
164
|
server.off('diagnostic', onDiagnostic)
|
|
76
165
|
}
|
|
77
166
|
}
|
|
167
|
+
|
|
168
|
+
function pushActivity(state, level, message) {
|
|
169
|
+
if (state.activity.length === MAX_ACTIVITY) state.activity.shift()
|
|
170
|
+
state.activity.push({
|
|
171
|
+
elapsedMs: Date.now() - state.startedAt,
|
|
172
|
+
level,
|
|
173
|
+
message: String(message),
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export function createDashboardState({
|
|
178
|
+
command,
|
|
179
|
+
root = '.',
|
|
180
|
+
endpointLabel = 'LOCAL',
|
|
181
|
+
watchLabel = 'HMR · source maps · watching',
|
|
182
|
+
}) {
|
|
183
|
+
const state = {
|
|
184
|
+
command,
|
|
185
|
+
root,
|
|
186
|
+
endpointLabel,
|
|
187
|
+
endpoint: '',
|
|
188
|
+
watchLabel,
|
|
189
|
+
status: 'starting',
|
|
190
|
+
metrics: undefined,
|
|
191
|
+
rebuilds: 0,
|
|
192
|
+
startedAt: Date.now(),
|
|
193
|
+
activity: [],
|
|
194
|
+
scrollFromBottom: 0,
|
|
195
|
+
}
|
|
196
|
+
pushActivity(state, 'info', 'Starting Wake…')
|
|
197
|
+
return state
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
export function applyDashboardEvent(state, event) {
|
|
201
|
+
if (event.type === 'rebuildStart') {
|
|
202
|
+
const count = event.changedPaths?.length || 0
|
|
203
|
+
state.status = 'rebuilding'
|
|
204
|
+
pushActivity(
|
|
205
|
+
state,
|
|
206
|
+
'warning',
|
|
207
|
+
count === 1
|
|
208
|
+
? 'Rebuilding after 1 file change…'
|
|
209
|
+
: count > 1
|
|
210
|
+
? `Rebuilding after ${count} file changes…`
|
|
211
|
+
: 'Rebuilding…',
|
|
212
|
+
)
|
|
213
|
+
} else if (event.type === 'rebuilt') {
|
|
214
|
+
state.status = 'ready'
|
|
215
|
+
state.metrics = {
|
|
216
|
+
modules: event.modules,
|
|
217
|
+
updatedModules: event.updatedModules,
|
|
218
|
+
cachedModules: event.cachedModules,
|
|
219
|
+
chunks: event.chunks,
|
|
220
|
+
assets: event.assets,
|
|
221
|
+
durationMs: event.durationMs,
|
|
222
|
+
}
|
|
223
|
+
if (!event.initial) state.rebuilds += 1
|
|
224
|
+
pushActivity(
|
|
225
|
+
state,
|
|
226
|
+
'success',
|
|
227
|
+
event.initial
|
|
228
|
+
? `Initial build completed: ${event.modules} modules in ${humanDuration(event.durationMs)}`
|
|
229
|
+
: `Updated ${moduleCount(event.updatedModules)} · ${cacheHitCount(event.cachedModules)} in ${humanDuration(event.durationMs)}`,
|
|
230
|
+
)
|
|
231
|
+
} else if (event.type === 'diagnostic') {
|
|
232
|
+
state.status = 'error'
|
|
233
|
+
pushActivity(state, 'error', event.message)
|
|
234
|
+
} else if (event.type === 'closed') {
|
|
235
|
+
state.status = 'stopped'
|
|
236
|
+
pushActivity(state, 'info', 'Wake stopped')
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
export function setDashboardEndpoint(state, endpoint) {
|
|
241
|
+
state.endpoint = String(endpoint)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
export function setDashboardStopping(state, reason) {
|
|
245
|
+
state.status = 'stopping'
|
|
246
|
+
pushActivity(state, 'info', `Stopping (${reason})…`)
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export function setDashboardStopped(state) {
|
|
250
|
+
state.status = 'stopped'
|
|
251
|
+
pushActivity(state, 'info', 'Wake stopped')
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
function statusLabel(status) {
|
|
255
|
+
return {
|
|
256
|
+
starting: 'STARTING',
|
|
257
|
+
ready: 'READY',
|
|
258
|
+
rebuilding: 'REBUILDING',
|
|
259
|
+
error: 'ERROR',
|
|
260
|
+
stopping: 'STOPPING',
|
|
261
|
+
stopped: 'STOPPED',
|
|
262
|
+
}[status] || 'STARTING'
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
function statusSymbol(state) {
|
|
266
|
+
if (state.status === 'ready') return '✓'
|
|
267
|
+
if (state.status === 'error') return '✗'
|
|
268
|
+
if (state.status === 'stopping') return '◌'
|
|
269
|
+
if (state.status === 'stopped') return '■'
|
|
270
|
+
return SPINNER[Math.floor((Date.now() - state.startedAt) / 100) % SPINNER.length]
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function elapsedStamp(durationMs) {
|
|
274
|
+
const seconds = Math.floor(durationMs / 1_000)
|
|
275
|
+
return `+${String(Math.floor(seconds / 60) % 100).padStart(2, '0')}:${String(seconds % 60).padStart(2, '0')}`
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
function charLength(text) {
|
|
279
|
+
return [...stripAnsi(String(text))].length
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
function truncate(text, width) {
|
|
283
|
+
const chars = [...String(text)]
|
|
284
|
+
if (chars.length <= width) return String(text)
|
|
285
|
+
if (width <= 1) return chars.slice(0, width).join('')
|
|
286
|
+
return `${chars.slice(0, width - 1).join('')}…`
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function pad(text, width) {
|
|
290
|
+
const value = truncate(text, width)
|
|
291
|
+
return value + ' '.repeat(Math.max(0, width - charLength(value)))
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
function boxLine(text, width) {
|
|
295
|
+
if (width < 4) return pad(text, width)
|
|
296
|
+
return `│ ${pad(text, width - 4)} │`
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
function topBorder(state, width) {
|
|
300
|
+
const title = ` ⚡ WAKE / ${state.command.toUpperCase()} v${state.version || ''} `
|
|
301
|
+
if (width < 4) return '─'.repeat(width)
|
|
302
|
+
const clipped = truncate(title, width - 2)
|
|
303
|
+
return `╭${clipped}${'─'.repeat(Math.max(0, width - 2 - charLength(clipped)))}╮`
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function separator(width, title = '') {
|
|
307
|
+
if (width < 4) return '─'.repeat(width)
|
|
308
|
+
const center = title ? ` ${title} ` : ''
|
|
309
|
+
return `├${center}${'─'.repeat(Math.max(0, width - 2 - charLength(center)))}┤`
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
function bottomBorder(width) {
|
|
313
|
+
return width < 4 ? '─'.repeat(width) : `╰${'─'.repeat(width - 2)}╯`
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
function metricsText(state) {
|
|
317
|
+
const metrics = state.metrics
|
|
318
|
+
if (!metrics) return 'BUILD waiting for metrics…'
|
|
319
|
+
return `BUILD ${metrics.modules} modules · ${metrics.chunks} chunks · ${metrics.assets} assets · ${humanDuration(metrics.durationMs)}`
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function activityRows(state, available) {
|
|
323
|
+
const end = Math.max(0, state.activity.length - state.scrollFromBottom)
|
|
324
|
+
const start = Math.max(0, end - Math.max(1, available))
|
|
325
|
+
return state.activity.slice(start, end).map((item) => {
|
|
326
|
+
const symbol = { info: '·', success: '✓', warning: '↻', error: '✗' }[item.level]
|
|
327
|
+
return `${elapsedStamp(item.elapsedMs)} ${symbol} ${String(item.message).replaceAll('\n', ' ')}`
|
|
328
|
+
})
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
function plainFrame(state, width, height) {
|
|
332
|
+
width = Math.max(10, width || 80)
|
|
333
|
+
height = Math.max(6, height || 24)
|
|
334
|
+
const runtime = humanRuntime(Date.now() - state.startedAt)
|
|
335
|
+
const header = `${statusSymbol(state)} ${statusLabel(state.status)} uptime ${runtime} ${state.rebuilds} rebuilds`
|
|
336
|
+
const endpoint = state.endpoint || 'waiting…'
|
|
337
|
+
let fixed
|
|
338
|
+
let activityHeight
|
|
339
|
+
|
|
340
|
+
if (width < 60 || height < 14) {
|
|
341
|
+
fixed = [
|
|
342
|
+
topBorder(state, width),
|
|
343
|
+
boxLine(header, width),
|
|
344
|
+
boxLine(state.endpoint || state.watchLabel, width),
|
|
345
|
+
boxLine(state.activity.at(-1)?.message || 'Starting Wake…', width),
|
|
346
|
+
boxLine('Resize for details · q/Ctrl-C quit', width),
|
|
347
|
+
]
|
|
348
|
+
activityHeight = 0
|
|
349
|
+
} else if (width < 80 || height < 20) {
|
|
350
|
+
fixed = [
|
|
351
|
+
topBorder(state, width),
|
|
352
|
+
boxLine(header, width),
|
|
353
|
+
boxLine(`${state.endpointLabel} ${endpoint}`, width),
|
|
354
|
+
boxLine(metricsText(state), width),
|
|
355
|
+
separator(width, 'ACTIVITY'),
|
|
356
|
+
]
|
|
357
|
+
activityHeight = Math.max(1, height - fixed.length - 2)
|
|
358
|
+
} else {
|
|
359
|
+
fixed = [
|
|
360
|
+
topBorder(state, width),
|
|
361
|
+
boxLine(header, width),
|
|
362
|
+
separator(width),
|
|
363
|
+
boxLine(`${state.endpointLabel.padEnd(7)} ${endpoint}`, width),
|
|
364
|
+
boxLine(`ROOT ${state.root}`, width),
|
|
365
|
+
boxLine(`MODE ${state.watchLabel}`, width),
|
|
366
|
+
separator(width),
|
|
367
|
+
boxLine(metricsText(state), width),
|
|
368
|
+
separator(width, 'ACTIVITY'),
|
|
369
|
+
]
|
|
370
|
+
activityHeight = Math.max(1, height - fixed.length - 2)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
for (const row of activityRows(state, activityHeight)) fixed.push(boxLine(row, width))
|
|
374
|
+
while (activityHeight > 0 && fixed.length < height - 2) fixed.push(boxLine('', width))
|
|
375
|
+
if (height >= 14) fixed.push(boxLine('↑↓/PgUp/PgDn scroll · End follow · c clear · q/Ctrl-C quit', width))
|
|
376
|
+
fixed.push(bottomBorder(width))
|
|
377
|
+
return fixed.slice(0, height)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
function colorizeLine(line, ui) {
|
|
381
|
+
if (!ui.color) return line
|
|
382
|
+
let value = line
|
|
383
|
+
value = value.replace('WAKE', ui.brand('WAKE'))
|
|
384
|
+
value = value.replace(/(✓|■)/, (match) => ui.ok(match))
|
|
385
|
+
value = value.replace(/(✗)/, (match) => ui.error(match))
|
|
386
|
+
value = value.replace(/(↻|⠋|⠙|⠹|⠸|⠼|⠴|⠦|⠧|◌)/, (match) => ui.warn(match))
|
|
387
|
+
value = value.replace(/(https?:\/\/\S+)/, (match) => ui.accent(match))
|
|
388
|
+
return value
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
export function renderDashboard(state, width = 80, height = 24, ui = createUi(false)) {
|
|
392
|
+
return plainFrame(state, width, height).map((line) => colorizeLine(line, ui)).join('\n')
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
export function createDashboardSession(
|
|
396
|
+
state,
|
|
397
|
+
{ input = process.stdin, output = process.stderr, ui = createUi() } = {},
|
|
398
|
+
) {
|
|
399
|
+
let closed = false
|
|
400
|
+
let previousRaw = false
|
|
401
|
+
let resolveExit
|
|
402
|
+
const exit = new Promise((resolve) => { resolveExit = resolve })
|
|
403
|
+
|
|
404
|
+
const draw = () => {
|
|
405
|
+
if (closed) return
|
|
406
|
+
const width = output.columns || 80
|
|
407
|
+
const height = output.rows || 24
|
|
408
|
+
output.write(`\x1b[H${renderDashboard(state, width, height, ui)}\x1b[J`)
|
|
409
|
+
}
|
|
410
|
+
const requestExit = (reason) => {
|
|
411
|
+
if (!closed) resolveExit(reason)
|
|
412
|
+
}
|
|
413
|
+
const onData = (chunk) => {
|
|
414
|
+
const key = chunk.toString('utf8')
|
|
415
|
+
if (key === '\u0003') requestExit('SIGINT')
|
|
416
|
+
else if (key === 'q' || key === 'Q') requestExit('q')
|
|
417
|
+
else if (key === 'c' || key === 'C') {
|
|
418
|
+
state.activity.length = 0
|
|
419
|
+
state.scrollFromBottom = 0
|
|
420
|
+
draw()
|
|
421
|
+
} else if (key === '\x1b[A') state.scrollFromBottom = Math.max(0, Math.min(state.activity.length - 1, state.scrollFromBottom + 1))
|
|
422
|
+
else if (key === '\x1b[B') state.scrollFromBottom = Math.max(0, state.scrollFromBottom - 1)
|
|
423
|
+
else if (key === '\x1b[5~') state.scrollFromBottom = Math.max(0, Math.min(state.activity.length - 1, state.scrollFromBottom + 10))
|
|
424
|
+
else if (key === '\x1b[6~') state.scrollFromBottom = Math.max(0, state.scrollFromBottom - 10)
|
|
425
|
+
else if (key === '\x1b[F' || key === '\x1b[4~') state.scrollFromBottom = 0
|
|
426
|
+
draw()
|
|
427
|
+
}
|
|
428
|
+
const onResize = () => draw()
|
|
429
|
+
|
|
430
|
+
previousRaw = input.isRaw === true
|
|
431
|
+
if (typeof input.setRawMode === 'function') input.setRawMode(true)
|
|
432
|
+
input.resume?.()
|
|
433
|
+
input.on('data', onData)
|
|
434
|
+
output.on?.('resize', onResize)
|
|
435
|
+
output.write('\x1b[?1049h\x1b[?25l\x1b[2J')
|
|
436
|
+
const timer = setInterval(draw, 100)
|
|
437
|
+
timer.unref?.()
|
|
438
|
+
draw()
|
|
439
|
+
|
|
440
|
+
return {
|
|
441
|
+
draw,
|
|
442
|
+
exit,
|
|
443
|
+
requestExit,
|
|
444
|
+
close() {
|
|
445
|
+
if (closed) return
|
|
446
|
+
closed = true
|
|
447
|
+
clearInterval(timer)
|
|
448
|
+
input.off('data', onData)
|
|
449
|
+
output.off?.('resize', onResize)
|
|
450
|
+
if (typeof input.setRawMode === 'function') input.setRawMode(previousRaw)
|
|
451
|
+
if (!previousRaw) input.pause?.()
|
|
452
|
+
output.write('\x1b[?25h\x1b[?1049l')
|
|
453
|
+
},
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function stripAnsi(value) {
|
|
458
|
+
return String(value).replace(/\x1b\[[0-?]*[ -/]*[@-~]/g, '')
|
|
459
|
+
}
|
package/bin/wake.mjs
CHANGED
|
@@ -10,26 +10,39 @@ import {
|
|
|
10
10
|
} from '../index.mjs'
|
|
11
11
|
import { parse, tokenize } from '../experimental.mjs'
|
|
12
12
|
import {
|
|
13
|
+
applyDashboardEvent,
|
|
14
|
+
createDashboardSession,
|
|
15
|
+
createDashboardState,
|
|
13
16
|
createUi,
|
|
14
17
|
formatBanner,
|
|
18
|
+
formatBuildResult,
|
|
19
|
+
formatError,
|
|
20
|
+
formatFinalSummary,
|
|
15
21
|
formatServerReady,
|
|
16
22
|
observeServer,
|
|
23
|
+
setDashboardEndpoint,
|
|
24
|
+
setDashboardStopped,
|
|
25
|
+
setDashboardStopping,
|
|
17
26
|
supportsColor,
|
|
27
|
+
supportsTui,
|
|
18
28
|
} from './terminal.mjs'
|
|
19
29
|
|
|
20
30
|
const HELP = `Wake ${version()}
|
|
21
31
|
|
|
22
32
|
Usage:
|
|
33
|
+
wake [--ui auto|tui|plain] [--no-color] <command>
|
|
23
34
|
wake build [entry] [--outdir DIR] [--cache] [--sourcemap]
|
|
24
35
|
wake dev [root] [--entry FILE] [--host HOST] [--port PORT] [--open]
|
|
25
|
-
wake docs build [root] [--outdir DIR] [--base PATH]
|
|
26
|
-
wake docs dev [root] [--host HOST] [--port PORT] [--open]
|
|
27
|
-
wake parse <file>
|
|
28
|
-
wake tokenize <file>
|
|
36
|
+
wake docs build [root] [--mode site|components] [--outdir DIR] [--base PATH]
|
|
37
|
+
wake docs dev [root] [--mode site|components] [--host HOST] [--port PORT] [--open]
|
|
38
|
+
wake parse <file> [--format auto|human|json]
|
|
39
|
+
wake tokenize <file> [--format auto|human|json]
|
|
29
40
|
wake --version
|
|
30
41
|
|
|
31
42
|
Options:
|
|
32
|
-
--
|
|
43
|
+
--ui MODE Terminal UI mode for long-running commands (default: auto)
|
|
44
|
+
--no-color Disable terminal colors; also honors NO_COLOR
|
|
45
|
+
--format Human or JSON output for parse/tokenize (default: auto)
|
|
33
46
|
`
|
|
34
47
|
|
|
35
48
|
function takeOption(args, name) {
|
|
@@ -54,54 +67,161 @@ function commonOptions(args) {
|
|
|
54
67
|
}
|
|
55
68
|
}
|
|
56
69
|
|
|
57
|
-
function
|
|
58
|
-
const
|
|
59
|
-
console.log(
|
|
60
|
-
`wake: built ${result.moduleCount} modules and ${files} files in ${result.durationMs.toFixed(1)}ms`,
|
|
61
|
-
)
|
|
62
|
-
if (result.outputDir) console.log(`wake: output ${result.outputDir}`)
|
|
70
|
+
function printLines(lines, output = console.error) {
|
|
71
|
+
for (const line of lines) output(line)
|
|
63
72
|
}
|
|
64
73
|
|
|
65
|
-
function
|
|
66
|
-
|
|
74
|
+
function validateChoice(value, name, choices) {
|
|
75
|
+
if (!choices.includes(value)) {
|
|
76
|
+
throw new Error(`${name} must be one of: ${choices.join(', ')}`)
|
|
77
|
+
}
|
|
78
|
+
return value
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function ensureStaticMode(uiMode) {
|
|
82
|
+
if (uiMode === 'tui') {
|
|
83
|
+
throw new Error('--ui tui is only available for dev and docs dev')
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function resolveTui(uiMode) {
|
|
88
|
+
const supported = supportsTui()
|
|
89
|
+
if (uiMode === 'plain') return false
|
|
90
|
+
if (uiMode === 'tui' && !supported) {
|
|
91
|
+
throw new Error('--ui tui requires interactive stdin and stderr and a capable terminal')
|
|
92
|
+
}
|
|
93
|
+
return supported
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function resolveFormat(value) {
|
|
97
|
+
const format = validateChoice(value || 'auto', '--format', ['auto', 'human', 'json'])
|
|
98
|
+
return format === 'auto' ? (process.stdout.isTTY ? 'human' : 'json') : format
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function printResult(ui, result, label, extra = '') {
|
|
102
|
+
printLines(formatBuildResult(ui, result, label, extra))
|
|
67
103
|
}
|
|
68
104
|
|
|
69
|
-
|
|
105
|
+
function metricsFromEvent(event) {
|
|
106
|
+
return {
|
|
107
|
+
modules: event.modules,
|
|
108
|
+
updatedModules: event.updatedModules,
|
|
109
|
+
cachedModules: event.cachedModules,
|
|
110
|
+
chunks: event.chunks,
|
|
111
|
+
assets: event.assets,
|
|
112
|
+
durationMs: event.durationMs,
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function runServer(factory, options, command, root, ui, uiMode) {
|
|
70
117
|
const controller = new AbortController()
|
|
71
|
-
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
118
|
+
const useTui = resolveTui(uiMode)
|
|
119
|
+
const state = createDashboardState({
|
|
120
|
+
command,
|
|
121
|
+
root: root || '.',
|
|
122
|
+
watchLabel: command === 'docs dev'
|
|
123
|
+
? 'MDX · HMR · search index · watching'
|
|
124
|
+
: command === 'docs components'
|
|
125
|
+
? 'Demo · Controls · HMR · watching'
|
|
126
|
+
: 'HMR · source maps · watching',
|
|
127
|
+
})
|
|
128
|
+
state.version = version()
|
|
129
|
+
let dashboard
|
|
130
|
+
let server
|
|
131
|
+
let stopObserving = () => {}
|
|
132
|
+
let initialMetrics
|
|
133
|
+
let finalReason = 'server closed'
|
|
134
|
+
|
|
135
|
+
if (useTui) dashboard = createDashboardSession(state, { ui })
|
|
136
|
+
else printLines(formatBanner(ui, command, version()))
|
|
137
|
+
|
|
138
|
+
try {
|
|
139
|
+
server = await factory({ ...options, signal: controller.signal })
|
|
140
|
+
setDashboardEndpoint(state, server.url)
|
|
141
|
+
|
|
142
|
+
const onRebuildStart = (event) => {
|
|
143
|
+
applyDashboardEvent(state, event)
|
|
144
|
+
dashboard?.draw()
|
|
145
|
+
}
|
|
146
|
+
const onRebuilt = (event) => {
|
|
147
|
+
if (event.initial) initialMetrics = metricsFromEvent(event)
|
|
148
|
+
applyDashboardEvent(state, event)
|
|
149
|
+
dashboard?.draw()
|
|
150
|
+
}
|
|
151
|
+
const onDiagnostic = (diagnostic) => {
|
|
152
|
+
applyDashboardEvent(state, { type: 'diagnostic', message: diagnostic.message })
|
|
153
|
+
dashboard?.draw()
|
|
154
|
+
}
|
|
155
|
+
const onClosed = () => {
|
|
156
|
+
applyDashboardEvent(state, { type: 'closed' })
|
|
157
|
+
dashboard?.draw()
|
|
158
|
+
}
|
|
159
|
+
server.on('rebuildStart', onRebuildStart)
|
|
160
|
+
server.on('rebuilt', onRebuilt)
|
|
161
|
+
server.on('diagnostic', onDiagnostic)
|
|
162
|
+
server.on('closed', onClosed)
|
|
163
|
+
|
|
164
|
+
if (!useTui) stopObserving = observeServer(server, ui)
|
|
165
|
+
await new Promise((resolve) => setTimeout(resolve, 35))
|
|
166
|
+
if (!useTui) {
|
|
167
|
+
printLines(formatServerReady(ui, server.url, initialMetrics))
|
|
168
|
+
} else {
|
|
169
|
+
dashboard.draw()
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let resolveSignal
|
|
173
|
+
const signalExit = new Promise((resolve) => { resolveSignal = resolve })
|
|
174
|
+
const onSigint = () => resolveSignal('SIGINT')
|
|
175
|
+
const onSigterm = () => resolveSignal('SIGTERM')
|
|
176
|
+
process.once('SIGINT', onSigint)
|
|
177
|
+
process.once('SIGTERM', onSigterm)
|
|
178
|
+
|
|
82
179
|
try {
|
|
83
|
-
|
|
180
|
+
const closed = server.waitUntilClosed().then(() => 'closed')
|
|
181
|
+
const reason = await Promise.race([
|
|
182
|
+
closed,
|
|
183
|
+
signalExit,
|
|
184
|
+
dashboard ? dashboard.exit : new Promise(() => {}),
|
|
185
|
+
])
|
|
186
|
+
if (reason !== 'closed') {
|
|
187
|
+
finalReason = reason
|
|
188
|
+
setDashboardStopping(state, reason === 'q' ? 'q' : reason)
|
|
189
|
+
dashboard?.draw()
|
|
190
|
+
controller.abort()
|
|
191
|
+
await server.close()
|
|
192
|
+
await closed
|
|
193
|
+
}
|
|
194
|
+
setDashboardStopped(state)
|
|
195
|
+
dashboard?.draw()
|
|
196
|
+
return reason
|
|
84
197
|
} finally {
|
|
85
|
-
process.
|
|
198
|
+
process.off('SIGINT', onSigint)
|
|
199
|
+
process.off('SIGTERM', onSigterm)
|
|
200
|
+
server.off('rebuildStart', onRebuildStart)
|
|
201
|
+
server.off('rebuilt', onRebuilt)
|
|
202
|
+
server.off('diagnostic', onDiagnostic)
|
|
203
|
+
server.off('closed', onClosed)
|
|
86
204
|
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (dashboard) {
|
|
207
|
+
dashboard.close()
|
|
208
|
+
dashboard = undefined
|
|
209
|
+
printLines(formatBanner(ui, command, version()))
|
|
210
|
+
}
|
|
211
|
+
throw error
|
|
94
212
|
} finally {
|
|
95
213
|
stopObserving()
|
|
96
|
-
|
|
97
|
-
|
|
214
|
+
dashboard?.close()
|
|
215
|
+
if (server) printLines(formatFinalSummary(ui, state, finalReason))
|
|
98
216
|
}
|
|
99
217
|
}
|
|
100
218
|
|
|
101
219
|
export async function runCli(argv = process.argv.slice(2)) {
|
|
102
220
|
const args = [...argv]
|
|
103
221
|
const noColor = takeFlag(args, '--no-color')
|
|
222
|
+
const uiMode = validateChoice(takeOption(args, '--ui') || 'auto', '--ui', ['auto', 'tui', 'plain'])
|
|
104
223
|
const ui = createUi(!noColor && supportsColor())
|
|
224
|
+
|
|
105
225
|
if (takeFlag(args, '--version') || takeFlag(args, '-V')) {
|
|
106
226
|
console.log(version())
|
|
107
227
|
return 0
|
|
@@ -113,13 +233,15 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
113
233
|
|
|
114
234
|
const command = args.shift()
|
|
115
235
|
if (command === 'build') {
|
|
236
|
+
ensureStaticMode(uiMode)
|
|
116
237
|
const options = commonOptions(args)
|
|
117
238
|
options.outdir = takeOption(args, '--outdir')
|
|
118
239
|
options.cache = takeFlag(args, '--cache')
|
|
119
240
|
options.sourceMap = takeFlag(args, '--sourcemap')
|
|
120
241
|
if (args[0]) options.entry = args.shift()
|
|
121
242
|
if (args.length) throw new Error(`unknown build arguments: ${args.join(' ')}`)
|
|
122
|
-
|
|
243
|
+
printLines(formatBanner(ui, 'build', version()))
|
|
244
|
+
printResult(ui, await build(options), 'Built')
|
|
123
245
|
return 0
|
|
124
246
|
}
|
|
125
247
|
|
|
@@ -132,8 +254,10 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
132
254
|
options.open = takeFlag(args, '--open')
|
|
133
255
|
if (args[0]) options.cwd = args.shift()
|
|
134
256
|
if (args.length) throw new Error(`unknown dev arguments: ${args.join(' ')}`)
|
|
135
|
-
await runServer(startDevServer, options, 'dev', ui)
|
|
136
|
-
|
|
257
|
+
const reason = await runServer(startDevServer, options, 'dev', options.cwd, ui, uiMode)
|
|
258
|
+
if (reason === 'SIGINT') return 130
|
|
259
|
+
if (reason === 'SIGTERM') return 143
|
|
260
|
+
return 0
|
|
137
261
|
}
|
|
138
262
|
|
|
139
263
|
if (command === 'docs') {
|
|
@@ -141,6 +265,7 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
141
265
|
const options = commonOptions(args)
|
|
142
266
|
options.outdir = takeOption(args, '--outdir')
|
|
143
267
|
options.basePath = takeOption(args, '--base')
|
|
268
|
+
options.mode = validateChoice(takeOption(args, '--mode') || 'site', '--mode', ['site', 'components'])
|
|
144
269
|
options.host = takeOption(args, '--host')
|
|
145
270
|
const port = takeOption(args, '--port')
|
|
146
271
|
if (port) options.port = Number(port)
|
|
@@ -148,33 +273,64 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
148
273
|
if (args[0]) options.cwd = args.shift()
|
|
149
274
|
if (args.length) throw new Error(`unknown docs arguments: ${args.join(' ')}`)
|
|
150
275
|
if (action === 'build') {
|
|
151
|
-
|
|
276
|
+
ensureStaticMode(uiMode)
|
|
277
|
+
const components = options.mode === 'components'
|
|
278
|
+
printLines(formatBanner(ui, components ? 'docs components build' : 'docs build', version()))
|
|
279
|
+
const result = await buildDocs(options)
|
|
280
|
+
const count = components ? (result.demos || []).length : (result.routes || []).length
|
|
281
|
+
const noun = components ? 'demos' : 'routes'
|
|
282
|
+
printResult(ui, result, components ? 'Component workbench built' : 'Documentation built', ` ${ui.dim('·')} ${count} ${noun}`)
|
|
152
283
|
return 0
|
|
153
284
|
}
|
|
154
285
|
if (action === 'dev') {
|
|
155
|
-
|
|
156
|
-
|
|
286
|
+
const commandName = options.mode === 'components' ? 'docs components' : 'docs dev'
|
|
287
|
+
const reason = await runServer(startDocsDevServer, options, commandName, options.cwd, ui, uiMode)
|
|
288
|
+
if (reason === 'SIGINT') return 130
|
|
289
|
+
if (reason === 'SIGTERM') return 143
|
|
290
|
+
return 0
|
|
157
291
|
}
|
|
158
292
|
throw new Error('docs requires build or dev')
|
|
159
293
|
}
|
|
160
294
|
|
|
161
295
|
if (command === 'parse' || command === 'tokenize') {
|
|
296
|
+
ensureStaticMode(uiMode)
|
|
297
|
+
const format = resolveFormat(takeOption(args, '--format'))
|
|
162
298
|
const file = args.shift()
|
|
163
299
|
if (!file || args.length) throw new Error(`${command} requires one source file`)
|
|
164
300
|
const source = await readFile(file, 'utf8')
|
|
301
|
+
if (format === 'human') printLines(formatBanner(ui, command, version()))
|
|
302
|
+
|
|
165
303
|
if (command === 'tokenize') {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
304
|
+
const result = tokenize(source)
|
|
305
|
+
if (format === 'json') {
|
|
306
|
+
console.log(JSON.stringify(result, null, 2))
|
|
307
|
+
} else {
|
|
308
|
+
console.log(' START..END KIND TEXT')
|
|
309
|
+
for (const token of result.tokens) {
|
|
310
|
+
const newline = token.newlineBefore ? ' ↵' : ''
|
|
311
|
+
console.log(
|
|
312
|
+
` ${String(token.start).padStart(5)}..${String(token.end).padEnd(5)} ${String(token.kind).padEnd(18)} ${JSON.stringify(token.text)}${newline}`,
|
|
313
|
+
)
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return result.diagnostics?.some((diagnostic) => diagnostic.severity === 'error') ? 1 : 0
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
const module = parse(source, {
|
|
320
|
+
sourceType: file.endsWith('.cjs') ? 'script' : 'module',
|
|
321
|
+
})
|
|
322
|
+
try {
|
|
323
|
+
if (format === 'json') {
|
|
172
324
|
console.log(JSON.stringify(module.summary, null, 2))
|
|
173
|
-
}
|
|
174
|
-
|
|
325
|
+
} else {
|
|
326
|
+
console.log(`Parsed ${file}`)
|
|
327
|
+
console.log(` Statements ${String(module.summary.statementCount).padEnd(8)} Dependencies ${module.summary.dependencies}`)
|
|
328
|
+
console.log(` Source bytes ${module.summary.sourceBytes}`)
|
|
175
329
|
}
|
|
330
|
+
return module.summary.diagnostics?.some((diagnostic) => diagnostic.severity === 'error') ? 1 : 0
|
|
331
|
+
} finally {
|
|
332
|
+
module.dispose()
|
|
176
333
|
}
|
|
177
|
-
return 0
|
|
178
334
|
}
|
|
179
335
|
|
|
180
336
|
throw new Error(`unknown command: ${command}`)
|
|
@@ -183,10 +339,8 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
183
339
|
try {
|
|
184
340
|
process.exitCode = await runCli()
|
|
185
341
|
} catch (error) {
|
|
186
|
-
const
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
console.error(` ${diagnostic.severity}: ${diagnostic.message}`)
|
|
190
|
-
}
|
|
342
|
+
const noColor = process.argv.includes('--no-color')
|
|
343
|
+
const ui = createUi(!noColor && supportsColor())
|
|
344
|
+
printLines(formatError(ui, error))
|
|
191
345
|
process.exitCode = 1
|
|
192
346
|
}
|
package/index.d.ts
CHANGED
|
@@ -13,6 +13,7 @@ export interface Diagnostic {
|
|
|
13
13
|
severity: 'error' | 'warning' | 'note' | 'help'
|
|
14
14
|
code?: string
|
|
15
15
|
message: string
|
|
16
|
+
path?: string
|
|
16
17
|
start?: number
|
|
17
18
|
end?: number
|
|
18
19
|
notes?: string[]
|
|
@@ -47,6 +48,8 @@ export interface OutputFile {
|
|
|
47
48
|
export interface BuildResult {
|
|
48
49
|
success: true
|
|
49
50
|
moduleCount: number
|
|
51
|
+
updatedModuleCount: number
|
|
52
|
+
cachedModuleCount: number
|
|
50
53
|
durationMs: number
|
|
51
54
|
outputDir?: string
|
|
52
55
|
code?: string
|
|
@@ -59,6 +62,8 @@ export interface BundleResult extends BuildResult {
|
|
|
59
62
|
outputDir?: undefined
|
|
60
63
|
}
|
|
61
64
|
|
|
65
|
+
export type DocsMode = 'site' | 'components'
|
|
66
|
+
|
|
62
67
|
export interface DocsRoute {
|
|
63
68
|
id: string
|
|
64
69
|
file: string
|
|
@@ -72,14 +77,26 @@ export interface DocsRoute {
|
|
|
72
77
|
draft: boolean
|
|
73
78
|
headings: Array<{ depth: number; title: string; id: string }>
|
|
74
79
|
}
|
|
80
|
+
export interface DocsDemo {
|
|
81
|
+
id: string
|
|
82
|
+
title: string
|
|
83
|
+
group: string
|
|
84
|
+
component: string
|
|
85
|
+
order: number
|
|
86
|
+
controlCount: number
|
|
87
|
+
warnings: string[]
|
|
88
|
+
}
|
|
75
89
|
|
|
76
90
|
export interface DocsBuildOptions extends ProjectOptions {
|
|
77
91
|
outdir?: string
|
|
78
92
|
basePath?: string
|
|
93
|
+
mode?: DocsMode
|
|
79
94
|
}
|
|
80
95
|
|
|
81
96
|
export interface DocsBuildResult extends BuildResult {
|
|
82
97
|
routes: DocsRoute[]
|
|
98
|
+
mode: DocsMode
|
|
99
|
+
demos: DocsDemo[]
|
|
83
100
|
}
|
|
84
101
|
|
|
85
102
|
export interface DevServerOptions extends ProjectOptions {
|
|
@@ -88,6 +105,9 @@ export interface DevServerOptions extends ProjectOptions {
|
|
|
88
105
|
port?: number
|
|
89
106
|
open?: boolean
|
|
90
107
|
}
|
|
108
|
+
export interface DocsDevServerOptions extends DevServerOptions {
|
|
109
|
+
mode?: DocsMode
|
|
110
|
+
}
|
|
91
111
|
|
|
92
112
|
export interface DevServerRebuildStartEvent {
|
|
93
113
|
type: 'rebuildStart'
|
|
@@ -96,7 +116,12 @@ export interface DevServerRebuildStartEvent {
|
|
|
96
116
|
|
|
97
117
|
export interface DevServerRebuiltEvent {
|
|
98
118
|
type: 'rebuilt'
|
|
119
|
+
initial: boolean
|
|
99
120
|
modules: number
|
|
121
|
+
updatedModules: number
|
|
122
|
+
cachedModules: number
|
|
123
|
+
chunks: number
|
|
124
|
+
assets: number
|
|
100
125
|
durationMs: number
|
|
101
126
|
}
|
|
102
127
|
|
|
@@ -126,7 +151,7 @@ export function build(options?: BuildOptions): Promise<BuildResult>
|
|
|
126
151
|
export function createBuildContext(options?: BuildOptions): Promise<BuildContext>
|
|
127
152
|
export function startDevServer(options?: DevServerOptions): Promise<DevServer>
|
|
128
153
|
export function buildDocs(options?: DocsBuildOptions): Promise<DocsBuildResult>
|
|
129
|
-
export function startDocsDevServer(options?:
|
|
154
|
+
export function startDocsDevServer(options?: DocsDevServerOptions): Promise<DevServer>
|
|
130
155
|
|
|
131
156
|
declare const wake: {
|
|
132
157
|
BuildContext: typeof BuildContext
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crab-dev/wake",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Wake native web build tools for Node.js",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"repository": {
|
|
@@ -45,11 +45,11 @@
|
|
|
45
45
|
"node": ">=22.14 <27"
|
|
46
46
|
},
|
|
47
47
|
"optionalDependencies": {
|
|
48
|
-
"@crab-dev/wake-
|
|
49
|
-
"@crab-dev/wake-
|
|
50
|
-
"@crab-dev/wake-linux-arm64-gnu": "0.1.
|
|
51
|
-
"@crab-dev/wake-
|
|
52
|
-
"@crab-dev/wake-
|
|
48
|
+
"@crab-dev/wake-darwin-arm64": "0.1.5",
|
|
49
|
+
"@crab-dev/wake-darwin-x64": "0.1.5",
|
|
50
|
+
"@crab-dev/wake-linux-arm64-gnu": "0.1.5",
|
|
51
|
+
"@crab-dev/wake-linux-x64-gnu": "0.1.5",
|
|
52
|
+
"@crab-dev/wake-win32-x64-msvc": "0.1.5"
|
|
53
53
|
},
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public",
|