@wp-typia/project-tools 0.23.1 → 0.24.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/dist/runtime/built-in-block-non-ts-basic-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-basic-artifacts.js +84 -0
- package/dist/runtime/built-in-block-non-ts-compound-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-compound-artifacts.js +36 -0
- package/dist/runtime/built-in-block-non-ts-compound-templates.d.ts +23 -0
- package/dist/runtime/built-in-block-non-ts-compound-templates.js +453 -0
- package/dist/runtime/built-in-block-non-ts-family-artifacts.d.ts +8 -26
- package/dist/runtime/built-in-block-non-ts-family-artifacts.js +8 -1034
- package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.js +83 -0
- package/dist/runtime/built-in-block-non-ts-persistence-artifacts.d.ts +9 -0
- package/dist/runtime/built-in-block-non-ts-persistence-artifacts.js +33 -0
- package/dist/runtime/built-in-block-non-ts-persistence-templates.d.ts +23 -0
- package/dist/runtime/built-in-block-non-ts-persistence-templates.js +395 -0
- package/dist/runtime/cli-add-collision.js +8 -0
- package/dist/runtime/cli-add-help.js +10 -7
- package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
- package/dist/runtime/cli-add-kind-ids.js +1 -0
- package/dist/runtime/cli-add-types.d.ts +28 -1
- package/dist/runtime/cli-add-types.js +2 -0
- package/dist/runtime/cli-add-workspace-ability-anchors.d.ts +24 -0
- package/dist/runtime/cli-add-workspace-ability-anchors.js +294 -0
- package/dist/runtime/cli-add-workspace-ability-registry.d.ts +10 -0
- package/dist/runtime/cli-add-workspace-ability-registry.js +51 -0
- package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +1 -1
- package/dist/runtime/cli-add-workspace-ability-scaffold.js +5 -311
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +1 -1
- package/dist/runtime/cli-add-workspace-ai-anchors.d.ts +4 -4
- package/dist/runtime/cli-add-workspace-ai-anchors.js +4 -232
- package/dist/runtime/cli-add-workspace-ai-scaffold.js +4 -2
- package/dist/runtime/cli-add-workspace-ai-source-emitters.d.ts +1 -4
- package/dist/runtime/cli-add-workspace-ai-source-emitters.js +1 -145
- package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.d.ts +5 -0
- package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.js +236 -0
- package/dist/runtime/cli-add-workspace-ai-sync-script-source.d.ts +4 -0
- package/dist/runtime/cli-add-workspace-ai-sync-script-source.js +145 -0
- package/dist/runtime/cli-add-workspace-assets.d.ts +6 -63
- package/dist/runtime/cli-add-workspace-assets.js +6 -950
- package/dist/runtime/cli-add-workspace-binding-source-anchors.d.ts +23 -0
- package/dist/runtime/cli-add-workspace-binding-source-anchors.js +112 -0
- package/dist/runtime/cli-add-workspace-binding-source-source-emitters.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-binding-source-source-emitters.js +436 -0
- package/dist/runtime/cli-add-workspace-binding-source-types.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-binding-source-types.js +1 -0
- package/dist/runtime/cli-add-workspace-binding-source.d.ts +40 -0
- package/dist/runtime/cli-add-workspace-binding-source.js +275 -0
- package/dist/runtime/cli-add-workspace-block-style.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-block-style.js +148 -0
- package/dist/runtime/cli-add-workspace-block-transform.d.ts +32 -0
- package/dist/runtime/cli-add-workspace-block-transform.js +197 -0
- package/dist/runtime/cli-add-workspace-contract.js +1 -1
- package/dist/runtime/cli-add-workspace-core-variation.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-core-variation.js +322 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-anchors.d.ts +37 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-anchors.js +206 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.d.ts +47 -0
- package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.js +219 -0
- package/dist/runtime/cli-add-workspace-editor-plugin.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-editor-plugin.js +78 -0
- package/dist/runtime/cli-add-workspace-hooked-block.d.ts +23 -0
- package/dist/runtime/cli-add-workspace-hooked-block.js +57 -0
- package/dist/runtime/cli-add-workspace-integration-env-files.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-integration-env-files.js +65 -0
- package/dist/runtime/cli-add-workspace-integration-env-package-json.d.ts +38 -0
- package/dist/runtime/cli-add-workspace-integration-env-package-json.js +122 -0
- package/dist/runtime/cli-add-workspace-integration-env-source-emitters.d.ts +44 -0
- package/dist/runtime/cli-add-workspace-integration-env-source-emitters.js +262 -0
- package/dist/runtime/cli-add-workspace-integration-env.js +5 -345
- package/dist/runtime/cli-add-workspace-pattern-anchors.d.ts +10 -0
- package/dist/runtime/cli-add-workspace-pattern-anchors.js +95 -0
- package/dist/runtime/cli-add-workspace-pattern-options.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-pattern-options.js +113 -0
- package/dist/runtime/cli-add-workspace-pattern-source-emitters.d.ts +20 -0
- package/dist/runtime/cli-add-workspace-pattern-source-emitters.js +57 -0
- package/dist/runtime/cli-add-workspace-pattern.d.ts +42 -0
- package/dist/runtime/cli-add-workspace-pattern.js +99 -0
- package/dist/runtime/cli-add-workspace-post-meta.js +1 -1
- package/dist/runtime/cli-add-workspace-registration-hooks.d.ts +50 -0
- package/dist/runtime/cli-add-workspace-registration-hooks.js +162 -0
- package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +6 -9
- package/dist/runtime/cli-add-workspace-rest-anchors.js +6 -466
- package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.d.ts +17 -0
- package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.js +108 -0
- package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.js +142 -0
- package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.d.ts +51 -0
- package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.js +415 -0
- package/dist/runtime/cli-add-workspace-rest-generated.js +5 -3
- package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.d.ts +80 -0
- package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.js +238 -0
- package/dist/runtime/cli-add-workspace-rest-manual.js +3 -16
- package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +1 -7
- package/dist/runtime/cli-add-workspace-rest-php-templates.js +3 -322
- package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.d.ts +33 -0
- package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.js +145 -0
- package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.d.ts +9 -0
- package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.js +162 -0
- package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.d.ts +7 -0
- package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.js +193 -0
- package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +5 -99
- package/dist/runtime/cli-add-workspace-rest-source-emitters.js +5 -663
- package/dist/runtime/cli-add-workspace-rest-source-utils.d.ts +17 -0
- package/dist/runtime/cli-add-workspace-rest-source-utils.js +50 -0
- package/dist/runtime/cli-add-workspace-rest-sync-script-shared.d.ts +56 -0
- package/dist/runtime/cli-add-workspace-rest-sync-script-shared.js +122 -0
- package/dist/runtime/cli-add-workspace-rest-types.d.ts +3 -3
- package/dist/runtime/cli-add-workspace-variation.d.ts +22 -0
- package/dist/runtime/cli-add-workspace-variation.js +162 -0
- package/dist/runtime/cli-add-workspace.d.ts +42 -107
- package/dist/runtime/cli-add-workspace.js +42 -674
- package/dist/runtime/cli-add.d.ts +3 -3
- package/dist/runtime/cli-add.js +2 -2
- package/dist/runtime/cli-core.d.ts +2 -1
- package/dist/runtime/cli-core.js +1 -1
- package/dist/runtime/cli-doctor-workspace-bindings.js +59 -0
- package/dist/runtime/cli-doctor-workspace-block-addons.js +33 -5
- package/dist/runtime/cli-doctor.d.ts +2 -0
- package/dist/runtime/cli-doctor.js +13 -2
- package/dist/runtime/cli-help.js +6 -4
- package/dist/runtime/index.d.ts +5 -2
- package/dist/runtime/index.js +4 -2
- package/dist/runtime/local-dev-presets.js +2 -1
- package/dist/runtime/package-versions.d.ts +1 -0
- package/dist/runtime/package-versions.js +10 -2
- package/dist/runtime/pattern-catalog.d.ts +122 -0
- package/dist/runtime/pattern-catalog.js +471 -0
- package/dist/runtime/post-meta-binding-fields.d.ts +46 -0
- package/dist/runtime/post-meta-binding-fields.js +135 -0
- package/dist/runtime/typia-llm-json-schema.d.ts +24 -0
- package/dist/runtime/typia-llm-json-schema.js +33 -0
- package/dist/runtime/typia-llm-openapi-constraints.d.ts +20 -0
- package/dist/runtime/typia-llm-openapi-constraints.js +254 -0
- package/dist/runtime/typia-llm-projection.d.ts +25 -0
- package/dist/runtime/typia-llm-projection.js +58 -0
- package/dist/runtime/typia-llm-render.d.ts +21 -0
- package/dist/runtime/typia-llm-render.js +252 -0
- package/dist/runtime/typia-llm-sync.d.ts +10 -0
- package/dist/runtime/typia-llm-sync.js +63 -0
- package/dist/runtime/typia-llm-types.d.ts +197 -0
- package/dist/runtime/typia-llm-types.js +1 -0
- package/dist/runtime/typia-llm.d.ts +9 -255
- package/dist/runtime/typia-llm.js +5 -634
- package/dist/runtime/workspace-inventory-mutations.js +13 -0
- package/dist/runtime/workspace-inventory-section-descriptors.js +9 -1
- package/dist/runtime/workspace-inventory-templates.d.ts +2 -2
- package/dist/runtime/workspace-inventory-templates.js +9 -1
- package/dist/runtime/workspace-inventory-types.d.ts +9 -1
- package/package.json +8 -3
- package/templates/_shared/compound/core/scripts/block-config.ts.mustache +22 -0
- package/templates/_shared/compound/core/scripts/sync-types-to-block-json.ts.mustache +103 -2
- package/templates/_shared/compound/core/src/inner-blocks-templates.ts.mustache +13 -0
- package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +22 -1
|
@@ -1,953 +1,9 @@
|
|
|
1
|
-
import { promises as fsp } from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { syncBlockMetadata, } from "@wp-typia/block-runtime/metadata-core";
|
|
4
|
-
import ts from "typescript";
|
|
5
|
-
import { resolveWorkspaceProject, } from "./workspace-project.js";
|
|
6
|
-
import { appendWorkspaceInventoryEntries, readWorkspaceInventoryAsync, } from "./workspace-inventory.js";
|
|
7
|
-
import { toPascalCase, toTitleCase } from "./string-case.js";
|
|
8
|
-
import { findPhpFunctionRange, hasPhpFunctionDefinition, quotePhpString, replacePhpFunctionDefinition, } from "./php-utils.js";
|
|
9
|
-
import { assertBindingSourceDoesNotExist, assertEditorPluginDoesNotExist, assertPatternDoesNotExist, assertValidEditorPluginSlot, assertValidGeneratedSlug, getWorkspaceBootstrapPath, normalizeBlockSlug, patchFile, quoteTsString, resolveWorkspaceBlock, rollbackWorkspaceMutation, snapshotWorkspaceFiles, } from "./cli-add-shared.js";
|
|
10
|
-
import { appendPhpSnippetBeforeClosingTag, insertPhpSnippetBeforeWorkspaceAnchors, } from "./cli-add-workspace-mutation.js";
|
|
11
|
-
import { resolveWorkspaceBlockTargetName } from "./block-targets.js";
|
|
12
|
-
import { pathExists, readOptionalUtf8File } from "./fs-async.js";
|
|
13
|
-
import { normalizeOptionalCliString } from "./cli-validation.js";
|
|
14
|
-
import { getPropertyNameText } from "./ts-property-names.js";
|
|
15
|
-
const PATTERN_BOOTSTRAP_CATEGORY = "register_block_pattern_category";
|
|
16
|
-
const BINDING_SOURCE_SERVER_GLOB = "/src/bindings/*/server.php";
|
|
17
|
-
const BINDING_SOURCE_EDITOR_SCRIPT = "build/bindings/index.js";
|
|
18
|
-
const BINDING_SOURCE_EDITOR_ASSET = "build/bindings/index.asset.php";
|
|
19
|
-
const EDITOR_PLUGIN_EDITOR_SCRIPT = "build/editor-plugins/index.js";
|
|
20
|
-
const EDITOR_PLUGIN_EDITOR_ASSET = "build/editor-plugins/index.asset.php";
|
|
21
|
-
const EDITOR_PLUGIN_EDITOR_STYLE = "build/editor-plugins/style-index.css";
|
|
22
|
-
const EDITOR_PLUGIN_EDITOR_STYLE_RTL = "build/editor-plugins/style-index-rtl.css";
|
|
23
|
-
const BINDING_ATTRIBUTE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/u;
|
|
24
|
-
function buildPatternConfigEntry(patternSlug) {
|
|
25
|
-
return [
|
|
26
|
-
"\t{",
|
|
27
|
-
`\t\tfile: ${quoteTsString(`src/patterns/${patternSlug}.php`)},`,
|
|
28
|
-
`\t\tslug: ${quoteTsString(patternSlug)},`,
|
|
29
|
-
"\t},",
|
|
30
|
-
].join("\n");
|
|
31
|
-
}
|
|
32
|
-
function buildBindingSourceConfigEntry(bindingSourceSlug, target) {
|
|
33
|
-
return [
|
|
34
|
-
"\t{",
|
|
35
|
-
...(target ? [`\t\tattribute: ${quoteTsString(target.attributeName)},`] : []),
|
|
36
|
-
...(target ? [`\t\tblock: ${quoteTsString(target.blockSlug)},`] : []),
|
|
37
|
-
`\t\teditorFile: ${quoteTsString(`src/bindings/${bindingSourceSlug}/editor.ts`)},`,
|
|
38
|
-
`\t\tserverFile: ${quoteTsString(`src/bindings/${bindingSourceSlug}/server.php`)},`,
|
|
39
|
-
`\t\tslug: ${quoteTsString(bindingSourceSlug)},`,
|
|
40
|
-
"\t},",
|
|
41
|
-
].join("\n");
|
|
42
|
-
}
|
|
43
|
-
function assertValidBindingAttributeName(attributeName) {
|
|
44
|
-
const trimmed = attributeName.trim();
|
|
45
|
-
if (!trimmed) {
|
|
46
|
-
throw new Error("`wp-typia add binding-source` requires --attribute <attribute> to include a value when --block is provided.");
|
|
47
|
-
}
|
|
48
|
-
if (!BINDING_ATTRIBUTE_NAME_PATTERN.test(trimmed)) {
|
|
49
|
-
throw new Error(`Binding attribute "${attributeName}" must start with a letter and use only letters, numbers, underscores, or hyphens.`);
|
|
50
|
-
}
|
|
51
|
-
return trimmed;
|
|
52
|
-
}
|
|
53
|
-
function buildEditorPluginConfigEntry(editorPluginSlug, slot) {
|
|
54
|
-
return [
|
|
55
|
-
"\t{",
|
|
56
|
-
`\t\tfile: ${quoteTsString(`src/editor-plugins/${editorPluginSlug}/index.tsx`)},`,
|
|
57
|
-
`\t\tslug: ${quoteTsString(editorPluginSlug)},`,
|
|
58
|
-
`\t\tslot: ${quoteTsString(slot)},`,
|
|
59
|
-
"\t},",
|
|
60
|
-
].join("\n");
|
|
61
|
-
}
|
|
62
|
-
function buildPatternSource(patternSlug, namespace, textDomain) {
|
|
63
|
-
const patternTitle = toTitleCase(patternSlug);
|
|
64
|
-
return `<?php
|
|
65
|
-
if ( ! defined( 'ABSPATH' ) ) {
|
|
66
|
-
\treturn;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
register_block_pattern(
|
|
70
|
-
\t'${namespace}/${patternSlug}',
|
|
71
|
-
\tarray(
|
|
72
|
-
\t\t'title' => __( ${JSON.stringify(patternTitle)}, '${textDomain}' ),
|
|
73
|
-
\t\t'description' => __( ${JSON.stringify(`A starter pattern for ${patternTitle}.`)}, '${textDomain}' ),
|
|
74
|
-
\t\t'categories' => array( '${namespace}' ),
|
|
75
|
-
\t\t'content' => '<!-- wp:paragraph --><p>' . esc_html__( 'Describe this pattern here.', '${textDomain}' ) . '</p><!-- /wp:paragraph -->',
|
|
76
|
-
\t)
|
|
77
|
-
);
|
|
78
|
-
`;
|
|
79
|
-
}
|
|
80
|
-
function buildBindingSourceServerSource(bindingSourceSlug, phpPrefix, namespace, textDomain, target) {
|
|
81
|
-
const bindingSourceTitle = toTitleCase(bindingSourceSlug);
|
|
82
|
-
const bindingSourcePhpId = bindingSourceSlug.replace(/-/g, "_");
|
|
83
|
-
const bindingSourceValueFunctionName = `${phpPrefix}_${bindingSourcePhpId}_binding_source_values`;
|
|
84
|
-
const bindingSourceResolveFunctionName = `${phpPrefix}_${bindingSourcePhpId}_resolve_binding_source_value`;
|
|
85
|
-
const bindingSourceSupportedAttributesFunctionName = `${phpPrefix}_${bindingSourcePhpId}_supported_binding_attributes`;
|
|
86
|
-
const starterValue = `${bindingSourceTitle} starter value`;
|
|
87
|
-
const supportedAttributesSource = target
|
|
88
|
-
? `
|
|
89
|
-
if ( ! function_exists( '${bindingSourceSupportedAttributesFunctionName}' ) ) {
|
|
90
|
-
\tfunction ${bindingSourceSupportedAttributesFunctionName}( array $supported_attributes ) : array {
|
|
91
|
-
\t\tif ( ! in_array( ${quotePhpString(target.attributeName)}, $supported_attributes, true ) ) {
|
|
92
|
-
\t\t\t$supported_attributes[] = ${quotePhpString(target.attributeName)};
|
|
93
|
-
\t\t}
|
|
94
|
-
|
|
95
|
-
\t\treturn $supported_attributes;
|
|
96
|
-
\t}
|
|
97
|
-
}
|
|
98
|
-
`
|
|
99
|
-
: "";
|
|
100
|
-
const supportedAttributesHook = target
|
|
101
|
-
? `
|
|
102
|
-
if ( function_exists( '${bindingSourceSupportedAttributesFunctionName}' ) ) {
|
|
103
|
-
\tadd_filter(
|
|
104
|
-
\t\t${quotePhpString(`block_bindings_supported_attributes_${namespace}/${target.blockSlug}`)},
|
|
105
|
-
\t\t${quotePhpString(bindingSourceSupportedAttributesFunctionName)}
|
|
106
|
-
\t);
|
|
107
|
-
}
|
|
108
|
-
`
|
|
109
|
-
: "";
|
|
110
|
-
return `<?php
|
|
111
|
-
if ( ! defined( 'ABSPATH' ) ) {
|
|
112
|
-
\treturn;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
if ( ! function_exists( 'register_block_bindings_source' ) ) {
|
|
116
|
-
\treturn;
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if ( ! function_exists( '${bindingSourceValueFunctionName}' ) ) {
|
|
120
|
-
\tfunction ${bindingSourceValueFunctionName}() : array {
|
|
121
|
-
\t\treturn array(
|
|
122
|
-
\t\t\t${quotePhpString(bindingSourceSlug)} => ${quotePhpString(starterValue)},
|
|
123
|
-
\t\t);
|
|
124
|
-
\t}
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if ( ! function_exists( '${bindingSourceResolveFunctionName}' ) ) {
|
|
128
|
-
\tfunction ${bindingSourceResolveFunctionName}( array $source_args ) : string {
|
|
129
|
-
\t\t$field = isset( $source_args['field'] ) && is_string( $source_args['field'] )
|
|
130
|
-
\t\t\t? $source_args['field']
|
|
131
|
-
\t\t\t: '${bindingSourceSlug}';
|
|
132
|
-
\t\t$binding_source_values = ${bindingSourceValueFunctionName}();
|
|
133
|
-
\t\t$value = $binding_source_values[ $field ] ?? '';
|
|
134
|
-
|
|
135
|
-
\t\treturn is_string( $value ) ? $value : '';
|
|
136
|
-
\t}
|
|
137
|
-
}
|
|
138
|
-
${supportedAttributesSource}
|
|
139
|
-
|
|
140
|
-
register_block_bindings_source(
|
|
141
|
-
\t${quotePhpString(`${namespace}/${bindingSourceSlug}`)},
|
|
142
|
-
\tarray(
|
|
143
|
-
\t\t'label' => __( ${quotePhpString(bindingSourceTitle)}, ${quotePhpString(textDomain)} ),
|
|
144
|
-
\t\t'get_value_callback' => ${quotePhpString(bindingSourceResolveFunctionName)},
|
|
145
|
-
\t)
|
|
146
|
-
);
|
|
147
|
-
${supportedAttributesHook}`;
|
|
148
|
-
}
|
|
149
|
-
function buildBindingSourceEditorSource(bindingSourceSlug, namespace, textDomain, target) {
|
|
150
|
-
const bindingSourceTitle = toTitleCase(bindingSourceSlug);
|
|
151
|
-
const starterValue = `${bindingSourceTitle} starter value`;
|
|
152
|
-
const bindingSourceName = `${namespace}/${bindingSourceSlug}`;
|
|
153
|
-
const targetSource = target
|
|
154
|
-
? `
|
|
155
|
-
export const BINDING_SOURCE_TARGET = {
|
|
156
|
-
\tattribute: ${quoteTsString(target.attributeName)},
|
|
157
|
-
\tblock: ${quoteTsString(`${namespace}/${target.blockSlug}`)},
|
|
158
|
-
\tfield: ${quoteTsString(bindingSourceSlug)},
|
|
159
|
-
\tsource: ${quoteTsString(bindingSourceName)},
|
|
160
|
-
} as const;
|
|
161
|
-
`
|
|
162
|
-
: "";
|
|
163
|
-
return `import { registerBlockBindingsSource } from '@wordpress/blocks';
|
|
164
|
-
import { __ } from '@wordpress/i18n';
|
|
165
|
-
|
|
166
|
-
interface BindingSourceRegistration {
|
|
167
|
-
\targs?: {
|
|
168
|
-
\t\tfield?: string;
|
|
169
|
-
\t};
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
const BINDING_SOURCE_VALUES: Record<string, string> = {
|
|
173
|
-
\t${quoteTsString(bindingSourceSlug)}: ${quoteTsString(starterValue)},
|
|
174
|
-
};
|
|
175
|
-
${targetSource}
|
|
176
|
-
|
|
177
|
-
function resolveBindingSourceValue( field: string ): string {
|
|
178
|
-
\treturn BINDING_SOURCE_VALUES[ field ] ?? '';
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
registerBlockBindingsSource( {
|
|
182
|
-
\tname: ${quoteTsString(bindingSourceName)},
|
|
183
|
-
\tlabel: __( ${quoteTsString(bindingSourceTitle)}, ${quoteTsString(textDomain)} ),
|
|
184
|
-
\tgetFieldsList() {
|
|
185
|
-
\t\treturn [
|
|
186
|
-
\t\t\t{
|
|
187
|
-
\t\t\t\tlabel: __( ${quoteTsString(bindingSourceTitle)}, ${quoteTsString(textDomain)} ),
|
|
188
|
-
\t\t\t\ttype: 'string',
|
|
189
|
-
\t\t\t\targs: {
|
|
190
|
-
\t\t\t\t\tfield: ${quoteTsString(bindingSourceSlug)},
|
|
191
|
-
\t\t\t\t},
|
|
192
|
-
\t\t\t},
|
|
193
|
-
\t\t];
|
|
194
|
-
\t},
|
|
195
|
-
\tgetValues( { bindings } ) {
|
|
196
|
-
\t\tconst values: Record<string, string> = {};
|
|
197
|
-
\t\tfor ( const [ attributeName, binding ] of Object.entries(
|
|
198
|
-
\t\t\tbindings as Record<string, BindingSourceRegistration>
|
|
199
|
-
\t\t) ) {
|
|
200
|
-
\t\t\tconst field =
|
|
201
|
-
\t\t\t\ttypeof binding?.args?.field === 'string'
|
|
202
|
-
\t\t\t\t\t? binding.args.field
|
|
203
|
-
\t\t\t\t\t: ${quoteTsString(bindingSourceSlug)};
|
|
204
|
-
\t\t\tvalues[ attributeName ] = resolveBindingSourceValue( field );
|
|
205
|
-
\t\t}
|
|
206
|
-
\t\treturn values;
|
|
207
|
-
\t},
|
|
208
|
-
} );
|
|
209
|
-
`;
|
|
210
|
-
}
|
|
211
|
-
function resolveBindingTarget(options, namespace) {
|
|
212
|
-
const blockName = normalizeOptionalCliString(options.blockName);
|
|
213
|
-
const attributeName = normalizeOptionalCliString(options.attributeName);
|
|
214
|
-
const hasBlock = blockName !== undefined;
|
|
215
|
-
const hasAttribute = attributeName !== undefined;
|
|
216
|
-
if (!hasBlock && !hasAttribute) {
|
|
217
|
-
return undefined;
|
|
218
|
-
}
|
|
219
|
-
if (!hasBlock || !hasAttribute) {
|
|
220
|
-
throw new Error("`wp-typia add binding-source` requires --block and --attribute to be provided together.");
|
|
221
|
-
}
|
|
222
|
-
const targetBlock = resolveWorkspaceBlockTargetName(blockName ?? "", namespace, {
|
|
223
|
-
empty: () => "`wp-typia add binding-source` requires --block <block-slug|namespace/block-slug> to include a value when --attribute is provided.",
|
|
224
|
-
emptySegment: (input) => `Binding target block "${input}" must use <block-slug> or <namespace/block-slug> format without empty path segments.`,
|
|
225
|
-
invalidFormat: (input) => `Binding target block "${input}" must use <block-slug> or <namespace/block-slug> format.`,
|
|
226
|
-
namespaceMismatch: (input, actualNamespace, expectedNamespace) => `Binding target block "${input}" uses namespace "${actualNamespace}". Expected "${expectedNamespace}".`,
|
|
227
|
-
});
|
|
228
|
-
return {
|
|
229
|
-
attributeName: assertValidBindingAttributeName(attributeName ?? ""),
|
|
230
|
-
blockSlug: targetBlock.blockSlug,
|
|
231
|
-
};
|
|
232
|
-
}
|
|
233
|
-
function formatBindingAttributeTypeMember(attributeName) {
|
|
234
|
-
const propertyName = /^[A-Za-z_$][\w$]*$/u.test(attributeName)
|
|
235
|
-
? attributeName
|
|
236
|
-
: JSON.stringify(attributeName);
|
|
237
|
-
return [
|
|
238
|
-
"\t/**",
|
|
239
|
-
"\t * Starter string attribute declared for WordPress Block Bindings.",
|
|
240
|
-
"\t */",
|
|
241
|
-
`\t${propertyName}?: string;`,
|
|
242
|
-
].join("\n");
|
|
243
|
-
}
|
|
244
|
-
function getInterfaceDeclaration(source, interfaceName) {
|
|
245
|
-
const sourceFile = ts.createSourceFile("types.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
|
|
246
|
-
let declaration;
|
|
247
|
-
const visit = (node) => {
|
|
248
|
-
if (ts.isInterfaceDeclaration(node) && node.name.text === interfaceName) {
|
|
249
|
-
declaration = node;
|
|
250
|
-
return true;
|
|
251
|
-
}
|
|
252
|
-
return ts.forEachChild(node, (child) => (visit(child) ? true : undefined)) ?? false;
|
|
253
|
-
};
|
|
254
|
-
visit(sourceFile);
|
|
255
|
-
return declaration ? { declaration, sourceFile } : undefined;
|
|
256
|
-
}
|
|
257
|
-
function interfaceHasAttributeMember(declaration, attributeName) {
|
|
258
|
-
return declaration.members.some((member) => ts.isPropertySignature(member) &&
|
|
259
|
-
member.name !== undefined &&
|
|
260
|
-
getPropertyNameText(member.name) === attributeName);
|
|
261
|
-
}
|
|
262
|
-
function insertBindingAttributeTypeMember(source, declaration, attributeName) {
|
|
263
|
-
let closeBracePosition = declaration.end - 1;
|
|
264
|
-
while (closeBracePosition > declaration.pos && source[closeBracePosition] !== "}") {
|
|
265
|
-
closeBracePosition -= 1;
|
|
266
|
-
}
|
|
267
|
-
if (source[closeBracePosition] !== "}") {
|
|
268
|
-
throw new Error("Unable to locate the target interface closing brace.");
|
|
269
|
-
}
|
|
270
|
-
const lineEnding = source.includes("\r\n") ? "\r\n" : "\n";
|
|
271
|
-
const beforeCloseBrace = source.slice(0, closeBracePosition);
|
|
272
|
-
const afterCloseBrace = source.slice(closeBracePosition);
|
|
273
|
-
const memberSource = formatBindingAttributeTypeMember(attributeName)
|
|
274
|
-
.split("\n")
|
|
275
|
-
.join(lineEnding);
|
|
276
|
-
const prefix = beforeCloseBrace.endsWith(lineEnding) ? "" : lineEnding;
|
|
277
|
-
return `${beforeCloseBrace}${prefix}${memberSource}${lineEnding}${afterCloseBrace}`;
|
|
278
|
-
}
|
|
279
|
-
async function ensureBindingTargetBlockAttributeType(projectDir, block, target) {
|
|
280
|
-
if (!block.attributeTypeName) {
|
|
281
|
-
throw new Error(`Workspace block "${block.slug}" must include attributeTypeName in scripts/block-config.ts before it can receive binding-source targets.`);
|
|
282
|
-
}
|
|
283
|
-
const typesPath = path.join(projectDir, block.typesFile);
|
|
284
|
-
const source = await fsp.readFile(typesPath, "utf8");
|
|
285
|
-
const targetInterface = getInterfaceDeclaration(source, block.attributeTypeName);
|
|
286
|
-
if (!targetInterface) {
|
|
287
|
-
throw new Error(`Unable to locate interface ${block.attributeTypeName} in ${block.typesFile}.`);
|
|
288
|
-
}
|
|
289
|
-
let nextSource = source;
|
|
290
|
-
if (!interfaceHasAttributeMember(targetInterface.declaration, target.attributeName)) {
|
|
291
|
-
nextSource = insertBindingAttributeTypeMember(source, targetInterface.declaration, target.attributeName);
|
|
292
|
-
await fsp.writeFile(typesPath, nextSource, "utf8");
|
|
293
|
-
}
|
|
294
|
-
await syncBlockMetadata({
|
|
295
|
-
blockJsonFile: path.join("src", "blocks", block.slug, "block.json"),
|
|
296
|
-
jsonSchemaFile: path.join("src", "blocks", block.slug, "typia.schema.json"),
|
|
297
|
-
manifestFile: path.join("src", "blocks", block.slug, "typia.manifest.json"),
|
|
298
|
-
openApiFile: path.join("src", "blocks", block.slug, "typia.openapi.json"),
|
|
299
|
-
projectRoot: projectDir,
|
|
300
|
-
sourceTypeName: block.attributeTypeName,
|
|
301
|
-
typesFile: block.typesFile,
|
|
302
|
-
});
|
|
303
|
-
}
|
|
304
|
-
function buildEditorPluginTypesSource(editorPluginSlug) {
|
|
305
|
-
const typeName = `${toPascalCase(editorPluginSlug)}EditorPluginModel`;
|
|
306
|
-
return `export interface ${typeName} {
|
|
307
|
-
\tprimaryActionLabel: string;
|
|
308
|
-
\tsummary: string;
|
|
309
|
-
}
|
|
310
|
-
`;
|
|
311
|
-
}
|
|
312
|
-
function buildEditorPluginDataSource(editorPluginSlug, slot) {
|
|
313
|
-
const typeName = `${toPascalCase(editorPluginSlug)}EditorPluginModel`;
|
|
314
|
-
const pluginTitle = toTitleCase(editorPluginSlug);
|
|
315
|
-
const modelFactoryName = `get${toPascalCase(editorPluginSlug)}EditorPluginModel`;
|
|
316
|
-
const enabledFactoryName = `is${toPascalCase(editorPluginSlug)}Enabled`;
|
|
317
|
-
return `import type { ${typeName} } from './types';
|
|
318
|
-
|
|
319
|
-
export const EDITOR_PLUGIN_SLOT = ${quoteTsString(slot)} as const;
|
|
320
|
-
export const REQUIRED_CAPABILITY = 'edit_posts' as const;
|
|
321
|
-
|
|
322
|
-
const DEFAULT_EDITOR_PLUGIN_MODEL: ${typeName} = {
|
|
323
|
-
\tprimaryActionLabel: ${quoteTsString(`Review ${pluginTitle}`)},
|
|
324
|
-
\tsummary: ${quoteTsString(`Replace this summary with your ${pluginTitle} workflow state.`)},
|
|
325
|
-
};
|
|
326
|
-
|
|
327
|
-
export function ${modelFactoryName}(): ${typeName} {
|
|
328
|
-
\treturn DEFAULT_EDITOR_PLUGIN_MODEL;
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
export function ${enabledFactoryName}(): boolean {
|
|
332
|
-
\treturn true;
|
|
333
|
-
}
|
|
334
|
-
`;
|
|
335
|
-
}
|
|
336
|
-
function buildEditorPluginSurfaceSource(editorPluginSlug, slot, textDomain) {
|
|
337
|
-
const pascalName = toPascalCase(editorPluginSlug);
|
|
338
|
-
const modelFactoryName = `get${pascalName}EditorPluginModel`;
|
|
339
|
-
const enabledFactoryName = `is${pascalName}Enabled`;
|
|
340
|
-
const componentName = `${pascalName}Surface`;
|
|
341
|
-
if (slot === "document-setting-panel") {
|
|
342
|
-
return `import { Button } from '@wordpress/components';
|
|
343
|
-
import { PluginDocumentSettingPanel } from '@wordpress/editor';
|
|
344
|
-
import { __ } from '@wordpress/i18n';
|
|
345
|
-
|
|
346
|
-
import { ${modelFactoryName}, ${enabledFactoryName} } from './data';
|
|
347
|
-
import './style.scss';
|
|
348
|
-
|
|
349
|
-
export interface ${componentName}Props {
|
|
350
|
-
\tsurfaceName: string;
|
|
351
|
-
\ttitle: string;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
export function ${componentName}( {
|
|
355
|
-
\tsurfaceName,
|
|
356
|
-
\ttitle,
|
|
357
|
-
}: ${componentName}Props ) {
|
|
358
|
-
\tif ( ! ${enabledFactoryName}() ) {
|
|
359
|
-
\t\treturn null;
|
|
360
|
-
\t}
|
|
361
|
-
|
|
362
|
-
\tconst editorPluginModel = ${modelFactoryName}();
|
|
363
|
-
|
|
364
|
-
\treturn (
|
|
365
|
-
\t\t<PluginDocumentSettingPanel
|
|
366
|
-
\t\t\tclassName="wp-typia-editor-plugin-shell"
|
|
367
|
-
\t\t\tname={ surfaceName }
|
|
368
|
-
\t\t\ttitle={ title }
|
|
369
|
-
\t\t>
|
|
370
|
-
\t\t\t<p>{ editorPluginModel.summary }</p>
|
|
371
|
-
\t\t\t<Button variant="secondary">
|
|
372
|
-
\t\t\t\t{ editorPluginModel.primaryActionLabel }
|
|
373
|
-
\t\t\t</Button>
|
|
374
|
-
\t\t\t<p className="wp-typia-editor-plugin-shell__hint">
|
|
375
|
-
\t\t\t\t{ __( 'Use data.ts to add post type, capability, or editor context guards before showing this panel.', ${quoteTsString(textDomain)} ) }
|
|
376
|
-
\t\t\t</p>
|
|
377
|
-
\t\t</PluginDocumentSettingPanel>
|
|
378
|
-
\t);
|
|
379
|
-
}
|
|
380
|
-
`;
|
|
381
|
-
}
|
|
382
|
-
return `import { Button, PanelBody } from '@wordpress/components';
|
|
383
|
-
import { PluginSidebar, PluginSidebarMoreMenuItem } from '@wordpress/editor';
|
|
384
|
-
import { __ } from '@wordpress/i18n';
|
|
385
|
-
|
|
386
|
-
import { ${modelFactoryName}, ${enabledFactoryName} } from './data';
|
|
387
|
-
import './style.scss';
|
|
388
|
-
|
|
389
|
-
export interface ${componentName}Props {
|
|
390
|
-
\tsurfaceName: string;
|
|
391
|
-
\ttitle: string;
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
export function ${componentName}( {
|
|
395
|
-
\tsurfaceName,
|
|
396
|
-
\ttitle,
|
|
397
|
-
}: ${componentName}Props ) {
|
|
398
|
-
\tif ( ! ${enabledFactoryName}() ) {
|
|
399
|
-
\t\treturn null;
|
|
400
|
-
\t}
|
|
401
|
-
|
|
402
|
-
\tconst editorPluginModel = ${modelFactoryName}();
|
|
403
|
-
|
|
404
|
-
\treturn (
|
|
405
|
-
\t\t<>
|
|
406
|
-
\t\t\t<PluginSidebarMoreMenuItem target={ surfaceName }>
|
|
407
|
-
\t\t\t\t{ title }
|
|
408
|
-
\t\t\t</PluginSidebarMoreMenuItem>
|
|
409
|
-
\t\t\t<PluginSidebar name={ surfaceName } title={ title }>
|
|
410
|
-
\t\t\t\t<div className="wp-typia-editor-plugin-shell">
|
|
411
|
-
\t\t\t\t\t<PanelBody
|
|
412
|
-
\t\t\t\t\t\tinitialOpen
|
|
413
|
-
\t\t\t\t\t\ttitle={ __( 'Document workflow', ${quoteTsString(textDomain)} ) }
|
|
414
|
-
\t\t\t\t\t>
|
|
415
|
-
\t\t\t\t\t\t<p>{ editorPluginModel.summary }</p>
|
|
416
|
-
\t\t\t\t\t\t<Button variant="secondary">
|
|
417
|
-
\t\t\t\t\t\t\t{ editorPluginModel.primaryActionLabel }
|
|
418
|
-
\t\t\t\t\t\t</Button>
|
|
419
|
-
\t\t\t\t\t</PanelBody>
|
|
420
|
-
\t\t\t\t</div>
|
|
421
|
-
\t\t\t</PluginSidebar>
|
|
422
|
-
\t\t</>
|
|
423
|
-
\t);
|
|
424
|
-
}
|
|
425
|
-
`;
|
|
426
|
-
}
|
|
427
|
-
function buildEditorPluginEntrySource(editorPluginSlug, namespace, textDomain) {
|
|
428
|
-
const pascalName = toPascalCase(editorPluginSlug);
|
|
429
|
-
const componentName = `${pascalName}Surface`;
|
|
430
|
-
const pluginName = `${namespace}-${editorPluginSlug}`;
|
|
431
|
-
const surfaceName = `${pluginName}-surface`;
|
|
432
|
-
const pluginTitle = toTitleCase(editorPluginSlug);
|
|
433
|
-
return `import { registerPlugin } from '@wordpress/plugins';
|
|
434
|
-
import { __ } from '@wordpress/i18n';
|
|
435
|
-
|
|
436
|
-
import { REQUIRED_CAPABILITY } from './data';
|
|
437
|
-
import { ${componentName} } from './Surface';
|
|
438
|
-
|
|
439
|
-
const EDITOR_PLUGIN_NAME = ${quoteTsString(pluginName)};
|
|
440
|
-
const EDITOR_PLUGIN_SURFACE_NAME = ${quoteTsString(surfaceName)};
|
|
441
|
-
const EDITOR_PLUGIN_TITLE = __( ${quoteTsString(pluginTitle)}, ${quoteTsString(textDomain)} );
|
|
442
|
-
|
|
443
|
-
registerPlugin( EDITOR_PLUGIN_NAME, {
|
|
444
|
-
\ticon: 'admin-generic',
|
|
445
|
-
\trender: () => (
|
|
446
|
-
\t\t<${componentName}
|
|
447
|
-
\t\t\tsurfaceName={ EDITOR_PLUGIN_SURFACE_NAME }
|
|
448
|
-
\t\t\ttitle={ EDITOR_PLUGIN_TITLE }
|
|
449
|
-
\t\t/>
|
|
450
|
-
\t),
|
|
451
|
-
} );
|
|
452
|
-
|
|
453
|
-
export { REQUIRED_CAPABILITY };
|
|
454
|
-
`;
|
|
455
|
-
}
|
|
456
|
-
function buildEditorPluginStyleSource() {
|
|
457
|
-
return `.wp-typia-editor-plugin-shell {
|
|
458
|
-
\tpadding: 16px;
|
|
459
|
-
}
|
|
460
|
-
|
|
461
|
-
.wp-typia-editor-plugin-shell p {
|
|
462
|
-
\tmargin: 0 0 12px;
|
|
463
|
-
}
|
|
464
|
-
|
|
465
|
-
.wp-typia-editor-plugin-shell__hint {
|
|
466
|
-
\tcolor: #757575;
|
|
467
|
-
\tfont-size: 12px;
|
|
468
|
-
}
|
|
469
|
-
`;
|
|
470
|
-
}
|
|
471
|
-
function buildBindingSourceIndexSource(bindingSourceSlugs) {
|
|
472
|
-
const importLines = bindingSourceSlugs
|
|
473
|
-
.map((bindingSourceSlug) => `import './${bindingSourceSlug}/editor';`)
|
|
474
|
-
.join("\n");
|
|
475
|
-
return `${importLines}${importLines ? "\n\n" : ""}// wp-typia add binding-source entries\n`;
|
|
476
|
-
}
|
|
477
|
-
function buildEditorPluginRegistrySource(editorPluginSlugs) {
|
|
478
|
-
const importLines = editorPluginSlugs
|
|
479
|
-
.map((editorPluginSlug) => `import './${editorPluginSlug}';`)
|
|
480
|
-
.join("\n");
|
|
481
|
-
return `${importLines}${importLines ? "\n\n" : ""}// wp-typia add editor-plugin entries\n`;
|
|
482
|
-
}
|
|
483
|
-
async function ensurePatternBootstrapAnchors(workspace) {
|
|
484
|
-
const workspaceBaseName = workspace.packageName.split("/").pop() ?? workspace.packageName;
|
|
485
|
-
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
486
|
-
await patchFile(bootstrapPath, (source) => {
|
|
487
|
-
let nextSource = source;
|
|
488
|
-
const patternCategoryFunctionName = `${workspace.workspace.phpPrefix}_register_pattern_category`;
|
|
489
|
-
const patternRegistrationFunctionName = `${workspace.workspace.phpPrefix}_register_patterns`;
|
|
490
|
-
const patternCategoryHook = `add_action( 'init', '${patternCategoryFunctionName}' );`;
|
|
491
|
-
const patternRegistrationHook = `add_action( 'init', '${patternRegistrationFunctionName}', 20 );`;
|
|
492
|
-
const patternFunctions = `
|
|
493
|
-
|
|
494
|
-
function ${patternCategoryFunctionName}() {
|
|
495
|
-
\tif ( function_exists( 'register_block_pattern_category' ) ) {
|
|
496
|
-
\t\tregister_block_pattern_category(
|
|
497
|
-
\t\t\t'${workspace.workspace.namespace}',
|
|
498
|
-
\t\t\tarray(
|
|
499
|
-
\t\t\t\t'label' => __( ${JSON.stringify(`${toTitleCase(workspaceBaseName)} Patterns`)}, '${workspace.workspace.textDomain}' ),
|
|
500
|
-
\t\t\t)
|
|
501
|
-
\t\t);
|
|
502
|
-
\t}
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
function ${patternRegistrationFunctionName}() {
|
|
506
|
-
\tforeach ( glob( __DIR__ . '/src/patterns/*.php' ) ?: array() as $pattern_module ) {
|
|
507
|
-
\t\trequire $pattern_module;
|
|
508
|
-
\t}
|
|
509
|
-
}
|
|
510
|
-
`;
|
|
511
|
-
if (!nextSource.includes(PATTERN_BOOTSTRAP_CATEGORY)) {
|
|
512
|
-
const insertionAnchors = [
|
|
513
|
-
/add_action\(\s*["']init["']\s*,\s*["'][^"']+_load_textdomain["']\s*\);\s*\n/u,
|
|
514
|
-
/\?>\s*$/u,
|
|
515
|
-
];
|
|
516
|
-
let inserted = false;
|
|
517
|
-
for (const anchor of insertionAnchors) {
|
|
518
|
-
const candidate = nextSource.replace(anchor, (match) => `${patternFunctions}\n${match}`);
|
|
519
|
-
if (candidate !== nextSource) {
|
|
520
|
-
nextSource = candidate;
|
|
521
|
-
inserted = true;
|
|
522
|
-
break;
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
if (!inserted) {
|
|
526
|
-
nextSource = `${nextSource.trimEnd()}\n${patternFunctions}\n`;
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
if (!nextSource.includes(patternCategoryFunctionName) ||
|
|
530
|
-
!nextSource.includes(patternRegistrationFunctionName)) {
|
|
531
|
-
throw new Error(`Unable to inject pattern bootstrap functions into ${path.basename(bootstrapPath)}.`);
|
|
532
|
-
}
|
|
533
|
-
if (!nextSource.includes(patternCategoryHook)) {
|
|
534
|
-
nextSource = `${nextSource.trimEnd()}\n${patternCategoryHook}\n`;
|
|
535
|
-
}
|
|
536
|
-
if (!nextSource.includes(patternRegistrationHook)) {
|
|
537
|
-
nextSource = `${nextSource.trimEnd()}\n${patternRegistrationHook}\n`;
|
|
538
|
-
}
|
|
539
|
-
return nextSource;
|
|
540
|
-
});
|
|
541
|
-
}
|
|
542
|
-
async function ensureBindingSourceBootstrapAnchors(workspace) {
|
|
543
|
-
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
544
|
-
await patchFile(bootstrapPath, (source) => {
|
|
545
|
-
let nextSource = source;
|
|
546
|
-
const workspaceBaseName = workspace.packageName.split("/").pop() ?? workspace.packageName;
|
|
547
|
-
const bindingRegistrationFunctionName = `${workspace.workspace.phpPrefix}_register_binding_sources`;
|
|
548
|
-
const bindingEditorEnqueueFunctionName = `${workspace.workspace.phpPrefix}_enqueue_binding_sources_editor`;
|
|
549
|
-
const bindingRegistrationHook = `add_action( 'init', '${bindingRegistrationFunctionName}', 20 );`;
|
|
550
|
-
const bindingEditorEnqueueHook = `add_action( 'enqueue_block_editor_assets', '${bindingEditorEnqueueFunctionName}' );`;
|
|
551
|
-
const bindingRegistrationFunction = `
|
|
552
|
-
|
|
553
|
-
function ${bindingRegistrationFunctionName}() {
|
|
554
|
-
\tforeach ( glob( __DIR__ . '${BINDING_SOURCE_SERVER_GLOB}' ) ?: array() as $binding_source_module ) {
|
|
555
|
-
\t\trequire_once $binding_source_module;
|
|
556
|
-
\t}
|
|
557
|
-
}
|
|
558
|
-
`;
|
|
559
|
-
const bindingEditorEnqueueFunction = `
|
|
560
|
-
|
|
561
|
-
function ${bindingEditorEnqueueFunctionName}() {
|
|
562
|
-
\t$script_path = __DIR__ . '/${BINDING_SOURCE_EDITOR_SCRIPT}';
|
|
563
|
-
\t$asset_path = __DIR__ . '/${BINDING_SOURCE_EDITOR_ASSET}';
|
|
564
|
-
|
|
565
|
-
\tif ( ! file_exists( $script_path ) || ! file_exists( $asset_path ) ) {
|
|
566
|
-
\t\treturn;
|
|
567
|
-
\t}
|
|
568
|
-
|
|
569
|
-
\t$asset = require $asset_path;
|
|
570
|
-
\tif ( ! is_array( $asset ) ) {
|
|
571
|
-
\t\t$asset = array();
|
|
572
|
-
\t}
|
|
573
|
-
|
|
574
|
-
\twp_enqueue_script(
|
|
575
|
-
\t\t'${workspaceBaseName}-binding-sources',
|
|
576
|
-
\t\tplugins_url( '${BINDING_SOURCE_EDITOR_SCRIPT}', __FILE__ ),
|
|
577
|
-
\t\tisset( $asset['dependencies'] ) && is_array( $asset['dependencies'] ) ? $asset['dependencies'] : array(),
|
|
578
|
-
\t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $script_path ),
|
|
579
|
-
\t\ttrue
|
|
580
|
-
\t);
|
|
581
|
-
}
|
|
582
|
-
`;
|
|
583
|
-
if (!hasPhpFunctionDefinition(nextSource, bindingRegistrationFunctionName)) {
|
|
584
|
-
nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, bindingRegistrationFunction);
|
|
585
|
-
}
|
|
586
|
-
if (!hasPhpFunctionDefinition(nextSource, bindingEditorEnqueueFunctionName)) {
|
|
587
|
-
nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, bindingEditorEnqueueFunction);
|
|
588
|
-
}
|
|
589
|
-
if (!nextSource.includes(bindingRegistrationHook)) {
|
|
590
|
-
nextSource = appendPhpSnippetBeforeClosingTag(nextSource, bindingRegistrationHook);
|
|
591
|
-
}
|
|
592
|
-
if (!nextSource.includes(bindingEditorEnqueueHook)) {
|
|
593
|
-
nextSource = appendPhpSnippetBeforeClosingTag(nextSource, bindingEditorEnqueueHook);
|
|
594
|
-
}
|
|
595
|
-
return nextSource;
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
async function ensureEditorPluginBootstrapAnchors(workspace) {
|
|
599
|
-
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
600
|
-
await patchFile(bootstrapPath, (source) => {
|
|
601
|
-
let nextSource = source;
|
|
602
|
-
const workspaceBaseName = workspace.packageName.split("/").pop() ?? workspace.packageName;
|
|
603
|
-
const enqueueFunctionName = `${workspace.workspace.phpPrefix}_enqueue_editor_plugins_editor`;
|
|
604
|
-
const enqueueHook = `add_action( 'enqueue_block_editor_assets', '${enqueueFunctionName}' );`;
|
|
605
|
-
const enqueueFunction = `
|
|
606
|
-
|
|
607
|
-
function ${enqueueFunctionName}() {
|
|
608
|
-
\t$script_path = __DIR__ . '/${EDITOR_PLUGIN_EDITOR_SCRIPT}';
|
|
609
|
-
\t$asset_path = __DIR__ . '/${EDITOR_PLUGIN_EDITOR_ASSET}';
|
|
610
|
-
\t$style_path = __DIR__ . '/${EDITOR_PLUGIN_EDITOR_STYLE}';
|
|
611
|
-
\t$style_rtl_path = __DIR__ . '/${EDITOR_PLUGIN_EDITOR_STYLE_RTL}';
|
|
612
|
-
|
|
613
|
-
\tif ( ! file_exists( $script_path ) || ! file_exists( $asset_path ) ) {
|
|
614
|
-
\t\treturn;
|
|
615
|
-
\t}
|
|
616
|
-
|
|
617
|
-
\t$asset = require $asset_path;
|
|
618
|
-
\tif ( ! is_array( $asset ) ) {
|
|
619
|
-
\t\t$asset = array();
|
|
620
|
-
\t}
|
|
621
|
-
|
|
622
|
-
\twp_enqueue_script(
|
|
623
|
-
\t\t'${workspaceBaseName}-editor-plugins',
|
|
624
|
-
\t\tplugins_url( '${EDITOR_PLUGIN_EDITOR_SCRIPT}', __FILE__ ),
|
|
625
|
-
\t\tisset( $asset['dependencies'] ) && is_array( $asset['dependencies'] ) ? $asset['dependencies'] : array(),
|
|
626
|
-
\t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $script_path ),
|
|
627
|
-
\t\ttrue
|
|
628
|
-
\t);
|
|
629
|
-
|
|
630
|
-
\tif ( file_exists( $style_path ) ) {
|
|
631
|
-
\t\twp_enqueue_style(
|
|
632
|
-
\t\t\t'${workspaceBaseName}-editor-plugins',
|
|
633
|
-
\t\t\tplugins_url( '${EDITOR_PLUGIN_EDITOR_STYLE}', __FILE__ ),
|
|
634
|
-
\t\t\tarray(),
|
|
635
|
-
\t\t\tisset( $asset['version'] ) ? $asset['version'] : filemtime( $style_path )
|
|
636
|
-
\t\t);
|
|
637
|
-
\t\tif ( file_exists( $style_rtl_path ) ) {
|
|
638
|
-
\t\t\twp_style_add_data( '${workspaceBaseName}-editor-plugins', 'rtl', 'replace' );
|
|
639
|
-
\t\t}
|
|
640
|
-
\t}
|
|
641
|
-
}
|
|
642
|
-
`;
|
|
643
|
-
if (!hasPhpFunctionDefinition(nextSource, enqueueFunctionName)) {
|
|
644
|
-
nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, enqueueFunction);
|
|
645
|
-
}
|
|
646
|
-
else {
|
|
647
|
-
const requiredReferences = [
|
|
648
|
-
EDITOR_PLUGIN_EDITOR_SCRIPT,
|
|
649
|
-
EDITOR_PLUGIN_EDITOR_ASSET,
|
|
650
|
-
EDITOR_PLUGIN_EDITOR_STYLE,
|
|
651
|
-
EDITOR_PLUGIN_EDITOR_STYLE_RTL,
|
|
652
|
-
"wp_style_add_data",
|
|
653
|
-
];
|
|
654
|
-
const functionRange = findPhpFunctionRange(nextSource, enqueueFunctionName);
|
|
655
|
-
const functionSource = functionRange
|
|
656
|
-
? nextSource.slice(functionRange.start, functionRange.end)
|
|
657
|
-
: "";
|
|
658
|
-
const missingReferences = requiredReferences.filter((reference) => !functionSource.includes(reference));
|
|
659
|
-
if (missingReferences.length > 0) {
|
|
660
|
-
const replacedSource = replacePhpFunctionDefinition(nextSource, enqueueFunctionName, enqueueFunction);
|
|
661
|
-
if (!replacedSource) {
|
|
662
|
-
throw new Error(`Unable to repair ${path.basename(bootstrapPath)} for ${enqueueFunctionName}.`);
|
|
663
|
-
}
|
|
664
|
-
nextSource = replacedSource;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
if (!nextSource.includes(enqueueHook)) {
|
|
668
|
-
nextSource = appendPhpSnippetBeforeClosingTag(nextSource, enqueueHook);
|
|
669
|
-
}
|
|
670
|
-
return nextSource;
|
|
671
|
-
});
|
|
672
|
-
}
|
|
673
|
-
async function ensureEditorPluginBuildScriptAnchors(workspace) {
|
|
674
|
-
const buildScriptPath = path.join(workspace.projectDir, "scripts", "build-workspace.mjs");
|
|
675
|
-
await patchFile(buildScriptPath, (source) => {
|
|
676
|
-
if (/['"]src\/editor-plugins\/index\.(?:ts|js)['"]/u.test(source)) {
|
|
677
|
-
return source;
|
|
678
|
-
}
|
|
679
|
-
const legacySharedEntriesPattern = /\[\s*['"]src\/bindings\/index\.ts['"]\s*,\s*['"]src\/bindings\/index\.js['"]\s*(?:,\s*)?\]/u;
|
|
680
|
-
const nextSource = source.replace(legacySharedEntriesPattern, `[
|
|
681
|
-
\t\t'src/bindings/index.ts',
|
|
682
|
-
\t\t'src/bindings/index.js',
|
|
683
|
-
\t\t'src/editor-plugins/index.ts',
|
|
684
|
-
\t\t'src/editor-plugins/index.js',
|
|
685
|
-
\t]`);
|
|
686
|
-
if (nextSource === source) {
|
|
687
|
-
throw new Error(`Unable to update ${path.relative(workspace.projectDir, buildScriptPath)} for editor plugin shared entries.`);
|
|
688
|
-
}
|
|
689
|
-
return nextSource;
|
|
690
|
-
});
|
|
691
|
-
}
|
|
692
|
-
async function ensureEditorPluginWebpackAnchors(workspace) {
|
|
693
|
-
const webpackConfigPath = path.join(workspace.projectDir, "webpack.config.js");
|
|
694
|
-
await patchFile(webpackConfigPath, (source) => {
|
|
695
|
-
if (/['"]editor-plugins\/index['"]/u.test(source)) {
|
|
696
|
-
return source;
|
|
697
|
-
}
|
|
698
|
-
const legacySharedEntriesBlockPattern = /for\s*\(\s*const\s+relativePath\s+of\s+\[\s*['"]src\/bindings\/index\.ts['"]\s*,\s*['"]src\/bindings\/index\.js['"]\s*(?:,\s*)?\]\s*\)\s*\{[\s\S]*?entries\.push\(\s*\[\s*['"]bindings\/index['"]\s*,\s*entryPath\s*\]\s*\);\s*break;\s*\}/u;
|
|
699
|
-
const nextSharedEntriesBlock = `\tfor ( const [ entryName, candidates ] of [\n\t\t[\n\t\t\t'bindings/index',\n\t\t\t[ 'src/bindings/index.ts', 'src/bindings/index.js' ],\n\t\t],\n\t\t[\n\t\t\t'editor-plugins/index',\n\t\t\t[ 'src/editor-plugins/index.ts', 'src/editor-plugins/index.js' ],\n\t\t],\n\t] ) {\n\t\tfor ( const relativePath of candidates ) {\n\t\t\tconst entryPath = path.resolve( process.cwd(), relativePath );\n\t\t\tif ( ! fs.existsSync( entryPath ) ) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tentries.push( [ entryName, entryPath ] );\n\t\t\tbreak;\n\t\t}\n\t}`;
|
|
700
|
-
const nextSource = source.replace(legacySharedEntriesBlockPattern, nextSharedEntriesBlock);
|
|
701
|
-
if (nextSource === source) {
|
|
702
|
-
throw new Error(`Unable to update ${path.relative(workspace.projectDir, webpackConfigPath)} for editor plugin shared entries.`);
|
|
703
|
-
}
|
|
704
|
-
return nextSource;
|
|
705
|
-
});
|
|
706
|
-
}
|
|
707
|
-
async function resolveBindingSourceRegistryPath(projectDir) {
|
|
708
|
-
const bindingsDir = path.join(projectDir, "src", "bindings");
|
|
709
|
-
for (const candidatePath of [
|
|
710
|
-
path.join(bindingsDir, "index.ts"),
|
|
711
|
-
path.join(bindingsDir, "index.js"),
|
|
712
|
-
]) {
|
|
713
|
-
if (await pathExists(candidatePath)) {
|
|
714
|
-
return candidatePath;
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
return path.join(bindingsDir, "index.ts");
|
|
718
|
-
}
|
|
719
|
-
async function writeBindingSourceRegistry(projectDir, bindingSourceSlug) {
|
|
720
|
-
const bindingsDir = path.join(projectDir, "src", "bindings");
|
|
721
|
-
const bindingsIndexPath = await resolveBindingSourceRegistryPath(projectDir);
|
|
722
|
-
await fsp.mkdir(bindingsDir, { recursive: true });
|
|
723
|
-
const existingBindingSourceSlugs = (await fsp.readdir(bindingsDir, { withFileTypes: true }))
|
|
724
|
-
.filter((entry) => entry.isDirectory())
|
|
725
|
-
.map((entry) => entry.name);
|
|
726
|
-
const nextBindingSourceSlugs = Array.from(new Set([...existingBindingSourceSlugs, bindingSourceSlug])).sort();
|
|
727
|
-
await fsp.writeFile(bindingsIndexPath, buildBindingSourceIndexSource(nextBindingSourceSlugs), "utf8");
|
|
728
|
-
}
|
|
729
|
-
async function resolveEditorPluginRegistryPath(projectDir) {
|
|
730
|
-
const editorPluginsDir = path.join(projectDir, "src", "editor-plugins");
|
|
731
|
-
for (const candidatePath of [
|
|
732
|
-
path.join(editorPluginsDir, "index.ts"),
|
|
733
|
-
path.join(editorPluginsDir, "index.js"),
|
|
734
|
-
]) {
|
|
735
|
-
if (await pathExists(candidatePath)) {
|
|
736
|
-
return candidatePath;
|
|
737
|
-
}
|
|
738
|
-
}
|
|
739
|
-
return path.join(editorPluginsDir, "index.ts");
|
|
740
|
-
}
|
|
741
|
-
async function readEditorPluginRegistrySlugs(registryPath) {
|
|
742
|
-
const source = await readOptionalUtf8File(registryPath);
|
|
743
|
-
if (source === null) {
|
|
744
|
-
return [];
|
|
745
|
-
}
|
|
746
|
-
return Array.from(source.matchAll(/^\s*import\s+['"]\.\/([^/'"]+)(?:\/index(?:\.[cm]?[jt]sx?)?)?['"];?\s*$/gmu)).map((match) => match[1]);
|
|
747
|
-
}
|
|
748
|
-
async function writeEditorPluginRegistry(projectDir, editorPluginSlug) {
|
|
749
|
-
const editorPluginsDir = path.join(projectDir, "src", "editor-plugins");
|
|
750
|
-
const registryPath = await resolveEditorPluginRegistryPath(projectDir);
|
|
751
|
-
await fsp.mkdir(editorPluginsDir, { recursive: true });
|
|
752
|
-
const existingEditorPluginSlugs = (await readWorkspaceInventoryAsync(projectDir)).editorPlugins.map((entry) => entry.slug);
|
|
753
|
-
const existingRegistrySlugs = await readEditorPluginRegistrySlugs(registryPath);
|
|
754
|
-
const nextEditorPluginSlugs = Array.from(new Set([...existingEditorPluginSlugs, ...existingRegistrySlugs, editorPluginSlug])).sort();
|
|
755
|
-
await fsp.writeFile(registryPath, buildEditorPluginRegistrySource(nextEditorPluginSlugs), "utf8");
|
|
756
|
-
}
|
|
757
1
|
/**
|
|
758
|
-
*
|
|
2
|
+
* Compatibility facade for workspace asset add commands.
|
|
759
3
|
*
|
|
760
|
-
*
|
|
761
|
-
*
|
|
762
|
-
* Defaults to `process.cwd()`.
|
|
763
|
-
* @param options.editorPluginName Human-entered editor-plugin name that will be
|
|
764
|
-
* normalized and validated before files are written.
|
|
765
|
-
* @param options.slot Optional editor plugin shell slot. Defaults to `sidebar`.
|
|
766
|
-
* @returns A promise that resolves with the normalized `editorPluginSlug`, chosen
|
|
767
|
-
* `slot`, and owning `projectDir` after the scaffold files and inventory entry
|
|
768
|
-
* are written successfully.
|
|
769
|
-
* @throws {Error} When the command is run outside an official workspace, when the
|
|
770
|
-
* slug or slot is invalid, or when a conflicting file or inventory entry exists.
|
|
4
|
+
* Keep the public runtime import path stable while each workflow lives in a
|
|
5
|
+
* focused implementation module.
|
|
771
6
|
*/
|
|
772
|
-
export
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
const resolvedSlot = assertValidEditorPluginSlot(slot);
|
|
776
|
-
const inventory = await readWorkspaceInventoryAsync(workspace.projectDir);
|
|
777
|
-
assertEditorPluginDoesNotExist(workspace.projectDir, editorPluginSlug, inventory);
|
|
778
|
-
const blockConfigPath = path.join(workspace.projectDir, "scripts", "block-config.ts");
|
|
779
|
-
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
780
|
-
const buildScriptPath = path.join(workspace.projectDir, "scripts", "build-workspace.mjs");
|
|
781
|
-
const editorPluginsIndexPath = await resolveEditorPluginRegistryPath(workspace.projectDir);
|
|
782
|
-
const webpackConfigPath = path.join(workspace.projectDir, "webpack.config.js");
|
|
783
|
-
const editorPluginDir = path.join(workspace.projectDir, "src", "editor-plugins", editorPluginSlug);
|
|
784
|
-
const entryFilePath = path.join(editorPluginDir, "index.tsx");
|
|
785
|
-
const surfaceFilePath = path.join(editorPluginDir, "Surface.tsx");
|
|
786
|
-
const dataFilePath = path.join(editorPluginDir, "data.ts");
|
|
787
|
-
const typesFilePath = path.join(editorPluginDir, "types.ts");
|
|
788
|
-
const styleFilePath = path.join(editorPluginDir, "style.scss");
|
|
789
|
-
const mutationSnapshot = {
|
|
790
|
-
fileSources: await snapshotWorkspaceFiles([
|
|
791
|
-
blockConfigPath,
|
|
792
|
-
bootstrapPath,
|
|
793
|
-
buildScriptPath,
|
|
794
|
-
editorPluginsIndexPath,
|
|
795
|
-
webpackConfigPath,
|
|
796
|
-
]),
|
|
797
|
-
snapshotDirs: [],
|
|
798
|
-
targetPaths: [editorPluginDir],
|
|
799
|
-
};
|
|
800
|
-
try {
|
|
801
|
-
await fsp.mkdir(editorPluginDir, { recursive: true });
|
|
802
|
-
await ensureEditorPluginBootstrapAnchors(workspace);
|
|
803
|
-
await ensureEditorPluginBuildScriptAnchors(workspace);
|
|
804
|
-
await ensureEditorPluginWebpackAnchors(workspace);
|
|
805
|
-
await fsp.writeFile(entryFilePath, buildEditorPluginEntrySource(editorPluginSlug, workspace.workspace.namespace, workspace.workspace.textDomain), "utf8");
|
|
806
|
-
await fsp.writeFile(surfaceFilePath, buildEditorPluginSurfaceSource(editorPluginSlug, resolvedSlot, workspace.workspace.textDomain), "utf8");
|
|
807
|
-
await fsp.writeFile(dataFilePath, buildEditorPluginDataSource(editorPluginSlug, resolvedSlot), "utf8");
|
|
808
|
-
await fsp.writeFile(typesFilePath, buildEditorPluginTypesSource(editorPluginSlug), "utf8");
|
|
809
|
-
await fsp.writeFile(styleFilePath, buildEditorPluginStyleSource(), "utf8");
|
|
810
|
-
await writeEditorPluginRegistry(workspace.projectDir, editorPluginSlug);
|
|
811
|
-
await appendWorkspaceInventoryEntries(workspace.projectDir, {
|
|
812
|
-
editorPluginEntries: [
|
|
813
|
-
buildEditorPluginConfigEntry(editorPluginSlug, resolvedSlot),
|
|
814
|
-
],
|
|
815
|
-
});
|
|
816
|
-
return {
|
|
817
|
-
editorPluginSlug,
|
|
818
|
-
projectDir: workspace.projectDir,
|
|
819
|
-
slot: resolvedSlot,
|
|
820
|
-
};
|
|
821
|
-
}
|
|
822
|
-
catch (error) {
|
|
823
|
-
await rollbackWorkspaceMutation(mutationSnapshot);
|
|
824
|
-
throw error;
|
|
825
|
-
}
|
|
826
|
-
}
|
|
827
|
-
/**
|
|
828
|
-
* Add one PHP block pattern shell to an official workspace project.
|
|
829
|
-
*
|
|
830
|
-
* @param options Command options for the pattern scaffold workflow.
|
|
831
|
-
* @param options.cwd Working directory used to resolve the nearest official workspace.
|
|
832
|
-
* Defaults to `process.cwd()`.
|
|
833
|
-
* @param options.patternName Human-entered pattern name that will be normalized
|
|
834
|
-
* and validated before files are written.
|
|
835
|
-
* @returns A promise that resolves with the normalized `patternSlug` and
|
|
836
|
-
* owning `projectDir` after the pattern file and inventory entry have been
|
|
837
|
-
* written successfully.
|
|
838
|
-
* @throws {Error} When the command is run outside an official workspace, when
|
|
839
|
-
* the pattern slug is invalid, or when a conflicting file or inventory entry
|
|
840
|
-
* already exists.
|
|
841
|
-
*/
|
|
842
|
-
export async function runAddPatternCommand({ cwd = process.cwd(), patternName, }) {
|
|
843
|
-
const workspace = resolveWorkspaceProject(cwd);
|
|
844
|
-
const patternSlug = assertValidGeneratedSlug("Pattern name", normalizeBlockSlug(patternName), "wp-typia add pattern <name>");
|
|
845
|
-
const inventory = await readWorkspaceInventoryAsync(workspace.projectDir);
|
|
846
|
-
assertPatternDoesNotExist(workspace.projectDir, patternSlug, inventory);
|
|
847
|
-
const blockConfigPath = path.join(workspace.projectDir, "scripts", "block-config.ts");
|
|
848
|
-
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
849
|
-
const patternFilePath = path.join(workspace.projectDir, "src", "patterns", `${patternSlug}.php`);
|
|
850
|
-
const mutationSnapshot = {
|
|
851
|
-
fileSources: await snapshotWorkspaceFiles([blockConfigPath, bootstrapPath]),
|
|
852
|
-
snapshotDirs: [],
|
|
853
|
-
targetPaths: [patternFilePath],
|
|
854
|
-
};
|
|
855
|
-
try {
|
|
856
|
-
await fsp.mkdir(path.dirname(patternFilePath), { recursive: true });
|
|
857
|
-
await ensurePatternBootstrapAnchors(workspace);
|
|
858
|
-
await fsp.writeFile(patternFilePath, buildPatternSource(patternSlug, workspace.workspace.namespace, workspace.workspace.textDomain), "utf8");
|
|
859
|
-
await appendWorkspaceInventoryEntries(workspace.projectDir, {
|
|
860
|
-
patternEntries: [buildPatternConfigEntry(patternSlug)],
|
|
861
|
-
});
|
|
862
|
-
return {
|
|
863
|
-
patternSlug,
|
|
864
|
-
projectDir: workspace.projectDir,
|
|
865
|
-
};
|
|
866
|
-
}
|
|
867
|
-
catch (error) {
|
|
868
|
-
await rollbackWorkspaceMutation(mutationSnapshot);
|
|
869
|
-
throw error;
|
|
870
|
-
}
|
|
871
|
-
}
|
|
872
|
-
/**
|
|
873
|
-
* Add one block binding source scaffold to an official workspace project.
|
|
874
|
-
*
|
|
875
|
-
* @param options Command options for the binding-source scaffold workflow.
|
|
876
|
-
* @param options.attributeName Optional generated block attribute to declare as
|
|
877
|
-
* bindable. Must be provided together with `blockName`.
|
|
878
|
-
* @param options.blockName Optional generated block slug or full block name to
|
|
879
|
-
* receive the bindable attribute wiring. Must be provided together with
|
|
880
|
-
* `attributeName`.
|
|
881
|
-
* @param options.bindingSourceName Human-entered binding source name that will
|
|
882
|
-
* be normalized and validated before files are written.
|
|
883
|
-
* @param options.cwd Working directory used to resolve the nearest official
|
|
884
|
-
* workspace. Defaults to `process.cwd()`.
|
|
885
|
-
* @returns A promise that resolves with the normalized `bindingSourceSlug` and
|
|
886
|
-
* owning `projectDir` after the server/editor files, optional target block
|
|
887
|
-
* metadata, and inventory entry have been written successfully.
|
|
888
|
-
* @throws {Error} When the command is run outside an official workspace, when
|
|
889
|
-
* the slug is invalid, when a binding target is incomplete or unknown, or when
|
|
890
|
-
* a conflicting file or inventory entry exists.
|
|
891
|
-
*/
|
|
892
|
-
export async function runAddBindingSourceCommand({ attributeName, bindingSourceName, blockName, cwd = process.cwd(), }) {
|
|
893
|
-
const workspace = resolveWorkspaceProject(cwd);
|
|
894
|
-
const bindingSourceSlug = assertValidGeneratedSlug("Binding source name", normalizeBlockSlug(bindingSourceName), "wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>]");
|
|
895
|
-
const inventory = await readWorkspaceInventoryAsync(workspace.projectDir);
|
|
896
|
-
assertBindingSourceDoesNotExist(workspace.projectDir, bindingSourceSlug, inventory);
|
|
897
|
-
const target = resolveBindingTarget({
|
|
898
|
-
attributeName,
|
|
899
|
-
blockName,
|
|
900
|
-
}, workspace.workspace.namespace);
|
|
901
|
-
const targetBlock = target ? resolveWorkspaceBlock(inventory, target.blockSlug) : undefined;
|
|
902
|
-
const blockConfigPath = path.join(workspace.projectDir, "scripts", "block-config.ts");
|
|
903
|
-
const bootstrapPath = getWorkspaceBootstrapPath(workspace);
|
|
904
|
-
const bindingsIndexPath = await resolveBindingSourceRegistryPath(workspace.projectDir);
|
|
905
|
-
const bindingSourceDir = path.join(workspace.projectDir, "src", "bindings", bindingSourceSlug);
|
|
906
|
-
const serverFilePath = path.join(bindingSourceDir, "server.php");
|
|
907
|
-
const editorFilePath = path.join(bindingSourceDir, "editor.ts");
|
|
908
|
-
const blockJsonPath = target
|
|
909
|
-
? path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "block.json")
|
|
910
|
-
: undefined;
|
|
911
|
-
const targetGeneratedMetadataPaths = target
|
|
912
|
-
? [
|
|
913
|
-
path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "typia.manifest.json"),
|
|
914
|
-
path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "typia.openapi.json"),
|
|
915
|
-
path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "typia.schema.json"),
|
|
916
|
-
path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "typia-validator.php"),
|
|
917
|
-
]
|
|
918
|
-
: [];
|
|
919
|
-
const mutationSnapshot = {
|
|
920
|
-
fileSources: await snapshotWorkspaceFiles([
|
|
921
|
-
blockConfigPath,
|
|
922
|
-
bootstrapPath,
|
|
923
|
-
bindingsIndexPath,
|
|
924
|
-
...(blockJsonPath ? [blockJsonPath] : []),
|
|
925
|
-
...(targetBlock ? [path.join(workspace.projectDir, targetBlock.typesFile)] : []),
|
|
926
|
-
...targetGeneratedMetadataPaths,
|
|
927
|
-
]),
|
|
928
|
-
snapshotDirs: [],
|
|
929
|
-
targetPaths: [bindingSourceDir],
|
|
930
|
-
};
|
|
931
|
-
try {
|
|
932
|
-
await fsp.mkdir(bindingSourceDir, { recursive: true });
|
|
933
|
-
await ensureBindingSourceBootstrapAnchors(workspace);
|
|
934
|
-
await fsp.writeFile(serverFilePath, buildBindingSourceServerSource(bindingSourceSlug, workspace.workspace.phpPrefix, workspace.workspace.namespace, workspace.workspace.textDomain, target), "utf8");
|
|
935
|
-
await fsp.writeFile(editorFilePath, buildBindingSourceEditorSource(bindingSourceSlug, workspace.workspace.namespace, workspace.workspace.textDomain, target), "utf8");
|
|
936
|
-
if (target && targetBlock) {
|
|
937
|
-
await ensureBindingTargetBlockAttributeType(workspace.projectDir, targetBlock, target);
|
|
938
|
-
}
|
|
939
|
-
await writeBindingSourceRegistry(workspace.projectDir, bindingSourceSlug);
|
|
940
|
-
await appendWorkspaceInventoryEntries(workspace.projectDir, {
|
|
941
|
-
bindingSourceEntries: [buildBindingSourceConfigEntry(bindingSourceSlug, target)],
|
|
942
|
-
});
|
|
943
|
-
return {
|
|
944
|
-
...(target ? { attributeName: target.attributeName, blockSlug: target.blockSlug } : {}),
|
|
945
|
-
bindingSourceSlug,
|
|
946
|
-
projectDir: workspace.projectDir,
|
|
947
|
-
};
|
|
948
|
-
}
|
|
949
|
-
catch (error) {
|
|
950
|
-
await rollbackWorkspaceMutation(mutationSnapshot);
|
|
951
|
-
throw error;
|
|
952
|
-
}
|
|
953
|
-
}
|
|
7
|
+
export { runAddBindingSourceCommand, } from "./cli-add-workspace-binding-source.js";
|
|
8
|
+
export { runAddEditorPluginCommand } from "./cli-add-workspace-editor-plugin.js";
|
|
9
|
+
export { runAddPatternCommand } from "./cli-add-workspace-pattern.js";
|