sdc-build-wp 5.2.0 → 5.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/build.js +17 -2
- package/lib/components/scripts.js +38 -6
- package/lib/components/server.js +9 -3
- package/lib/logging.js +17 -31
- package/lib/project.js +32 -30
- package/lib/tui.js +344 -0
- package/lib/utils.js +2 -0
- package/package.json +2 -2
package/lib/build.js
CHANGED
|
@@ -2,9 +2,20 @@ import { default as project } from './project.js';
|
|
|
2
2
|
import * as utils from './utils.js';
|
|
3
3
|
import log from './logging.js';
|
|
4
4
|
import chalk from 'chalk';
|
|
5
|
+
import tui from './tui.js';
|
|
5
6
|
|
|
6
7
|
|
|
7
8
|
export async function build(watch = false) {
|
|
9
|
+
|
|
10
|
+
if (watch) {
|
|
11
|
+
tui.init();
|
|
12
|
+
tui.setComponents(project.builds, true);
|
|
13
|
+
const commands = `Commands: ${chalk.underline.green('r')}estart, ${chalk.underline.green('c')}lear cache, ${chalk.underline.green('p')}ause/resume, ${chalk.underline.green('n')}ew component, ${chalk.underline.green('q')}uit`;
|
|
14
|
+
tui.setCommands(commands);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
log('info', `Started sdc-build-wp`);
|
|
18
|
+
|
|
8
19
|
if (project.builds.includes('cache')) {
|
|
9
20
|
try {
|
|
10
21
|
await project.components.cache.init();
|
|
@@ -44,15 +55,18 @@ export async function build(watch = false) {
|
|
|
44
55
|
}
|
|
45
56
|
|
|
46
57
|
utils.clearScreen();
|
|
47
|
-
log('info', `Finished initial build in ${Math.round((performance.now() - initialBuildTimerStart) / 1000)} seconds`);
|
|
48
58
|
|
|
49
59
|
if (watch && project.builds.includes('server')) {
|
|
50
60
|
project.isRunning = true;
|
|
51
61
|
project.builds.splice(project.builds.indexOf('server'), 1);
|
|
52
62
|
project.builds.push('server');
|
|
63
|
+
|
|
64
|
+
log('info', `Finished initial build in ${Math.round((performance.now() - initialBuildTimerStart) / 1000)} seconds`);
|
|
53
65
|
log('info', `Started watching [${project.builds.join(', ')}]`);
|
|
66
|
+
|
|
67
|
+
tui.setComponents(project.builds, true);
|
|
68
|
+
|
|
54
69
|
project.components.server.logURLs();
|
|
55
|
-
log('info', `${chalk.underline.green('r')}estart, ${chalk.underline.green('c')}lear cache, ${chalk.underline.green('p')}ause/resume, ${chalk.underline.green('n')}ew component, ${chalk.underline.green('q')}uit`);
|
|
56
70
|
|
|
57
71
|
for (let build of project.builds) {
|
|
58
72
|
try {
|
|
@@ -63,6 +77,7 @@ export async function build(watch = false) {
|
|
|
63
77
|
}
|
|
64
78
|
}
|
|
65
79
|
} else {
|
|
80
|
+
log('info', `Finished initial build in ${Math.round((performance.now() - initialBuildTimerStart) / 1000)} seconds`);
|
|
66
81
|
process.emit('SIGINT');
|
|
67
82
|
}
|
|
68
83
|
}
|
|
@@ -2,6 +2,7 @@ import BaseComponent from './base.js';
|
|
|
2
2
|
import * as esbuild from 'esbuild';
|
|
3
3
|
import { ESLint } from 'eslint';
|
|
4
4
|
import * as eslintConfig from '../../eslint.config.js';
|
|
5
|
+
import tui from '../tui.js';
|
|
5
6
|
|
|
6
7
|
export default class ScriptsComponent extends BaseComponent {
|
|
7
8
|
|
|
@@ -35,7 +36,11 @@ export default class ScriptsComponent extends BaseComponent {
|
|
|
35
36
|
throw thisLint;
|
|
36
37
|
}
|
|
37
38
|
} catch (error) {
|
|
38
|
-
|
|
39
|
+
if (tui.isInitialized) {
|
|
40
|
+
tui.log(String(error.stack || error));
|
|
41
|
+
} else {
|
|
42
|
+
console.error(error);
|
|
43
|
+
}
|
|
39
44
|
this.log('error', `Failed linting ${entry.replace(`${this.project.path}/${this.project.paths.src.src}/${this.project.paths.src.scripts}/`, '')} - See above error.`);
|
|
40
45
|
return false;
|
|
41
46
|
}
|
|
@@ -72,7 +77,11 @@ export default class ScriptsComponent extends BaseComponent {
|
|
|
72
77
|
|
|
73
78
|
await this.updateBuildCache(entry, outFile, dependencies);
|
|
74
79
|
} catch (error) {
|
|
75
|
-
|
|
80
|
+
if (tui.isInitialized) {
|
|
81
|
+
tui.log(String(error.stack || error));
|
|
82
|
+
} else {
|
|
83
|
+
console.error(error);
|
|
84
|
+
}
|
|
76
85
|
this.log('error', `Failed building ${entryLabel} - See above error.`);
|
|
77
86
|
return false;
|
|
78
87
|
}
|
|
@@ -103,7 +112,11 @@ export default class ScriptsComponent extends BaseComponent {
|
|
|
103
112
|
await this.checkAndRebuildAffectedBlocks(path);
|
|
104
113
|
}
|
|
105
114
|
} catch (error) {
|
|
106
|
-
|
|
115
|
+
if (tui.isInitialized) {
|
|
116
|
+
tui.log(String(error.stack || error));
|
|
117
|
+
} else {
|
|
118
|
+
console.error(error);
|
|
119
|
+
}
|
|
107
120
|
this.log('error', `Failed to process scripts`);
|
|
108
121
|
}
|
|
109
122
|
});
|
|
@@ -121,7 +134,11 @@ export default class ScriptsComponent extends BaseComponent {
|
|
|
121
134
|
affectedBlocks.add(blockPath);
|
|
122
135
|
}
|
|
123
136
|
} catch (error) {
|
|
124
|
-
|
|
137
|
+
if (tui.isInitialized) {
|
|
138
|
+
tui.log(String(error.stack || error));
|
|
139
|
+
} else {
|
|
140
|
+
console.error(error);
|
|
141
|
+
}
|
|
125
142
|
}
|
|
126
143
|
}
|
|
127
144
|
|
|
@@ -149,10 +166,25 @@ export default class ScriptsComponent extends BaseComponent {
|
|
|
149
166
|
await ESLint.outputFixes(lintresults);
|
|
150
167
|
const formatter = await eslint.loadFormatter('stylish');
|
|
151
168
|
const formatterOutput = formatter.format(lintresults);
|
|
152
|
-
if (formatterOutput) {
|
|
169
|
+
if (formatterOutput) {
|
|
170
|
+
const cleanedOutput = formatterOutput.replace(`${this.project.path}/${this.project.paths.src.src}/${this.project.paths.src.scripts}/`, '');
|
|
171
|
+
if (tui.isInitialized) {
|
|
172
|
+
cleanedOutput.split('\n').forEach(line => {
|
|
173
|
+
if (line.trim()) {
|
|
174
|
+
tui.log(line);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
} else {
|
|
178
|
+
console.log(cleanedOutput);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
153
181
|
return true;
|
|
154
182
|
} catch (error) {
|
|
155
|
-
|
|
183
|
+
if (tui.isInitialized) {
|
|
184
|
+
tui.log(String(error.stack || error));
|
|
185
|
+
} else {
|
|
186
|
+
console.error(error);
|
|
187
|
+
}
|
|
156
188
|
return error;
|
|
157
189
|
}
|
|
158
190
|
}
|
package/lib/components/server.js
CHANGED
|
@@ -4,6 +4,7 @@ import { fileURLToPath } from 'url';
|
|
|
4
4
|
import { readFile } from 'fs/promises';
|
|
5
5
|
import { create } from 'browser-sync';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
+
import tui from '../tui.js';
|
|
7
8
|
|
|
8
9
|
export default class ServerComponent extends BaseComponent {
|
|
9
10
|
|
|
@@ -115,9 +116,14 @@ export default class ServerComponent extends BaseComponent {
|
|
|
115
116
|
if (this.usedOptions.proxy) {
|
|
116
117
|
localURL = localURL.replace('localhost', this.usedOptions.proxy.url.host);
|
|
117
118
|
}
|
|
118
|
-
|
|
119
|
-
if (
|
|
120
|
-
|
|
119
|
+
|
|
120
|
+
if (tui.isInitialized) {
|
|
121
|
+
tui.setURLs(localURL, this.usedOptions.urls.external || '');
|
|
122
|
+
} else {
|
|
123
|
+
this.log('info', `Local server: ${chalk.green(localURL)} (${this.usedOptions.urls.local})`);
|
|
124
|
+
if (this.usedOptions.urls.external) {
|
|
125
|
+
this.log('info', `External server: ${chalk.green(this.usedOptions.urls.external)}`);
|
|
126
|
+
}
|
|
121
127
|
}
|
|
122
128
|
}
|
|
123
129
|
|
package/lib/logging.js
CHANGED
|
@@ -2,59 +2,45 @@
|
|
|
2
2
|
// https://github.com/callmenick/node-pretty-log
|
|
3
3
|
import chalk from 'chalk';
|
|
4
4
|
import { default as project } from './project.js';
|
|
5
|
+
import tui from './tui.js';
|
|
5
6
|
|
|
6
7
|
function getTime() {
|
|
7
8
|
return new Date().toLocaleTimeString('en-US');
|
|
8
9
|
}
|
|
9
10
|
|
|
10
11
|
function log(type, ...messages) {
|
|
12
|
+
let icon, time, prefix = '';
|
|
13
|
+
|
|
11
14
|
switch (type) {
|
|
12
15
|
case 'success':
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
chalk.green('✔'),
|
|
16
|
-
chalk.gray(getTime()),
|
|
17
|
-
...messages
|
|
18
|
-
);
|
|
16
|
+
icon = chalk.green('✔');
|
|
17
|
+
time = chalk.gray(getTime());
|
|
19
18
|
break;
|
|
20
19
|
case 'error':
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
chalk.red('✖'),
|
|
24
|
-
chalk.bgRed.gray(getTime()),
|
|
25
|
-
...messages
|
|
26
|
-
);
|
|
20
|
+
icon = chalk.red('✖');
|
|
21
|
+
time = chalk.bgRed.gray(getTime());
|
|
27
22
|
if (project.builds.includes('server') && project.isRunning) {
|
|
28
23
|
project.components.server.server.notify('ERROR', 2500);
|
|
29
24
|
}
|
|
30
25
|
break;
|
|
31
26
|
case 'warn':
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
chalk.yellow('⚠'),
|
|
35
|
-
chalk.bgYellow.gray(getTime()),
|
|
36
|
-
...messages
|
|
37
|
-
);
|
|
27
|
+
icon = chalk.yellow('⚠');
|
|
28
|
+
time = chalk.bgYellow.gray(getTime());
|
|
38
29
|
break;
|
|
39
30
|
case 'php':
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
chalk.gray(getTime()),
|
|
44
|
-
chalk.gray('PHP: '),
|
|
45
|
-
...messages
|
|
46
|
-
);
|
|
31
|
+
icon = chalk.blue('ℹ');
|
|
32
|
+
time = chalk.gray(getTime());
|
|
33
|
+
prefix = chalk.gray('PHP: ');
|
|
47
34
|
break;
|
|
48
35
|
case 'info':
|
|
49
36
|
default:
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
chalk.blue('ℹ'),
|
|
53
|
-
chalk.bgBlue.gray(getTime()),
|
|
54
|
-
...messages
|
|
55
|
-
);
|
|
37
|
+
icon = chalk.blue('ℹ');
|
|
38
|
+
time = chalk.bgBlue.gray(getTime());
|
|
56
39
|
break;
|
|
57
40
|
}
|
|
41
|
+
|
|
42
|
+
const logMessage = [icon, time, prefix, ...messages].filter(Boolean).join(' ');
|
|
43
|
+
tui.log(logMessage);
|
|
58
44
|
}
|
|
59
45
|
|
|
60
46
|
export default log;
|
package/lib/project.js
CHANGED
|
@@ -11,7 +11,7 @@ import log from './logging.js';
|
|
|
11
11
|
import * as LibComponents from './components/index.js';
|
|
12
12
|
import help from './help.js';
|
|
13
13
|
import { validateConfig, mergeWithDefaults } from './config-validator.js';
|
|
14
|
-
import
|
|
14
|
+
import tui from './tui.js';
|
|
15
15
|
|
|
16
16
|
let project = {
|
|
17
17
|
config: {},
|
|
@@ -163,12 +163,19 @@ export async function init() {
|
|
|
163
163
|
await project.configWatcher.close();
|
|
164
164
|
project.configWatcher = null;
|
|
165
165
|
}
|
|
166
|
+
tui.destroy();
|
|
167
|
+
if (tui.getLogHistory) {
|
|
168
|
+
const logDump = tui.getLogHistory();
|
|
169
|
+
if (logDump && logDump.trim()) {
|
|
170
|
+
console.log(logDump);
|
|
171
|
+
}
|
|
172
|
+
}
|
|
166
173
|
log('info', `Exited sdc-build-wp`);
|
|
167
174
|
if (process.stdin.isTTY) {
|
|
168
175
|
process.stdin.setRawMode(false);
|
|
169
176
|
process.stdin.pause();
|
|
170
177
|
}
|
|
171
|
-
process.exit(0);
|
|
178
|
+
setTimeout(() => process.exit(0), 100);
|
|
172
179
|
});
|
|
173
180
|
|
|
174
181
|
}
|
|
@@ -180,7 +187,9 @@ export function keypressListen() {
|
|
|
180
187
|
|
|
181
188
|
const installRaw = () => {
|
|
182
189
|
if (!process.stdin.isTTY) return;
|
|
183
|
-
|
|
190
|
+
if (!tui.isInitialized) {
|
|
191
|
+
try { process.stdin.setRawMode(true); } catch {}
|
|
192
|
+
}
|
|
184
193
|
process.stdin.resume();
|
|
185
194
|
process.stdin.setEncoding('utf8');
|
|
186
195
|
};
|
|
@@ -202,8 +211,10 @@ export function keypressListen() {
|
|
|
202
211
|
utils.clearScreen();
|
|
203
212
|
if (project.isRunning) {
|
|
204
213
|
log('success', 'Resumed build process');
|
|
214
|
+
tui.setPaused(false);
|
|
205
215
|
} else {
|
|
206
216
|
log('warn', 'Paused build process');
|
|
217
|
+
tui.setPaused(true);
|
|
207
218
|
}
|
|
208
219
|
break;
|
|
209
220
|
case 'c':
|
|
@@ -216,8 +227,8 @@ export function keypressListen() {
|
|
|
216
227
|
case 'n': // New menu
|
|
217
228
|
isPrompting = true;
|
|
218
229
|
process.stdin.removeListener('data', handler);
|
|
230
|
+
|
|
219
231
|
try {
|
|
220
|
-
try { process.stdin.setRawMode(false); } catch {}
|
|
221
232
|
await handleCreateNew();
|
|
222
233
|
} finally {
|
|
223
234
|
isPrompting = false;
|
|
@@ -235,28 +246,21 @@ async function handleCreateNew() {
|
|
|
235
246
|
if (!project.isRunning) {
|
|
236
247
|
log('warn', 'Build process paused. Press [p] to resume if needed. Continuing creation.');
|
|
237
248
|
}
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
}
|
|
252
|
-
if (typeKey === 'cancel') { return; }
|
|
249
|
+
|
|
250
|
+
|
|
251
|
+
const menuOptions = ['Block', 'Pattern', 'Style variation', 'Cancel'];
|
|
252
|
+
const menuMap = { Block: 'b', Pattern: 'p', 'Style variation': 's', Cancel: 'cancel' };
|
|
253
|
+
const menuPrompt = 'Create new:';
|
|
254
|
+
const blockPrompt = 'Block name:';
|
|
255
|
+
const patternPrompt = 'Pattern name:';
|
|
256
|
+
const stylePrompt = 'Style variation name:';
|
|
257
|
+
|
|
258
|
+
let menuResult = await tui.showMenu(menuOptions, menuPrompt);
|
|
259
|
+
if (!menuResult || menuMap[menuResult.value] === 'cancel') return;
|
|
260
|
+
let typeKey = menuMap[menuResult.value];
|
|
261
|
+
|
|
253
262
|
if (typeKey === 'b') {
|
|
254
|
-
let name;
|
|
255
|
-
try {
|
|
256
|
-
name = await input({ message: 'Block name:' });
|
|
257
|
-
} catch (error) {
|
|
258
|
-
return;
|
|
259
|
-
}
|
|
263
|
+
let name = await tui.showInput(blockPrompt);
|
|
260
264
|
if (!name) { log('warn', 'No name provided.'); return; }
|
|
261
265
|
const slug = utils.slugify(name);
|
|
262
266
|
const blockDir = `${project.path}/blocks/${slug}`;
|
|
@@ -290,8 +294,7 @@ async function handleCreateNew() {
|
|
|
290
294
|
log('error', `Failed to scaffold block`);
|
|
291
295
|
}
|
|
292
296
|
} else if (typeKey === 'p') {
|
|
293
|
-
let name;
|
|
294
|
-
try { name = await input({ message: 'Pattern name:' }); } catch (error) { return; }
|
|
297
|
+
let name = await tui.showInput(patternPrompt);
|
|
295
298
|
if (!name) { log('warn', 'No name provided.'); return; }
|
|
296
299
|
const slug = utils.slugify(name);
|
|
297
300
|
const patternsDir = `${project.path}/patterns`;
|
|
@@ -322,8 +325,7 @@ async function handleCreateNew() {
|
|
|
322
325
|
log('error', `Failed to create pattern`);
|
|
323
326
|
}
|
|
324
327
|
} else if (typeKey === 's') {
|
|
325
|
-
let name;
|
|
326
|
-
try { name = await input({ message: 'Style variation name:' }); } catch (error) { return; }
|
|
328
|
+
let name = await tui.showInput(stylePrompt);
|
|
327
329
|
if (!name) { log('warn', 'No name provided.'); return; }
|
|
328
330
|
const slug = utils.slugify(name);
|
|
329
331
|
const stylesDir = `${project.path}/styles`;
|
|
@@ -334,7 +336,7 @@ async function handleCreateNew() {
|
|
|
334
336
|
log('warn', `Style variation ${slug}.json already exists.`);
|
|
335
337
|
return;
|
|
336
338
|
} catch (error) {
|
|
337
|
-
|
|
339
|
+
//
|
|
338
340
|
}
|
|
339
341
|
try {
|
|
340
342
|
const libDir = path.dirname(fileURLToPath(import.meta.url));
|
package/lib/tui.js
ADDED
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
import blessed from 'blessed';
|
|
2
|
+
import chalk from 'chalk';
|
|
3
|
+
|
|
4
|
+
class TUI {
|
|
5
|
+
constructor() {
|
|
6
|
+
this.screen = null;
|
|
7
|
+
this.headerBox = null;
|
|
8
|
+
this.logBox = null;
|
|
9
|
+
this.isInitialized = false;
|
|
10
|
+
this.urls = {
|
|
11
|
+
local: '',
|
|
12
|
+
external: ''
|
|
13
|
+
};
|
|
14
|
+
this.commands = '';
|
|
15
|
+
this.components = [];
|
|
16
|
+
this.watchMode = false;
|
|
17
|
+
this.isPaused = false;
|
|
18
|
+
this._logHistory = [];
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
init() {
|
|
22
|
+
if (this.isInitialized) {
|
|
23
|
+
return;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
this.screen = blessed.screen({
|
|
27
|
+
smartCSR: true,
|
|
28
|
+
fullUnicode: true,
|
|
29
|
+
title: 'SDC Build WP',
|
|
30
|
+
input: process.stdin,
|
|
31
|
+
output: process.stdout
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
this.headerBox = blessed.box({
|
|
35
|
+
top: 0,
|
|
36
|
+
left: 0,
|
|
37
|
+
width: '100%',
|
|
38
|
+
height: 5,
|
|
39
|
+
content: '',
|
|
40
|
+
tags: true,
|
|
41
|
+
style: {
|
|
42
|
+
fg: 'white',
|
|
43
|
+
bg: 'black',
|
|
44
|
+
border: {
|
|
45
|
+
fg: 'blue'
|
|
46
|
+
}
|
|
47
|
+
},
|
|
48
|
+
border: {
|
|
49
|
+
type: 'line',
|
|
50
|
+
bottom: true
|
|
51
|
+
},
|
|
52
|
+
shrink: false,
|
|
53
|
+
scrollable: false
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
this.logBox = blessed.log({
|
|
57
|
+
top: 5,
|
|
58
|
+
left: 0,
|
|
59
|
+
width: '100%',
|
|
60
|
+
height: '100%-5',
|
|
61
|
+
tags: true,
|
|
62
|
+
scrollable: true,
|
|
63
|
+
alwaysScroll: true,
|
|
64
|
+
scrollbar: {
|
|
65
|
+
ch: ' ',
|
|
66
|
+
track: {
|
|
67
|
+
bg: 'blue'
|
|
68
|
+
},
|
|
69
|
+
style: {
|
|
70
|
+
inverse: true
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
mouse: true,
|
|
74
|
+
keys: true,
|
|
75
|
+
vi: true,
|
|
76
|
+
style: {
|
|
77
|
+
fg: 'white',
|
|
78
|
+
bg: 'black'
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
this.screen.append(this.logBox);
|
|
83
|
+
this.screen.append(this.headerBox);
|
|
84
|
+
|
|
85
|
+
this.screen.on('resize', () => {
|
|
86
|
+
this.updateHeader();
|
|
87
|
+
this.screen.render();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
this.screen.key(['escape', 'q', 'C-c'], () => {
|
|
91
|
+
return false;
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
this.screen.key(['enter', 'return'], () => {
|
|
95
|
+
this.logBox.log('');
|
|
96
|
+
this.screen.render();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
this.screen.key(['down'], () => {
|
|
100
|
+
this.logBox.scroll(1);
|
|
101
|
+
this.screen.render();
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
this.screen.key(['up'], () => {
|
|
105
|
+
this.logBox.scroll(-1);
|
|
106
|
+
this.screen.render();
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
this.screen.key(['pagedown'], () => {
|
|
110
|
+
this.logBox.scroll(this.logBox.height);
|
|
111
|
+
this.screen.render();
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
this.screen.key(['pageup'], () => {
|
|
115
|
+
this.logBox.scroll(-this.logBox.height);
|
|
116
|
+
this.screen.render();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
this.updateHeader();
|
|
120
|
+
this.screen.render();
|
|
121
|
+
|
|
122
|
+
this.isInitialized = true;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
updateHeader() {
|
|
126
|
+
if (!this.isInitialized) {
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
const lines = [];
|
|
131
|
+
|
|
132
|
+
let titleLine = ' ' + chalk.bold.blue('SDC Build WP');
|
|
133
|
+
if (this.watchMode) {
|
|
134
|
+
titleLine += chalk.gray(' (watch mode)');
|
|
135
|
+
}
|
|
136
|
+
if (this.isPaused) {
|
|
137
|
+
titleLine += chalk.bold.yellow(' [PAUSED]');
|
|
138
|
+
}
|
|
139
|
+
if (this.components.length > 0) {
|
|
140
|
+
titleLine += chalk.gray(' [') + chalk.cyan(this.components.join(', ')) + chalk.gray(']');
|
|
141
|
+
}
|
|
142
|
+
lines.push(titleLine);
|
|
143
|
+
|
|
144
|
+
if (this.urls.local || this.urls.external) {
|
|
145
|
+
let urlLine = ' ';
|
|
146
|
+
if (this.urls.local) {
|
|
147
|
+
urlLine += `Local: ${chalk.green(this.urls.local)}`;
|
|
148
|
+
}
|
|
149
|
+
if (this.urls.external) {
|
|
150
|
+
if (urlLine.length > 1) urlLine += ' ';
|
|
151
|
+
urlLine += `External: ${chalk.green(this.urls.external)}`;
|
|
152
|
+
}
|
|
153
|
+
lines.push(urlLine);
|
|
154
|
+
} else {
|
|
155
|
+
lines.push(' ');
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
if (this.commands) {
|
|
159
|
+
lines.push(' ' + this.commands);
|
|
160
|
+
} else {
|
|
161
|
+
lines.push(' ');
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
lines.push(' ');
|
|
165
|
+
|
|
166
|
+
this.headerBox.setContent(lines.join('\n'));
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
setURLs(local, external) {
|
|
170
|
+
this.urls.local = local;
|
|
171
|
+
this.urls.external = external;
|
|
172
|
+
this.updateHeader();
|
|
173
|
+
this.render();
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
setCommands(commands) {
|
|
177
|
+
this.commands = commands;
|
|
178
|
+
this.updateHeader();
|
|
179
|
+
this.render();
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
setPaused(isPaused) {
|
|
183
|
+
this.isPaused = isPaused;
|
|
184
|
+
this.updateHeader();
|
|
185
|
+
this.render();
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
setComponents(components, watchMode = false) {
|
|
189
|
+
this.components = components;
|
|
190
|
+
this.watchMode = watchMode;
|
|
191
|
+
this.updateHeader();
|
|
192
|
+
this.render();
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
log(message) {
|
|
196
|
+
this._logHistory.push(message);
|
|
197
|
+
if (!this.isInitialized) {
|
|
198
|
+
console.log(message);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
this.logBox.log(message);
|
|
202
|
+
this.render();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
getLogHistory() {
|
|
206
|
+
return this._logHistory.join('\n');
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
render() {
|
|
210
|
+
if (this.isInitialized && this.screen) {
|
|
211
|
+
this.screen.render();
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
async showMenu(options, prompt = 'Choose an option:') {
|
|
216
|
+
return new Promise((resolve) => {
|
|
217
|
+
const menu = blessed.list({
|
|
218
|
+
parent: this.screen,
|
|
219
|
+
top: 'center',
|
|
220
|
+
left: 'center',
|
|
221
|
+
width: '50%',
|
|
222
|
+
height: options.length + 4,
|
|
223
|
+
label: ` ${prompt} `,
|
|
224
|
+
items: options,
|
|
225
|
+
keys: true,
|
|
226
|
+
mouse: true,
|
|
227
|
+
border: 'line',
|
|
228
|
+
style: {
|
|
229
|
+
fg: 'white',
|
|
230
|
+
bg: 'black',
|
|
231
|
+
border: { fg: 'blue' },
|
|
232
|
+
selected: { bg: 'blue', fg: 'white' }
|
|
233
|
+
}
|
|
234
|
+
});
|
|
235
|
+
menu.focus();
|
|
236
|
+
const stopLogScroll = (ch, key) => {
|
|
237
|
+
if (['up', 'down', 'pagedown', 'pageup'].includes(key.name)) {
|
|
238
|
+
return false;
|
|
239
|
+
}
|
|
240
|
+
};
|
|
241
|
+
this.logBox.ignoreKeys = true;
|
|
242
|
+
menu.on('detach', () => {
|
|
243
|
+
this.logBox.ignoreKeys = false;
|
|
244
|
+
});
|
|
245
|
+
menu.on('keypress', stopLogScroll);
|
|
246
|
+
this.screen.render();
|
|
247
|
+
menu.on('select', (item, idx) => {
|
|
248
|
+
menu.destroy();
|
|
249
|
+
this.screen.render();
|
|
250
|
+
resolve({ value: item.getText(), index: idx });
|
|
251
|
+
});
|
|
252
|
+
menu.on('cancel', () => {
|
|
253
|
+
menu.destroy();
|
|
254
|
+
this.screen.render();
|
|
255
|
+
resolve(null);
|
|
256
|
+
});
|
|
257
|
+
menu.key(['escape', 'q'], () => {
|
|
258
|
+
menu.emit('cancel');
|
|
259
|
+
});
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
async showInput(prompt = 'Enter value:') {
|
|
264
|
+
return new Promise((resolve) => {
|
|
265
|
+
const box = blessed.box({
|
|
266
|
+
parent: this.screen,
|
|
267
|
+
top: 'center',
|
|
268
|
+
left: 'center',
|
|
269
|
+
width: '50%',
|
|
270
|
+
height: 5,
|
|
271
|
+
label: ` ${prompt} `,
|
|
272
|
+
border: 'line',
|
|
273
|
+
style: {
|
|
274
|
+
fg: 'white',
|
|
275
|
+
bg: 'black',
|
|
276
|
+
border: { fg: 'blue' }
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
const input = blessed.textbox({
|
|
280
|
+
parent: box,
|
|
281
|
+
top: 2,
|
|
282
|
+
left: 2,
|
|
283
|
+
width: '90%',
|
|
284
|
+
height: 1,
|
|
285
|
+
inputOnFocus: true,
|
|
286
|
+
style: {
|
|
287
|
+
fg: 'white',
|
|
288
|
+
bg: 'black',
|
|
289
|
+
focus: { bg: 'blue' }
|
|
290
|
+
}
|
|
291
|
+
});
|
|
292
|
+
input.focus();
|
|
293
|
+
this.screen.render();
|
|
294
|
+
input.on('submit', (value) => {
|
|
295
|
+
box.destroy();
|
|
296
|
+
this.screen.render();
|
|
297
|
+
resolve(value);
|
|
298
|
+
});
|
|
299
|
+
input.on('cancel', () => {
|
|
300
|
+
box.destroy();
|
|
301
|
+
this.screen.render();
|
|
302
|
+
resolve(null);
|
|
303
|
+
});
|
|
304
|
+
input.key(['escape', 'q'], () => {
|
|
305
|
+
input.emit('cancel');
|
|
306
|
+
});
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
getState() {
|
|
311
|
+
return {
|
|
312
|
+
urls: { ...this.urls },
|
|
313
|
+
commands: this.commands,
|
|
314
|
+
components: [...this.components],
|
|
315
|
+
watchMode: this.watchMode,
|
|
316
|
+
isPaused: this.isPaused
|
|
317
|
+
};
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
setState(state) {
|
|
321
|
+
if (state) {
|
|
322
|
+
this.urls = { ...state.urls };
|
|
323
|
+
this.commands = state.commands;
|
|
324
|
+
this.components = [...state.components];
|
|
325
|
+
this.watchMode = state.watchMode;
|
|
326
|
+
this.isPaused = state.isPaused;
|
|
327
|
+
this.updateHeader();
|
|
328
|
+
this.render();
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
destroy() {
|
|
333
|
+
if (this.isInitialized && this.screen) {
|
|
334
|
+
this.screen.destroy();
|
|
335
|
+
this.isInitialized = false;
|
|
336
|
+
this.screen = null;
|
|
337
|
+
this.headerBox = null;
|
|
338
|
+
this.logBox = null;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const tui = new TUI();
|
|
344
|
+
export default tui;
|
package/lib/utils.js
CHANGED
|
@@ -4,6 +4,7 @@ import { readdir } from 'node:fs/promises';
|
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import project from './project.js';
|
|
6
6
|
import log from './logging.js';
|
|
7
|
+
import tui from './tui.js';
|
|
7
8
|
|
|
8
9
|
export async function getThisPackageVersion() {
|
|
9
10
|
return JSON.parse(await fs.readFile(path.join(path.dirname(fileURLToPath(import.meta.url)), '../package.json'))).version
|
|
@@ -11,6 +12,7 @@ export async function getThisPackageVersion() {
|
|
|
11
12
|
|
|
12
13
|
export function clearScreen() {
|
|
13
14
|
if (!process.stdout.isTTY) { return; }
|
|
15
|
+
if (tui.isInitialized) { return; }
|
|
14
16
|
process.stdout.write('\x1B[2J\x1B[0f');
|
|
15
17
|
}
|
|
16
18
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sdc-build-wp",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.3.0",
|
|
4
4
|
"description": "Custom WordPress build process.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -22,13 +22,13 @@
|
|
|
22
22
|
"sdc-build-wp": "./index.js"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@inquirer/prompts": "^7.9.0",
|
|
26
25
|
"@stylistic/eslint-plugin": "^5.4.0",
|
|
27
26
|
"@stylistic/stylelint-plugin": "^4.0.0",
|
|
28
27
|
"@typescript-eslint/eslint-plugin": "^8.46.1",
|
|
29
28
|
"@typescript-eslint/parser": "^8.46.1",
|
|
30
29
|
"@wordpress/scripts": "^30.25.0",
|
|
31
30
|
"autoprefixer": "^10.4.21",
|
|
31
|
+
"blessed": "^0.1.81",
|
|
32
32
|
"browser-sync": "^3.0.4",
|
|
33
33
|
"chalk": "^5.6.2",
|
|
34
34
|
"chokidar": "^4.0.3",
|