@wp-typia/project-tools 0.23.0 → 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 (228) hide show
  1. package/dist/runtime/ai-feature-artifacts.js +4 -1
  2. package/dist/runtime/block-generator-service-spec.js +2 -1
  3. package/dist/runtime/built-in-block-non-ts-basic-artifacts.d.ts +9 -0
  4. package/dist/runtime/built-in-block-non-ts-basic-artifacts.js +84 -0
  5. package/dist/runtime/built-in-block-non-ts-compound-artifacts.d.ts +9 -0
  6. package/dist/runtime/built-in-block-non-ts-compound-artifacts.js +36 -0
  7. package/dist/runtime/built-in-block-non-ts-compound-templates.d.ts +23 -0
  8. package/dist/runtime/built-in-block-non-ts-compound-templates.js +453 -0
  9. package/dist/runtime/built-in-block-non-ts-family-artifacts.d.ts +8 -26
  10. package/dist/runtime/built-in-block-non-ts-family-artifacts.js +8 -1034
  11. package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.d.ts +9 -0
  12. package/dist/runtime/built-in-block-non-ts-interactivity-artifacts.js +83 -0
  13. package/dist/runtime/built-in-block-non-ts-persistence-artifacts.d.ts +9 -0
  14. package/dist/runtime/built-in-block-non-ts-persistence-artifacts.js +33 -0
  15. package/dist/runtime/built-in-block-non-ts-persistence-templates.d.ts +23 -0
  16. package/dist/runtime/built-in-block-non-ts-persistence-templates.js +395 -0
  17. package/dist/runtime/cli-add-block-json.js +5 -1
  18. package/dist/runtime/cli-add-collision.js +8 -0
  19. package/dist/runtime/cli-add-help.js +14 -10
  20. package/dist/runtime/cli-add-kind-ids.d.ts +1 -1
  21. package/dist/runtime/cli-add-kind-ids.js +1 -0
  22. package/dist/runtime/cli-add-types.d.ts +45 -6
  23. package/dist/runtime/cli-add-types.js +2 -0
  24. package/dist/runtime/cli-add-validation.d.ts +7 -0
  25. package/dist/runtime/cli-add-validation.js +9 -0
  26. package/dist/runtime/cli-add-workspace-ability-anchors.d.ts +24 -0
  27. package/dist/runtime/cli-add-workspace-ability-anchors.js +294 -0
  28. package/dist/runtime/cli-add-workspace-ability-registry.d.ts +10 -0
  29. package/dist/runtime/cli-add-workspace-ability-registry.js +51 -0
  30. package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +1 -1
  31. package/dist/runtime/cli-add-workspace-ability-scaffold.js +5 -308
  32. package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +6 -2
  33. package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.d.ts +34 -0
  34. package/dist/runtime/cli-add-workspace-admin-view-templates-core-data.js +483 -0
  35. package/dist/runtime/cli-add-workspace-admin-view-templates-default.d.ts +30 -0
  36. package/dist/runtime/cli-add-workspace-admin-view-templates-default.js +310 -0
  37. package/dist/runtime/cli-add-workspace-admin-view-templates-rest.d.ts +25 -0
  38. package/dist/runtime/cli-add-workspace-admin-view-templates-rest.js +124 -0
  39. package/dist/runtime/cli-add-workspace-admin-view-templates-settings.d.ts +34 -0
  40. package/dist/runtime/cli-add-workspace-admin-view-templates-settings.js +370 -0
  41. package/dist/runtime/cli-add-workspace-admin-view-templates-shared.d.ts +49 -0
  42. package/dist/runtime/cli-add-workspace-admin-view-templates-shared.js +259 -0
  43. package/dist/runtime/cli-add-workspace-admin-view-templates.d.ts +18 -27
  44. package/dist/runtime/cli-add-workspace-admin-view-templates.js +30 -1326
  45. package/dist/runtime/cli-add-workspace-ai-anchors.d.ts +4 -4
  46. package/dist/runtime/cli-add-workspace-ai-anchors.js +8 -233
  47. package/dist/runtime/cli-add-workspace-ai-scaffold.js +4 -2
  48. package/dist/runtime/cli-add-workspace-ai-source-emitters.d.ts +1 -4
  49. package/dist/runtime/cli-add-workspace-ai-source-emitters.js +1 -129
  50. package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.d.ts +5 -0
  51. package/dist/runtime/cli-add-workspace-ai-sync-rest-anchors.js +236 -0
  52. package/dist/runtime/cli-add-workspace-ai-sync-script-source.d.ts +4 -0
  53. package/dist/runtime/cli-add-workspace-ai-sync-script-source.js +145 -0
  54. package/dist/runtime/cli-add-workspace-assets.d.ts +6 -63
  55. package/dist/runtime/cli-add-workspace-assets.js +6 -950
  56. package/dist/runtime/cli-add-workspace-binding-source-anchors.d.ts +23 -0
  57. package/dist/runtime/cli-add-workspace-binding-source-anchors.js +112 -0
  58. package/dist/runtime/cli-add-workspace-binding-source-source-emitters.d.ts +33 -0
  59. package/dist/runtime/cli-add-workspace-binding-source-source-emitters.js +436 -0
  60. package/dist/runtime/cli-add-workspace-binding-source-types.d.ts +20 -0
  61. package/dist/runtime/cli-add-workspace-binding-source-types.js +1 -0
  62. package/dist/runtime/cli-add-workspace-binding-source.d.ts +40 -0
  63. package/dist/runtime/cli-add-workspace-binding-source.js +275 -0
  64. package/dist/runtime/cli-add-workspace-block-style.d.ts +22 -0
  65. package/dist/runtime/cli-add-workspace-block-style.js +148 -0
  66. package/dist/runtime/cli-add-workspace-block-transform.d.ts +32 -0
  67. package/dist/runtime/cli-add-workspace-block-transform.js +197 -0
  68. package/dist/runtime/cli-add-workspace-contract.js +1 -1
  69. package/dist/runtime/cli-add-workspace-core-variation.d.ts +20 -0
  70. package/dist/runtime/cli-add-workspace-core-variation.js +322 -0
  71. package/dist/runtime/cli-add-workspace-editor-plugin-anchors.d.ts +37 -0
  72. package/dist/runtime/cli-add-workspace-editor-plugin-anchors.js +206 -0
  73. package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.d.ts +47 -0
  74. package/dist/runtime/cli-add-workspace-editor-plugin-source-emitters.js +219 -0
  75. package/dist/runtime/cli-add-workspace-editor-plugin.d.ts +22 -0
  76. package/dist/runtime/cli-add-workspace-editor-plugin.js +78 -0
  77. package/dist/runtime/cli-add-workspace-hooked-block.d.ts +23 -0
  78. package/dist/runtime/cli-add-workspace-hooked-block.js +57 -0
  79. package/dist/runtime/cli-add-workspace-integration-env-files.d.ts +33 -0
  80. package/dist/runtime/cli-add-workspace-integration-env-files.js +65 -0
  81. package/dist/runtime/cli-add-workspace-integration-env-package-json.d.ts +38 -0
  82. package/dist/runtime/cli-add-workspace-integration-env-package-json.js +122 -0
  83. package/dist/runtime/cli-add-workspace-integration-env-source-emitters.d.ts +44 -0
  84. package/dist/runtime/cli-add-workspace-integration-env-source-emitters.js +262 -0
  85. package/dist/runtime/cli-add-workspace-integration-env.d.ts +3 -1
  86. package/dist/runtime/cli-add-workspace-integration-env.js +10 -313
  87. package/dist/runtime/cli-add-workspace-pattern-anchors.d.ts +10 -0
  88. package/dist/runtime/cli-add-workspace-pattern-anchors.js +95 -0
  89. package/dist/runtime/cli-add-workspace-pattern-options.d.ts +20 -0
  90. package/dist/runtime/cli-add-workspace-pattern-options.js +113 -0
  91. package/dist/runtime/cli-add-workspace-pattern-source-emitters.d.ts +20 -0
  92. package/dist/runtime/cli-add-workspace-pattern-source-emitters.js +57 -0
  93. package/dist/runtime/cli-add-workspace-pattern.d.ts +42 -0
  94. package/dist/runtime/cli-add-workspace-pattern.js +99 -0
  95. package/dist/runtime/cli-add-workspace-post-meta.js +1 -1
  96. package/dist/runtime/cli-add-workspace-registration-hooks.d.ts +50 -0
  97. package/dist/runtime/cli-add-workspace-registration-hooks.js +162 -0
  98. package/dist/runtime/cli-add-workspace-rest-anchors.d.ts +9 -4
  99. package/dist/runtime/cli-add-workspace-rest-anchors.js +9 -428
  100. package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.d.ts +17 -0
  101. package/dist/runtime/cli-add-workspace-rest-bootstrap-anchors.js +108 -0
  102. package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.d.ts +9 -0
  103. package/dist/runtime/cli-add-workspace-rest-contract-sync-anchors.js +142 -0
  104. package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.d.ts +51 -0
  105. package/dist/runtime/cli-add-workspace-rest-generated-source-emitters.js +415 -0
  106. package/dist/runtime/cli-add-workspace-rest-generated.d.ts +9 -0
  107. package/dist/runtime/cli-add-workspace-rest-generated.js +160 -0
  108. package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.d.ts +80 -0
  109. package/dist/runtime/cli-add-workspace-rest-manual-source-emitters.js +238 -0
  110. package/dist/runtime/cli-add-workspace-rest-manual.d.ts +8 -0
  111. package/dist/runtime/cli-add-workspace-rest-manual.js +266 -0
  112. package/dist/runtime/cli-add-workspace-rest-php-templates.d.ts +18 -0
  113. package/dist/runtime/cli-add-workspace-rest-php-templates.js +359 -0
  114. package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.d.ts +33 -0
  115. package/dist/runtime/cli-add-workspace-rest-resource-php-routing-template.js +145 -0
  116. package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.d.ts +9 -0
  117. package/dist/runtime/cli-add-workspace-rest-resource-sync-anchors.js +162 -0
  118. package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.d.ts +7 -0
  119. package/dist/runtime/cli-add-workspace-rest-schema-helper-php-template.js +193 -0
  120. package/dist/runtime/cli-add-workspace-rest-source-emitters.d.ts +5 -91
  121. package/dist/runtime/cli-add-workspace-rest-source-emitters.js +5 -642
  122. package/dist/runtime/cli-add-workspace-rest-source-utils.d.ts +17 -0
  123. package/dist/runtime/cli-add-workspace-rest-source-utils.js +50 -0
  124. package/dist/runtime/cli-add-workspace-rest-sync-script-shared.d.ts +56 -0
  125. package/dist/runtime/cli-add-workspace-rest-sync-script-shared.js +122 -0
  126. package/dist/runtime/cli-add-workspace-rest-types.d.ts +108 -0
  127. package/dist/runtime/cli-add-workspace-rest-types.js +1 -0
  128. package/dist/runtime/cli-add-workspace-rest.d.ts +3 -20
  129. package/dist/runtime/cli-add-workspace-rest.js +33 -788
  130. package/dist/runtime/cli-add-workspace-variation.d.ts +22 -0
  131. package/dist/runtime/cli-add-workspace-variation.js +162 -0
  132. package/dist/runtime/cli-add-workspace.d.ts +42 -107
  133. package/dist/runtime/cli-add-workspace.js +42 -674
  134. package/dist/runtime/cli-add.d.ts +3 -3
  135. package/dist/runtime/cli-add.js +2 -2
  136. package/dist/runtime/cli-core.d.ts +3 -2
  137. package/dist/runtime/cli-core.js +2 -2
  138. package/dist/runtime/cli-diagnostics.d.ts +3 -1
  139. package/dist/runtime/cli-diagnostics.js +17 -5
  140. package/dist/runtime/cli-doctor-workspace-bindings.js +63 -1
  141. package/dist/runtime/cli-doctor-workspace-block-addons.d.ts +12 -0
  142. package/dist/runtime/cli-doctor-workspace-block-addons.js +162 -0
  143. package/dist/runtime/cli-doctor-workspace-block-iframe.d.ts +9 -0
  144. package/dist/runtime/cli-doctor-workspace-block-iframe.js +228 -0
  145. package/dist/runtime/cli-doctor-workspace-block-metadata.d.ts +11 -0
  146. package/dist/runtime/cli-doctor-workspace-block-metadata.js +111 -0
  147. package/dist/runtime/cli-doctor-workspace-blocks.js +6 -424
  148. package/dist/runtime/cli-doctor-workspace-features-abilities.d.ts +11 -0
  149. package/dist/runtime/cli-doctor-workspace-features-abilities.js +112 -0
  150. package/dist/runtime/cli-doctor-workspace-features-admin-views.d.ts +11 -0
  151. package/dist/runtime/cli-doctor-workspace-features-admin-views.js +128 -0
  152. package/dist/runtime/cli-doctor-workspace-features-ai.d.ts +11 -0
  153. package/dist/runtime/cli-doctor-workspace-features-ai.js +57 -0
  154. package/dist/runtime/cli-doctor-workspace-features-editor-plugins.d.ts +11 -0
  155. package/dist/runtime/cli-doctor-workspace-features-editor-plugins.js +80 -0
  156. package/dist/runtime/cli-doctor-workspace-features-post-meta.d.ts +11 -0
  157. package/dist/runtime/cli-doctor-workspace-features-post-meta.js +77 -0
  158. package/dist/runtime/cli-doctor-workspace-features-rest.d.ts +11 -0
  159. package/dist/runtime/cli-doctor-workspace-features-rest.js +120 -0
  160. package/dist/runtime/cli-doctor-workspace-features.js +14 -487
  161. package/dist/runtime/cli-doctor.d.ts +54 -3
  162. package/dist/runtime/cli-doctor.js +92 -10
  163. package/dist/runtime/cli-help.js +12 -7
  164. package/dist/runtime/cli-init-package-json.js +4 -2
  165. package/dist/runtime/cli-prompt.d.ts +16 -2
  166. package/dist/runtime/cli-prompt.js +29 -12
  167. package/dist/runtime/cli-scaffold.d.ts +2 -1
  168. package/dist/runtime/cli-scaffold.js +19 -10
  169. package/dist/runtime/external-template-guards.js +4 -6
  170. package/dist/runtime/index.d.ts +6 -3
  171. package/dist/runtime/index.js +4 -2
  172. package/dist/runtime/json-utils.d.ts +62 -4
  173. package/dist/runtime/json-utils.js +78 -4
  174. package/dist/runtime/local-dev-presets.js +6 -2
  175. package/dist/runtime/migration-ui-capability.js +4 -1
  176. package/dist/runtime/migration-utils.js +4 -1
  177. package/dist/runtime/package-managers.js +6 -1
  178. package/dist/runtime/package-versions.d.ts +1 -0
  179. package/dist/runtime/package-versions.js +16 -3
  180. package/dist/runtime/pattern-catalog.d.ts +122 -0
  181. package/dist/runtime/pattern-catalog.js +471 -0
  182. package/dist/runtime/post-meta-binding-fields.d.ts +46 -0
  183. package/dist/runtime/post-meta-binding-fields.js +135 -0
  184. package/dist/runtime/scaffold-bootstrap.js +7 -2
  185. package/dist/runtime/scaffold-package-manager-files.js +5 -1
  186. package/dist/runtime/scaffold-repository-reference.js +4 -2
  187. package/dist/runtime/scaffold-template-variables.js +2 -1
  188. package/dist/runtime/scaffold.d.ts +18 -1
  189. package/dist/runtime/scaffold.js +55 -2
  190. package/dist/runtime/temp-roots.js +4 -1
  191. package/dist/runtime/template-layers.js +4 -1
  192. package/dist/runtime/template-registry.js +9 -3
  193. package/dist/runtime/template-source-contracts.d.ts +2 -0
  194. package/dist/runtime/template-source-normalization.js +2 -1
  195. package/dist/runtime/template-source-remote.js +18 -5
  196. package/dist/runtime/template-source-seeds.js +10 -3
  197. package/dist/runtime/typia-llm-json-schema.d.ts +24 -0
  198. package/dist/runtime/typia-llm-json-schema.js +33 -0
  199. package/dist/runtime/typia-llm-openapi-constraints.d.ts +20 -0
  200. package/dist/runtime/typia-llm-openapi-constraints.js +254 -0
  201. package/dist/runtime/typia-llm-projection.d.ts +25 -0
  202. package/dist/runtime/typia-llm-projection.js +58 -0
  203. package/dist/runtime/typia-llm-render.d.ts +21 -0
  204. package/dist/runtime/typia-llm-render.js +252 -0
  205. package/dist/runtime/typia-llm-sync.d.ts +10 -0
  206. package/dist/runtime/typia-llm-sync.js +63 -0
  207. package/dist/runtime/typia-llm-types.d.ts +197 -0
  208. package/dist/runtime/typia-llm-types.js +1 -0
  209. package/dist/runtime/typia-llm.d.ts +9 -255
  210. package/dist/runtime/typia-llm.js +5 -634
  211. package/dist/runtime/workspace-inventory-mutations.js +15 -1
  212. package/dist/runtime/workspace-inventory-parser-entries.d.ts +17 -0
  213. package/dist/runtime/workspace-inventory-parser-entries.js +157 -0
  214. package/dist/runtime/workspace-inventory-parser-validation.d.ts +104 -0
  215. package/dist/runtime/workspace-inventory-parser-validation.js +34 -0
  216. package/dist/runtime/workspace-inventory-parser.d.ts +3 -45
  217. package/dist/runtime/workspace-inventory-parser.js +3 -581
  218. package/dist/runtime/workspace-inventory-section-descriptors.d.ts +19 -0
  219. package/dist/runtime/workspace-inventory-section-descriptors.js +443 -0
  220. package/dist/runtime/workspace-inventory-templates.d.ts +3 -3
  221. package/dist/runtime/workspace-inventory-templates.js +10 -1
  222. package/dist/runtime/workspace-inventory-types.d.ts +10 -1
  223. package/dist/runtime/workspace-project.js +4 -6
  224. package/package.json +8 -3
  225. package/templates/_shared/compound/core/scripts/block-config.ts.mustache +22 -0
  226. package/templates/_shared/compound/core/scripts/sync-types-to-block-json.ts.mustache +103 -2
  227. package/templates/_shared/compound/core/src/inner-blocks-templates.ts.mustache +13 -0
  228. package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +22 -1
@@ -1,324 +1,18 @@
1
- import { promises as fsp } from "node:fs";
2
1
  import path from "node:path";
3
2
  import { assertValidGeneratedSlug, assertValidIntegrationEnvService, normalizeBlockSlug, } from "./cli-add-shared.js";
4
- import { formatRunScript, } from "./package-managers.js";
5
- import { pathExists, readOptionalUtf8File } from "./fs-async.js";
3
+ import { appendMissingLines, writeFileIfAbsent, writeNewScaffoldFile, } from "./cli-add-workspace-integration-env-files.js";
4
+ import { addIntegrationEnvPackageJsonEntries, mutateIntegrationEnvPackageJson, } from "./cli-add-workspace-integration-env-package-json.js";
5
+ import { buildDockerComposeSource, buildEnvExampleSource, buildIntegrationEnvReadmeSource, buildIntegrationSmokeScriptSource, buildWpEnvConfigSource, } from "./cli-add-workspace-integration-env-source-emitters.js";
6
6
  import { executeWorkspaceMutationPlan } from "./cli-add-workspace-mutation.js";
7
+ import { pathExists } from "./fs-async.js";
7
8
  import { resolveWorkspaceProject } from "./workspace-project.js";
8
- import { toTitleCase } from "./string-case.js";
9
- const WP_ENV_PACKAGE_VERSION = "^11.2.0";
10
- function buildWpEnvConfigSource() {
11
- return `${JSON.stringify({
12
- $schema: "https://schemas.wp.org/trunk/wp-env.json",
13
- core: null,
14
- port: 8888,
15
- testsEnvironment: false,
16
- plugins: ["."],
17
- config: {
18
- WP_DEBUG: true,
19
- WP_DEBUG_LOG: true,
20
- WP_DEBUG_DISPLAY: false,
21
- SCRIPT_DEBUG: true,
22
- WP_ENVIRONMENT_TYPE: "local",
23
- },
24
- }, null, 2)}\n`;
25
- }
26
- function buildDockerComposeSource() {
27
- return `services:
28
- integration-service:
29
- image: node:22-alpine
30
- working_dir: /workspace
31
- volumes:
32
- - .:/workspace
33
- command: >
34
- node -e "require('node:http').createServer((request, response) => {
35
- response.writeHead(request.url === '/health' ? 200 : 404, {
36
- 'content-type': 'application/json'
37
- });
38
- response.end(JSON.stringify({
39
- ok: request.url === '/health',
40
- service: 'wp-typia-integration-starter'
41
- }));
42
- }).listen(3000, '0.0.0.0')"
43
- ports:
44
- - "3000:3000"
45
- `;
46
- }
47
- function buildIntegrationSmokeScriptSource(integrationEnvSlug) {
48
- return `import fs from "node:fs";
49
- import path from "node:path";
50
- import { fileURLToPath } from "node:url";
51
-
52
- const ROOT_DIR = path.resolve(
53
- fileURLToPath(new URL("../..", import.meta.url)),
54
- );
55
- const ENV_FILE = path.join(ROOT_DIR, ".env");
56
-
57
- function parseEnvValue(value) {
58
- const trimmed = value.trim();
59
- if (
60
- (trimmed.startsWith('"') && trimmed.endsWith('"')) ||
61
- (trimmed.startsWith("'") && trimmed.endsWith("'"))
62
- ) {
63
- return trimmed.slice(1, -1);
64
- }
65
-
66
- return trimmed;
67
- }
68
-
69
- function readEnvFile(filePath) {
70
- if (!fs.existsSync(filePath)) {
71
- return {};
72
- }
73
-
74
- return Object.fromEntries(
75
- fs
76
- .readFileSync(filePath, "utf8")
77
- .split(/\\r?\\n/u)
78
- .map((line) => line.trim())
79
- .filter((line) => line.length > 0 && !line.startsWith("#"))
80
- .map((line) => {
81
- const separatorIndex = line.indexOf("=");
82
- if (separatorIndex === -1) {
83
- return null;
84
- }
85
-
86
- return [
87
- line.slice(0, separatorIndex).trim(),
88
- parseEnvValue(line.slice(separatorIndex + 1)),
89
- ];
90
- })
91
- .filter(Boolean),
92
- );
93
- }
94
-
95
- const envFile = readEnvFile(ENV_FILE);
96
-
97
- function getEnv(name, fallback) {
98
- return process.env[name] ?? envFile[name] ?? fallback;
99
- }
100
-
101
- function resolveEndpointUrl(baseUrl, endpointPath) {
102
- const normalizedBaseUrl = new URL(baseUrl);
103
- if (!normalizedBaseUrl.pathname.endsWith("/")) {
104
- normalizedBaseUrl.pathname = \`\${normalizedBaseUrl.pathname}/\`;
105
- }
106
-
107
- const relativePath = endpointPath.replace(/^\\/+/u, "");
108
- return new URL(relativePath, normalizedBaseUrl);
109
- }
110
-
111
- async function assertJsonEndpoint(label, url) {
112
- const response = await fetch(url, {
113
- headers: {
114
- accept: "application/json",
115
- },
116
- });
117
-
118
- if (!response.ok) {
119
- throw new Error(
120
- \`\${label} failed at \${url} with HTTP \${response.status}.\`,
121
- );
122
- }
123
-
124
- const contentType = response.headers.get("content-type") ?? "";
125
- if (!contentType.includes("application/json")) {
126
- throw new Error(
127
- \`\${label} at \${url} did not return JSON (content-type: \${contentType || "missing"}).\`,
128
- );
129
- }
130
-
131
- return response.json();
132
- }
133
-
134
- const baseUrl = new URL(
135
- getEnv("WP_TYPIA_SMOKE_BASE_URL", "http://localhost:8888"),
136
- );
137
- const serviceUrl = getEnv("WP_TYPIA_SERVICE_URL", "").trim();
138
-
139
- await assertJsonEndpoint(
140
- "WordPress REST index",
141
- resolveEndpointUrl(baseUrl, "wp-json/"),
142
- );
143
-
144
- if (serviceUrl.length > 0) {
145
- await assertJsonEndpoint(
146
- "Local integration service healthcheck",
147
- resolveEndpointUrl(serviceUrl, "health"),
148
- );
149
- }
150
-
151
- console.log("wp-typia integration smoke passed: ${integrationEnvSlug}");
152
- `;
153
- }
154
- function buildEnvExampleSource(service) {
155
- return [
156
- "# wp-typia integration smoke settings",
157
- "WP_TYPIA_SMOKE_BASE_URL=http://localhost:8888",
158
- "WP_TYPIA_SMOKE_USERNAME=admin",
159
- "WP_TYPIA_SMOKE_PASSWORD=password",
160
- ...(service === "docker-compose"
161
- ? [
162
- "",
163
- "# Optional docker-compose integration service starter.",
164
- "WP_TYPIA_SERVICE_URL=http://localhost:3000",
165
- ]
166
- : [
167
- "",
168
- "# Set this when your smoke test needs a project-specific service.",
169
- "# WP_TYPIA_SERVICE_URL=http://localhost:3000",
170
- ]),
171
- "",
172
- ].join("\n");
173
- }
174
- function buildIntegrationEnvReadmeSource({ integrationEnvSlug, service, withWpEnv, }) {
175
- const title = toTitleCase(integrationEnvSlug);
176
- const setupSteps = [
177
- "Copy `.env.example` to `.env` and adjust the URLs or credentials for your local project.",
178
- ...(withWpEnv
179
- ? [
180
- "Run `npm run wp-env:start` to start the generated WordPress environment.",
181
- ]
182
- : [
183
- "Point `WP_TYPIA_SMOKE_BASE_URL` at the WordPress environment you already run locally.",
184
- ]),
185
- ...(service === "docker-compose"
186
- ? [
187
- "Run `npm run service:start` if you want the placeholder docker-compose service available at `WP_TYPIA_SERVICE_URL`.",
188
- ]
189
- : [
190
- "Set `WP_TYPIA_SERVICE_URL` only when your integration smoke needs a local service dependency.",
191
- ]),
192
- `Run \`npm run smoke:${integrationEnvSlug}\` to execute the starter smoke check.`,
193
- ];
194
- return `# ${title} Integration Environment
195
-
196
- This starter keeps local WordPress integration smoke checks opt-in and editable.
197
- It does not change default block scaffolds or require wp-env unless this add
198
- workflow was run with \`--wp-env\`.
199
-
200
- ## Setup
201
-
202
- ${setupSteps.map((step, index) => `${index + 1}. ${step}`).join("\n")}
203
-
204
- ## Adapting the Starter
205
-
206
- - Extend \`scripts/integration-smoke/${integrationEnvSlug}.mjs\` with the REST,
207
- editor, or service assertions that matter for this project.
208
- - Keep secrets in \`.env\`; \`.env.example\` should document only safe defaults.
209
- - If your project uses a real service stack, replace the placeholder
210
- \`docker-compose.integration.yml\` service with your database, queue, API, or
211
- emulator containers.
212
- - Keep the smoke script focused on high-signal integration checks so CI and
213
- local debugging stay fast.
214
- `;
215
- }
216
- async function appendMissingLines(filePath, lines) {
217
- const current = (await readOptionalUtf8File(filePath)) ?? "";
218
- const missingLines = lines.filter((line) => !current.includes(`${line}\n`) && !current.endsWith(line));
219
- if (missingLines.length === 0) {
220
- return;
221
- }
222
- const separator = current.length === 0 || current.endsWith("\n") ? "" : "\n";
223
- await fsp.mkdir(path.dirname(filePath), { recursive: true });
224
- await fsp.writeFile(filePath, `${current}${separator}${missingLines.join("\n")}\n`, "utf8");
225
- }
226
- async function writeFileIfAbsent({ filePath, source, warnings, }) {
227
- if (await pathExists(filePath)) {
228
- warnings.push(`Preserved existing ${path.basename(filePath)}; review it manually if you need different local integration settings.`);
229
- return;
230
- }
231
- await fsp.mkdir(path.dirname(filePath), { recursive: true });
232
- await fsp.writeFile(filePath, source, "utf8");
233
- }
234
- async function writeNewScaffoldFile(filePath, source) {
235
- if (await pathExists(filePath)) {
236
- throw new Error(`An integration environment scaffold already exists at ${filePath}. Choose a different name.`);
237
- }
238
- await fsp.mkdir(path.dirname(filePath), { recursive: true });
239
- await fsp.writeFile(filePath, source, "utf8");
240
- }
241
- function addScriptIfMissing({ scriptName, scripts, scriptValue, warnings, }) {
242
- if (scripts[scriptName] === undefined) {
243
- scripts[scriptName] = scriptValue;
244
- return;
245
- }
246
- if (scripts[scriptName] !== scriptValue) {
247
- warnings.push(`Preserved existing package script "${scriptName}"; add "${scriptValue}" manually if you want the generated integration command.`);
248
- }
249
- }
250
- async function mutatePackageJson(projectDir, mutate) {
251
- const packageJsonPath = path.join(projectDir, "package.json");
252
- const packageJson = JSON.parse(await fsp.readFile(packageJsonPath, "utf8"));
253
- mutate(packageJson);
254
- await fsp.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, "\t")}\n`, "utf8");
255
- }
256
- function addIntegrationEnvPackageJsonEntries({ integrationEnvSlug, packageManager, packageJson, service, warnings, withWpEnv, }) {
257
- const devDependencies = {
258
- ...(packageJson.devDependencies ?? {}),
259
- };
260
- if (withWpEnv && devDependencies["@wordpress/env"] === undefined) {
261
- devDependencies["@wordpress/env"] = WP_ENV_PACKAGE_VERSION;
262
- }
263
- packageJson.devDependencies = devDependencies;
264
- const scripts = {
265
- ...(packageJson.scripts ?? {}),
266
- };
267
- addScriptIfMissing({
268
- scriptName: `smoke:${integrationEnvSlug}`,
269
- scriptValue: `node scripts/integration-smoke/${integrationEnvSlug}.mjs`,
270
- scripts,
271
- warnings,
272
- });
273
- addScriptIfMissing({
274
- scriptName: "smoke:integration",
275
- scriptValue: formatRunScript(packageManager, `smoke:${integrationEnvSlug}`),
276
- scripts,
277
- warnings,
278
- });
279
- if (withWpEnv) {
280
- addScriptIfMissing({
281
- scriptName: "wp-env:start",
282
- scriptValue: "wp-env start",
283
- scripts,
284
- warnings,
285
- });
286
- addScriptIfMissing({
287
- scriptName: "wp-env:stop",
288
- scriptValue: "wp-env stop",
289
- scripts,
290
- warnings,
291
- });
292
- addScriptIfMissing({
293
- scriptName: "wp-env:reset",
294
- scriptValue: "wp-env destroy all && wp-env start",
295
- scripts,
296
- warnings,
297
- });
298
- }
299
- if (service === "docker-compose") {
300
- addScriptIfMissing({
301
- scriptName: "service:start",
302
- scriptValue: "docker compose -f docker-compose.integration.yml up -d",
303
- scripts,
304
- warnings,
305
- });
306
- addScriptIfMissing({
307
- scriptName: "service:stop",
308
- scriptValue: "docker compose -f docker-compose.integration.yml down",
309
- scripts,
310
- warnings,
311
- });
312
- }
313
- packageJson.scripts = scripts;
314
- }
315
9
  /**
316
10
  * Add an opt-in local WordPress integration environment starter to an official
317
11
  * workspace.
318
12
  */
319
- export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integrationEnvName, service, withWpEnv = false, }) {
13
+ export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integrationEnvName, service, withReleaseZip = false, withWpEnv = false, }) {
320
14
  const workspace = resolveWorkspaceProject(cwd);
321
- const integrationEnvSlug = assertValidGeneratedSlug("Integration environment name", normalizeBlockSlug(integrationEnvName), "wp-typia add integration-env <name> [--wp-env]");
15
+ const integrationEnvSlug = assertValidGeneratedSlug("Integration environment name", normalizeBlockSlug(integrationEnvName), "wp-typia add integration-env <name> [--wp-env] [--release-zip]");
322
16
  const serviceId = assertValidIntegrationEnvService(service);
323
17
  const warnings = [];
324
18
  const packageJsonPath = path.join(workspace.projectDir, "package.json");
@@ -351,6 +45,7 @@ export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integra
351
45
  await writeNewScaffoldFile(docsPath, buildIntegrationEnvReadmeSource({
352
46
  integrationEnvSlug,
353
47
  service: serviceId,
48
+ withReleaseZip,
354
49
  withWpEnv,
355
50
  }));
356
51
  await appendMissingLines(envExamplePath, [
@@ -371,11 +66,12 @@ export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integra
371
66
  warnings,
372
67
  });
373
68
  }
374
- await mutatePackageJson(workspace.projectDir, (packageJson) => addIntegrationEnvPackageJsonEntries({
69
+ await mutateIntegrationEnvPackageJson(workspace.projectDir, (packageJson) => addIntegrationEnvPackageJsonEntries({
375
70
  integrationEnvSlug,
376
71
  packageManager: workspace.packageManager,
377
72
  packageJson,
378
73
  service: serviceId,
74
+ withReleaseZip,
379
75
  warnings,
380
76
  withWpEnv,
381
77
  }));
@@ -386,6 +82,7 @@ export async function runAddIntegrationEnvCommand({ cwd = process.cwd(), integra
386
82
  projectDir: workspace.projectDir,
387
83
  service: serviceId,
388
84
  warnings: warnings.length > 0 ? warnings : undefined,
85
+ withReleaseZip,
389
86
  withWpEnv,
390
87
  };
391
88
  }
@@ -0,0 +1,10 @@
1
+ import type { WorkspaceProject } from "./workspace-project.js";
2
+ /**
3
+ * Ensure workspace bootstrap PHP registers pattern categories and loads
4
+ * generated pattern modules from both flat and nested pattern directories.
5
+ *
6
+ * @param workspace Resolved official workspace project metadata.
7
+ * @returns A promise that resolves after the workspace bootstrap is patched.
8
+ * @throws {Error} When existing bootstrap source cannot be safely patched.
9
+ */
10
+ export declare function ensurePatternBootstrapAnchors(workspace: WorkspaceProject): Promise<void>;
@@ -0,0 +1,95 @@
1
+ import path from "node:path";
2
+ import { getWorkspaceBootstrapPath, patchFile } from "./cli-add-shared.js";
3
+ import { appendPhpSnippetBeforeClosingTag, insertPhpSnippetBeforeWorkspaceAnchors, } from "./cli-add-workspace-mutation.js";
4
+ import { hasPhpFunctionDefinition } from "./php-utils.js";
5
+ import { toTitleCase } from "./string-case.js";
6
+ const FLAT_PATTERN_GLOB = "glob( __DIR__ . '/src/patterns/*.php' ) ?: array()";
7
+ const NESTED_PATTERN_GLOB = "glob( __DIR__ . '/src/patterns/*/*.php' ) ?: array()";
8
+ const LEGACY_FLAT_PATTERN_MODULES_ASSIGNMENT_PATTERN = /^[ \t]*\$pattern_modules\s*=\s*glob\( __DIR__ \. '\/src\/patterns\/\*\.php' \) \?: array\(\);\s*$/mu;
9
+ const LEGACY_FLAT_PATTERN_FOREACH_PATTERN = /^[ \t]*foreach\s*\(\s*glob\( __DIR__ \. '\/src\/patterns\/\*\.php' \) \?: array\(\)\s+as\s+\$pattern_module\s*\)\s*\{\r?\n[ \t]*require\s+\$pattern_module;\r?\n[ \t]*\}/mu;
10
+ function buildNestedPatternModulesAssignment() {
11
+ return [
12
+ "\t$pattern_modules = array_merge(",
13
+ `\t\t${FLAT_PATTERN_GLOB},`,
14
+ `\t\t${NESTED_PATTERN_GLOB}`,
15
+ "\t);",
16
+ ].join("\n");
17
+ }
18
+ function ensureNestedPatternLoaderSource(source, bootstrapPath) {
19
+ if (source.includes(NESTED_PATTERN_GLOB)) {
20
+ return source;
21
+ }
22
+ if (LEGACY_FLAT_PATTERN_FOREACH_PATTERN.test(source)) {
23
+ return source.replace(LEGACY_FLAT_PATTERN_FOREACH_PATTERN, [
24
+ buildNestedPatternModulesAssignment(),
25
+ "\tforeach ( $pattern_modules as $pattern_module ) {",
26
+ "\t\trequire $pattern_module;",
27
+ "\t}",
28
+ ].join("\n"));
29
+ }
30
+ if (LEGACY_FLAT_PATTERN_MODULES_ASSIGNMENT_PATTERN.test(source)) {
31
+ return source.replace(LEGACY_FLAT_PATTERN_MODULES_ASSIGNMENT_PATTERN, buildNestedPatternModulesAssignment());
32
+ }
33
+ if (source.includes("array_merge(") && source.includes(FLAT_PATTERN_GLOB)) {
34
+ return source.replace(FLAT_PATTERN_GLOB, `${FLAT_PATTERN_GLOB},\n\t\t${NESTED_PATTERN_GLOB}`);
35
+ }
36
+ throw new Error(`Unable to repair ${path.basename(bootstrapPath)} pattern loader for nested src/patterns directories.`);
37
+ }
38
+ /**
39
+ * Ensure workspace bootstrap PHP registers pattern categories and loads
40
+ * generated pattern modules from both flat and nested pattern directories.
41
+ *
42
+ * @param workspace Resolved official workspace project metadata.
43
+ * @returns A promise that resolves after the workspace bootstrap is patched.
44
+ * @throws {Error} When existing bootstrap source cannot be safely patched.
45
+ */
46
+ export async function ensurePatternBootstrapAnchors(workspace) {
47
+ const workspaceBaseName = workspace.packageName.split("/").pop() ?? workspace.packageName;
48
+ const bootstrapPath = getWorkspaceBootstrapPath(workspace);
49
+ await patchFile(bootstrapPath, (source) => {
50
+ let nextSource = source;
51
+ const patternCategoryFunctionName = `${workspace.workspace.phpPrefix}_register_pattern_category`;
52
+ const patternRegistrationFunctionName = `${workspace.workspace.phpPrefix}_register_patterns`;
53
+ const patternCategoryHook = `add_action( 'init', '${patternCategoryFunctionName}' );`;
54
+ const patternRegistrationHook = `add_action( 'init', '${patternRegistrationFunctionName}', 20 );`;
55
+ const patternFunctions = `
56
+
57
+ function ${patternCategoryFunctionName}() {
58
+ if ( function_exists( 'register_block_pattern_category' ) ) {
59
+ register_block_pattern_category(
60
+ '${workspace.workspace.namespace}',
61
+ array(
62
+ 'label' => __( ${JSON.stringify(`${toTitleCase(workspaceBaseName)} Patterns`)}, '${workspace.workspace.textDomain}' ),
63
+ )
64
+ );
65
+ }
66
+ }
67
+
68
+ function ${patternRegistrationFunctionName}() {
69
+ $pattern_modules = array_merge(
70
+ ${FLAT_PATTERN_GLOB},
71
+ ${NESTED_PATTERN_GLOB}
72
+ );
73
+ foreach ( $pattern_modules as $pattern_module ) {
74
+ require $pattern_module;
75
+ }
76
+ }
77
+ `;
78
+ if (!hasPhpFunctionDefinition(nextSource, patternCategoryFunctionName) &&
79
+ !hasPhpFunctionDefinition(nextSource, patternRegistrationFunctionName)) {
80
+ nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, patternFunctions);
81
+ }
82
+ if (!hasPhpFunctionDefinition(nextSource, patternCategoryFunctionName) ||
83
+ !hasPhpFunctionDefinition(nextSource, patternRegistrationFunctionName)) {
84
+ throw new Error(`Unable to inject pattern bootstrap functions into ${path.basename(bootstrapPath)}.`);
85
+ }
86
+ nextSource = ensureNestedPatternLoaderSource(nextSource, bootstrapPath);
87
+ if (!nextSource.includes(patternCategoryHook)) {
88
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, patternCategoryHook);
89
+ }
90
+ if (!nextSource.includes(patternRegistrationHook)) {
91
+ nextSource = appendPhpSnippetBeforeClosingTag(nextSource, patternRegistrationHook);
92
+ }
93
+ return nextSource;
94
+ });
95
+ }
@@ -0,0 +1,20 @@
1
+ import { type RunAddPatternCommandOptions } from "./cli-add-shared.js";
2
+ import { type PatternCatalogScope } from "./pattern-catalog.js";
3
+ export type ResolvedPatternCatalogOptions = {
4
+ contentFile: string;
5
+ patternScope: PatternCatalogScope;
6
+ sectionRole?: string;
7
+ tags: string[];
8
+ thumbnailUrl?: string;
9
+ title: string;
10
+ };
11
+ /**
12
+ * Resolve and validate catalog metadata for a generated workspace pattern.
13
+ *
14
+ * @param patternSlug Normalized and validated pattern slug.
15
+ * @param options Raw add-pattern command options from the CLI layer.
16
+ * @returns Resolved catalog metadata and safe relative content path.
17
+ * @throws {Error} When scope, section-role coupling, tags, thumbnail URL, or
18
+ * content file paths are invalid.
19
+ */
20
+ export declare function resolvePatternCatalogOptions(patternSlug: string, options: RunAddPatternCommandOptions): ResolvedPatternCatalogOptions;
@@ -0,0 +1,113 @@
1
+ import path from "node:path";
2
+ import { assertValidGeneratedSlug, normalizeBlockSlug, } from "./cli-add-shared.js";
3
+ import { isValidPatternThumbnailUrl, PATTERN_CATALOG_SCOPE_IDS, } from "./pattern-catalog.js";
4
+ import { toTitleCase } from "./string-case.js";
5
+ const PATTERN_CONTENT_FILE_ROOT = "src/patterns/";
6
+ const PATTERN_TAG_PATTERN = /^[a-z0-9][a-z0-9-]*$/u;
7
+ function assertValidPatternRelativePath(label, value, usage) {
8
+ const normalizedPath = value.trim().replace(/\\/gu, "/");
9
+ if (normalizedPath.length === 0 ||
10
+ path.isAbsolute(normalizedPath) ||
11
+ normalizedPath.split("/").includes("..") ||
12
+ /[<>:"|?*\u0000-\u001F]/u.test(normalizedPath)) {
13
+ throw new Error(`${label} must be a safe relative project path. Use \`${usage}\`.`);
14
+ }
15
+ return normalizedPath;
16
+ }
17
+ function assertValidPatternContentFile(value, usage) {
18
+ const normalizedPath = assertValidPatternRelativePath("Pattern content file", value, usage);
19
+ if (!isLoadablePatternContentFilePath(normalizedPath)) {
20
+ throw new Error("Pattern content file must live directly under `src/patterns/` or one nested directory under `src/patterns/` and end in `.php` so the generated PHP loader can require it.");
21
+ }
22
+ return normalizedPath;
23
+ }
24
+ function isLoadablePatternContentFilePath(normalizedPath) {
25
+ if (!normalizedPath.startsWith(PATTERN_CONTENT_FILE_ROOT) ||
26
+ !normalizedPath.endsWith(".php")) {
27
+ return false;
28
+ }
29
+ const patternRelativePath = normalizedPath.slice(PATTERN_CONTENT_FILE_ROOT.length);
30
+ const segments = patternRelativePath.split("/");
31
+ return ((segments.length === 1 || segments.length === 2) &&
32
+ segments.every((segment) => segment.length > 0));
33
+ }
34
+ function resolvePatternScope(scope) {
35
+ if (scope === undefined || scope.trim() === "") {
36
+ return "full";
37
+ }
38
+ const normalizedScope = scope.trim();
39
+ if (PATTERN_CATALOG_SCOPE_IDS.includes(normalizedScope)) {
40
+ return normalizedScope;
41
+ }
42
+ throw new Error(`Pattern scope must be one of: ${PATTERN_CATALOG_SCOPE_IDS.join(", ")}.`);
43
+ }
44
+ function normalizeOptionalSlug(label, value, usage) {
45
+ if (value === undefined || value.trim() === "") {
46
+ return undefined;
47
+ }
48
+ return assertValidGeneratedSlug(label, normalizeBlockSlug(value), usage);
49
+ }
50
+ function normalizePatternTags(tags) {
51
+ const rawTags = typeof tags === "string"
52
+ ? tags.split(",")
53
+ : Array.isArray(tags)
54
+ ? [...tags]
55
+ : [];
56
+ const normalizedTags = rawTags
57
+ .map((tag) => normalizeBlockSlug(tag))
58
+ .filter((tag) => tag.length > 0);
59
+ for (const tag of normalizedTags) {
60
+ if (!PATTERN_TAG_PATTERN.test(tag)) {
61
+ throw new Error(`Pattern tag "${tag}" must contain only lowercase letters, numbers, and hyphens.`);
62
+ }
63
+ }
64
+ return [...new Set(normalizedTags)].sort();
65
+ }
66
+ function normalizePatternThumbnailUrl(value) {
67
+ if (value === undefined || value.trim() === "") {
68
+ return undefined;
69
+ }
70
+ const thumbnailUrl = value.trim();
71
+ if (!isValidPatternThumbnailUrl(thumbnailUrl)) {
72
+ throw new Error("Pattern thumbnail URL must be an http(s) URL or safe relative project path.");
73
+ }
74
+ return thumbnailUrl;
75
+ }
76
+ function resolvePatternContentFile(patternSlug, patternScope, contentFile) {
77
+ if (contentFile && contentFile.trim() !== "") {
78
+ return assertValidPatternContentFile(contentFile, "wp-typia add pattern <name> [--scope <full|section>]");
79
+ }
80
+ const scopeDirectory = patternScope === "section" ? "sections" : "full";
81
+ return path.posix.join("src", "patterns", scopeDirectory, `${patternSlug}.php`);
82
+ }
83
+ /**
84
+ * Resolve and validate catalog metadata for a generated workspace pattern.
85
+ *
86
+ * @param patternSlug Normalized and validated pattern slug.
87
+ * @param options Raw add-pattern command options from the CLI layer.
88
+ * @returns Resolved catalog metadata and safe relative content path.
89
+ * @throws {Error} When scope, section-role coupling, tags, thumbnail URL, or
90
+ * content file paths are invalid.
91
+ */
92
+ export function resolvePatternCatalogOptions(patternSlug, options) {
93
+ const patternScope = resolvePatternScope(options.patternScope);
94
+ const sectionRole = normalizeOptionalSlug("Pattern section role", options.sectionRole, "wp-typia add pattern <name> --scope section --section-role <role>");
95
+ if (patternScope === "section" && !sectionRole) {
96
+ throw new Error("`wp-typia add pattern --scope section` requires --section-role <role>.");
97
+ }
98
+ if (patternScope !== "section" && sectionRole) {
99
+ throw new Error("`--section-role` requires `--scope section`.");
100
+ }
101
+ const title = options.catalogTitle && options.catalogTitle.trim() !== ""
102
+ ? options.catalogTitle.trim()
103
+ : toTitleCase(patternSlug);
104
+ const thumbnailUrl = normalizePatternThumbnailUrl(options.thumbnailUrl);
105
+ return {
106
+ contentFile: resolvePatternContentFile(patternSlug, patternScope, options.contentFile),
107
+ patternScope,
108
+ ...(sectionRole ? { sectionRole } : {}),
109
+ tags: normalizePatternTags(options.tags),
110
+ ...(thumbnailUrl ? { thumbnailUrl } : {}),
111
+ title,
112
+ };
113
+ }
@@ -0,0 +1,20 @@
1
+ import type { ResolvedPatternCatalogOptions } from "./cli-add-workspace-pattern-options.js";
2
+ /**
3
+ * Render the block-config inventory entry for a generated pattern.
4
+ *
5
+ * @param patternSlug Normalized and validated pattern slug.
6
+ * @param options Resolved pattern catalog metadata.
7
+ * @returns A TypeScript object literal snippet for the workspace inventory.
8
+ */
9
+ export declare function buildPatternConfigEntry(patternSlug: string, options: ResolvedPatternCatalogOptions): string;
10
+ /**
11
+ * Render the PHP pattern module registered by the workspace add command.
12
+ *
13
+ * @param patternSlug Normalized and validated pattern slug.
14
+ * @param namespace WordPress block namespace for the workspace.
15
+ * @param sectionRole Optional section role for section-scoped patterns.
16
+ * @param textDomain Translation text domain for generated labels.
17
+ * @param title Human-readable pattern title.
18
+ * @returns PHP source for a single generated block pattern module.
19
+ */
20
+ export declare function buildPatternSource(patternSlug: string, namespace: string, sectionRole: string | undefined, textDomain: string, title: string): string;
@@ -0,0 +1,57 @@
1
+ import { quoteTsString } from "./cli-add-shared.js";
2
+ /**
3
+ * Render the block-config inventory entry for a generated pattern.
4
+ *
5
+ * @param patternSlug Normalized and validated pattern slug.
6
+ * @param options Resolved pattern catalog metadata.
7
+ * @returns A TypeScript object literal snippet for the workspace inventory.
8
+ */
9
+ export function buildPatternConfigEntry(patternSlug, options) {
10
+ const lines = [
11
+ "\t{",
12
+ `\t\tcontentFile: ${quoteTsString(options.contentFile)},`,
13
+ `\t\tfile: ${quoteTsString(options.contentFile)},`,
14
+ `\t\tscope: ${quoteTsString(options.patternScope)},`,
15
+ ...(options.sectionRole
16
+ ? [`\t\tsectionRole: ${quoteTsString(options.sectionRole)},`]
17
+ : []),
18
+ `\t\tslug: ${quoteTsString(patternSlug)},`,
19
+ `\t\ttags: [${options.tags.map((tag) => quoteTsString(tag)).join(", ")}],`,
20
+ ...(options.thumbnailUrl
21
+ ? [`\t\tthumbnailUrl: ${quoteTsString(options.thumbnailUrl)},`]
22
+ : []),
23
+ `\t\ttitle: ${quoteTsString(options.title)},`,
24
+ "\t},",
25
+ ];
26
+ return lines.join("\n");
27
+ }
28
+ /**
29
+ * Render the PHP pattern module registered by the workspace add command.
30
+ *
31
+ * @param patternSlug Normalized and validated pattern slug.
32
+ * @param namespace WordPress block namespace for the workspace.
33
+ * @param sectionRole Optional section role for section-scoped patterns.
34
+ * @param textDomain Translation text domain for generated labels.
35
+ * @param title Human-readable pattern title.
36
+ * @returns PHP source for a single generated block pattern module.
37
+ */
38
+ export function buildPatternSource(patternSlug, namespace, sectionRole, textDomain, title) {
39
+ const content = sectionRole
40
+ ? `'<!-- wp:group {"className":"section section--${sectionRole}"} --><div class="wp-block-group section section--${sectionRole}"><!-- wp:paragraph --><p>' . esc_html__( 'Describe this section pattern here.', '${textDomain}' ) . '</p><!-- /wp:paragraph --></div><!-- /wp:group -->'`
41
+ : `'<!-- wp:paragraph --><p>' . esc_html__( 'Describe this pattern here.', '${textDomain}' ) . '</p><!-- /wp:paragraph -->'`;
42
+ return `<?php
43
+ if ( ! defined( 'ABSPATH' ) ) {
44
+ return;
45
+ }
46
+
47
+ register_block_pattern(
48
+ '${namespace}/${patternSlug}',
49
+ array(
50
+ 'title' => __( ${JSON.stringify(title)}, '${textDomain}' ),
51
+ 'description' => __( ${JSON.stringify(`A starter pattern for ${title}.`)}, '${textDomain}' ),
52
+ 'categories' => array( '${namespace}' ),
53
+ 'content' => ${content},
54
+ )
55
+ );
56
+ `;
57
+ }