@wp-typia/project-tools 0.12.0 → 0.13.1
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/dist/runtime/cli-add.d.ts +51 -1
- package/dist/runtime/cli-add.js +339 -2
- package/dist/runtime/cli-core.d.ts +5 -1
- package/dist/runtime/cli-core.js +4 -1
- package/dist/runtime/cli-doctor.js +78 -1
- package/dist/runtime/cli-help.js +4 -0
- package/dist/runtime/hooked-blocks.d.ts +17 -0
- package/dist/runtime/hooked-blocks.js +13 -0
- package/dist/runtime/index.d.ts +5 -4
- package/dist/runtime/index.js +4 -3
- package/dist/runtime/workspace-inventory.d.ts +10 -1
- package/dist/runtime/workspace-inventory.js +55 -19
- package/package.json +2 -2
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { getWorkspaceBlockSelectOptions } from "./workspace-inventory.js";
|
|
2
|
+
import { type HookedBlockPositionId } from "./hooked-blocks.js";
|
|
2
3
|
/**
|
|
3
4
|
* Supported top-level `wp-typia add` kinds exposed by the canonical CLI.
|
|
4
5
|
*/
|
|
5
|
-
export declare const ADD_KIND_IDS: readonly ["block", "variation", "pattern"];
|
|
6
|
+
export declare const ADD_KIND_IDS: readonly ["block", "variation", "pattern", "binding-source", "hooked-block"];
|
|
6
7
|
export type AddKindId = (typeof ADD_KIND_IDS)[number];
|
|
7
8
|
/**
|
|
8
9
|
* Supported built-in block families accepted by `wp-typia add block --template`.
|
|
@@ -18,6 +19,16 @@ interface RunAddPatternCommandOptions {
|
|
|
18
19
|
cwd?: string;
|
|
19
20
|
patternName: string;
|
|
20
21
|
}
|
|
22
|
+
interface RunAddBindingSourceCommandOptions {
|
|
23
|
+
bindingSourceName: string;
|
|
24
|
+
cwd?: string;
|
|
25
|
+
}
|
|
26
|
+
interface RunAddHookedBlockCommandOptions {
|
|
27
|
+
anchorBlockName: string;
|
|
28
|
+
blockName: string;
|
|
29
|
+
cwd?: string;
|
|
30
|
+
position: string;
|
|
31
|
+
}
|
|
21
32
|
interface RunAddBlockCommandOptions {
|
|
22
33
|
blockName: string;
|
|
23
34
|
cwd?: string;
|
|
@@ -81,4 +92,43 @@ export declare function runAddPatternCommand({ cwd, patternName, }: RunAddPatter
|
|
|
81
92
|
patternSlug: string;
|
|
82
93
|
projectDir: string;
|
|
83
94
|
}>;
|
|
95
|
+
/**
|
|
96
|
+
* Add one block binding source scaffold to an official workspace project.
|
|
97
|
+
*
|
|
98
|
+
* @param options Command options for the binding-source scaffold workflow.
|
|
99
|
+
* @param options.bindingSourceName Human-entered binding source name that will
|
|
100
|
+
* be normalized and validated before files are written.
|
|
101
|
+
* @param options.cwd Working directory used to resolve the nearest official
|
|
102
|
+
* workspace. Defaults to `process.cwd()`.
|
|
103
|
+
* @returns A promise that resolves with the normalized `bindingSourceSlug` and
|
|
104
|
+
* owning `projectDir` after the server/editor files and inventory entry have
|
|
105
|
+
* been written successfully.
|
|
106
|
+
* @throws {Error} When the command is run outside an official workspace, when
|
|
107
|
+
* the slug is invalid, or when a conflicting file or inventory entry exists.
|
|
108
|
+
*/
|
|
109
|
+
export declare function runAddBindingSourceCommand({ bindingSourceName, cwd, }: RunAddBindingSourceCommandOptions): Promise<{
|
|
110
|
+
bindingSourceSlug: string;
|
|
111
|
+
projectDir: string;
|
|
112
|
+
}>;
|
|
113
|
+
/**
|
|
114
|
+
* Add one `blockHooks` entry to an existing official workspace block.
|
|
115
|
+
*
|
|
116
|
+
* @param options Command options for the hooked-block workflow.
|
|
117
|
+
* @param options.anchorBlockName Full block name that will anchor the insertion.
|
|
118
|
+
* @param options.blockName Existing workspace block slug to patch.
|
|
119
|
+
* @param options.cwd Working directory used to resolve the nearest official workspace.
|
|
120
|
+
* Defaults to `process.cwd()`.
|
|
121
|
+
* @param options.position Hook position to store in `block.json`.
|
|
122
|
+
* @returns A promise that resolves with the normalized target block slug, anchor
|
|
123
|
+
* block name, position, and owning project directory after `block.json` is written.
|
|
124
|
+
* @throws {Error} When the command is run outside an official workspace, when
|
|
125
|
+
* the target block is unknown, when required flags are missing, or when the
|
|
126
|
+
* block already defines a hook for the requested anchor.
|
|
127
|
+
*/
|
|
128
|
+
export declare function runAddHookedBlockCommand({ anchorBlockName, blockName, cwd, position, }: RunAddHookedBlockCommandOptions): Promise<{
|
|
129
|
+
anchorBlockName: string;
|
|
130
|
+
blockSlug: string;
|
|
131
|
+
position: HookedBlockPositionId;
|
|
132
|
+
projectDir: string;
|
|
133
|
+
}>;
|
|
84
134
|
export { getWorkspaceBlockSelectOptions };
|
package/dist/runtime/cli-add.js
CHANGED
|
@@ -10,11 +10,12 @@ import { SHARED_WORKSPACE_TEMPLATE_ROOT, } from "./template-registry.js";
|
|
|
10
10
|
import { copyInterpolatedDirectory } from "./template-render.js";
|
|
11
11
|
import { toKebabCase, toTitleCase, toSnakeCase, } from "./string-case.js";
|
|
12
12
|
import { appendWorkspaceInventoryEntries, getWorkspaceBlockSelectOptions, readWorkspaceInventory, } from "./workspace-inventory.js";
|
|
13
|
+
import { HOOKED_BLOCK_ANCHOR_PATTERN, HOOKED_BLOCK_POSITION_IDS, } from "./hooked-blocks.js";
|
|
13
14
|
import { resolveWorkspaceProject, WORKSPACE_TEMPLATE_PACKAGE, } from "./workspace-project.js";
|
|
14
15
|
/**
|
|
15
16
|
* Supported top-level `wp-typia add` kinds exposed by the canonical CLI.
|
|
16
17
|
*/
|
|
17
|
-
export const ADD_KIND_IDS = ["block", "variation", "pattern"];
|
|
18
|
+
export const ADD_KIND_IDS = ["block", "variation", "pattern", "binding-source", "hooked-block"];
|
|
18
19
|
/**
|
|
19
20
|
* Supported built-in block families accepted by `wp-typia add block --template`.
|
|
20
21
|
*/
|
|
@@ -29,6 +30,9 @@ const REST_MANIFEST_IMPORT_PATTERN = /import\s*\{[^}]*\bdefineEndpointManifest\b
|
|
|
29
30
|
const VARIATIONS_IMPORT_LINE = "import { registerWorkspaceVariations } from './variations';";
|
|
30
31
|
const VARIATIONS_CALL_LINE = "registerWorkspaceVariations();";
|
|
31
32
|
const PATTERN_BOOTSTRAP_CATEGORY = "register_block_pattern_category";
|
|
33
|
+
const BINDING_SOURCE_SERVER_GLOB = "/src/bindings/*/server.php";
|
|
34
|
+
const BINDING_SOURCE_EDITOR_SCRIPT = "build/bindings/index.js";
|
|
35
|
+
const BINDING_SOURCE_EDITOR_ASSET = "build/bindings/index.asset.php";
|
|
32
36
|
const WORKSPACE_GENERATED_SLUG_PATTERN = /^[a-z][a-z0-9-]*$/;
|
|
33
37
|
function normalizeBlockSlug(input) {
|
|
34
38
|
return toKebabCase(input);
|
|
@@ -42,6 +46,12 @@ function assertValidGeneratedSlug(label, slug, usage) {
|
|
|
42
46
|
}
|
|
43
47
|
return slug;
|
|
44
48
|
}
|
|
49
|
+
function assertValidHookedBlockPosition(position) {
|
|
50
|
+
if (HOOKED_BLOCK_POSITION_IDS.includes(position)) {
|
|
51
|
+
return position;
|
|
52
|
+
}
|
|
53
|
+
throw new Error(`Hook position must be one of: ${HOOKED_BLOCK_POSITION_IDS.join(", ")}.`);
|
|
54
|
+
}
|
|
45
55
|
function getWorkspaceBootstrapPath(workspace) {
|
|
46
56
|
const workspaceBaseName = workspace.packageName.split("/").pop() ?? workspace.packageName;
|
|
47
57
|
return path.join(workspace.projectDir, `${workspaceBaseName}.php`);
|
|
@@ -284,6 +294,15 @@ function buildPatternConfigEntry(patternSlug) {
|
|
|
284
294
|
"\t},",
|
|
285
295
|
].join("\n");
|
|
286
296
|
}
|
|
297
|
+
function buildBindingSourceConfigEntry(bindingSourceSlug) {
|
|
298
|
+
return [
|
|
299
|
+
"\t{",
|
|
300
|
+
`\t\teditorFile: ${quoteTsString(`src/bindings/${bindingSourceSlug}/editor.ts`)},`,
|
|
301
|
+
`\t\tserverFile: ${quoteTsString(`src/bindings/${bindingSourceSlug}/server.php`)},`,
|
|
302
|
+
`\t\tslug: ${quoteTsString(bindingSourceSlug)},`,
|
|
303
|
+
"\t},",
|
|
304
|
+
].join("\n");
|
|
305
|
+
}
|
|
287
306
|
function buildVariationConstName(variationSlug) {
|
|
288
307
|
const identifierSegments = toKebabCase(variationSlug)
|
|
289
308
|
.split("-")
|
|
@@ -364,6 +383,70 @@ register_block_pattern(
|
|
|
364
383
|
);
|
|
365
384
|
`;
|
|
366
385
|
}
|
|
386
|
+
function buildBindingSourceServerSource(bindingSourceSlug, namespace, textDomain) {
|
|
387
|
+
const bindingSourceTitle = toTitleCase(bindingSourceSlug);
|
|
388
|
+
return `<?php
|
|
389
|
+
if ( ! defined( 'ABSPATH' ) ) {
|
|
390
|
+
\treturn;
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
if ( ! function_exists( 'register_block_bindings_source' ) ) {
|
|
394
|
+
\treturn;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
register_block_bindings_source(
|
|
398
|
+
\t'${namespace}/${bindingSourceSlug}',
|
|
399
|
+
\tarray(
|
|
400
|
+
\t\t'label' => __( ${JSON.stringify(bindingSourceTitle)}, '${textDomain}' ),
|
|
401
|
+
\t\t'get_value_callback' => static function( array $source_args ) : string {
|
|
402
|
+
\t\t\t$field = isset( $source_args['field'] ) && is_string( $source_args['field'] )
|
|
403
|
+
\t\t\t\t? $source_args['field']
|
|
404
|
+
\t\t\t\t: '${bindingSourceSlug}';
|
|
405
|
+
|
|
406
|
+
\t\t\treturn sprintf(
|
|
407
|
+
\t\t\t\t__( 'Replace %s with real binding source data.', '${textDomain}' ),
|
|
408
|
+
\t\t\t\t$field
|
|
409
|
+
\t\t\t);
|
|
410
|
+
\t\t},
|
|
411
|
+
\t)
|
|
412
|
+
);
|
|
413
|
+
`;
|
|
414
|
+
}
|
|
415
|
+
function buildBindingSourceEditorSource(bindingSourceSlug, namespace, textDomain) {
|
|
416
|
+
const bindingSourceTitle = toTitleCase(bindingSourceSlug);
|
|
417
|
+
return `import { registerBlockBindingsSource } from '@wordpress/blocks';
|
|
418
|
+
import { __ } from '@wordpress/i18n';
|
|
419
|
+
|
|
420
|
+
registerBlockBindingsSource( {
|
|
421
|
+
\tname: ${quoteTsString(`${namespace}/${bindingSourceSlug}`)},
|
|
422
|
+
\tlabel: __( ${quoteTsString(bindingSourceTitle)}, ${quoteTsString(textDomain)} ),
|
|
423
|
+
\tgetFieldsList() {
|
|
424
|
+
\t\treturn [
|
|
425
|
+
\t\t\t{
|
|
426
|
+
\t\t\t\tlabel: __( ${quoteTsString(bindingSourceTitle)}, ${quoteTsString(textDomain)} ),
|
|
427
|
+
\t\t\t\ttype: 'string',
|
|
428
|
+
\t\t\t\targs: {
|
|
429
|
+
\t\t\t\t\tfield: ${quoteTsString(bindingSourceSlug)},
|
|
430
|
+
\t\t\t\t},
|
|
431
|
+
\t\t\t},
|
|
432
|
+
\t\t];
|
|
433
|
+
\t},
|
|
434
|
+
\tgetValues( { bindings } ) {
|
|
435
|
+
\t\tconst values: Record<string, string> = {};
|
|
436
|
+
\t\tfor ( const attributeName of Object.keys( bindings ) ) {
|
|
437
|
+
\t\t\tvalues[ attributeName ] = ${quoteTsString(`TODO: replace ${bindingSourceSlug} with real editor-side values.`)};
|
|
438
|
+
\t\t}
|
|
439
|
+
\t\treturn values;
|
|
440
|
+
\t},
|
|
441
|
+
} );
|
|
442
|
+
`;
|
|
443
|
+
}
|
|
444
|
+
function buildBindingSourceIndexSource(bindingSourceSlugs) {
|
|
445
|
+
const importLines = bindingSourceSlugs
|
|
446
|
+
.map((bindingSourceSlug) => `import './${bindingSourceSlug}/editor';`)
|
|
447
|
+
.join("\n");
|
|
448
|
+
return `${importLines}${importLines ? "\n\n" : ""}// wp-typia add binding-source entries\n`;
|
|
449
|
+
}
|
|
367
450
|
async function ensureVariationRegistrationHook(blockIndexPath) {
|
|
368
451
|
await patchFile(blockIndexPath, (source) => {
|
|
369
452
|
let nextSource = source;
|
|
@@ -466,6 +549,85 @@ function ${patternRegistrationFunctionName}() {
|
|
|
466
549
|
return nextSource;
|
|
467
550
|
});
|
|
468
551
|
}
|
|
552
|
+
async function ensureBindingSourceBootstrapAnchors(workspace) {
|
|
553
|
+
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
554
|
+
await patchFile(bootstrapPath, (source) => {
|
|
555
|
+
let nextSource = source;
|
|
556
|
+
const workspaceBaseName = workspace.packageName.split("/").pop() ?? workspace.packageName;
|
|
557
|
+
const bindingRegistrationFunctionName = `${workspace.workspace.phpPrefix}_register_binding_sources`;
|
|
558
|
+
const bindingEditorEnqueueFunctionName = `${workspace.workspace.phpPrefix}_enqueue_binding_sources_editor`;
|
|
559
|
+
const bindingRegistrationHook = `add_action( 'init', '${bindingRegistrationFunctionName}', 20 );`;
|
|
560
|
+
const bindingEditorEnqueueHook = `add_action( 'enqueue_block_editor_assets', '${bindingEditorEnqueueFunctionName}' );`;
|
|
561
|
+
const bindingRegistrationFunction = `
|
|
562
|
+
|
|
563
|
+
function ${bindingRegistrationFunctionName}() {
|
|
564
|
+
\tforeach ( glob( __DIR__ . '${BINDING_SOURCE_SERVER_GLOB}' ) ?: array() as $binding_source_module ) {
|
|
565
|
+
\t\trequire_once $binding_source_module;
|
|
566
|
+
\t}
|
|
567
|
+
}
|
|
568
|
+
`;
|
|
569
|
+
const bindingEditorEnqueueFunction = `
|
|
570
|
+
|
|
571
|
+
function ${bindingEditorEnqueueFunctionName}() {
|
|
572
|
+
\t$script_path = __DIR__ . '/${BINDING_SOURCE_EDITOR_SCRIPT}';
|
|
573
|
+
\t$asset_path = __DIR__ . '/${BINDING_SOURCE_EDITOR_ASSET}';
|
|
574
|
+
|
|
575
|
+
\tif ( ! file_exists( $script_path ) || ! file_exists( $asset_path ) ) {
|
|
576
|
+
\t\treturn;
|
|
577
|
+
\t}
|
|
578
|
+
|
|
579
|
+
\t$asset = require $asset_path;
|
|
580
|
+
\tif ( ! is_array( $asset ) ) {
|
|
581
|
+
\t\t$asset = array();
|
|
582
|
+
\t}
|
|
583
|
+
|
|
584
|
+
\twp_enqueue_script(
|
|
585
|
+
\t\t'${workspaceBaseName}-binding-sources',
|
|
586
|
+
\t\tplugins_url( '${BINDING_SOURCE_EDITOR_SCRIPT}', __FILE__ ),
|
|
587
|
+
\t\tisset( $asset['dependencies'] ) && is_array( $asset['dependencies'] ) ? $asset['dependencies'] : array(),
|
|
588
|
+
\t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $script_path ),
|
|
589
|
+
\t\ttrue
|
|
590
|
+
\t);
|
|
591
|
+
}
|
|
592
|
+
`;
|
|
593
|
+
const insertionAnchors = [
|
|
594
|
+
/add_action\(\s*["']init["']\s*,\s*["'][^"']+_load_textdomain["']\s*\);\s*\n/u,
|
|
595
|
+
/\?>\s*$/u,
|
|
596
|
+
];
|
|
597
|
+
const hasPhpFunctionDefinition = (functionName) => new RegExp(`function\\s+${functionName}\\s*\\(`, "u").test(nextSource);
|
|
598
|
+
const insertPhpSnippet = (snippet) => {
|
|
599
|
+
for (const anchor of insertionAnchors) {
|
|
600
|
+
const candidate = nextSource.replace(anchor, (match) => `${snippet}\n${match}`);
|
|
601
|
+
if (candidate !== nextSource) {
|
|
602
|
+
nextSource = candidate;
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
nextSource = `${nextSource.trimEnd()}\n${snippet}\n`;
|
|
607
|
+
};
|
|
608
|
+
const appendPhpSnippet = (snippet) => {
|
|
609
|
+
const closingTagPattern = /\?>\s*$/u;
|
|
610
|
+
if (closingTagPattern.test(nextSource)) {
|
|
611
|
+
nextSource = nextSource.replace(closingTagPattern, `${snippet}\n?>`);
|
|
612
|
+
return;
|
|
613
|
+
}
|
|
614
|
+
nextSource = `${nextSource.trimEnd()}\n${snippet}\n`;
|
|
615
|
+
};
|
|
616
|
+
if (!hasPhpFunctionDefinition(bindingRegistrationFunctionName)) {
|
|
617
|
+
insertPhpSnippet(bindingRegistrationFunction);
|
|
618
|
+
}
|
|
619
|
+
if (!hasPhpFunctionDefinition(bindingEditorEnqueueFunctionName)) {
|
|
620
|
+
insertPhpSnippet(bindingEditorEnqueueFunction);
|
|
621
|
+
}
|
|
622
|
+
if (!nextSource.includes(bindingRegistrationHook)) {
|
|
623
|
+
appendPhpSnippet(bindingRegistrationHook);
|
|
624
|
+
}
|
|
625
|
+
if (!nextSource.includes(bindingEditorEnqueueHook)) {
|
|
626
|
+
appendPhpSnippet(bindingEditorEnqueueHook);
|
|
627
|
+
}
|
|
628
|
+
return nextSource;
|
|
629
|
+
});
|
|
630
|
+
}
|
|
469
631
|
function ensureBlockConfigCanAddRestManifests(source) {
|
|
470
632
|
const importLine = "import { defineEndpointManifest } from '@wp-typia/block-runtime/metadata-core';";
|
|
471
633
|
if (REST_MANIFEST_IMPORT_PATTERN.test(source)) {
|
|
@@ -479,6 +641,23 @@ async function appendBlockConfigEntries(projectDir, entries, needsRestManifestIm
|
|
|
479
641
|
transformSource: needsRestManifestImport ? ensureBlockConfigCanAddRestManifests : undefined,
|
|
480
642
|
});
|
|
481
643
|
}
|
|
644
|
+
async function writeBindingSourceRegistry(projectDir, bindingSourceSlug) {
|
|
645
|
+
const bindingsDir = path.join(projectDir, "src", "bindings");
|
|
646
|
+
const bindingsIndexPath = resolveBindingSourceRegistryPath(projectDir);
|
|
647
|
+
await fsp.mkdir(bindingsDir, { recursive: true });
|
|
648
|
+
const existingBindingSourceSlugs = fs.existsSync(bindingsDir)
|
|
649
|
+
? fs
|
|
650
|
+
.readdirSync(bindingsDir, { withFileTypes: true })
|
|
651
|
+
.filter((entry) => entry.isDirectory())
|
|
652
|
+
.map((entry) => entry.name)
|
|
653
|
+
: [];
|
|
654
|
+
const nextBindingSourceSlugs = Array.from(new Set([...existingBindingSourceSlugs, bindingSourceSlug])).sort();
|
|
655
|
+
await fsp.writeFile(bindingsIndexPath, buildBindingSourceIndexSource(nextBindingSourceSlugs), "utf8");
|
|
656
|
+
}
|
|
657
|
+
function resolveBindingSourceRegistryPath(projectDir) {
|
|
658
|
+
const bindingsDir = path.join(projectDir, "src", "bindings");
|
|
659
|
+
return [path.join(bindingsDir, "index.ts"), path.join(bindingsDir, "index.js")].find((candidatePath) => fs.existsSync(candidatePath)) ?? path.join(bindingsDir, "index.ts");
|
|
660
|
+
}
|
|
482
661
|
async function snapshotWorkspaceFiles(filePaths) {
|
|
483
662
|
const uniquePaths = Array.from(new Set(filePaths));
|
|
484
663
|
return Promise.all(uniquePaths.map(async (filePath) => ({
|
|
@@ -616,11 +795,15 @@ export function formatAddHelpText() {
|
|
|
616
795
|
wp-typia add block <name> --template <${ADD_BLOCK_TEMPLATE_IDS.join("|")}> [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>]
|
|
617
796
|
wp-typia add variation <name> --block <block-slug>
|
|
618
797
|
wp-typia add pattern <name>
|
|
798
|
+
wp-typia add binding-source <name>
|
|
799
|
+
wp-typia add hooked-block <block-slug> --anchor <anchor-block-name> --position <${HOOKED_BLOCK_POSITION_IDS.join("|")}>
|
|
619
800
|
|
|
620
801
|
Notes:
|
|
621
802
|
\`wp-typia add\` runs only inside official ${WORKSPACE_TEMPLATE_PACKAGE} workspaces.
|
|
622
803
|
\`add variation\` targets an existing block slug from \`scripts/block-config.ts\`.
|
|
623
|
-
\`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns
|
|
804
|
+
\`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/\`.
|
|
805
|
+
\`add binding-source\` scaffolds shared PHP and editor registration under \`src/bindings/\`.
|
|
806
|
+
\`add hooked-block\` patches an existing workspace block's \`block.json\` \`blockHooks\` metadata.`;
|
|
624
807
|
}
|
|
625
808
|
/**
|
|
626
809
|
* Seeds an empty official workspace migration project before any blocks are added.
|
|
@@ -728,6 +911,50 @@ function resolveWorkspaceBlock(inventory, blockSlug) {
|
|
|
728
911
|
}
|
|
729
912
|
return block;
|
|
730
913
|
}
|
|
914
|
+
function assertValidHookAnchor(anchorBlockName) {
|
|
915
|
+
const trimmed = anchorBlockName.trim();
|
|
916
|
+
if (!trimmed) {
|
|
917
|
+
throw new Error("`wp-typia add hooked-block` requires --anchor <anchor-block-name>.");
|
|
918
|
+
}
|
|
919
|
+
if (!HOOKED_BLOCK_ANCHOR_PATTERN.test(trimmed)) {
|
|
920
|
+
throw new Error("`wp-typia add hooked-block` requires --anchor <anchor-block-name> to use the full `namespace/slug` block name format.");
|
|
921
|
+
}
|
|
922
|
+
return trimmed;
|
|
923
|
+
}
|
|
924
|
+
function readWorkspaceBlockJson(projectDir, blockSlug) {
|
|
925
|
+
const blockJsonPath = path.join(projectDir, "src", "blocks", blockSlug, "block.json");
|
|
926
|
+
if (!fs.existsSync(blockJsonPath)) {
|
|
927
|
+
throw new Error(`Missing ${path.relative(projectDir, blockJsonPath)} for workspace block "${blockSlug}".`);
|
|
928
|
+
}
|
|
929
|
+
let blockJson;
|
|
930
|
+
try {
|
|
931
|
+
blockJson = JSON.parse(fs.readFileSync(blockJsonPath, "utf8"));
|
|
932
|
+
}
|
|
933
|
+
catch (error) {
|
|
934
|
+
throw new Error(error instanceof Error
|
|
935
|
+
? `Failed to parse ${path.relative(projectDir, blockJsonPath)}: ${error.message}`
|
|
936
|
+
: `Failed to parse ${path.relative(projectDir, blockJsonPath)}.`);
|
|
937
|
+
}
|
|
938
|
+
if (!blockJson || typeof blockJson !== "object" || Array.isArray(blockJson)) {
|
|
939
|
+
throw new Error(`${path.relative(projectDir, blockJsonPath)} must contain a JSON object.`);
|
|
940
|
+
}
|
|
941
|
+
return {
|
|
942
|
+
blockJson: blockJson,
|
|
943
|
+
blockJsonPath,
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
function getMutableBlockHooks(blockJson, blockJsonRelativePath) {
|
|
947
|
+
const blockHooks = blockJson.blockHooks;
|
|
948
|
+
if (blockHooks === undefined) {
|
|
949
|
+
const nextHooks = {};
|
|
950
|
+
blockJson.blockHooks = nextHooks;
|
|
951
|
+
return nextHooks;
|
|
952
|
+
}
|
|
953
|
+
if (!blockHooks || typeof blockHooks !== "object" || Array.isArray(blockHooks)) {
|
|
954
|
+
throw new Error(`${blockJsonRelativePath} must define blockHooks as an object when present.`);
|
|
955
|
+
}
|
|
956
|
+
return blockHooks;
|
|
957
|
+
}
|
|
731
958
|
function assertVariationDoesNotExist(projectDir, blockSlug, variationSlug, inventory) {
|
|
732
959
|
const variationPath = path.join(projectDir, "src", "blocks", blockSlug, "variations", `${variationSlug}.ts`);
|
|
733
960
|
if (fs.existsSync(variationPath)) {
|
|
@@ -746,6 +973,15 @@ function assertPatternDoesNotExist(projectDir, patternSlug, inventory) {
|
|
|
746
973
|
throw new Error(`A pattern inventory entry already exists for ${patternSlug}. Choose a different name.`);
|
|
747
974
|
}
|
|
748
975
|
}
|
|
976
|
+
function assertBindingSourceDoesNotExist(projectDir, bindingSourceSlug, inventory) {
|
|
977
|
+
const bindingSourceDir = path.join(projectDir, "src", "bindings", bindingSourceSlug);
|
|
978
|
+
if (fs.existsSync(bindingSourceDir)) {
|
|
979
|
+
throw new Error(`A binding source already exists at ${path.relative(projectDir, bindingSourceDir)}. Choose a different name.`);
|
|
980
|
+
}
|
|
981
|
+
if (inventory.bindingSources.some((entry) => entry.slug === bindingSourceSlug)) {
|
|
982
|
+
throw new Error(`A binding source inventory entry already exists for ${bindingSourceSlug}. Choose a different name.`);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
749
985
|
/**
|
|
750
986
|
* Add one variation entry to an existing workspace block.
|
|
751
987
|
*
|
|
@@ -847,4 +1083,105 @@ export async function runAddPatternCommand({ cwd = process.cwd(), patternName, }
|
|
|
847
1083
|
throw error;
|
|
848
1084
|
}
|
|
849
1085
|
}
|
|
1086
|
+
/**
|
|
1087
|
+
* Add one block binding source scaffold to an official workspace project.
|
|
1088
|
+
*
|
|
1089
|
+
* @param options Command options for the binding-source scaffold workflow.
|
|
1090
|
+
* @param options.bindingSourceName Human-entered binding source name that will
|
|
1091
|
+
* be normalized and validated before files are written.
|
|
1092
|
+
* @param options.cwd Working directory used to resolve the nearest official
|
|
1093
|
+
* workspace. Defaults to `process.cwd()`.
|
|
1094
|
+
* @returns A promise that resolves with the normalized `bindingSourceSlug` and
|
|
1095
|
+
* owning `projectDir` after the server/editor files and inventory entry have
|
|
1096
|
+
* been written successfully.
|
|
1097
|
+
* @throws {Error} When the command is run outside an official workspace, when
|
|
1098
|
+
* the slug is invalid, or when a conflicting file or inventory entry exists.
|
|
1099
|
+
*/
|
|
1100
|
+
export async function runAddBindingSourceCommand({ bindingSourceName, cwd = process.cwd(), }) {
|
|
1101
|
+
const workspace = resolveWorkspaceProject(cwd);
|
|
1102
|
+
const bindingSourceSlug = assertValidGeneratedSlug("Binding source name", normalizeBlockSlug(bindingSourceName), "wp-typia add binding-source <name>");
|
|
1103
|
+
const inventory = readWorkspaceInventory(workspace.projectDir);
|
|
1104
|
+
assertBindingSourceDoesNotExist(workspace.projectDir, bindingSourceSlug, inventory);
|
|
1105
|
+
const blockConfigPath = path.join(workspace.projectDir, "scripts", "block-config.ts");
|
|
1106
|
+
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
1107
|
+
const bindingsIndexPath = resolveBindingSourceRegistryPath(workspace.projectDir);
|
|
1108
|
+
const bindingSourceDir = path.join(workspace.projectDir, "src", "bindings", bindingSourceSlug);
|
|
1109
|
+
const serverFilePath = path.join(bindingSourceDir, "server.php");
|
|
1110
|
+
const editorFilePath = path.join(bindingSourceDir, "editor.ts");
|
|
1111
|
+
const mutationSnapshot = {
|
|
1112
|
+
fileSources: await snapshotWorkspaceFiles([blockConfigPath, bootstrapPath, bindingsIndexPath]),
|
|
1113
|
+
snapshotDirs: [],
|
|
1114
|
+
targetPaths: [bindingSourceDir],
|
|
1115
|
+
};
|
|
1116
|
+
try {
|
|
1117
|
+
await fsp.mkdir(bindingSourceDir, { recursive: true });
|
|
1118
|
+
await ensureBindingSourceBootstrapAnchors(workspace);
|
|
1119
|
+
await fsp.writeFile(serverFilePath, buildBindingSourceServerSource(bindingSourceSlug, workspace.workspace.namespace, workspace.workspace.textDomain), "utf8");
|
|
1120
|
+
await fsp.writeFile(editorFilePath, buildBindingSourceEditorSource(bindingSourceSlug, workspace.workspace.namespace, workspace.workspace.textDomain), "utf8");
|
|
1121
|
+
await writeBindingSourceRegistry(workspace.projectDir, bindingSourceSlug);
|
|
1122
|
+
await appendWorkspaceInventoryEntries(workspace.projectDir, {
|
|
1123
|
+
bindingSourceEntries: [buildBindingSourceConfigEntry(bindingSourceSlug)],
|
|
1124
|
+
});
|
|
1125
|
+
return {
|
|
1126
|
+
bindingSourceSlug,
|
|
1127
|
+
projectDir: workspace.projectDir,
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
catch (error) {
|
|
1131
|
+
await rollbackWorkspaceMutation(mutationSnapshot);
|
|
1132
|
+
throw error;
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Add one `blockHooks` entry to an existing official workspace block.
|
|
1137
|
+
*
|
|
1138
|
+
* @param options Command options for the hooked-block workflow.
|
|
1139
|
+
* @param options.anchorBlockName Full block name that will anchor the insertion.
|
|
1140
|
+
* @param options.blockName Existing workspace block slug to patch.
|
|
1141
|
+
* @param options.cwd Working directory used to resolve the nearest official workspace.
|
|
1142
|
+
* Defaults to `process.cwd()`.
|
|
1143
|
+
* @param options.position Hook position to store in `block.json`.
|
|
1144
|
+
* @returns A promise that resolves with the normalized target block slug, anchor
|
|
1145
|
+
* block name, position, and owning project directory after `block.json` is written.
|
|
1146
|
+
* @throws {Error} When the command is run outside an official workspace, when
|
|
1147
|
+
* the target block is unknown, when required flags are missing, or when the
|
|
1148
|
+
* block already defines a hook for the requested anchor.
|
|
1149
|
+
*/
|
|
1150
|
+
export async function runAddHookedBlockCommand({ anchorBlockName, blockName, cwd = process.cwd(), position, }) {
|
|
1151
|
+
const workspace = resolveWorkspaceProject(cwd);
|
|
1152
|
+
const blockSlug = normalizeBlockSlug(blockName);
|
|
1153
|
+
const inventory = readWorkspaceInventory(workspace.projectDir);
|
|
1154
|
+
resolveWorkspaceBlock(inventory, blockSlug);
|
|
1155
|
+
const resolvedAnchorBlockName = assertValidHookAnchor(anchorBlockName);
|
|
1156
|
+
const resolvedPosition = assertValidHookedBlockPosition(position);
|
|
1157
|
+
const selfHookAnchor = `${workspace.workspace.namespace}/${blockSlug}`;
|
|
1158
|
+
if (resolvedAnchorBlockName === selfHookAnchor) {
|
|
1159
|
+
throw new Error("`wp-typia add hooked-block` cannot hook a block relative to its own block name.");
|
|
1160
|
+
}
|
|
1161
|
+
const { blockJson, blockJsonPath } = readWorkspaceBlockJson(workspace.projectDir, blockSlug);
|
|
1162
|
+
const blockJsonRelativePath = path.relative(workspace.projectDir, blockJsonPath);
|
|
1163
|
+
const blockHooks = getMutableBlockHooks(blockJson, blockJsonRelativePath);
|
|
1164
|
+
if (Object.prototype.hasOwnProperty.call(blockHooks, resolvedAnchorBlockName)) {
|
|
1165
|
+
throw new Error(`${blockJsonRelativePath} already defines a blockHooks entry for "${resolvedAnchorBlockName}".`);
|
|
1166
|
+
}
|
|
1167
|
+
const mutationSnapshot = {
|
|
1168
|
+
fileSources: await snapshotWorkspaceFiles([blockJsonPath]),
|
|
1169
|
+
snapshotDirs: [],
|
|
1170
|
+
targetPaths: [],
|
|
1171
|
+
};
|
|
1172
|
+
try {
|
|
1173
|
+
blockHooks[resolvedAnchorBlockName] = resolvedPosition;
|
|
1174
|
+
await fsp.writeFile(blockJsonPath, JSON.stringify(blockJson, null, "\t"), "utf8");
|
|
1175
|
+
return {
|
|
1176
|
+
anchorBlockName: resolvedAnchorBlockName,
|
|
1177
|
+
blockSlug,
|
|
1178
|
+
position: resolvedPosition,
|
|
1179
|
+
projectDir: workspace.projectDir,
|
|
1180
|
+
};
|
|
1181
|
+
}
|
|
1182
|
+
catch (error) {
|
|
1183
|
+
await rollbackWorkspaceMutation(mutationSnapshot);
|
|
1184
|
+
throw error;
|
|
1185
|
+
}
|
|
1186
|
+
}
|
|
850
1187
|
export { getWorkspaceBlockSelectOptions };
|
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Import `formatAddHelpText`, `runAddBlockCommand`,
|
|
9
9
|
* `runAddVariationCommand`, `runAddPatternCommand`,
|
|
10
|
+
* `runAddBindingSourceCommand`, `runAddHookedBlockCommand`,
|
|
11
|
+
* and `HOOKED_BLOCK_POSITION_IDS`,
|
|
10
12
|
* `getWorkspaceBlockSelectOptions`, and `seedWorkspaceMigrationProject` for
|
|
11
13
|
* explicit `wp-typia add` flows,
|
|
12
14
|
* `getDoctorChecks`, `runDoctor`, and `DoctorCheck` for diagnostics,
|
|
@@ -19,7 +21,9 @@
|
|
|
19
21
|
* template inspection flows.
|
|
20
22
|
*/
|
|
21
23
|
export { getDoctorChecks, runDoctor, type DoctorCheck } from "./cli-doctor.js";
|
|
22
|
-
export { formatAddHelpText, getWorkspaceBlockSelectOptions, runAddBlockCommand, runAddPatternCommand, runAddVariationCommand, seedWorkspaceMigrationProject, } from "./cli-add.js";
|
|
24
|
+
export { formatAddHelpText, getWorkspaceBlockSelectOptions, runAddBindingSourceCommand, runAddBlockCommand, runAddHookedBlockCommand, runAddPatternCommand, runAddVariationCommand, seedWorkspaceMigrationProject, } from "./cli-add.js";
|
|
25
|
+
export { HOOKED_BLOCK_POSITION_IDS } from "./hooked-blocks.js";
|
|
26
|
+
export type { HookedBlockPositionId } from "./hooked-blocks.js";
|
|
23
27
|
export { formatHelpText } from "./cli-help.js";
|
|
24
28
|
export { getNextSteps, getOptionalOnboarding, runScaffoldFlow, } from "./cli-scaffold.js";
|
|
25
29
|
export { createReadlinePrompt, type ReadlinePrompt } from "./cli-prompt.js";
|
package/dist/runtime/cli-core.js
CHANGED
|
@@ -7,6 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Import `formatAddHelpText`, `runAddBlockCommand`,
|
|
9
9
|
* `runAddVariationCommand`, `runAddPatternCommand`,
|
|
10
|
+
* `runAddBindingSourceCommand`, `runAddHookedBlockCommand`,
|
|
11
|
+
* and `HOOKED_BLOCK_POSITION_IDS`,
|
|
10
12
|
* `getWorkspaceBlockSelectOptions`, and `seedWorkspaceMigrationProject` for
|
|
11
13
|
* explicit `wp-typia add` flows,
|
|
12
14
|
* `getDoctorChecks`, `runDoctor`, and `DoctorCheck` for diagnostics,
|
|
@@ -19,7 +21,8 @@
|
|
|
19
21
|
* template inspection flows.
|
|
20
22
|
*/
|
|
21
23
|
export { getDoctorChecks, runDoctor } from "./cli-doctor.js";
|
|
22
|
-
export { formatAddHelpText, getWorkspaceBlockSelectOptions, runAddBlockCommand, runAddPatternCommand, runAddVariationCommand, seedWorkspaceMigrationProject, } from "./cli-add.js";
|
|
24
|
+
export { formatAddHelpText, getWorkspaceBlockSelectOptions, runAddBindingSourceCommand, runAddBlockCommand, runAddHookedBlockCommand, runAddPatternCommand, runAddVariationCommand, seedWorkspaceMigrationProject, } from "./cli-add.js";
|
|
25
|
+
export { HOOKED_BLOCK_POSITION_IDS } from "./hooked-blocks.js";
|
|
23
26
|
export { formatHelpText } from "./cli-help.js";
|
|
24
27
|
export { getNextSteps, getOptionalOnboarding, runScaffoldFlow, } from "./cli-scaffold.js";
|
|
25
28
|
export { createReadlinePrompt } from "./cli-prompt.js";
|
|
@@ -4,11 +4,15 @@ import path from "node:path";
|
|
|
4
4
|
import { execFileSync } from "node:child_process";
|
|
5
5
|
import { access, constants as fsConstants, rm, writeFile } from "node:fs/promises";
|
|
6
6
|
import { getBuiltInTemplateLayerDirs } from "./template-builtins.js";
|
|
7
|
+
import { HOOKED_BLOCK_ANCHOR_PATTERN, HOOKED_BLOCK_POSITION_SET, } from "./hooked-blocks.js";
|
|
7
8
|
import { listTemplates } from "./template-registry.js";
|
|
8
9
|
import { readWorkspaceInventory } from "./workspace-inventory.js";
|
|
9
10
|
import { getInvalidWorkspaceProjectReason, parseWorkspacePackageJson, WORKSPACE_TEMPLATE_PACKAGE, tryResolveWorkspaceProject, } from "./workspace-project.js";
|
|
10
11
|
const WORKSPACE_COLLECTION_IMPORT_LINE = "import '../../collection';";
|
|
11
12
|
const WORKSPACE_COLLECTION_IMPORT_PATTERN = /^\s*import\s+["']\.\.\/\.\.\/collection["']\s*;?\s*$/m;
|
|
13
|
+
const WORKSPACE_BINDING_SERVER_GLOB = "/src/bindings/*/server.php";
|
|
14
|
+
const WORKSPACE_BINDING_EDITOR_SCRIPT = "build/bindings/index.js";
|
|
15
|
+
const WORKSPACE_BINDING_EDITOR_ASSET = "build/bindings/index.asset.php";
|
|
12
16
|
const WORKSPACE_GENERATED_BLOCK_ARTIFACTS = [
|
|
13
17
|
"block.json",
|
|
14
18
|
"typia.manifest.json",
|
|
@@ -129,6 +133,41 @@ function checkWorkspaceBlockMetadata(projectDir, workspace, block) {
|
|
|
129
133
|
? `block.json matches ${expectedName} and ${workspace.workspace.textDomain}`
|
|
130
134
|
: issues.join("; "));
|
|
131
135
|
}
|
|
136
|
+
function checkWorkspaceBlockHooks(projectDir, blockSlug) {
|
|
137
|
+
const blockJsonRelativePath = path.join("src", "blocks", blockSlug, "block.json");
|
|
138
|
+
const blockJsonPath = path.join(projectDir, blockJsonRelativePath);
|
|
139
|
+
if (!fs.existsSync(blockJsonPath)) {
|
|
140
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", `Missing ${blockJsonRelativePath}`);
|
|
141
|
+
}
|
|
142
|
+
let blockJson;
|
|
143
|
+
try {
|
|
144
|
+
blockJson = JSON.parse(fs.readFileSync(blockJsonPath, "utf8"));
|
|
145
|
+
}
|
|
146
|
+
catch (error) {
|
|
147
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", error instanceof Error ? error.message : String(error));
|
|
148
|
+
}
|
|
149
|
+
const blockHooks = blockJson.blockHooks;
|
|
150
|
+
if (blockHooks === undefined) {
|
|
151
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, "pass", "No blockHooks metadata configured");
|
|
152
|
+
}
|
|
153
|
+
if (!blockHooks || typeof blockHooks !== "object" || Array.isArray(blockHooks)) {
|
|
154
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, "fail", `${blockJsonRelativePath} must define blockHooks as an object when present.`);
|
|
155
|
+
}
|
|
156
|
+
const blockName = typeof blockJson.name === "string" && blockJson.name.trim().length > 0
|
|
157
|
+
? blockJson.name.trim()
|
|
158
|
+
: null;
|
|
159
|
+
const invalidEntries = Object.entries(blockHooks).filter(([anchor, position]) => (blockName !== null && anchor.trim() === blockName) ||
|
|
160
|
+
anchor.trim().length === 0 ||
|
|
161
|
+
anchor !== anchor.trim() ||
|
|
162
|
+
!HOOKED_BLOCK_ANCHOR_PATTERN.test(anchor) ||
|
|
163
|
+
typeof position !== "string" ||
|
|
164
|
+
!HOOKED_BLOCK_POSITION_SET.has(position));
|
|
165
|
+
return createDoctorCheck(`Block hooks ${blockSlug}`, invalidEntries.length === 0 ? "pass" : "fail", invalidEntries.length === 0
|
|
166
|
+
? `blockHooks metadata is valid${Object.keys(blockHooks).length > 0 ? ` (${Object.keys(blockHooks).join(", ")})` : ""}`
|
|
167
|
+
: `Invalid blockHooks entries: ${invalidEntries
|
|
168
|
+
.map(([anchor, position]) => `${anchor || "<empty>"} => ${String(position)}`)
|
|
169
|
+
.join(", ")}`);
|
|
170
|
+
}
|
|
132
171
|
function checkWorkspaceBlockCollectionImport(projectDir, blockSlug) {
|
|
133
172
|
const entryRelativePath = path.join("src", "blocks", blockSlug, "index.tsx");
|
|
134
173
|
const entryPath = path.join(projectDir, entryRelativePath);
|
|
@@ -154,6 +193,33 @@ function checkWorkspacePatternBootstrap(projectDir, packageName) {
|
|
|
154
193
|
? "Pattern category and loader hooks are present"
|
|
155
194
|
: "Missing pattern category registration or src/patterns loader hook");
|
|
156
195
|
}
|
|
196
|
+
function checkWorkspaceBindingBootstrap(projectDir, packageName) {
|
|
197
|
+
const packageBaseName = packageName.split("/").pop() ?? packageName;
|
|
198
|
+
const bootstrapPath = path.join(projectDir, `${packageBaseName}.php`);
|
|
199
|
+
if (!fs.existsSync(bootstrapPath)) {
|
|
200
|
+
return createDoctorCheck("Binding bootstrap", "fail", `Missing ${path.basename(bootstrapPath)}`);
|
|
201
|
+
}
|
|
202
|
+
const source = fs.readFileSync(bootstrapPath, "utf8");
|
|
203
|
+
const hasServerGlob = source.includes(WORKSPACE_BINDING_SERVER_GLOB);
|
|
204
|
+
const hasEditorEnqueueHook = source.includes("enqueue_block_editor_assets");
|
|
205
|
+
const hasEditorScript = source.includes(WORKSPACE_BINDING_EDITOR_SCRIPT);
|
|
206
|
+
const hasEditorAsset = source.includes(WORKSPACE_BINDING_EDITOR_ASSET);
|
|
207
|
+
return createDoctorCheck("Binding bootstrap", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset ? "pass" : "fail", hasServerGlob && hasEditorEnqueueHook && hasEditorScript && hasEditorAsset
|
|
208
|
+
? "Binding source PHP and editor bootstrap hooks are present"
|
|
209
|
+
: "Missing binding source PHP require glob or editor enqueue hook");
|
|
210
|
+
}
|
|
211
|
+
function checkWorkspaceBindingSourcesIndex(projectDir, bindingSources) {
|
|
212
|
+
const indexRelativePath = [path.join("src", "bindings", "index.ts"), path.join("src", "bindings", "index.js")].find((relativePath) => fs.existsSync(path.join(projectDir, relativePath)));
|
|
213
|
+
if (!indexRelativePath) {
|
|
214
|
+
return createDoctorCheck("Binding sources index", "fail", "Missing src/bindings/index.ts or src/bindings/index.js");
|
|
215
|
+
}
|
|
216
|
+
const indexPath = path.join(projectDir, indexRelativePath);
|
|
217
|
+
const source = fs.readFileSync(indexPath, "utf8");
|
|
218
|
+
const missingImports = bindingSources.filter((bindingSource) => !source.includes(`./${bindingSource.slug}/editor`));
|
|
219
|
+
return createDoctorCheck("Binding sources index", missingImports.length === 0 ? "pass" : "fail", missingImports.length === 0
|
|
220
|
+
? "Binding source editor registrations are aggregated"
|
|
221
|
+
: `Missing editor imports for: ${missingImports.map((entry) => entry.slug).join(", ")}`);
|
|
222
|
+
}
|
|
157
223
|
function checkVariationEntrypoint(projectDir, blockSlug) {
|
|
158
224
|
const entryPath = path.join(projectDir, "src", "blocks", blockSlug, "index.tsx");
|
|
159
225
|
if (!fs.existsSync(entryPath)) {
|
|
@@ -274,12 +340,13 @@ export async function getDoctorChecks(cwd) {
|
|
|
274
340
|
checks.push(checkWorkspacePackageMetadata(workspace, workspacePackageJson));
|
|
275
341
|
try {
|
|
276
342
|
const inventory = readWorkspaceInventory(workspace.projectDir);
|
|
277
|
-
checks.push(createDoctorCheck("Workspace inventory", "pass", `${inventory.blocks.length} block(s), ${inventory.variations.length} variation(s), ${inventory.patterns.length} pattern(s)`));
|
|
343
|
+
checks.push(createDoctorCheck("Workspace inventory", "pass", `${inventory.blocks.length} block(s), ${inventory.variations.length} variation(s), ${inventory.patterns.length} pattern(s), ${inventory.bindingSources.length} binding source(s)`));
|
|
278
344
|
for (const block of inventory.blocks) {
|
|
279
345
|
checks.push(checkExistingFiles(workspace.projectDir, `Block ${block.slug}`, [
|
|
280
346
|
...getWorkspaceBlockRequiredFiles(block),
|
|
281
347
|
]));
|
|
282
348
|
checks.push(checkWorkspaceBlockMetadata(workspace.projectDir, workspace, block));
|
|
349
|
+
checks.push(checkWorkspaceBlockHooks(workspace.projectDir, block.slug));
|
|
283
350
|
checks.push(checkWorkspaceBlockCollectionImport(workspace.projectDir, block.slug));
|
|
284
351
|
}
|
|
285
352
|
const registeredBlockSlugs = new Set(inventory.blocks.map((block) => block.slug));
|
|
@@ -303,6 +370,16 @@ export async function getDoctorChecks(cwd) {
|
|
|
303
370
|
for (const pattern of inventory.patterns) {
|
|
304
371
|
checks.push(checkExistingFiles(workspace.projectDir, `Pattern ${pattern.slug}`, [pattern.file]));
|
|
305
372
|
}
|
|
373
|
+
if (inventory.bindingSources.length > 0) {
|
|
374
|
+
checks.push(checkWorkspaceBindingBootstrap(workspace.projectDir, workspace.packageName));
|
|
375
|
+
checks.push(checkWorkspaceBindingSourcesIndex(workspace.projectDir, inventory.bindingSources));
|
|
376
|
+
}
|
|
377
|
+
for (const bindingSource of inventory.bindingSources) {
|
|
378
|
+
checks.push(checkExistingFiles(workspace.projectDir, `Binding source ${bindingSource.slug}`, [
|
|
379
|
+
bindingSource.serverFile,
|
|
380
|
+
bindingSource.editorFile,
|
|
381
|
+
]));
|
|
382
|
+
}
|
|
306
383
|
const migrationWorkspaceCheck = checkMigrationWorkspaceHint(workspace, workspacePackageJson);
|
|
307
384
|
if (migrationWorkspaceCheck) {
|
|
308
385
|
checks.push(migrationWorkspaceCheck);
|
package/dist/runtime/cli-help.js
CHANGED
|
@@ -19,6 +19,8 @@ export function formatHelpText() {
|
|
|
19
19
|
wp-typia add block <name> --template <basic|interactivity|persistence|compound> [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>]
|
|
20
20
|
wp-typia add variation <name> --block <block-slug>
|
|
21
21
|
wp-typia add pattern <name>
|
|
22
|
+
wp-typia add binding-source <name>
|
|
23
|
+
wp-typia add hooked-block <block-slug> --anchor <anchor-block-name> --position <before|after|firstChild|lastChild>
|
|
22
24
|
wp-typia migrate <init|snapshot|diff|scaffold|verify|doctor|fixtures|fuzz> [...]
|
|
23
25
|
wp-typia templates list
|
|
24
26
|
wp-typia templates inspect <id>
|
|
@@ -34,6 +36,8 @@ Notes:
|
|
|
34
36
|
\`wp-typia <project-dir>\` remains a backward-compatible alias to \`create\`.
|
|
35
37
|
\`add variation\` uses an existing workspace block from \`scripts/block-config.ts\`.
|
|
36
38
|
\`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/\`.
|
|
39
|
+
\`add binding-source\` scaffolds shared PHP and editor registration under \`src/bindings/\`.
|
|
40
|
+
\`add hooked-block\` patches an existing workspace block's \`block.json\` \`blockHooks\` metadata.
|
|
37
41
|
\`wp-typia doctor\` checks environment readiness plus workspace inventory and source-tree drift.
|
|
38
42
|
\`wp-typia migrate doctor --all\` checks migration target alignment, snapshots, fixtures, and generated migration artifacts.
|
|
39
43
|
\`migrate\` is the canonical migration command; \`migrations\` is no longer supported.`;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared hooked-block metadata primitives used by add flows, doctor checks,
|
|
3
|
+
* and interactive prompts.
|
|
4
|
+
*/
|
|
5
|
+
export declare const HOOKED_BLOCK_POSITION_IDS: readonly ["before", "after", "firstChild", "lastChild"];
|
|
6
|
+
/**
|
|
7
|
+
* Union of valid `blockHooks` positions accepted by wp-typia workspace flows.
|
|
8
|
+
*/
|
|
9
|
+
export type HookedBlockPositionId = (typeof HOOKED_BLOCK_POSITION_IDS)[number];
|
|
10
|
+
/**
|
|
11
|
+
* Fast lookup set for validating hooked-block positions across runtime surfaces.
|
|
12
|
+
*/
|
|
13
|
+
export declare const HOOKED_BLOCK_POSITION_SET: Set<string>;
|
|
14
|
+
/**
|
|
15
|
+
* Canonical `namespace/slug` block name format required for hooked-block anchors.
|
|
16
|
+
*/
|
|
17
|
+
export declare const HOOKED_BLOCK_ANCHOR_PATTERN: RegExp;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared hooked-block metadata primitives used by add flows, doctor checks,
|
|
3
|
+
* and interactive prompts.
|
|
4
|
+
*/
|
|
5
|
+
export const HOOKED_BLOCK_POSITION_IDS = ["before", "after", "firstChild", "lastChild"];
|
|
6
|
+
/**
|
|
7
|
+
* Fast lookup set for validating hooked-block positions across runtime surfaces.
|
|
8
|
+
*/
|
|
9
|
+
export const HOOKED_BLOCK_POSITION_SET = new Set(HOOKED_BLOCK_POSITION_IDS);
|
|
10
|
+
/**
|
|
11
|
+
* Canonical `namespace/slug` block name format required for hooked-block anchors.
|
|
12
|
+
*/
|
|
13
|
+
export const HOOKED_BLOCK_ANCHOR_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/;
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* CLI while keeping reusable project logic out of the CLI package itself.
|
|
6
6
|
* Consumers should prefer these exports for scaffold, add, migrate, doctor,
|
|
7
7
|
* and workspace-aware helpers such as `getWorkspaceBlockSelectOptions`,
|
|
8
|
-
* `runAddBlockCommand`, `runAddVariationCommand`, `runAddPatternCommand`,
|
|
9
|
-
* `
|
|
8
|
+
* `runAddBlockCommand`, `runAddVariationCommand`, `runAddPatternCommand`,
|
|
9
|
+
* `runAddBindingSourceCommand`, `runAddHookedBlockCommand`,
|
|
10
|
+
* `HOOKED_BLOCK_POSITION_IDS`, and `runDoctor`.
|
|
10
11
|
*/
|
|
11
12
|
export { scaffoldProject, collectScaffoldAnswers, getDefaultAnswers, getTemplateVariables, resolvePackageManagerId, resolveTemplateId, } from "./scaffold.js";
|
|
12
13
|
export { formatMigrationHelpText, parseMigrationArgs, runMigrationCommand, } from "./migrations.js";
|
|
@@ -16,5 +17,5 @@ export { buildCompoundChildStarterManifestDocument, getStarterManifestFiles, str
|
|
|
16
17
|
export type { EndpointAuthIntent, EndpointOpenApiAuthMode, EndpointOpenApiContractDocument, EndpointOpenApiDocumentOptions, EndpointOpenApiEndpointDefinition, EndpointOpenApiMethod, EndpointWordPressAuthDefinition, EndpointWordPressAuthMechanism, JsonSchemaDocument, JsonSchemaProjectionProfile, JsonSchemaObject, NormalizedEndpointAuthDefinition, OpenApiDocument, OpenApiInfo, OpenApiOperation, OpenApiParameter, OpenApiPathItem, OpenApiSecurityScheme, } from "./schema-core.js";
|
|
17
18
|
export { PACKAGE_MANAGER_IDS, PACKAGE_MANAGERS, formatPackageExecCommand, formatInstallCommand, formatRunScript, getPackageManager, getPackageManagerSelectOptions, transformPackageManagerText, } from "./package-managers.js";
|
|
18
19
|
export { TEMPLATE_IDS, TEMPLATE_REGISTRY, getTemplateById, getTemplateSelectOptions, listTemplates, } from "./template-registry.js";
|
|
19
|
-
export { createReadlinePrompt, formatAddHelpText, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, runAddBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
20
|
-
export type { DoctorCheck, ReadlinePrompt } from "./cli-core.js";
|
|
20
|
+
export { createReadlinePrompt, formatAddHelpText, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, runAddBindingSourceCommand, runAddBlockCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
21
|
+
export type { DoctorCheck, HookedBlockPositionId, ReadlinePrompt } from "./cli-core.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -5,8 +5,9 @@
|
|
|
5
5
|
* CLI while keeping reusable project logic out of the CLI package itself.
|
|
6
6
|
* Consumers should prefer these exports for scaffold, add, migrate, doctor,
|
|
7
7
|
* and workspace-aware helpers such as `getWorkspaceBlockSelectOptions`,
|
|
8
|
-
* `runAddBlockCommand`, `runAddVariationCommand`, `runAddPatternCommand`,
|
|
9
|
-
* `
|
|
8
|
+
* `runAddBlockCommand`, `runAddVariationCommand`, `runAddPatternCommand`,
|
|
9
|
+
* `runAddBindingSourceCommand`, `runAddHookedBlockCommand`,
|
|
10
|
+
* `HOOKED_BLOCK_POSITION_IDS`, and `runDoctor`.
|
|
10
11
|
*/
|
|
11
12
|
export { scaffoldProject, collectScaffoldAnswers, getDefaultAnswers, getTemplateVariables, resolvePackageManagerId, resolveTemplateId, } from "./scaffold.js";
|
|
12
13
|
export { formatMigrationHelpText, parseMigrationArgs, runMigrationCommand, } from "./migrations.js";
|
|
@@ -15,4 +16,4 @@ export { manifestAttributeToJsonSchema, projectJsonSchemaDocument, manifestToJso
|
|
|
15
16
|
export { buildCompoundChildStarterManifestDocument, getStarterManifestFiles, stringifyStarterManifest, } from "./starter-manifests.js";
|
|
16
17
|
export { PACKAGE_MANAGER_IDS, PACKAGE_MANAGERS, formatPackageExecCommand, formatInstallCommand, formatRunScript, getPackageManager, getPackageManagerSelectOptions, transformPackageManagerText, } from "./package-managers.js";
|
|
17
18
|
export { TEMPLATE_IDS, TEMPLATE_REGISTRY, getTemplateById, getTemplateSelectOptions, listTemplates, } from "./template-registry.js";
|
|
18
|
-
export { createReadlinePrompt, formatAddHelpText, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, runAddBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
19
|
+
export { createReadlinePrompt, formatAddHelpText, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, runAddBindingSourceCommand, runAddBlockCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
@@ -14,9 +14,16 @@ export interface WorkspacePatternInventoryEntry {
|
|
|
14
14
|
file: string;
|
|
15
15
|
slug: string;
|
|
16
16
|
}
|
|
17
|
+
export interface WorkspaceBindingSourceInventoryEntry {
|
|
18
|
+
editorFile: string;
|
|
19
|
+
serverFile: string;
|
|
20
|
+
slug: string;
|
|
21
|
+
}
|
|
17
22
|
export interface WorkspaceInventory {
|
|
23
|
+
bindingSources: WorkspaceBindingSourceInventoryEntry[];
|
|
18
24
|
blockConfigPath: string;
|
|
19
25
|
blocks: WorkspaceBlockInventoryEntry[];
|
|
26
|
+
hasBindingSourcesSection: boolean;
|
|
20
27
|
hasPatternsSection: boolean;
|
|
21
28
|
hasVariationsSection: boolean;
|
|
22
29
|
patterns: WorkspacePatternInventoryEntry[];
|
|
@@ -26,6 +33,7 @@ export interface WorkspaceInventory {
|
|
|
26
33
|
export declare const BLOCK_CONFIG_ENTRY_MARKER = "\t// wp-typia add block entries";
|
|
27
34
|
export declare const VARIATION_CONFIG_ENTRY_MARKER = "\t// wp-typia add variation entries";
|
|
28
35
|
export declare const PATTERN_CONFIG_ENTRY_MARKER = "\t// wp-typia add pattern entries";
|
|
36
|
+
export declare const BINDING_SOURCE_CONFIG_ENTRY_MARKER = "\t// wp-typia add binding-source entries";
|
|
29
37
|
/**
|
|
30
38
|
* Parse workspace inventory entries from the source of `scripts/block-config.ts`.
|
|
31
39
|
*
|
|
@@ -67,8 +75,9 @@ export declare function getWorkspaceBlockSelectOptions(projectDir: string): Arra
|
|
|
67
75
|
* @param options Entry lists plus an optional source transformer.
|
|
68
76
|
* @returns Updated source text with all requested inventory entries appended.
|
|
69
77
|
*/
|
|
70
|
-
export declare function updateWorkspaceInventorySource(source: string, { blockEntries, patternEntries, variationEntries, transformSource, }?: {
|
|
78
|
+
export declare function updateWorkspaceInventorySource(source: string, { blockEntries, bindingSourceEntries, patternEntries, variationEntries, transformSource, }?: {
|
|
71
79
|
blockEntries?: string[];
|
|
80
|
+
bindingSourceEntries?: string[];
|
|
72
81
|
patternEntries?: string[];
|
|
73
82
|
transformSource?: (source: string) => string;
|
|
74
83
|
variationEntries?: string[];
|
|
@@ -5,29 +5,48 @@ import ts from "typescript";
|
|
|
5
5
|
export const BLOCK_CONFIG_ENTRY_MARKER = "\t// wp-typia add block entries";
|
|
6
6
|
export const VARIATION_CONFIG_ENTRY_MARKER = "\t// wp-typia add variation entries";
|
|
7
7
|
export const PATTERN_CONFIG_ENTRY_MARKER = "\t// wp-typia add pattern entries";
|
|
8
|
-
const
|
|
8
|
+
export const BINDING_SOURCE_CONFIG_ENTRY_MARKER = "\t// wp-typia add binding-source entries";
|
|
9
|
+
const VARIATIONS_INTERFACE_SECTION = `
|
|
9
10
|
|
|
10
11
|
export interface WorkspaceVariationConfig {
|
|
11
12
|
\tblock: string;
|
|
12
13
|
\tfile: string;
|
|
13
14
|
\tslug: string;
|
|
14
15
|
}
|
|
16
|
+
`;
|
|
17
|
+
const VARIATIONS_CONST_SECTION = `
|
|
15
18
|
|
|
16
19
|
export const VARIATIONS: WorkspaceVariationConfig[] = [
|
|
17
20
|
\t// wp-typia add variation entries
|
|
18
21
|
];
|
|
19
22
|
`;
|
|
20
|
-
const
|
|
23
|
+
const PATTERNS_INTERFACE_SECTION = `
|
|
21
24
|
|
|
22
25
|
export interface WorkspacePatternConfig {
|
|
23
26
|
\tfile: string;
|
|
24
27
|
\tslug: string;
|
|
25
28
|
}
|
|
29
|
+
`;
|
|
30
|
+
const PATTERNS_CONST_SECTION = `
|
|
26
31
|
|
|
27
32
|
export const PATTERNS: WorkspacePatternConfig[] = [
|
|
28
33
|
\t// wp-typia add pattern entries
|
|
29
34
|
];
|
|
30
35
|
`;
|
|
36
|
+
const BINDING_SOURCES_INTERFACE_SECTION = `
|
|
37
|
+
|
|
38
|
+
export interface WorkspaceBindingSourceConfig {
|
|
39
|
+
\teditorFile: string;
|
|
40
|
+
\tserverFile: string;
|
|
41
|
+
\tslug: string;
|
|
42
|
+
}
|
|
43
|
+
`;
|
|
44
|
+
const BINDING_SOURCES_CONST_SECTION = `
|
|
45
|
+
|
|
46
|
+
export const BINDING_SOURCES: WorkspaceBindingSourceConfig[] = [
|
|
47
|
+
\t// wp-typia add binding-source entries
|
|
48
|
+
];
|
|
49
|
+
`;
|
|
31
50
|
function getPropertyNameText(name) {
|
|
32
51
|
if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
|
|
33
52
|
return name.text;
|
|
@@ -123,6 +142,18 @@ function parsePatternEntries(arrayLiteral) {
|
|
|
123
142
|
};
|
|
124
143
|
});
|
|
125
144
|
}
|
|
145
|
+
function parseBindingSourceEntries(arrayLiteral) {
|
|
146
|
+
return arrayLiteral.elements.map((element, elementIndex) => {
|
|
147
|
+
if (!ts.isObjectLiteralExpression(element)) {
|
|
148
|
+
throw new Error(`BINDING_SOURCES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
|
|
149
|
+
}
|
|
150
|
+
return {
|
|
151
|
+
editorFile: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "editorFile"),
|
|
152
|
+
serverFile: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "serverFile"),
|
|
153
|
+
slug: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "slug"),
|
|
154
|
+
};
|
|
155
|
+
});
|
|
156
|
+
}
|
|
126
157
|
/**
|
|
127
158
|
* Parse workspace inventory entries from the source of `scripts/block-config.ts`.
|
|
128
159
|
*
|
|
@@ -138,14 +169,22 @@ export function parseWorkspaceInventorySource(source) {
|
|
|
138
169
|
}
|
|
139
170
|
const variationArray = findExportedArrayLiteral(sourceFile, "VARIATIONS");
|
|
140
171
|
const patternArray = findExportedArrayLiteral(sourceFile, "PATTERNS");
|
|
172
|
+
const bindingSourceArray = findExportedArrayLiteral(sourceFile, "BINDING_SOURCES");
|
|
141
173
|
if (variationArray.found && !variationArray.array) {
|
|
142
174
|
throw new Error("scripts/block-config.ts must export VARIATIONS as an array literal.");
|
|
143
175
|
}
|
|
144
176
|
if (patternArray.found && !patternArray.array) {
|
|
145
177
|
throw new Error("scripts/block-config.ts must export PATTERNS as an array literal.");
|
|
146
178
|
}
|
|
179
|
+
if (bindingSourceArray.found && !bindingSourceArray.array) {
|
|
180
|
+
throw new Error("scripts/block-config.ts must export BINDING_SOURCES as an array literal.");
|
|
181
|
+
}
|
|
147
182
|
return {
|
|
183
|
+
bindingSources: bindingSourceArray.array
|
|
184
|
+
? parseBindingSourceEntries(bindingSourceArray.array)
|
|
185
|
+
: [],
|
|
148
186
|
blocks: parseBlockEntries(blockArray.array),
|
|
187
|
+
hasBindingSourcesSection: bindingSourceArray.found,
|
|
149
188
|
hasPatternsSection: patternArray.found,
|
|
150
189
|
hasVariationsSection: variationArray.found,
|
|
151
190
|
patterns: patternArray.array ? parsePatternEntries(patternArray.array) : [],
|
|
@@ -199,26 +238,22 @@ export function getWorkspaceBlockSelectOptions(projectDir) {
|
|
|
199
238
|
function ensureWorkspaceInventorySections(source) {
|
|
200
239
|
let nextSource = source.trimEnd();
|
|
201
240
|
if (!/export\s+interface\s+WorkspaceVariationConfig\b/u.test(nextSource)) {
|
|
202
|
-
nextSource +=
|
|
241
|
+
nextSource += VARIATIONS_INTERFACE_SECTION;
|
|
203
242
|
}
|
|
204
|
-
|
|
205
|
-
nextSource +=
|
|
206
|
-
|
|
207
|
-
export const VARIATIONS: WorkspaceVariationConfig[] = [
|
|
208
|
-
\t// wp-typia add variation entries
|
|
209
|
-
];
|
|
210
|
-
`;
|
|
243
|
+
if (!/export\s+const\s+VARIATIONS\b/u.test(nextSource)) {
|
|
244
|
+
nextSource += VARIATIONS_CONST_SECTION;
|
|
211
245
|
}
|
|
212
246
|
if (!/export\s+interface\s+WorkspacePatternConfig\b/u.test(nextSource)) {
|
|
213
|
-
nextSource +=
|
|
247
|
+
nextSource += PATTERNS_INTERFACE_SECTION;
|
|
214
248
|
}
|
|
215
|
-
|
|
216
|
-
nextSource +=
|
|
217
|
-
|
|
218
|
-
export
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
249
|
+
if (!/export\s+const\s+PATTERNS\b/u.test(nextSource)) {
|
|
250
|
+
nextSource += PATTERNS_CONST_SECTION;
|
|
251
|
+
}
|
|
252
|
+
if (!/export\s+interface\s+WorkspaceBindingSourceConfig\b/u.test(nextSource)) {
|
|
253
|
+
nextSource += BINDING_SOURCES_INTERFACE_SECTION;
|
|
254
|
+
}
|
|
255
|
+
if (!/export\s+const\s+BINDING_SOURCES\b/u.test(nextSource)) {
|
|
256
|
+
nextSource += BINDING_SOURCES_CONST_SECTION;
|
|
222
257
|
}
|
|
223
258
|
return `${nextSource}\n`;
|
|
224
259
|
}
|
|
@@ -242,7 +277,7 @@ function appendEntriesAtMarker(source, marker, entries) {
|
|
|
242
277
|
* @param options Entry lists plus an optional source transformer.
|
|
243
278
|
* @returns Updated source text with all requested inventory entries appended.
|
|
244
279
|
*/
|
|
245
|
-
export function updateWorkspaceInventorySource(source, { blockEntries = [], patternEntries = [], variationEntries = [], transformSource, } = {}) {
|
|
280
|
+
export function updateWorkspaceInventorySource(source, { blockEntries = [], bindingSourceEntries = [], patternEntries = [], variationEntries = [], transformSource, } = {}) {
|
|
246
281
|
let nextSource = ensureWorkspaceInventorySections(source);
|
|
247
282
|
if (transformSource) {
|
|
248
283
|
nextSource = transformSource(nextSource);
|
|
@@ -250,6 +285,7 @@ export function updateWorkspaceInventorySource(source, { blockEntries = [], patt
|
|
|
250
285
|
nextSource = appendEntriesAtMarker(nextSource, BLOCK_CONFIG_ENTRY_MARKER, blockEntries);
|
|
251
286
|
nextSource = appendEntriesAtMarker(nextSource, VARIATION_CONFIG_ENTRY_MARKER, variationEntries);
|
|
252
287
|
nextSource = appendEntriesAtMarker(nextSource, PATTERN_CONFIG_ENTRY_MARKER, patternEntries);
|
|
288
|
+
nextSource = appendEntriesAtMarker(nextSource, BINDING_SOURCE_CONFIG_ENTRY_MARKER, bindingSourceEntries);
|
|
253
289
|
return nextSource;
|
|
254
290
|
}
|
|
255
291
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wp-typia/project-tools",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.1",
|
|
4
4
|
"description": "Project orchestration and programmatic tooling for wp-typia",
|
|
5
5
|
"packageManager": "bun@1.3.11",
|
|
6
6
|
"type": "module",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"dependencies": {
|
|
64
64
|
"@wp-typia/api-client": "^0.4.0",
|
|
65
65
|
"@wp-typia/block-runtime": "^0.4.0",
|
|
66
|
-
"@wp-typia/rest": "^0.3.
|
|
66
|
+
"@wp-typia/rest": "^0.3.2",
|
|
67
67
|
"@wp-typia/block-types": "^0.2.0",
|
|
68
68
|
"mustache": "^4.2.0",
|
|
69
69
|
"npm-package-arg": "^13.0.0",
|