sdc-build-wp 5.0.2 → 5.1.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 +3 -2
- package/lib/components/blocks.js +16 -2
- package/lib/components/scripts.js +32 -0
- package/lib/project.js +157 -6
- package/lib/templates/block/block.json +10 -0
- package/lib/templates/block/index.js +19 -0
- package/lib/templates/pattern/pattern.php +8 -0
- package/lib/templates/style/style.json +10 -0
- package/lib/utils.js +21 -0
- package/package.json +11 -10
package/lib/build.js
CHANGED
|
@@ -26,7 +26,8 @@ export async function build(watch = false) {
|
|
|
26
26
|
|
|
27
27
|
promisesBuilds.push(
|
|
28
28
|
project.components[build].init().catch(error => {
|
|
29
|
-
|
|
29
|
+
console.error(error);
|
|
30
|
+
log('error', `Failed to initialize ${build} component`);
|
|
30
31
|
return { failed: true, component: build, error };
|
|
31
32
|
})
|
|
32
33
|
);
|
|
@@ -48,7 +49,7 @@ export async function build(watch = false) {
|
|
|
48
49
|
project.builds.splice(project.builds.indexOf('server'), 1);
|
|
49
50
|
project.builds.push('server');
|
|
50
51
|
log('info', `Started watching [${project.builds.join(', ')}]`);
|
|
51
|
-
log('info', `[r]
|
|
52
|
+
log('info', `[r]estart, [c]lear cache, [p]ause/resume, [n]ew component, [q]uit`);
|
|
52
53
|
|
|
53
54
|
for (let build of project.builds) {
|
|
54
55
|
try {
|
package/lib/components/blocks.js
CHANGED
|
@@ -108,7 +108,7 @@ export default class BlocksComponent extends BaseComponent {
|
|
|
108
108
|
}
|
|
109
109
|
}
|
|
110
110
|
if (workingBlockJson === null) {
|
|
111
|
-
this.log('error', `Failed building ${
|
|
111
|
+
this.log('error', `Failed building ${entryLabel} - no block.json found.`);
|
|
112
112
|
return false;
|
|
113
113
|
}
|
|
114
114
|
|
|
@@ -177,6 +177,19 @@ export default class BlocksComponent extends BaseComponent {
|
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
|
|
180
|
+
addBlock(blockPath) {
|
|
181
|
+
if (!this.globs.includes(blockPath)) {
|
|
182
|
+
this.globs.push(blockPath);
|
|
183
|
+
if (this.watcher) {
|
|
184
|
+
this.watcher.add([`${blockPath}/src`, `${blockPath}/src/**/*`]);
|
|
185
|
+
}
|
|
186
|
+
this.build(blockPath).catch(err => {
|
|
187
|
+
console.error(err);
|
|
188
|
+
this.log('error', `Failed initial build for new block ${blockPath}`);
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
180
193
|
watch() {
|
|
181
194
|
const watchPaths = this.globs.map(block => `${block}/src`);
|
|
182
195
|
const buildQueue = new Set();
|
|
@@ -277,7 +290,8 @@ export default class BlocksComponent extends BaseComponent {
|
|
|
277
290
|
if (path.endsWith('.js')) {
|
|
278
291
|
if (!this.project.components.scripts.isBuilding) {
|
|
279
292
|
this.project.components.scripts.lint(path).catch(lintError => {
|
|
280
|
-
|
|
293
|
+
console.error(lintError);
|
|
294
|
+
this.log('warn', `Linting failed for ${path}`);
|
|
281
295
|
});
|
|
282
296
|
}
|
|
283
297
|
}
|
|
@@ -99,6 +99,9 @@ export default class ScriptsComponent extends BaseComponent {
|
|
|
99
99
|
if (!this.project.isRunning) { return; }
|
|
100
100
|
try {
|
|
101
101
|
await this.process();
|
|
102
|
+
if (this.project.components.blocks && (path.endsWith('.js') || path.endsWith('.jsx') || path.endsWith('.ts') || path.endsWith('.tsx'))) {
|
|
103
|
+
await this.checkAndRebuildAffectedBlocks(path);
|
|
104
|
+
}
|
|
102
105
|
} catch (error) {
|
|
103
106
|
console.error(error);
|
|
104
107
|
this.log('error', `Failed to process scripts`);
|
|
@@ -106,6 +109,35 @@ export default class ScriptsComponent extends BaseComponent {
|
|
|
106
109
|
});
|
|
107
110
|
}
|
|
108
111
|
|
|
112
|
+
async checkAndRebuildAffectedBlocks(changedPath) {
|
|
113
|
+
if (!this.project.components.blocks || !this.project.components.blocks.globs) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const affectedBlocks = new Set();
|
|
117
|
+
for (const blockPath of this.project.components.blocks.globs) {
|
|
118
|
+
try {
|
|
119
|
+
const dependencies = await this.project.components.blocks.getBlockDependencies(blockPath);
|
|
120
|
+
if (dependencies.includes(changedPath)) {
|
|
121
|
+
affectedBlocks.add(blockPath);
|
|
122
|
+
}
|
|
123
|
+
} catch (error) {
|
|
124
|
+
console.error(error);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (!affectedBlocks.size) { return; }
|
|
129
|
+
for (const blockPath of affectedBlocks) {
|
|
130
|
+
try {
|
|
131
|
+
if (this.project.components.server?.server) {
|
|
132
|
+
this.project.components.server.server.notify('Building block...', 5000);
|
|
133
|
+
}
|
|
134
|
+
await this.project.components.blocks.process(blockPath);
|
|
135
|
+
} catch (error) {
|
|
136
|
+
//
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
109
141
|
async lint(entry, options) {
|
|
110
142
|
try {
|
|
111
143
|
const eslint = new ESLint({
|
package/lib/project.js
CHANGED
|
@@ -3,6 +3,7 @@ import { hideBin } from 'yargs/helpers';
|
|
|
3
3
|
import { readFile } from 'fs/promises';
|
|
4
4
|
import path from 'path';
|
|
5
5
|
import { promises as fs } from 'fs';
|
|
6
|
+
import { fileURLToPath } from 'url';
|
|
6
7
|
import chokidar from 'chokidar';
|
|
7
8
|
import { restartBuild } from './build.js';
|
|
8
9
|
import * as utils from './utils.js';
|
|
@@ -10,6 +11,7 @@ import log from './logging.js';
|
|
|
10
11
|
import * as LibComponents from './components/index.js';
|
|
11
12
|
import help from './help.js';
|
|
12
13
|
import { validateConfig, mergeWithDefaults } from './config-validator.js';
|
|
14
|
+
import { input, select } from '@inquirer/prompts';
|
|
13
15
|
|
|
14
16
|
let project = {
|
|
15
17
|
config: {},
|
|
@@ -114,7 +116,7 @@ export async function init() {
|
|
|
114
116
|
project.builds = project.argv.builds ? (Array.isArray(project.argv.builds) ? project.argv.builds : project.argv.builds.split(',')) : Object.keys(project.components).filter(component => component !== 'cache');
|
|
115
117
|
|
|
116
118
|
if (!project.argv['no-cache'] && !project.builds.includes('cache')) {
|
|
117
|
-
project.builds
|
|
119
|
+
project.builds = ['cache', ...project.builds];
|
|
118
120
|
}
|
|
119
121
|
|
|
120
122
|
if (Object.keys(project.entries).length === 0) {
|
|
@@ -174,11 +176,19 @@ export async function init() {
|
|
|
174
176
|
export function keypressListen() {
|
|
175
177
|
if (!process.stdin.isTTY) { return; }
|
|
176
178
|
|
|
177
|
-
|
|
178
|
-
process.stdin.resume();
|
|
179
|
-
process.stdin.setEncoding('utf8');
|
|
179
|
+
let isPrompting = false;
|
|
180
180
|
|
|
181
|
-
|
|
181
|
+
const installRaw = () => {
|
|
182
|
+
if (!process.stdin.isTTY) return;
|
|
183
|
+
try { process.stdin.setRawMode(true); } catch {}
|
|
184
|
+
process.stdin.resume();
|
|
185
|
+
process.stdin.setEncoding('utf8');
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
installRaw();
|
|
189
|
+
|
|
190
|
+
const handler = async (key) => {
|
|
191
|
+
if (isPrompting) { return; }
|
|
182
192
|
switch (key) {
|
|
183
193
|
case '\r': // [Enter]/[Return]
|
|
184
194
|
console.log('\r');
|
|
@@ -203,8 +213,149 @@ export function keypressListen() {
|
|
|
203
213
|
log('info', 'Restarted build process');
|
|
204
214
|
await restartBuild();
|
|
205
215
|
break;
|
|
216
|
+
case 'n': // New menu
|
|
217
|
+
isPrompting = true;
|
|
218
|
+
process.stdin.removeListener('data', handler);
|
|
219
|
+
try {
|
|
220
|
+
try { process.stdin.setRawMode(false); } catch {}
|
|
221
|
+
await handleCreateNew();
|
|
222
|
+
} finally {
|
|
223
|
+
isPrompting = false;
|
|
224
|
+
installRaw();
|
|
225
|
+
process.stdin.on('data', handler);
|
|
226
|
+
}
|
|
227
|
+
break;
|
|
206
228
|
}
|
|
207
|
-
}
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
process.stdin.on('data', handler);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
async function handleCreateNew() {
|
|
235
|
+
if (!project.isRunning) {
|
|
236
|
+
log('warn', 'Build process paused. Press [p] to resume if needed. Continuing creation.');
|
|
237
|
+
}
|
|
238
|
+
let typeKey;
|
|
239
|
+
try {
|
|
240
|
+
typeKey = await select({
|
|
241
|
+
message: 'Create new:',
|
|
242
|
+
choices: [
|
|
243
|
+
{ name: 'Block', value: 'b' },
|
|
244
|
+
{ name: 'Pattern', value: 'p' },
|
|
245
|
+
{ name: 'Style variation', value: 's' },
|
|
246
|
+
{ name: 'Cancel', value: 'cancel' }
|
|
247
|
+
]
|
|
248
|
+
});
|
|
249
|
+
} catch (error) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
252
|
+
if (typeKey === 'cancel') { return; }
|
|
253
|
+
if (typeKey === 'b') {
|
|
254
|
+
let name;
|
|
255
|
+
try {
|
|
256
|
+
name = await input({ message: 'Block name:' });
|
|
257
|
+
} catch (error) {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (!name) { log('warn', 'No name provided.'); return; }
|
|
261
|
+
const slug = utils.slugify(name);
|
|
262
|
+
const blockDir = `${project.path}/blocks/${slug}`;
|
|
263
|
+
const srcDir = `${blockDir}/src`;
|
|
264
|
+
try {
|
|
265
|
+
await fs.access(blockDir);
|
|
266
|
+
log('warn', `Block ${slug} already exists.`);
|
|
267
|
+
return;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
//
|
|
270
|
+
}
|
|
271
|
+
const created = await utils.ensureDir(srcDir);
|
|
272
|
+
if (!created) { return; }
|
|
273
|
+
const blockJsonPath = `${srcDir}/block.json`;
|
|
274
|
+
const indexJsPath = `${srcDir}/index.js`;
|
|
275
|
+
try {
|
|
276
|
+
const libDir = path.dirname(fileURLToPath(import.meta.url));
|
|
277
|
+
const templateBlockJsonRaw = await fs.readFile(path.resolve(libDir, 'templates/block/block.json'), 'utf8');
|
|
278
|
+
let templateBlock = JSON.parse(templateBlockJsonRaw);
|
|
279
|
+
templateBlock.name = `custom/${slug}`;
|
|
280
|
+
templateBlock.title = name;
|
|
281
|
+
await fs.writeFile(blockJsonPath, JSON.stringify(templateBlock, null, '\t'));
|
|
282
|
+
const templateIndex = await fs.readFile(path.resolve(libDir, 'templates/block/index.js'), 'utf8');
|
|
283
|
+
await fs.writeFile(indexJsPath, templateIndex);
|
|
284
|
+
log('success', `Created block at blocks/${slug}`);
|
|
285
|
+
if (project.components.blocks) {
|
|
286
|
+
project.components.blocks.addBlock(blockDir);
|
|
287
|
+
}
|
|
288
|
+
} catch (error) {
|
|
289
|
+
console.error(error);
|
|
290
|
+
log('error', `Failed to scaffold block`);
|
|
291
|
+
}
|
|
292
|
+
} else if (typeKey === 'p') {
|
|
293
|
+
let name;
|
|
294
|
+
try { name = await input({ message: 'Pattern name:' }); } catch (error) { return; }
|
|
295
|
+
if (!name) { log('warn', 'No name provided.'); return; }
|
|
296
|
+
const slug = utils.slugify(name);
|
|
297
|
+
const patternsDir = `${project.path}/patterns`;
|
|
298
|
+
await utils.ensureDir(patternsDir);
|
|
299
|
+
const filePath = `${patternsDir}/${slug}.php`;
|
|
300
|
+
try {
|
|
301
|
+
await fs.access(filePath);
|
|
302
|
+
log('warn', `Pattern ${slug}.php already exists.`);
|
|
303
|
+
return;
|
|
304
|
+
} catch (error) {
|
|
305
|
+
//
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
const libDir = path.dirname(fileURLToPath(import.meta.url));
|
|
309
|
+
const templatePath = path.resolve(libDir, 'templates/pattern/pattern.php');
|
|
310
|
+
let template = await fs.readFile(templatePath, 'utf8');
|
|
311
|
+
template = template.replace(/Title:\s.*$/m, `Title: ${name}`);
|
|
312
|
+
template = template.replace(/Slug:\s.*$/m, `Slug: custom/${slug}`);
|
|
313
|
+
await fs.writeFile(filePath, template);
|
|
314
|
+
log('success', `Created pattern at patterns/${slug}.php`);
|
|
315
|
+
if (project.components.php?.watcher) {
|
|
316
|
+
project.components.php.watcher.add(filePath);
|
|
317
|
+
} else if (project.components.php?.globs && !project.components.php.globs.includes(filePath)) {
|
|
318
|
+
project.components.php.globs.push(filePath);
|
|
319
|
+
}
|
|
320
|
+
} catch (error) {
|
|
321
|
+
console.error(error);
|
|
322
|
+
log('error', `Failed to create pattern`);
|
|
323
|
+
}
|
|
324
|
+
} else if (typeKey === 's') {
|
|
325
|
+
let name;
|
|
326
|
+
try { name = await input({ message: 'Style variation name:' }); } catch (error) { return; }
|
|
327
|
+
if (!name) { log('warn', 'No name provided.'); return; }
|
|
328
|
+
const slug = utils.slugify(name);
|
|
329
|
+
const stylesDir = `${project.path}/styles`;
|
|
330
|
+
await utils.ensureDir(stylesDir);
|
|
331
|
+
const filePath = `${stylesDir}/${slug}.json`;
|
|
332
|
+
try {
|
|
333
|
+
await fs.access(filePath);
|
|
334
|
+
log('warn', `Style variation ${slug}.json already exists.`);
|
|
335
|
+
return;
|
|
336
|
+
} catch (error) {
|
|
337
|
+
|
|
338
|
+
}
|
|
339
|
+
try {
|
|
340
|
+
const libDir = path.dirname(fileURLToPath(import.meta.url));
|
|
341
|
+
const templatePath = path.resolve(libDir, 'templates/style/style.json');
|
|
342
|
+
let templateRaw = await fs.readFile(templatePath, 'utf8');
|
|
343
|
+
let templateObj;
|
|
344
|
+
try {
|
|
345
|
+
templateObj = JSON.parse(templateRaw);
|
|
346
|
+
} catch (error) {
|
|
347
|
+
console.error(error);
|
|
348
|
+
throw new Error('Invalid style variation template JSON');
|
|
349
|
+
}
|
|
350
|
+
templateObj.title = name;
|
|
351
|
+
templateObj.slug = slug;
|
|
352
|
+
await fs.writeFile(filePath, JSON.stringify(templateObj, null, '\t'));
|
|
353
|
+
log('success', `Created style variation at styles/${slug}.json`);
|
|
354
|
+
} catch (error) {
|
|
355
|
+
console.error(error);
|
|
356
|
+
log('error', `Failed to create style variation`);
|
|
357
|
+
}
|
|
358
|
+
}
|
|
208
359
|
}
|
|
209
360
|
|
|
210
361
|
export async function convertPackageToConfig() {
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { registerBlockType } from '@wordpress/blocks';
|
|
2
|
+
import { useBlockProps } from '@wordpress/block-editor';
|
|
3
|
+
|
|
4
|
+
import metadata from './block.json';
|
|
5
|
+
|
|
6
|
+
// import './style.scss';
|
|
7
|
+
// import './editor.scss';
|
|
8
|
+
|
|
9
|
+
registerBlockType(metadata.name, {
|
|
10
|
+
edit: ({ attributes, setAttributes }) => {
|
|
11
|
+
const blockProps = useBlockProps();
|
|
12
|
+
return (
|
|
13
|
+
<div { ...blockProps }><em>Placeholder for {metadata.title}</em></div>
|
|
14
|
+
);
|
|
15
|
+
},
|
|
16
|
+
save: ({ attributes }) => {
|
|
17
|
+
return null;
|
|
18
|
+
},
|
|
19
|
+
});
|
package/lib/utils.js
CHANGED
|
@@ -3,6 +3,7 @@ import { promises as fs } from 'fs';
|
|
|
3
3
|
import { readdir } from 'node:fs/promises';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import project from './project.js';
|
|
6
|
+
import log from './logging.js';
|
|
6
7
|
|
|
7
8
|
export async function getThisPackageVersion() {
|
|
8
9
|
return JSON.parse(await fs.readFile(path.join(path.dirname(fileURLToPath(import.meta.url)), '../package.json'))).version
|
|
@@ -197,3 +198,23 @@ export function addEntriesByFiletypes(filetypes = []) {
|
|
|
197
198
|
}
|
|
198
199
|
return finalFiles;
|
|
199
200
|
}
|
|
201
|
+
|
|
202
|
+
export function slugify(str) {
|
|
203
|
+
return str
|
|
204
|
+
.toLowerCase()
|
|
205
|
+
.replace(/[^a-z0-9\s-]/g, '')
|
|
206
|
+
.trim()
|
|
207
|
+
.replace(/\s+/g, '-')
|
|
208
|
+
.replace(/-+/g, '-');
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
export async function ensureDir(dir) {
|
|
212
|
+
try {
|
|
213
|
+
await fs.mkdir(dir, { recursive: true });
|
|
214
|
+
return true;
|
|
215
|
+
} catch (error) {
|
|
216
|
+
console.error(error);
|
|
217
|
+
log('error', `Failed to create directory ${dir}`);
|
|
218
|
+
return false;
|
|
219
|
+
}
|
|
220
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sdc-build-wp",
|
|
3
|
-
"version": "5.0
|
|
3
|
+
"version": "5.1.0",
|
|
4
4
|
"description": "Custom WordPress build process.",
|
|
5
5
|
"engines": {
|
|
6
6
|
"node": ">=22"
|
|
@@ -22,24 +22,25 @@
|
|
|
22
22
|
"sdc-build-wp": "./index.js"
|
|
23
23
|
},
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"@
|
|
25
|
+
"@inquirer/prompts": "^7.8.1",
|
|
26
|
+
"@stylistic/eslint-plugin": "^5.2.3",
|
|
26
27
|
"@stylistic/stylelint-plugin": "^4.0.0",
|
|
27
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
28
|
-
"@typescript-eslint/parser": "^8.
|
|
29
|
-
"@wordpress/scripts": "^30.
|
|
28
|
+
"@typescript-eslint/eslint-plugin": "^8.39.0",
|
|
29
|
+
"@typescript-eslint/parser": "^8.39.0",
|
|
30
|
+
"@wordpress/scripts": "^30.21.0",
|
|
30
31
|
"autoprefixer": "^10.4.21",
|
|
31
32
|
"browser-sync": "^3.0.4",
|
|
32
|
-
"chalk": "^5.
|
|
33
|
+
"chalk": "^5.5.0",
|
|
33
34
|
"chokidar": "^4.0.3",
|
|
34
35
|
"esbuild": "^0.25.8",
|
|
35
|
-
"eslint": "^9.
|
|
36
|
-
"fs-extra": "^11.3.
|
|
36
|
+
"eslint": "^9.33.0",
|
|
37
|
+
"fs-extra": "^11.3.1",
|
|
37
38
|
"postcss": "^8.5.6",
|
|
38
39
|
"postcss-scss": "^4.0.9",
|
|
39
40
|
"postcss-sort-media-queries": "^5.2.0",
|
|
40
|
-
"sass": "^1.
|
|
41
|
+
"sass": "^1.90.0",
|
|
41
42
|
"sharp": "^0.34.3",
|
|
42
|
-
"stylelint": "^16.23.
|
|
43
|
+
"stylelint": "^16.23.1",
|
|
43
44
|
"svgo": "^4.0.0",
|
|
44
45
|
"tail": "^2.2.6",
|
|
45
46
|
"yargs": "^18.0.0"
|