@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.
Files changed (152) hide show
  1. package/dist/runtime/built-in-block-non-ts-basic-artifacts.d.ts +9 -0
  2. package/dist/runtime/built-in-block-non-ts-basic-artifacts.js +84 -0
  3. package/dist/runtime/built-in-block-non-ts-compound-artifacts.d.ts +9 -0
  4. package/dist/runtime/built-in-block-non-ts-compound-artifacts.js +36 -0
  5. package/dist/runtime/built-in-block-non-ts-compound-templates.d.ts +23 -0
  6. package/dist/runtime/built-in-block-non-ts-compound-templates.js +453 -0
  7. package/dist/runtime/built-in-block-non-ts-family-artifacts.d.ts +8 -26
  8. package/dist/runtime/built-in-block-non-ts-family-artifacts.js +8 -1034
  9. package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.d.ts +9 -0
  10. package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.js +83 -0
  11. package/dist/runtime/built-in-block-non-ts-persistence-artifacts.d.ts +9 -0
  12. package/dist/runtime/built-in-block-non-ts-persistence-artifacts.js +33 -0
  13. package/dist/runtime/built-in-block-non-ts-persistence-templates.d.ts +23 -0
  14. package/dist/runtime/built-in-block-non-ts-persistence-templates.js +395 -0
  15. package/dist/runtime/cli-add-collision.js +8 -0
  16. package/dist/runtime/cli-add-help.js +10 -7
  17. package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
  18. package/dist/runtime/cli-add-kind-ids.js +1 -0
  19. package/dist/runtime/cli-add-types.d.ts +28 -1
  20. package/dist/runtime/cli-add-types.js +2 -0
  21. package/dist/runtime/cli-add-workspace-ability-anchors.d.ts +24 -0
  22. package/dist/runtime/cli-add-workspace-ability-anchors.js +294 -0
  23. package/dist/runtime/cli-add-workspace-ability-registry.d.ts +10 -0
  24. package/dist/runtime/cli-add-workspace-ability-registry.js +51 -0
  25. package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +1 -1
  26. package/dist/runtime/cli-add-workspace-ability-scaffold.js +5 -311
  27. package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +1 -1
  28. package/dist/runtime/cli-add-workspace-ai-anchors.d.ts +4 -4
  29. package/dist/runtime/cli-add-workspace-ai-anchors.js +4 -232
  30. package/dist/runtime/cli-add-workspace-ai-scaffold.js +4 -2
  31. package/dist/runtime/cli-add-workspace-ai-source-emitters.d.ts +1 -4
  32. package/dist/runtime/cli-add-workspace-ai-source-emitters.js +1 -145
  33. package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.d.ts +5 -0
  34. package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.js +236 -0
  35. package/dist/runtime/cli-add-workspace-ai-sync-script-source.d.ts +4 -0
  36. package/dist/runtime/cli-add-workspace-ai-sync-script-source.js +145 -0
  37. package/dist/runtime/cli-add-workspace-assets.d.ts +6 -63
  38. package/dist/runtime/cli-add-workspace-assets.js +6 -950
  39. package/dist/runtime/cli-add-workspace-binding-source-anchors.d.ts +23 -0
  40. package/dist/runtime/cli-add-workspace-binding-source-anchors.js +112 -0
  41. package/dist/runtime/cli-add-workspace-binding-source-source-emitters.d.ts +33 -0
  42. package/dist/runtime/cli-add-workspace-binding-source-source-emitters.js +436 -0
  43. package/dist/runtime/cli-add-workspace-binding-source-types.d.ts +20 -0
  44. package/dist/runtime/cli-add-workspace-binding-source-types.js +1 -0
  45. package/dist/runtime/cli-add-workspace-binding-source.d.ts +40 -0
  46. package/dist/runtime/cli-add-workspace-binding-source.js +275 -0
  47. package/dist/runtime/cli-add-workspace-block-style.d.ts +22 -0
  48. package/dist/runtime/cli-add-workspace-block-style.js +148 -0
  49. package/dist/runtime/cli-add-workspace-block-transform.d.ts +32 -0
  50. package/dist/runtime/cli-add-workspace-block-transform.js +197 -0
  51. package/dist/runtime/cli-add-workspace-contract.js +1 -1
  52. package/dist/runtime/cli-add-workspace-core-variation.d.ts +20 -0
  53. package/dist/runtime/cli-add-workspace-core-variation.js +322 -0
  54. package/dist/runtime/cli-add-workspace-editor-plugin-anchors.d.ts +37 -0
  55. package/dist/runtime/cli-add-workspace-editor-plugin-anchors.js +206 -0
  56. package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.d.ts +47 -0
  57. package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.js +219 -0
  58. package/dist/runtime/cli-add-workspace-editor-plugin.d.ts +22 -0
  59. package/dist/runtime/cli-add-workspace-editor-plugin.js +78 -0
  60. package/dist/runtime/cli-add-workspace-hooked-block.d.ts +23 -0
  61. package/dist/runtime/cli-add-workspace-hooked-block.js +57 -0
  62. package/dist/runtime/cli-add-workspace-integration-env-files.d.ts +33 -0
  63. package/dist/runtime/cli-add-workspace-integration-env-files.js +65 -0
  64. package/dist/runtime/cli-add-workspace-integration-env-package-json.d.ts +38 -0
  65. package/dist/runtime/cli-add-workspace-integration-env-package-json.js +122 -0
  66. package/dist/runtime/cli-add-workspace-integration-env-source-emitters.d.ts +44 -0
  67. package/dist/runtime/cli-add-workspace-integration-env-source-emitters.js +262 -0
  68. package/dist/runtime/cli-add-workspace-integration-env.js +5 -345
  69. package/dist/runtime/cli-add-workspace-pattern-anchors.d.ts +10 -0
  70. package/dist/runtime/cli-add-workspace-pattern-anchors.js +95 -0
  71. package/dist/runtime/cli-add-workspace-pattern-options.d.ts +20 -0
  72. package/dist/runtime/cli-add-workspace-pattern-options.js +113 -0
  73. package/dist/runtime/cli-add-workspace-pattern-source-emitters.d.ts +20 -0
  74. package/dist/runtime/cli-add-workspace-pattern-source-emitters.js +57 -0
  75. package/dist/runtime/cli-add-workspace-pattern.d.ts +42 -0
  76. package/dist/runtime/cli-add-workspace-pattern.js +99 -0
  77. package/dist/runtime/cli-add-workspace-post-meta.js +1 -1
  78. package/dist/runtime/cli-add-workspace-registration-hooks.d.ts +50 -0
  79. package/dist/runtime/cli-add-workspace-registration-hooks.js +162 -0
  80. package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +6 -9
  81. package/dist/runtime/cli-add-workspace-rest-anchors.js +6 -466
  82. package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.d.ts +17 -0
  83. package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.js +108 -0
  84. package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.d.ts +9 -0
  85. package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.js +142 -0
  86. package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.d.ts +51 -0
  87. package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.js +415 -0
  88. package/dist/runtime/cli-add-workspace-rest-generated.js +5 -3
  89. package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.d.ts +80 -0
  90. package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.js +238 -0
  91. package/dist/runtime/cli-add-workspace-rest-manual.js +3 -16
  92. package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +1 -7
  93. package/dist/runtime/cli-add-workspace-rest-php-templates.js +3 -322
  94. package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.d.ts +33 -0
  95. package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.js +145 -0
  96. package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.d.ts +9 -0
  97. package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.js +162 -0
  98. package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.d.ts +7 -0
  99. package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.js +193 -0
  100. package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +5 -99
  101. package/dist/runtime/cli-add-workspace-rest-source-emitters.js +5 -663
  102. package/dist/runtime/cli-add-workspace-rest-source-utils.d.ts +17 -0
  103. package/dist/runtime/cli-add-workspace-rest-source-utils.js +50 -0
  104. package/dist/runtime/cli-add-workspace-rest-sync-script-shared.d.ts +56 -0
  105. package/dist/runtime/cli-add-workspace-rest-sync-script-shared.js +122 -0
  106. package/dist/runtime/cli-add-workspace-rest-types.d.ts +3 -3
  107. package/dist/runtime/cli-add-workspace-variation.d.ts +22 -0
  108. package/dist/runtime/cli-add-workspace-variation.js +162 -0
  109. package/dist/runtime/cli-add-workspace.d.ts +42 -107
  110. package/dist/runtime/cli-add-workspace.js +42 -674
  111. package/dist/runtime/cli-add.d.ts +3 -3
  112. package/dist/runtime/cli-add.js +2 -2
  113. package/dist/runtime/cli-core.d.ts +2 -1
  114. package/dist/runtime/cli-core.js +1 -1
  115. package/dist/runtime/cli-doctor-workspace-bindings.js +59 -0
  116. package/dist/runtime/cli-doctor-workspace-block-addons.js +33 -5
  117. package/dist/runtime/cli-doctor.d.ts +2 -0
  118. package/dist/runtime/cli-doctor.js +13 -2
  119. package/dist/runtime/cli-help.js +6 -4
  120. package/dist/runtime/index.d.ts +5 -2
  121. package/dist/runtime/index.js +4 -2
  122. package/dist/runtime/local-dev-presets.js +2 -1
  123. package/dist/runtime/package-versions.d.ts +1 -0
  124. package/dist/runtime/package-versions.js +10 -2
  125. package/dist/runtime/pattern-catalog.d.ts +122 -0
  126. package/dist/runtime/pattern-catalog.js +471 -0
  127. package/dist/runtime/post-meta-binding-fields.d.ts +46 -0
  128. package/dist/runtime/post-meta-binding-fields.js +135 -0
  129. package/dist/runtime/typia-llm-json-schema.d.ts +24 -0
  130. package/dist/runtime/typia-llm-json-schema.js +33 -0
  131. package/dist/runtime/typia-llm-openapi-constraints.d.ts +20 -0
  132. package/dist/runtime/typia-llm-openapi-constraints.js +254 -0
  133. package/dist/runtime/typia-llm-projection.d.ts +25 -0
  134. package/dist/runtime/typia-llm-projection.js +58 -0
  135. package/dist/runtime/typia-llm-render.d.ts +21 -0
  136. package/dist/runtime/typia-llm-render.js +252 -0
  137. package/dist/runtime/typia-llm-sync.d.ts +10 -0
  138. package/dist/runtime/typia-llm-sync.js +63 -0
  139. package/dist/runtime/typia-llm-types.d.ts +197 -0
  140. package/dist/runtime/typia-llm-types.js +1 -0
  141. package/dist/runtime/typia-llm.d.ts +9 -255
  142. package/dist/runtime/typia-llm.js +5 -634
  143. package/dist/runtime/workspace-inventory-mutations.js +13 -0
  144. package/dist/runtime/workspace-inventory-section-descriptors.js +9 -1
  145. package/dist/runtime/workspace-inventory-templates.d.ts +2 -2
  146. package/dist/runtime/workspace-inventory-templates.js +9 -1
  147. package/dist/runtime/workspace-inventory-types.d.ts +9 -1
  148. package/package.json +8 -3
  149. package/templates/_shared/compound/core/scripts/block-config.ts.mustache +22 -0
  150. package/templates/_shared/compound/core/scripts/sync-types-to-block-json.ts.mustache +103 -2
  151. package/templates/_shared/compound/core/src/inner-blocks-templates.ts.mustache +13 -0
  152. package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +22 -1
@@ -0,0 +1,275 @@
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 { assertBindingSourceDoesNotExist, assertValidGeneratedSlug, getWorkspaceBootstrapPath, normalizeBlockSlug, resolveWorkspaceBlock, rollbackWorkspaceMutation, snapshotWorkspaceFiles, } from "./cli-add-shared.js";
8
+ import { ensureBindingSourceBootstrapAnchors, resolveBindingSourceRegistryPath, writeBindingSourceRegistry, } from "./cli-add-workspace-binding-source-anchors.js";
9
+ import { buildBindingSourceConfigEntry, buildBindingSourceEditorSource, buildBindingSourceServerSource, } from "./cli-add-workspace-binding-source-source-emitters.js";
10
+ import { resolveWorkspaceBlockTargetName } from "./block-targets.js";
11
+ import { normalizeOptionalCliString } from "./cli-validation.js";
12
+ import { getPropertyNameText } from "./ts-property-names.js";
13
+ import { assertPostMetaBindingPath, loadPostMetaBindingFields, } from "./post-meta-binding-fields.js";
14
+ const BINDING_ATTRIBUTE_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/u;
15
+ function assertValidBindingAttributeName(attributeName) {
16
+ const trimmed = attributeName.trim();
17
+ if (!trimmed) {
18
+ throw new Error("`wp-typia add binding-source` requires --attribute <attribute> to include a value when --block is provided.");
19
+ }
20
+ if (!BINDING_ATTRIBUTE_NAME_PATTERN.test(trimmed)) {
21
+ throw new Error(`Binding attribute "${trimmed}" must start with a letter and use only letters, numbers, underscores, or hyphens.`);
22
+ }
23
+ return trimmed;
24
+ }
25
+ function resolveBindingTarget(options, namespace) {
26
+ const blockName = normalizeOptionalCliString(options.blockName);
27
+ const attributeName = normalizeOptionalCliString(options.attributeName);
28
+ const hasBlock = blockName !== undefined;
29
+ const hasAttribute = attributeName !== undefined;
30
+ if (!hasBlock && !hasAttribute) {
31
+ return undefined;
32
+ }
33
+ if (!hasBlock || !hasAttribute) {
34
+ throw new Error("`wp-typia add binding-source` requires --block and --attribute to be provided together.");
35
+ }
36
+ const targetBlock = resolveWorkspaceBlockTargetName(blockName ?? "", namespace, {
37
+ empty: () => "`wp-typia add binding-source` requires --block <block-slug|namespace/block-slug> to include a value when --attribute is provided.",
38
+ emptySegment: (input) => `Binding target block "${input}" must use <block-slug> or <namespace/block-slug> format without empty path segments.`,
39
+ invalidFormat: (input) => `Binding target block "${input}" must use <block-slug> or <namespace/block-slug> format.`,
40
+ namespaceMismatch: (input, actualNamespace, expectedNamespace) => `Binding target block "${input}" uses namespace "${actualNamespace}". Expected "${expectedNamespace}".`,
41
+ });
42
+ return {
43
+ attributeName: assertValidBindingAttributeName(attributeName ?? ""),
44
+ blockSlug: targetBlock.blockSlug,
45
+ };
46
+ }
47
+ function resolvePostMetaInventoryEntry(inventory, postMetaName) {
48
+ const postMetaSlug = assertValidGeneratedSlug("Post meta source", normalizeBlockSlug(postMetaName), "wp-typia add binding-source <name> --from-post-meta <post-meta> [--meta-path <field>]");
49
+ const postMeta = inventory.postMeta.find((entry) => entry.slug === postMetaSlug);
50
+ if (!postMeta) {
51
+ throw new Error(`Post meta contract "${postMetaSlug}" does not exist in scripts/block-config.ts. Run \`wp-typia add post-meta ${postMetaSlug} --post-type <post-type>\` first, then retry \`wp-typia add binding-source\`.`);
52
+ }
53
+ return postMeta;
54
+ }
55
+ async function resolveBindingPostMetaSource(projectDir, inventory, options) {
56
+ const postMetaName = normalizeOptionalCliString(options.postMetaName);
57
+ const metaPath = normalizeOptionalCliString(options.metaPath);
58
+ if (!postMetaName && !metaPath) {
59
+ return undefined;
60
+ }
61
+ if (!postMetaName) {
62
+ throw new Error("`wp-typia add binding-source` requires --from-post-meta <post-meta> or --post-meta <post-meta> when --meta-path is provided.");
63
+ }
64
+ const postMeta = resolvePostMetaInventoryEntry(inventory, postMetaName);
65
+ const fields = await loadPostMetaBindingFields(projectDir, postMeta);
66
+ const selectedField = metaPath
67
+ ? assertPostMetaBindingPath(fields, postMeta.slug, metaPath)
68
+ : fields[0];
69
+ if (!selectedField) {
70
+ throw new Error(`Post meta contract "${postMeta.slug}" does not expose a top-level field for binding-source defaults.`);
71
+ }
72
+ return {
73
+ fields,
74
+ metaKey: postMeta.metaKey,
75
+ metaPath: selectedField.name,
76
+ postMetaSlug: postMeta.slug,
77
+ postType: postMeta.postType,
78
+ schemaFile: postMeta.schemaFile,
79
+ sourceTypeName: postMeta.sourceTypeName,
80
+ };
81
+ }
82
+ function resolveBindingAttributeTsType(schemaType) {
83
+ switch (schemaType) {
84
+ case "array":
85
+ return "unknown[]";
86
+ case "boolean":
87
+ return "boolean";
88
+ case "integer":
89
+ case "number":
90
+ return "number";
91
+ case "object":
92
+ return "Record<string, unknown>";
93
+ default:
94
+ return "string";
95
+ }
96
+ }
97
+ function formatBindingAttributeTypeMember(attributeName, schemaType = "string") {
98
+ const propertyName = /^[A-Za-z_$][\w$]*$/u.test(attributeName)
99
+ ? attributeName
100
+ : JSON.stringify(attributeName);
101
+ const tsType = resolveBindingAttributeTsType(schemaType);
102
+ return [
103
+ "\t/**",
104
+ `\t * Starter ${tsType} attribute declared for WordPress Block Bindings.`,
105
+ "\t */",
106
+ `\t${propertyName}?: ${tsType};`,
107
+ ].join("\n");
108
+ }
109
+ function getInterfaceDeclaration(source, interfaceName) {
110
+ const sourceFile = ts.createSourceFile("types.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
111
+ let declaration;
112
+ const visit = (node) => {
113
+ if (ts.isInterfaceDeclaration(node) && node.name.text === interfaceName) {
114
+ declaration = node;
115
+ return true;
116
+ }
117
+ return ts.forEachChild(node, (child) => (visit(child) ? true : undefined)) ?? false;
118
+ };
119
+ visit(sourceFile);
120
+ return declaration ? { declaration, sourceFile } : undefined;
121
+ }
122
+ function interfaceHasAttributeMember(declaration, attributeName) {
123
+ return declaration.members.some((member) => ts.isPropertySignature(member) &&
124
+ member.name !== undefined &&
125
+ getPropertyNameText(member.name) === attributeName);
126
+ }
127
+ function insertBindingAttributeTypeMember(source, declaration, attributeName, schemaType = "string") {
128
+ let closeBracePosition = declaration.end - 1;
129
+ while (closeBracePosition > declaration.pos && source[closeBracePosition] !== "}") {
130
+ closeBracePosition -= 1;
131
+ }
132
+ if (source[closeBracePosition] !== "}") {
133
+ throw new Error("Unable to locate the target interface closing brace.");
134
+ }
135
+ const lineEnding = source.includes("\r\n") ? "\r\n" : "\n";
136
+ const beforeCloseBrace = source.slice(0, closeBracePosition);
137
+ const afterCloseBrace = source.slice(closeBracePosition);
138
+ const memberSource = formatBindingAttributeTypeMember(attributeName, schemaType)
139
+ .split("\n")
140
+ .join(lineEnding);
141
+ const prefix = beforeCloseBrace.endsWith(lineEnding) ? "" : lineEnding;
142
+ return `${beforeCloseBrace}${prefix}${memberSource}${lineEnding}${afterCloseBrace}`;
143
+ }
144
+ async function ensureBindingTargetBlockAttributeType(projectDir, block, target, schemaType = "string") {
145
+ if (!block.attributeTypeName) {
146
+ throw new Error(`Workspace block "${block.slug}" must include attributeTypeName in scripts/block-config.ts before it can receive binding-source targets.`);
147
+ }
148
+ const typesPath = path.join(projectDir, block.typesFile);
149
+ const source = await fsp.readFile(typesPath, "utf8");
150
+ const targetInterface = getInterfaceDeclaration(source, block.attributeTypeName);
151
+ if (!targetInterface) {
152
+ throw new Error(`Unable to locate interface ${block.attributeTypeName} in ${block.typesFile}.`);
153
+ }
154
+ let nextSource = source;
155
+ if (!interfaceHasAttributeMember(targetInterface.declaration, target.attributeName)) {
156
+ nextSource = insertBindingAttributeTypeMember(source, targetInterface.declaration, target.attributeName, schemaType);
157
+ await fsp.writeFile(typesPath, nextSource, "utf8");
158
+ }
159
+ await syncBlockMetadata({
160
+ blockJsonFile: path.join("src", "blocks", block.slug, "block.json"),
161
+ jsonSchemaFile: path.join("src", "blocks", block.slug, "typia.schema.json"),
162
+ manifestFile: path.join("src", "blocks", block.slug, "typia.manifest.json"),
163
+ openApiFile: path.join("src", "blocks", block.slug, "typia.openapi.json"),
164
+ projectRoot: projectDir,
165
+ sourceTypeName: block.attributeTypeName,
166
+ typesFile: block.typesFile,
167
+ });
168
+ }
169
+ /**
170
+ * Add one block binding source scaffold to an official workspace project.
171
+ *
172
+ * @param options Command options for the binding-source scaffold workflow.
173
+ * @param options.attributeName Optional generated block attribute to declare as
174
+ * bindable. Must be provided together with `blockName`.
175
+ * @param options.blockName Optional generated block slug or full block name to
176
+ * receive the bindable attribute wiring. Must be provided together with
177
+ * `attributeName`.
178
+ * @param options.bindingSourceName Human-entered binding source name that will
179
+ * be normalized and validated before files are written.
180
+ * @param options.cwd Working directory used to resolve the nearest official
181
+ * workspace. Defaults to `process.cwd()`.
182
+ * @param options.metaPath Optional top-level post-meta field used as the
183
+ * binding source's default `field` arg. Requires `postMetaName`.
184
+ * @param options.postMetaName Optional generated post-meta contract slug used
185
+ * to back the binding source with `get_post_meta()`.
186
+ * @returns A promise that resolves with the normalized `bindingSourceSlug` and
187
+ * owning `projectDir` after the server/editor files, optional target block
188
+ * metadata, and inventory entry have been written successfully. Post-meta
189
+ * backed results additionally include `metaKey`, `metaPath`, `postMetaSlug`,
190
+ * `postType`, and `schemaFile`.
191
+ * @throws {Error} When the command is run outside an official workspace, when
192
+ * the slug is invalid, when a binding target is incomplete or unknown, or when
193
+ * a conflicting file or inventory entry exists. Post-meta backed runs also
194
+ * throw when the referenced contract or requested top-level field cannot be
195
+ * resolved.
196
+ */
197
+ export async function runAddBindingSourceCommand({ attributeName, bindingSourceName, blockName, cwd = process.cwd(), metaPath, postMetaName, }) {
198
+ const workspace = resolveWorkspaceProject(cwd);
199
+ const bindingSourceSlug = assertValidGeneratedSlug("Binding source name", normalizeBlockSlug(bindingSourceName), "wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>] [--from-post-meta <post-meta> --meta-path <field>]");
200
+ const inventory = await readWorkspaceInventoryAsync(workspace.projectDir);
201
+ assertBindingSourceDoesNotExist(workspace.projectDir, bindingSourceSlug, inventory);
202
+ const target = resolveBindingTarget({
203
+ attributeName,
204
+ blockName,
205
+ }, workspace.workspace.namespace);
206
+ const targetBlock = target ? resolveWorkspaceBlock(inventory, target.blockSlug) : undefined;
207
+ const postMeta = await resolveBindingPostMetaSource(workspace.projectDir, inventory, {
208
+ metaPath,
209
+ postMetaName,
210
+ });
211
+ const blockConfigPath = path.join(workspace.projectDir, "scripts", "block-config.ts");
212
+ const bootstrapPath = getWorkspaceBootstrapPath(workspace);
213
+ const bindingsIndexPath = await resolveBindingSourceRegistryPath(workspace.projectDir);
214
+ const bindingSourceDir = path.join(workspace.projectDir, "src", "bindings", bindingSourceSlug);
215
+ const serverFilePath = path.join(bindingSourceDir, "server.php");
216
+ const editorFilePath = path.join(bindingSourceDir, "editor.ts");
217
+ const blockJsonPath = target
218
+ ? path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "block.json")
219
+ : undefined;
220
+ const targetGeneratedMetadataPaths = target
221
+ ? [
222
+ path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "typia.manifest.json"),
223
+ path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "typia.openapi.json"),
224
+ path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "typia.schema.json"),
225
+ path.join(workspace.projectDir, "src", "blocks", target.blockSlug, "typia-validator.php"),
226
+ ]
227
+ : [];
228
+ const mutationSnapshot = {
229
+ fileSources: await snapshotWorkspaceFiles([
230
+ blockConfigPath,
231
+ bootstrapPath,
232
+ bindingsIndexPath,
233
+ ...(blockJsonPath ? [blockJsonPath] : []),
234
+ ...(targetBlock ? [path.join(workspace.projectDir, targetBlock.typesFile)] : []),
235
+ ...targetGeneratedMetadataPaths,
236
+ ]),
237
+ snapshotDirs: [],
238
+ targetPaths: [bindingSourceDir],
239
+ };
240
+ try {
241
+ await fsp.mkdir(bindingSourceDir, { recursive: true });
242
+ await ensureBindingSourceBootstrapAnchors(workspace);
243
+ await fsp.writeFile(serverFilePath, buildBindingSourceServerSource(bindingSourceSlug, workspace.workspace.phpPrefix, workspace.workspace.namespace, workspace.workspace.textDomain, target, postMeta), "utf8");
244
+ await fsp.writeFile(editorFilePath, buildBindingSourceEditorSource(bindingSourceSlug, workspace.workspace.namespace, workspace.workspace.textDomain, target, postMeta), "utf8");
245
+ if (target && targetBlock) {
246
+ const targetSchemaType = postMeta?.fields.find((field) => field.name === postMeta.metaPath)?.schemaType ??
247
+ "string";
248
+ await ensureBindingTargetBlockAttributeType(workspace.projectDir, targetBlock, target, targetSchemaType);
249
+ }
250
+ await writeBindingSourceRegistry(workspace.projectDir, bindingSourceSlug);
251
+ await appendWorkspaceInventoryEntries(workspace.projectDir, {
252
+ bindingSourceEntries: [
253
+ buildBindingSourceConfigEntry(bindingSourceSlug, target, postMeta),
254
+ ],
255
+ });
256
+ return {
257
+ ...(target ? { attributeName: target.attributeName, blockSlug: target.blockSlug } : {}),
258
+ bindingSourceSlug,
259
+ ...(postMeta
260
+ ? {
261
+ metaKey: postMeta.metaKey,
262
+ metaPath: postMeta.metaPath,
263
+ postMetaSlug: postMeta.postMetaSlug,
264
+ postType: postMeta.postType,
265
+ schemaFile: postMeta.schemaFile,
266
+ }
267
+ : {}),
268
+ projectDir: workspace.projectDir,
269
+ };
270
+ }
271
+ catch (error) {
272
+ await rollbackWorkspaceMutation(mutationSnapshot);
273
+ throw error;
274
+ }
275
+ }
@@ -0,0 +1,22 @@
1
+ import { type RunAddBlockStyleCommandOptions } from "./cli-add-shared.js";
2
+ /**
3
+ * Add one Block Styles registration to an existing workspace block.
4
+ *
5
+ * @param options Command options for the Block Styles scaffold workflow.
6
+ * @param options.blockName Target workspace block slug that will own the style.
7
+ * @param options.cwd Working directory used to resolve the nearest official workspace.
8
+ * Defaults to `process.cwd()`.
9
+ * @param options.styleName Human-entered style name that will be normalized and
10
+ * validated before files are written.
11
+ * @returns A promise that resolves with the normalized `blockSlug`, `styleSlug`,
12
+ * and owning `projectDir` after the style module, style registry, entrypoint
13
+ * hook, and inventory entry have been written successfully.
14
+ * @throws {Error} When the command is run outside an official workspace, when
15
+ * the target block is unknown, when the style slug is invalid, or when a
16
+ * conflicting file or inventory entry already exists.
17
+ */
18
+ export declare function runAddBlockStyleCommand({ blockName, cwd, styleName, }: RunAddBlockStyleCommandOptions): Promise<{
19
+ blockSlug: string;
20
+ projectDir: string;
21
+ styleSlug: string;
22
+ }>;
@@ -0,0 +1,148 @@
1
+ import { promises as fsp } from "node:fs";
2
+ import path from "node:path";
3
+ import { pathExists } from "./fs-async.js";
4
+ import { assertBlockStyleDoesNotExist, assertValidGeneratedSlug, normalizeBlockSlug, quoteTsString, resolveWorkspaceBlock, rollbackWorkspaceMutation, snapshotWorkspaceFiles, } from "./cli-add-shared.js";
5
+ import { ensureWorkspaceEntrypointCall } from "./cli-add-workspace-registration-hooks.js";
6
+ import { appendWorkspaceInventoryEntries, readWorkspaceInventoryAsync, } from "./workspace-inventory.js";
7
+ import { resolveWorkspaceProject } from "./workspace-project.js";
8
+ import { toSnakeCase, toTitleCase } from "./string-case.js";
9
+ const BLOCK_STYLES_IMPORT_LINE = "import { registerWorkspaceBlockStyles } from './styles';";
10
+ const BLOCK_STYLES_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceBlockStyles\s*\}\s*from\s*["']\.\/styles["']\s*;?\s*$/mu;
11
+ const BLOCK_STYLES_CALL_LINE = "registerWorkspaceBlockStyles();";
12
+ const BLOCK_STYLES_CALL_PATTERN = /registerWorkspaceBlockStyles\s*\(\s*\)\s*;?/u;
13
+ function buildWorkspaceConstName(prefix, slug) {
14
+ return `workspace${prefix}_${toSnakeCase(slug)}`;
15
+ }
16
+ function buildBlockStyleConfigEntry(blockSlug, styleSlug) {
17
+ return [
18
+ "\t{",
19
+ `\t\tblock: ${quoteTsString(blockSlug)},`,
20
+ `\t\tfile: ${quoteTsString(`src/blocks/${blockSlug}/styles/${styleSlug}.ts`)},`,
21
+ `\t\tslug: ${quoteTsString(styleSlug)},`,
22
+ "\t},",
23
+ ].join("\n");
24
+ }
25
+ function getBlockStyleConstBindings(styleSlugs) {
26
+ const seenConstNames = new Map();
27
+ return styleSlugs.map((styleSlug) => {
28
+ const constName = buildWorkspaceConstName("BlockStyle", styleSlug);
29
+ const previousSlug = seenConstNames.get(constName);
30
+ if (previousSlug && previousSlug !== styleSlug) {
31
+ throw new Error(`Style slugs "${previousSlug}" and "${styleSlug}" generate the same registry identifier "${constName}". Rename one of the styles.`);
32
+ }
33
+ seenConstNames.set(constName, styleSlug);
34
+ return { constName, styleSlug };
35
+ });
36
+ }
37
+ function buildBlockStyleSource(styleSlug, textDomain) {
38
+ const styleTitle = toTitleCase(styleSlug);
39
+ const styleConstName = buildWorkspaceConstName("BlockStyle", styleSlug);
40
+ return `import { __ } from '@wordpress/i18n';
41
+
42
+ export const ${styleConstName} = {
43
+ \tname: ${quoteTsString(styleSlug)},
44
+ \tlabel: __( ${quoteTsString(styleTitle)}, ${quoteTsString(textDomain)} ),
45
+ } as const;
46
+ `;
47
+ }
48
+ function buildBlockStyleIndexSource(styleSlugs) {
49
+ const styleBindings = getBlockStyleConstBindings(styleSlugs);
50
+ const importLines = styleBindings
51
+ .map(({ constName, styleSlug }) => `import { ${constName} } from './${styleSlug}';`)
52
+ .join("\n");
53
+ const styleConstNames = styleBindings.map(({ constName }) => constName).join(",\n\t");
54
+ return `import { registerBlockStyle } from '@wordpress/blocks';
55
+ import metadata from '../block.json';
56
+ ${importLines ? `\n${importLines}` : ""}
57
+
58
+ const WORKSPACE_BLOCK_STYLES = [
59
+ \t${styleConstNames}
60
+ \t// wp-typia add style entries
61
+ ] as const;
62
+
63
+ export function registerWorkspaceBlockStyles() {
64
+ \tfor (const style of WORKSPACE_BLOCK_STYLES) {
65
+ \t\tregisterBlockStyle(metadata.name, style);
66
+ \t}
67
+ }
68
+ `;
69
+ }
70
+ async function ensureBlockStyleRegistrationHook(blockIndexPath) {
71
+ await ensureWorkspaceEntrypointCall({
72
+ blockIndexPath,
73
+ callLine: BLOCK_STYLES_CALL_LINE,
74
+ callPattern: BLOCK_STYLES_CALL_PATTERN,
75
+ importLine: BLOCK_STYLES_IMPORT_LINE,
76
+ importPattern: BLOCK_STYLES_IMPORT_PATTERN,
77
+ });
78
+ }
79
+ async function writeBlockStyleRegistry(projectDir, blockSlug, styleSlug) {
80
+ const stylesDir = path.join(projectDir, "src", "blocks", blockSlug, "styles");
81
+ const stylesIndexPath = path.join(stylesDir, "index.ts");
82
+ await fsp.mkdir(stylesDir, { recursive: true });
83
+ const existingStyleSlugs = (await fsp.readdir(stylesDir))
84
+ .filter((entry) => entry.endsWith(".ts") && entry !== "index.ts")
85
+ .map((entry) => entry.replace(/\.ts$/u, ""));
86
+ const nextStyleSlugs = Array.from(new Set([...existingStyleSlugs, styleSlug])).sort();
87
+ await fsp.writeFile(stylesIndexPath, buildBlockStyleIndexSource(nextStyleSlugs), "utf8");
88
+ }
89
+ /**
90
+ * Add one Block Styles registration to an existing workspace block.
91
+ *
92
+ * @param options Command options for the Block Styles scaffold workflow.
93
+ * @param options.blockName Target workspace block slug that will own the style.
94
+ * @param options.cwd Working directory used to resolve the nearest official workspace.
95
+ * Defaults to `process.cwd()`.
96
+ * @param options.styleName Human-entered style name that will be normalized and
97
+ * validated before files are written.
98
+ * @returns A promise that resolves with the normalized `blockSlug`, `styleSlug`,
99
+ * and owning `projectDir` after the style module, style registry, entrypoint
100
+ * hook, and inventory entry have been written successfully.
101
+ * @throws {Error} When the command is run outside an official workspace, when
102
+ * the target block is unknown, when the style slug is invalid, or when a
103
+ * conflicting file or inventory entry already exists.
104
+ */
105
+ export async function runAddBlockStyleCommand({ blockName, cwd = process.cwd(), styleName, }) {
106
+ const workspace = resolveWorkspaceProject(cwd);
107
+ const blockSlug = normalizeBlockSlug(blockName);
108
+ const styleSlug = assertValidGeneratedSlug("Style name", normalizeBlockSlug(styleName), "wp-typia add style <name> --block <block-slug>");
109
+ const inventory = await readWorkspaceInventoryAsync(workspace.projectDir);
110
+ resolveWorkspaceBlock(inventory, blockSlug);
111
+ assertBlockStyleDoesNotExist(workspace.projectDir, blockSlug, styleSlug, inventory);
112
+ const blockConfigPath = path.join(workspace.projectDir, "scripts", "block-config.ts");
113
+ const blockIndexPath = path.join(workspace.projectDir, "src", "blocks", blockSlug, "index.tsx");
114
+ const stylesDir = path.join(workspace.projectDir, "src", "blocks", blockSlug, "styles");
115
+ const styleFilePath = path.join(stylesDir, `${styleSlug}.ts`);
116
+ const stylesIndexPath = path.join(stylesDir, "index.ts");
117
+ const shouldRemoveStylesDirOnRollback = !(await pathExists(stylesDir));
118
+ const mutationSnapshot = {
119
+ fileSources: await snapshotWorkspaceFiles([
120
+ blockConfigPath,
121
+ blockIndexPath,
122
+ stylesIndexPath,
123
+ ]),
124
+ snapshotDirs: [],
125
+ targetPaths: [
126
+ styleFilePath,
127
+ ...(shouldRemoveStylesDirOnRollback ? [stylesDir] : []),
128
+ ],
129
+ };
130
+ try {
131
+ await fsp.mkdir(stylesDir, { recursive: true });
132
+ await fsp.writeFile(styleFilePath, buildBlockStyleSource(styleSlug, workspace.workspace.textDomain), "utf8");
133
+ await writeBlockStyleRegistry(workspace.projectDir, blockSlug, styleSlug);
134
+ await ensureBlockStyleRegistrationHook(blockIndexPath);
135
+ await appendWorkspaceInventoryEntries(workspace.projectDir, {
136
+ blockStyleEntries: [buildBlockStyleConfigEntry(blockSlug, styleSlug)],
137
+ });
138
+ return {
139
+ blockSlug,
140
+ projectDir: workspace.projectDir,
141
+ styleSlug,
142
+ };
143
+ }
144
+ catch (error) {
145
+ await rollbackWorkspaceMutation(mutationSnapshot);
146
+ throw error;
147
+ }
148
+ }
@@ -0,0 +1,32 @@
1
+ import { type RunAddBlockTransformCommandOptions } from "./cli-add-shared.js";
2
+ /**
3
+ * Add one block-to-block transform registration to an existing workspace block.
4
+ *
5
+ * @param options Command options for the block transform scaffold workflow.
6
+ * @param options.cwd Working directory used to resolve the nearest official workspace.
7
+ * Defaults to `process.cwd()`.
8
+ * @param options.fromBlockName Source block name for `--from`. This must be the
9
+ * full `namespace/block` form because transforms may originate from WordPress
10
+ * core or third-party blocks outside the workspace.
11
+ * @param options.toBlockName Target block for `--to`. A workspace block slug is
12
+ * resolved against the workspace namespace, while a full `namespace/block` name
13
+ * must still point at an existing workspace block.
14
+ * @param options.transformName Human-entered transform name that will be
15
+ * normalized and validated before files are written.
16
+ * @returns A promise that resolves with the normalized target `blockSlug`,
17
+ * resolved `fromBlockName`, resolved `toBlockName`, `transformSlug`, and owning
18
+ * `projectDir` after the transform module, transform registry, entrypoint hook,
19
+ * and inventory entry have been written successfully.
20
+ * @throws {Error} When the command is run outside an official workspace, when
21
+ * the target block is unknown, when `--from` is not a full block name, when
22
+ * `--to` uses a non-workspace namespace, when the target block entrypoint does
23
+ * not expose `registration.settings`, when the transform slug is invalid, or
24
+ * when a conflicting file or inventory entry already exists.
25
+ */
26
+ export declare function runAddBlockTransformCommand({ cwd, fromBlockName, toBlockName, transformName, }: RunAddBlockTransformCommandOptions): Promise<{
27
+ blockSlug: string;
28
+ fromBlockName: string;
29
+ projectDir: string;
30
+ toBlockName: string;
31
+ transformSlug: string;
32
+ }>;