@crab-dev/wake 0.1.2 → 0.1.4
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 +459 -0
- package/bin/wake.mjs +225 -44
- 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.4
|
|
4
|
+
|
|
5
|
+
- Added the opt-in Storybook-like documentation component workbench.
|
|
6
|
+
- Fixed Yarn PnP packages that expose entries and subpaths through `package.json#exports`.
|
|
7
|
+
- Expanded TypeScript and TSX parsing for optional arrow parameters, generic JSX, generic async arrows, and indexed type queries.
|
|
8
|
+
- Added source module paths to build diagnostics and corrected `wake parse` source-type selection.
|
|
9
|
+
|
|
10
|
+
## 0.1.3
|
|
11
|
+
|
|
12
|
+
- Improved the npm development-server terminal panel with Rust CLI-aligned styling, startup timing, rebuild progress, diagnostics, and color controls.
|
|
13
|
+
|
|
3
14
|
## 0.1.2
|
|
4
15
|
|
|
5
16
|
- Updated the npm release pipeline for private GitHub repositories while preserving immutable tarball audits.
|
package/bin/terminal.mjs
ADDED
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
const RESET = '\x1b[0m'
|
|
2
|
+
const BOLD = '\x1b[1m'
|
|
3
|
+
const DIM = '\x1b[2m'
|
|
4
|
+
const MAX_ACTIVITY = 200
|
|
5
|
+
const SPINNER = ['⠋', '⠙', '⠹', '⠸', '⠼', '⠴', '⠦', '⠧']
|
|
6
|
+
|
|
7
|
+
export function supportsColor(stream = process.stderr, env = process.env) {
|
|
8
|
+
return stream.isTTY === true && !Object.hasOwn(env, 'NO_COLOR')
|
|
9
|
+
}
|
|
10
|
+
|
|
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
|
+
}
|
|
26
|
+
return {
|
|
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),
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export function humanDuration(durationMs) {
|
|
39
|
+
const milliseconds = Math.max(1, Number(durationMs) || 0)
|
|
40
|
+
if (milliseconds < 1_000) return `${milliseconds.toFixed(0)}ms`
|
|
41
|
+
if (milliseconds < 60_000) return `${(milliseconds / 1_000).toFixed(2)}s`
|
|
42
|
+
const seconds = milliseconds / 1_000
|
|
43
|
+
return `${Math.floor(seconds / 60)}m${(seconds % 60).toFixed(1)}s`
|
|
44
|
+
}
|
|
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
|
+
|
|
68
|
+
export function formatBanner(ui, command, currentVersion) {
|
|
69
|
+
return [
|
|
70
|
+
'',
|
|
71
|
+
` ${ui.warn('⚡')} ${ui.brand('WAKE')} ${ui.dim('/')} ${ui.bold(command.toUpperCase())} ${ui.dim(`v${currentVersion}`)}`,
|
|
72
|
+
'',
|
|
73
|
+
]
|
|
74
|
+
}
|
|
75
|
+
|
|
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 = [
|
|
124
|
+
'',
|
|
125
|
+
` ${ui.dim('■')} ${ui.bold(label)} ${ui.dim(`(${reason})`)}`,
|
|
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
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export function observeServer(server, ui, output = console) {
|
|
138
|
+
const onRebuildStart = (event) => {
|
|
139
|
+
const count = event.changedPaths?.length || 0
|
|
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)}`)
|
|
146
|
+
}
|
|
147
|
+
const onRebuilt = (event) => {
|
|
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))}`,
|
|
151
|
+
)
|
|
152
|
+
}
|
|
153
|
+
const onDiagnostic = (diagnostic) => {
|
|
154
|
+
const code = diagnostic.code ? `[${diagnostic.code}] ` : ''
|
|
155
|
+
output.error(` ${ui.error('✗')} ${ui.bold('Build failed')} ${code}${diagnostic.message}`)
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
server.on('rebuildStart', onRebuildStart)
|
|
159
|
+
server.on('rebuilt', onRebuilt)
|
|
160
|
+
server.on('diagnostic', onDiagnostic)
|
|
161
|
+
return () => {
|
|
162
|
+
server.off('rebuildStart', onRebuildStart)
|
|
163
|
+
server.off('rebuilt', onRebuilt)
|
|
164
|
+
server.off('diagnostic', onDiagnostic)
|
|
165
|
+
}
|
|
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
|
@@ -9,17 +9,40 @@ import {
|
|
|
9
9
|
version,
|
|
10
10
|
} from '../index.mjs'
|
|
11
11
|
import { parse, tokenize } from '../experimental.mjs'
|
|
12
|
+
import {
|
|
13
|
+
applyDashboardEvent,
|
|
14
|
+
createDashboardSession,
|
|
15
|
+
createDashboardState,
|
|
16
|
+
createUi,
|
|
17
|
+
formatBanner,
|
|
18
|
+
formatBuildResult,
|
|
19
|
+
formatError,
|
|
20
|
+
formatFinalSummary,
|
|
21
|
+
formatServerReady,
|
|
22
|
+
observeServer,
|
|
23
|
+
setDashboardEndpoint,
|
|
24
|
+
setDashboardStopped,
|
|
25
|
+
setDashboardStopping,
|
|
26
|
+
supportsColor,
|
|
27
|
+
supportsTui,
|
|
28
|
+
} from './terminal.mjs'
|
|
12
29
|
|
|
13
30
|
const HELP = `Wake ${version()}
|
|
14
31
|
|
|
15
32
|
Usage:
|
|
33
|
+
wake [--ui auto|tui|plain] [--no-color] <command>
|
|
16
34
|
wake build [entry] [--outdir DIR] [--cache] [--sourcemap]
|
|
17
35
|
wake dev [root] [--entry FILE] [--host HOST] [--port PORT] [--open]
|
|
18
|
-
wake docs build [root] [--outdir DIR] [--base PATH]
|
|
19
|
-
wake docs dev [root] [--host HOST] [--port PORT] [--open]
|
|
20
|
-
wake parse <file>
|
|
21
|
-
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]
|
|
22
40
|
wake --version
|
|
41
|
+
|
|
42
|
+
Options:
|
|
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)
|
|
23
46
|
`
|
|
24
47
|
|
|
25
48
|
function takeOption(args, name) {
|
|
@@ -44,37 +67,161 @@ function commonOptions(args) {
|
|
|
44
67
|
}
|
|
45
68
|
}
|
|
46
69
|
|
|
47
|
-
function
|
|
48
|
-
const
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (
|
|
70
|
+
function printLines(lines, output = console.error) {
|
|
71
|
+
for (const line of lines) output(line)
|
|
72
|
+
}
|
|
73
|
+
|
|
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
|
|
53
94
|
}
|
|
54
95
|
|
|
55
|
-
|
|
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))
|
|
103
|
+
}
|
|
104
|
+
|
|
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) {
|
|
56
117
|
const controller = new AbortController()
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
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
|
+
|
|
65
179
|
try {
|
|
66
|
-
|
|
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
|
|
67
197
|
} finally {
|
|
68
|
-
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)
|
|
204
|
+
}
|
|
205
|
+
} catch (error) {
|
|
206
|
+
if (dashboard) {
|
|
207
|
+
dashboard.close()
|
|
208
|
+
dashboard = undefined
|
|
209
|
+
printLines(formatBanner(ui, command, version()))
|
|
69
210
|
}
|
|
211
|
+
throw error
|
|
212
|
+
} finally {
|
|
213
|
+
stopObserving()
|
|
214
|
+
dashboard?.close()
|
|
215
|
+
if (server) printLines(formatFinalSummary(ui, state, finalReason))
|
|
70
216
|
}
|
|
71
|
-
process.once('SIGINT', () => void stop('SIGINT'))
|
|
72
|
-
process.once('SIGTERM', () => void stop('SIGTERM'))
|
|
73
|
-
await server.waitUntilClosed()
|
|
74
217
|
}
|
|
75
218
|
|
|
76
219
|
export async function runCli(argv = process.argv.slice(2)) {
|
|
77
220
|
const args = [...argv]
|
|
221
|
+
const noColor = takeFlag(args, '--no-color')
|
|
222
|
+
const uiMode = validateChoice(takeOption(args, '--ui') || 'auto', '--ui', ['auto', 'tui', 'plain'])
|
|
223
|
+
const ui = createUi(!noColor && supportsColor())
|
|
224
|
+
|
|
78
225
|
if (takeFlag(args, '--version') || takeFlag(args, '-V')) {
|
|
79
226
|
console.log(version())
|
|
80
227
|
return 0
|
|
@@ -86,13 +233,15 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
86
233
|
|
|
87
234
|
const command = args.shift()
|
|
88
235
|
if (command === 'build') {
|
|
236
|
+
ensureStaticMode(uiMode)
|
|
89
237
|
const options = commonOptions(args)
|
|
90
238
|
options.outdir = takeOption(args, '--outdir')
|
|
91
239
|
options.cache = takeFlag(args, '--cache')
|
|
92
240
|
options.sourceMap = takeFlag(args, '--sourcemap')
|
|
93
241
|
if (args[0]) options.entry = args.shift()
|
|
94
242
|
if (args.length) throw new Error(`unknown build arguments: ${args.join(' ')}`)
|
|
95
|
-
|
|
243
|
+
printLines(formatBanner(ui, 'build', version()))
|
|
244
|
+
printResult(ui, await build(options), 'Built')
|
|
96
245
|
return 0
|
|
97
246
|
}
|
|
98
247
|
|
|
@@ -105,8 +254,10 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
105
254
|
options.open = takeFlag(args, '--open')
|
|
106
255
|
if (args[0]) options.cwd = args.shift()
|
|
107
256
|
if (args.length) throw new Error(`unknown dev arguments: ${args.join(' ')}`)
|
|
108
|
-
await runServer(startDevServer, options)
|
|
109
|
-
|
|
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
|
|
110
261
|
}
|
|
111
262
|
|
|
112
263
|
if (command === 'docs') {
|
|
@@ -114,6 +265,7 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
114
265
|
const options = commonOptions(args)
|
|
115
266
|
options.outdir = takeOption(args, '--outdir')
|
|
116
267
|
options.basePath = takeOption(args, '--base')
|
|
268
|
+
options.mode = validateChoice(takeOption(args, '--mode') || 'site', '--mode', ['site', 'components'])
|
|
117
269
|
options.host = takeOption(args, '--host')
|
|
118
270
|
const port = takeOption(args, '--port')
|
|
119
271
|
if (port) options.port = Number(port)
|
|
@@ -121,33 +273,64 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
121
273
|
if (args[0]) options.cwd = args.shift()
|
|
122
274
|
if (args.length) throw new Error(`unknown docs arguments: ${args.join(' ')}`)
|
|
123
275
|
if (action === 'build') {
|
|
124
|
-
|
|
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}`)
|
|
125
283
|
return 0
|
|
126
284
|
}
|
|
127
285
|
if (action === 'dev') {
|
|
128
|
-
|
|
129
|
-
|
|
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
|
|
130
291
|
}
|
|
131
292
|
throw new Error('docs requires build or dev')
|
|
132
293
|
}
|
|
133
294
|
|
|
134
295
|
if (command === 'parse' || command === 'tokenize') {
|
|
296
|
+
ensureStaticMode(uiMode)
|
|
297
|
+
const format = resolveFormat(takeOption(args, '--format'))
|
|
135
298
|
const file = args.shift()
|
|
136
299
|
if (!file || args.length) throw new Error(`${command} requires one source file`)
|
|
137
300
|
const source = await readFile(file, 'utf8')
|
|
301
|
+
if (format === 'human') printLines(formatBanner(ui, command, version()))
|
|
302
|
+
|
|
138
303
|
if (command === 'tokenize') {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
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') {
|
|
145
324
|
console.log(JSON.stringify(module.summary, null, 2))
|
|
146
|
-
}
|
|
147
|
-
|
|
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}`)
|
|
148
329
|
}
|
|
330
|
+
return module.summary.diagnostics?.some((diagnostic) => diagnostic.severity === 'error') ? 1 : 0
|
|
331
|
+
} finally {
|
|
332
|
+
module.dispose()
|
|
149
333
|
}
|
|
150
|
-
return 0
|
|
151
334
|
}
|
|
152
335
|
|
|
153
336
|
throw new Error(`unknown command: ${command}`)
|
|
@@ -156,10 +339,8 @@ export async function runCli(argv = process.argv.slice(2)) {
|
|
|
156
339
|
try {
|
|
157
340
|
process.exitCode = await runCli()
|
|
158
341
|
} catch (error) {
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
console.error(` ${diagnostic.severity}: ${diagnostic.message}`)
|
|
163
|
-
}
|
|
342
|
+
const noColor = process.argv.includes('--no-color')
|
|
343
|
+
const ui = createUi(!noColor && supportsColor())
|
|
344
|
+
printLines(formatError(ui, error))
|
|
164
345
|
process.exitCode = 1
|
|
165
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.4",
|
|
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.4",
|
|
49
|
+
"@crab-dev/wake-darwin-x64": "0.1.4",
|
|
50
|
+
"@crab-dev/wake-linux-arm64-gnu": "0.1.4",
|
|
51
|
+
"@crab-dev/wake-linux-x64-gnu": "0.1.4",
|
|
52
|
+
"@crab-dev/wake-win32-x64-msvc": "0.1.4"
|
|
53
53
|
},
|
|
54
54
|
"publishConfig": {
|
|
55
55
|
"access": "public",
|