@wp-typia/project-tools 0.18.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/runtime/alternate-render-targets.d.ts +5 -0
  2. package/dist/runtime/alternate-render-targets.js +29 -0
  3. package/dist/runtime/block-generator-service-core.d.ts +1 -1
  4. package/dist/runtime/block-generator-service-core.js +11 -7
  5. package/dist/runtime/block-generator-service-spec.d.ts +8 -1
  6. package/dist/runtime/block-generator-service-spec.js +248 -2
  7. package/dist/runtime/built-in-block-artifacts.js +3 -1
  8. package/dist/runtime/built-in-block-code-artifacts.js +3 -1
  9. package/dist/runtime/built-in-block-code-templates/compound-child.d.ts +1 -1
  10. package/dist/runtime/built-in-block-code-templates/compound-child.js +14 -9
  11. package/dist/runtime/built-in-block-code-templates/compound-parent.d.ts +2 -2
  12. package/dist/runtime/built-in-block-code-templates/compound-parent.js +100 -43
  13. package/dist/runtime/built-in-block-code-templates/compound-persistence.d.ts +1 -1
  14. package/dist/runtime/built-in-block-code-templates/compound-persistence.js +11 -8
  15. package/dist/runtime/built-in-block-non-ts-artifacts.js +505 -2
  16. package/dist/runtime/cli-add-block.d.ts +4 -1
  17. package/dist/runtime/cli-add-block.js +66 -31
  18. package/dist/runtime/cli-add-shared.d.ts +3 -1
  19. package/dist/runtime/cli-add-shared.js +12 -12
  20. package/dist/runtime/cli-core.d.ts +2 -0
  21. package/dist/runtime/cli-core.js +1 -0
  22. package/dist/runtime/cli-diagnostics.d.ts +26 -0
  23. package/dist/runtime/cli-diagnostics.js +107 -0
  24. package/dist/runtime/cli-doctor-workspace.js +4 -4
  25. package/dist/runtime/cli-help.js +4 -3
  26. package/dist/runtime/cli-scaffold.d.ts +3 -1
  27. package/dist/runtime/cli-scaffold.js +91 -15
  28. package/dist/runtime/cli-templates.js +26 -1
  29. package/dist/runtime/cli-validation.d.ts +66 -0
  30. package/dist/runtime/cli-validation.js +92 -0
  31. package/dist/runtime/compound-inner-blocks.d.ts +78 -0
  32. package/dist/runtime/compound-inner-blocks.js +88 -0
  33. package/dist/runtime/index.d.ts +5 -1
  34. package/dist/runtime/index.js +3 -1
  35. package/dist/runtime/migration-command-surface.js +2 -0
  36. package/dist/runtime/package-versions.d.ts +1 -0
  37. package/dist/runtime/package-versions.js +12 -0
  38. package/dist/runtime/scaffold-answer-resolution.js +10 -6
  39. package/dist/runtime/scaffold-bootstrap.js +5 -1
  40. package/dist/runtime/scaffold-documents.js +29 -6
  41. package/dist/runtime/scaffold-identifiers.d.ts +17 -0
  42. package/dist/runtime/scaffold-identifiers.js +22 -0
  43. package/dist/runtime/scaffold-onboarding.js +21 -13
  44. package/dist/runtime/scaffold-template-variable-groups.d.ts +154 -0
  45. package/dist/runtime/scaffold-template-variable-groups.js +13 -0
  46. package/dist/runtime/scaffold-template-variables.js +80 -1
  47. package/dist/runtime/scaffold.d.ts +21 -2
  48. package/dist/runtime/scaffold.js +12 -5
  49. package/dist/runtime/temp-roots.d.ts +44 -0
  50. package/dist/runtime/temp-roots.js +129 -0
  51. package/dist/runtime/template-builtins.js +4 -6
  52. package/dist/runtime/template-registry.d.ts +8 -0
  53. package/dist/runtime/template-registry.js +34 -1
  54. package/dist/runtime/template-source-external.d.ts +1 -0
  55. package/dist/runtime/template-source-external.js +4 -7
  56. package/dist/runtime/template-source-remote.js +44 -23
  57. package/dist/runtime/template-source-seeds.js +3 -9
  58. package/dist/runtime/template-source.d.ts +2 -3
  59. package/dist/runtime/template-source.js +13 -5
  60. package/dist/runtime/workspace-project.js +1 -1
  61. package/package.json +12 -2
  62. package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +318 -18
@@ -1,14 +1,17 @@
1
1
  import fs from "node:fs";
2
2
  import { promises as fsp } from "node:fs";
3
- import os from "node:os";
4
3
  import path from "node:path";
5
4
  import { collectScaffoldAnswers, DATA_STORAGE_MODES, PERSISTENCE_POLICIES, isDataStorageMode, isPersistencePolicy, resolvePackageManagerId, resolveTemplateId, scaffoldProject, } from "./scaffold.js";
5
+ import { parseAlternateRenderTargets } from "./alternate-render-targets.js";
6
+ import { parseCompoundInnerBlocksPreset } from "./compound-inner-blocks.js";
6
7
  import { formatInstallCommand, formatRunScript, } from "./package-managers.js";
7
8
  import { getPrimaryDevelopmentScript } from "./local-dev-presets.js";
9
+ import { createManagedTempRoot } from "./temp-roots.js";
8
10
  import { getOptionalOnboardingNote, getOptionalOnboardingSteps, } from "./scaffold-onboarding.js";
9
11
  import { formatNonEmptyTargetDirectoryError } from "./scaffold-bootstrap.js";
10
12
  import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, isBuiltInTemplateId, } from "./template-registry.js";
11
13
  import { resolveOptionalInteractiveExternalLayerId, } from "./external-layer-selection.js";
14
+ import { assertBuiltInTemplateVariantAllowed, resolveLocalCliPathOption, normalizeOptionalCliString, } from "./cli-validation.js";
12
15
  async function listRelativeProjectFiles(rootDir) {
13
16
  const relativeFiles = [];
14
17
  async function visit(currentDir) {
@@ -36,13 +39,14 @@ async function assertDryRunTargetDirectoryReady(projectDir, allowExistingDir) {
36
39
  throw new Error(formatNonEmptyTargetDirectoryError(projectDir));
37
40
  }
38
41
  }
39
- async function buildScaffoldDryRunPlan({ allowExistingDir, answers, cwd, dataStorageMode, externalLayerId, externalLayerSource, externalLayerSourceLabel, installDependencies, noInstall, onProgress, packageManager, persistencePolicy, projectDir, templateId, variant, withMigrationUi, withTestPreset, withWpEnv, }) {
42
+ async function buildScaffoldDryRunPlan({ allowExistingDir, alternateRenderTargets, answers, cwd, dataStorageMode, externalLayerId, externalLayerSource, externalLayerSourceLabel, installDependencies, noInstall, onProgress, packageManager, persistencePolicy, projectDir, templateId, variant, withMigrationUi, withTestPreset, withWpEnv, }) {
40
43
  await assertDryRunTargetDirectoryReady(projectDir, allowExistingDir);
41
- const tempRoot = await fsp.mkdtemp(path.join(os.tmpdir(), "wp-typia-scaffold-plan-"));
44
+ const { path: tempRoot, cleanup } = await createManagedTempRoot("wp-typia-scaffold-plan-");
42
45
  const previewProjectDir = path.join(tempRoot, "preview-project");
43
46
  try {
44
47
  const result = await scaffoldProject({
45
48
  allowExistingDir: false,
49
+ alternateRenderTargets,
46
50
  answers,
47
51
  cwd,
48
52
  dataStorageMode,
@@ -71,7 +75,7 @@ async function buildScaffoldDryRunPlan({ allowExistingDir, answers, cwd, dataSto
71
75
  };
72
76
  }
73
77
  finally {
74
- await fsp.rm(tempRoot, { force: true, recursive: true });
78
+ await cleanup();
75
79
  }
76
80
  }
77
81
  function validateCreateProjectInput(projectInput) {
@@ -109,14 +113,74 @@ function templateUsesPersistenceSettings(templateId, options) {
109
113
  function templateSupportsPersistenceFlags(templateId) {
110
114
  return templateId === "persistence" || templateId === "compound";
111
115
  }
116
+ function templateSupportsCompoundInnerBlocksPreset(templateId) {
117
+ return templateId === "compound";
118
+ }
119
+ function createTemplateLabel(templateId) {
120
+ return templateId === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
121
+ ? "`--template workspace`"
122
+ : `"${templateId}"`;
123
+ }
124
+ function collectTemplateCapabilityWarnings(options) {
125
+ const warnings = [];
126
+ const trimmedQueryPostType = options.queryPostType?.trim();
127
+ if (trimmedQueryPostType &&
128
+ options.templateId !== "query-loop" &&
129
+ (isBuiltInTemplateId(options.templateId) ||
130
+ options.templateId === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE)) {
131
+ warnings.push(`\`--query-post-type\` only applies to \`wp-typia create --template query-loop\`, which scaffolds a create-time \`core/query\` variation instead of a standalone block. ${createTemplateLabel(options.templateId)} will ignore "${trimmedQueryPostType}".`);
132
+ }
133
+ if (options.withMigrationUi === true &&
134
+ !isBuiltInTemplateId(options.templateId) &&
135
+ options.templateId !== OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
136
+ warnings.push(`\`--with-migration-ui\` was ignored for ${createTemplateLabel(options.templateId)}. Migration UI currently scaffolds built-in templates and the official \`--template workspace\` flow; external templates still need to opt into that surface explicitly.`);
137
+ }
138
+ return warnings;
139
+ }
140
+ function templateSupportsAlternateRenderTargets(options) {
141
+ if (!options.alternateRenderTargets) {
142
+ return false;
143
+ }
144
+ if (options.templateId === "persistence") {
145
+ return true;
146
+ }
147
+ if (options.templateId !== "compound") {
148
+ return false;
149
+ }
150
+ return templateUsesPersistenceSettings(options.templateId, {
151
+ dataStorageMode: options.dataStorageMode,
152
+ persistencePolicy: options.persistencePolicy,
153
+ });
154
+ }
112
155
  function validateCreateFlagContract(options) {
113
- const { dataStorageMode, persistencePolicy, templateId, variant } = options;
156
+ const { alternateRenderTargets, dataStorageMode, innerBlocksPreset, persistencePolicy, templateId, variant, } = options;
114
157
  if ((dataStorageMode || persistencePolicy) &&
115
158
  !templateSupportsPersistenceFlags(templateId)) {
116
159
  throw new Error("`--data-storage` and `--persistence-policy` are supported only for `wp-typia create --template persistence` or `--template compound`.");
117
160
  }
118
- if (variant && isBuiltInTemplateId(templateId)) {
119
- throw new Error(`--variant is only supported for official external template configs. Received variant "${variant}" for built-in template "${templateId}".`);
161
+ if (alternateRenderTargets &&
162
+ !templateSupportsAlternateRenderTargets({
163
+ alternateRenderTargets,
164
+ dataStorageMode,
165
+ persistencePolicy,
166
+ templateId,
167
+ })) {
168
+ if (templateId === "compound") {
169
+ throw new Error("`--alternate-render-targets` on `wp-typia create --template compound` requires the persistence-enabled server render path. Add `--data-storage <post-meta|custom-table>` or `--persistence-policy <authenticated|public>` first.");
170
+ }
171
+ throw new Error("`--alternate-render-targets` is supported only for `wp-typia create --template persistence` or persistence-enabled `--template compound` scaffolds.");
172
+ }
173
+ parseAlternateRenderTargets(alternateRenderTargets);
174
+ if (innerBlocksPreset &&
175
+ !templateSupportsCompoundInnerBlocksPreset(templateId)) {
176
+ throw new Error("`--inner-blocks-preset` is supported only for `wp-typia create --template compound`.");
177
+ }
178
+ parseCompoundInnerBlocksPreset(innerBlocksPreset);
179
+ if (isBuiltInTemplateId(templateId)) {
180
+ assertBuiltInTemplateVariantAllowed({
181
+ templateId,
182
+ variant,
183
+ });
120
184
  }
121
185
  }
122
186
  function parseSelectableValue(label, value, isValue, allowedValues) {
@@ -203,14 +267,13 @@ export function getOptionalOnboarding({ availableScripts, packageManager, templa
203
267
  * project.
204
268
  * @returns The scaffold result together with next-step guidance.
205
269
  */
206
- export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templateId, dataStorageMode, dryRun = false, externalLayerId, externalLayerSource, persistencePolicy, packageManager, namespace, textDomain, phpPrefix, queryPostType, yes = false, noInstall = false, onProgress, isInteractive = false, allowExistingDir = false, selectTemplate, selectDataStorage, selectExternalLayerId, selectPersistencePolicy, selectPackageManager, promptText, installDependencies = undefined, variant, selectWithTestPreset, selectWithWpEnv, selectWithMigrationUi, withMigrationUi, withTestPreset, withWpEnv, }) {
207
- const normalizedExternalLayerId = typeof externalLayerId === "string" && externalLayerId.trim().length > 0
208
- ? externalLayerId.trim()
209
- : undefined;
210
- const normalizedExternalLayerSource = typeof externalLayerSource === "string" &&
211
- externalLayerSource.trim().length > 0
212
- ? externalLayerSource.trim()
213
- : undefined;
270
+ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templateId, alternateRenderTargets, dataStorageMode, dryRun = false, externalLayerId, externalLayerSource, innerBlocksPreset, persistencePolicy, packageManager, namespace, textDomain, phpPrefix, queryPostType, yes = false, noInstall = false, onProgress, isInteractive = false, allowExistingDir = false, selectTemplate, selectDataStorage, selectExternalLayerId, selectPersistencePolicy, selectPackageManager, promptText, installDependencies = undefined, variant, selectWithTestPreset, selectWithWpEnv, selectWithMigrationUi, withMigrationUi, withTestPreset, withWpEnv, }) {
271
+ const normalizedExternalLayerId = normalizeOptionalCliString(externalLayerId);
272
+ const normalizedExternalLayerSource = resolveLocalCliPathOption({
273
+ cwd,
274
+ label: "--external-layer-source",
275
+ value: externalLayerSource,
276
+ });
214
277
  validateCreateProjectInput(projectInput);
215
278
  const resolvedTemplateId = await resolveTemplateId({
216
279
  templateId,
@@ -219,11 +282,14 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
219
282
  selectTemplate,
220
283
  });
221
284
  validateCreateFlagContract({
285
+ alternateRenderTargets,
222
286
  dataStorageMode,
287
+ innerBlocksPreset,
223
288
  persistencePolicy,
224
289
  templateId: resolvedTemplateId,
225
290
  variant,
226
291
  });
292
+ const resolvedInnerBlocksPreset = parseCompoundInnerBlocksPreset(innerBlocksPreset);
227
293
  const resolvedExternalLayerSelection = isBuiltInTemplateId(resolvedTemplateId) && isInteractive
228
294
  ? await resolveOptionalInteractiveExternalLayerId({
229
295
  callerCwd: cwd,
@@ -302,9 +368,13 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
302
368
  yes,
303
369
  promptText,
304
370
  });
371
+ if (resolvedTemplateId === "compound" && resolvedInnerBlocksPreset) {
372
+ answers.compoundInnerBlocksPreset = resolvedInnerBlocksPreset;
373
+ }
305
374
  const resolvedResult = dryRun
306
375
  ? await buildScaffoldDryRunPlan({
307
376
  allowExistingDir,
377
+ alternateRenderTargets,
308
378
  answers,
309
379
  cwd,
310
380
  dataStorageMode: resolvedDataStorage,
@@ -326,6 +396,7 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
326
396
  : {
327
397
  plan: undefined,
328
398
  result: await scaffoldProject({
399
+ alternateRenderTargets,
329
400
  answers,
330
401
  allowExistingDir,
331
402
  cwd,
@@ -386,6 +457,11 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
386
457
  ...resolvedResult.result,
387
458
  warnings: [
388
459
  ...resolvedResult.result.warnings,
460
+ ...collectTemplateCapabilityWarnings({
461
+ queryPostType,
462
+ templateId: resolvedTemplateId,
463
+ withMigrationUi,
464
+ }),
389
465
  ...collectProjectDirectoryWarnings(projectDir),
390
466
  ],
391
467
  },
@@ -21,6 +21,10 @@ export function formatTemplateFeatures(template) {
21
21
  if (capabilityHints.length > 0) {
22
22
  lines.push(` Supports: ${capabilityHints.join(" • ")}`);
23
23
  }
24
+ const specialNotes = getTemplateSpecialNotes(template);
25
+ if (specialNotes.length > 0) {
26
+ lines.push(` Notes: ${specialNotes.join(" • ")}`);
27
+ }
24
28
  if (template.id === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
25
29
  lines.push(` Alias: ${WORKSPACE_TEMPLATE_ALIAS} (\`--template ${WORKSPACE_TEMPLATE_ALIAS}\`)`);
26
30
  }
@@ -51,6 +55,13 @@ export function formatTemplateDetails(template) {
51
55
  detailLines.push(` - ${capabilityHint}`);
52
56
  }
53
57
  }
58
+ const specialNotes = getTemplateSpecialNotes(template);
59
+ if (specialNotes.length > 0) {
60
+ detailLines.push("Notes:");
61
+ for (const specialNote of specialNotes) {
62
+ detailLines.push(` - ${specialNote}`);
63
+ }
64
+ }
54
65
  detailLines.push("Logical layers:");
55
66
  for (const logicalLayer of getTemplateLogicalLayerSummaries(template)) {
56
67
  detailLines.push(` - ${logicalLayer}`);
@@ -60,7 +71,12 @@ export function formatTemplateDetails(template) {
60
71
  }
61
72
  function getTemplateCapabilityHints(template) {
62
73
  if (template.id === "persistence" || template.id === "compound") {
63
- return ["--data-storage", "--persistence-policy", "external layers"];
74
+ return [
75
+ "--alternate-render-targets",
76
+ "--data-storage",
77
+ "--persistence-policy",
78
+ "external layers",
79
+ ];
64
80
  }
65
81
  if (template.id === "query-loop") {
66
82
  return ["--query-post-type", "external layers"];
@@ -70,6 +86,15 @@ function getTemplateCapabilityHints(template) {
70
86
  }
71
87
  return [];
72
88
  }
89
+ function getTemplateSpecialNotes(template) {
90
+ if (template.id === "query-loop") {
91
+ return [
92
+ "Create-time variation scaffold only; use `wp-typia create <project-dir> --template query-loop` instead of `wp-typia add block`.",
93
+ "Owns a `core/query` variation, so it does not generate `src/types.ts`, `block.json`, or Typia manifests.",
94
+ ];
95
+ }
96
+ return [];
97
+ }
73
98
  function getTemplateIdentityLines(template) {
74
99
  if (template.id === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
75
100
  return [
@@ -0,0 +1,66 @@
1
+ /**
2
+ * Normalize one optional CLI string flag by trimming whitespace and collapsing
3
+ * empty strings to `undefined`.
4
+ *
5
+ * @param value Raw CLI value before normalization.
6
+ * @returns The trimmed string when present, otherwise `undefined`.
7
+ */
8
+ export declare function normalizeOptionalCliString(value?: string): string | undefined;
9
+ /**
10
+ * Resolve one CLI path flag relative to the caller when it is expressed as a
11
+ * local filesystem path.
12
+ *
13
+ * Non-local values such as npm package specs or `github:` locators pass
14
+ * through unchanged. Local relative and absolute paths are resolved against the
15
+ * provided `cwd` and must exist on disk.
16
+ *
17
+ * @param options Path resolution inputs for one CLI flag.
18
+ * @param options.cwd Caller working directory used for relative path
19
+ * resolution.
20
+ * @param options.label Human-readable option label used in thrown errors.
21
+ * @param options.value Raw CLI value before trimming and path resolution.
22
+ * @returns The normalized string, or `undefined` when the option was omitted.
23
+ * @throws When a local-looking path resolves to a missing filesystem entry.
24
+ */
25
+ export declare function resolveLocalCliPathOption(options: {
26
+ cwd: string;
27
+ label: string;
28
+ value?: string;
29
+ }): string | undefined;
30
+ /**
31
+ * Validate the built-in template composition rule for external layers.
32
+ *
33
+ * @param options External layer CLI options after normalization.
34
+ * @param options.externalLayerId Optional selected layer id.
35
+ * @param options.externalLayerSource Optional layer source locator or path.
36
+ * @throws When `externalLayerId` is provided without `externalLayerSource`.
37
+ */
38
+ export declare function assertExternalLayerCompositionOptions(options: {
39
+ externalLayerId?: string;
40
+ externalLayerSource?: string;
41
+ }): void;
42
+ /**
43
+ * Build the shared error message used when a built-in template receives a
44
+ * `--variant` override.
45
+ *
46
+ * @param options Built-in template context.
47
+ * @param options.templateId Built-in template id that rejected the variant.
48
+ * @param options.variant User-supplied variant override.
49
+ * @returns The canonical user-facing error message.
50
+ */
51
+ export declare function createBuiltInVariantErrorMessage(options: {
52
+ templateId: string;
53
+ variant: string;
54
+ }): string;
55
+ /**
56
+ * Reject unsupported `--variant` usage for built-in templates.
57
+ *
58
+ * @param options Built-in template validation context.
59
+ * @param options.templateId Built-in template id being scaffolded.
60
+ * @param options.variant Optional variant override from CLI flags.
61
+ * @throws When a built-in template receives any explicit `--variant` value.
62
+ */
63
+ export declare function assertBuiltInTemplateVariantAllowed(options: {
64
+ templateId: string;
65
+ variant?: string;
66
+ }): void;
@@ -0,0 +1,92 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ /**
4
+ * Normalize one optional CLI string flag by trimming whitespace and collapsing
5
+ * empty strings to `undefined`.
6
+ *
7
+ * @param value Raw CLI value before normalization.
8
+ * @returns The trimmed string when present, otherwise `undefined`.
9
+ */
10
+ export function normalizeOptionalCliString(value) {
11
+ if (typeof value !== "string") {
12
+ return undefined;
13
+ }
14
+ const trimmed = value.trim();
15
+ return trimmed.length > 0 ? trimmed : undefined;
16
+ }
17
+ function looksLikeLocalCliPath(value) {
18
+ return (path.isAbsolute(value) ||
19
+ value.startsWith("./") ||
20
+ value.startsWith("../") ||
21
+ value.startsWith(".\\") ||
22
+ value.startsWith("..\\"));
23
+ }
24
+ /**
25
+ * Resolve one CLI path flag relative to the caller when it is expressed as a
26
+ * local filesystem path.
27
+ *
28
+ * Non-local values such as npm package specs or `github:` locators pass
29
+ * through unchanged. Local relative and absolute paths are resolved against the
30
+ * provided `cwd` and must exist on disk.
31
+ *
32
+ * @param options Path resolution inputs for one CLI flag.
33
+ * @param options.cwd Caller working directory used for relative path
34
+ * resolution.
35
+ * @param options.label Human-readable option label used in thrown errors.
36
+ * @param options.value Raw CLI value before trimming and path resolution.
37
+ * @returns The normalized string, or `undefined` when the option was omitted.
38
+ * @throws When a local-looking path resolves to a missing filesystem entry.
39
+ */
40
+ export function resolveLocalCliPathOption(options) {
41
+ const normalizedValue = normalizeOptionalCliString(options.value);
42
+ if (!normalizedValue || !looksLikeLocalCliPath(normalizedValue)) {
43
+ return normalizedValue;
44
+ }
45
+ const resolvedPath = path.resolve(options.cwd, normalizedValue);
46
+ if (!fs.existsSync(resolvedPath)) {
47
+ throw new Error(`\`${options.label}\` path does not exist: ${resolvedPath}. Check the path relative to ${options.cwd}.`);
48
+ }
49
+ return resolvedPath;
50
+ }
51
+ /**
52
+ * Validate the built-in template composition rule for external layers.
53
+ *
54
+ * @param options External layer CLI options after normalization.
55
+ * @param options.externalLayerId Optional selected layer id.
56
+ * @param options.externalLayerSource Optional layer source locator or path.
57
+ * @throws When `externalLayerId` is provided without `externalLayerSource`.
58
+ */
59
+ export function assertExternalLayerCompositionOptions(options) {
60
+ if (options.externalLayerId && !options.externalLayerSource) {
61
+ throw new Error("externalLayerId requires externalLayerSource when composing built-in template layers.");
62
+ }
63
+ }
64
+ /**
65
+ * Build the shared error message used when a built-in template receives a
66
+ * `--variant` override.
67
+ *
68
+ * @param options Built-in template context.
69
+ * @param options.templateId Built-in template id that rejected the variant.
70
+ * @param options.variant User-supplied variant override.
71
+ * @returns The canonical user-facing error message.
72
+ */
73
+ export function createBuiltInVariantErrorMessage(options) {
74
+ return `--variant is only supported for official external template configs. Received variant "${options.variant}" for built-in template "${options.templateId}".`;
75
+ }
76
+ /**
77
+ * Reject unsupported `--variant` usage for built-in templates.
78
+ *
79
+ * @param options Built-in template validation context.
80
+ * @param options.templateId Built-in template id being scaffolded.
81
+ * @param options.variant Optional variant override from CLI flags.
82
+ * @throws When a built-in template receives any explicit `--variant` value.
83
+ */
84
+ export function assertBuiltInTemplateVariantAllowed(options) {
85
+ if (!options.variant) {
86
+ return;
87
+ }
88
+ throw new Error(createBuiltInVariantErrorMessage({
89
+ templateId: options.templateId,
90
+ variant: options.variant,
91
+ }));
92
+ }
@@ -0,0 +1,78 @@
1
+ /**
2
+ * Stable preset ids exposed to scaffold and UI consumers for compound
3
+ * InnerBlocks authoring behavior.
4
+ */
5
+ export declare const COMPOUND_INNER_BLOCKS_PRESET_IDS: readonly ["freeform", "ordered", "horizontal", "locked-structure"];
6
+ export type CompoundInnerBlocksPresetId = (typeof COMPOUND_INNER_BLOCKS_PRESET_IDS)[number];
7
+ /**
8
+ * Default preset applied when callers do not provide an explicit compound
9
+ * InnerBlocks mode.
10
+ */
11
+ export declare const DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID: CompoundInnerBlocksPresetId;
12
+ export type CompoundInnerBlocksOrientation = "horizontal" | "vertical";
13
+ export type CompoundInnerBlocksTemplateLock = false | "insert" | "all";
14
+ /**
15
+ * Runtime-facing description of one compound InnerBlocks preset.
16
+ */
17
+ export interface CompoundInnerBlocksPresetDefinition {
18
+ description: string;
19
+ directInsert: boolean;
20
+ label: string;
21
+ orientation?: CompoundInnerBlocksOrientation;
22
+ templateLock: CompoundInnerBlocksTemplateLock;
23
+ }
24
+ /**
25
+ * Canonical preset registry used by the CLI, generated scaffolds, and TUI
26
+ * forms.
27
+ */
28
+ export declare const COMPOUND_INNER_BLOCKS_PRESET_REGISTRY: {
29
+ readonly freeform: {
30
+ readonly description: "Unlocked nested authoring with the default inserter and starter child template.";
31
+ readonly directInsert: false;
32
+ readonly label: "freeform";
33
+ readonly orientation: "vertical";
34
+ readonly templateLock: false;
35
+ };
36
+ readonly ordered: {
37
+ readonly description: "Vertical ordered flow that keeps starter structure fixed while allowing new sibling inserts.";
38
+ readonly directInsert: true;
39
+ readonly label: "ordered";
40
+ readonly orientation: "vertical";
41
+ readonly templateLock: "insert";
42
+ };
43
+ readonly horizontal: {
44
+ readonly description: "Horizontal nested layout with one-click direct inserts for row or tab style containers.";
45
+ readonly directInsert: true;
46
+ readonly label: "horizontal";
47
+ readonly orientation: "horizontal";
48
+ readonly templateLock: false;
49
+ };
50
+ readonly "locked-structure": {
51
+ readonly description: "Locked starter structure for guided document shells where authors should only edit seeded children.";
52
+ readonly directInsert: false;
53
+ readonly label: "locked-structure";
54
+ readonly orientation: "vertical";
55
+ readonly templateLock: "all";
56
+ };
57
+ };
58
+ /**
59
+ * Returns whether a string matches one of the supported compound preset ids.
60
+ */
61
+ export declare function isCompoundInnerBlocksPresetId(value: string): value is CompoundInnerBlocksPresetId;
62
+ /**
63
+ * Parses a raw CLI or config value into a supported preset id.
64
+ *
65
+ * Returns `undefined` for non-string or empty input, and throws when the input
66
+ * is a non-empty unsupported preset id.
67
+ */
68
+ export declare function parseCompoundInnerBlocksPreset(value?: string): CompoundInnerBlocksPresetId | undefined;
69
+ /**
70
+ * Resolves an optional preset id to a concrete preset, defaulting to
71
+ * `DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID`.
72
+ */
73
+ export declare function resolveCompoundInnerBlocksPreset(value?: CompoundInnerBlocksPresetId): CompoundInnerBlocksPresetId;
74
+ /**
75
+ * Looks up the preset definition for the provided preset id, applying the
76
+ * default preset when the input is omitted.
77
+ */
78
+ export declare function getCompoundInnerBlocksPresetDefinition(value?: CompoundInnerBlocksPresetId): CompoundInnerBlocksPresetDefinition;
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Stable preset ids exposed to scaffold and UI consumers for compound
3
+ * InnerBlocks authoring behavior.
4
+ */
5
+ export const COMPOUND_INNER_BLOCKS_PRESET_IDS = [
6
+ "freeform",
7
+ "ordered",
8
+ "horizontal",
9
+ "locked-structure",
10
+ ];
11
+ /**
12
+ * Default preset applied when callers do not provide an explicit compound
13
+ * InnerBlocks mode.
14
+ */
15
+ export const DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID = "freeform";
16
+ /**
17
+ * Canonical preset registry used by the CLI, generated scaffolds, and TUI
18
+ * forms.
19
+ */
20
+ export const COMPOUND_INNER_BLOCKS_PRESET_REGISTRY = {
21
+ freeform: {
22
+ description: "Unlocked nested authoring with the default inserter and starter child template.",
23
+ directInsert: false,
24
+ label: "freeform",
25
+ orientation: "vertical",
26
+ templateLock: false,
27
+ },
28
+ ordered: {
29
+ description: "Vertical ordered flow that keeps starter structure fixed while allowing new sibling inserts.",
30
+ directInsert: true,
31
+ label: "ordered",
32
+ orientation: "vertical",
33
+ templateLock: "insert",
34
+ },
35
+ horizontal: {
36
+ description: "Horizontal nested layout with one-click direct inserts for row or tab style containers.",
37
+ directInsert: true,
38
+ label: "horizontal",
39
+ orientation: "horizontal",
40
+ templateLock: false,
41
+ },
42
+ "locked-structure": {
43
+ description: "Locked starter structure for guided document shells where authors should only edit seeded children.",
44
+ directInsert: false,
45
+ label: "locked-structure",
46
+ orientation: "vertical",
47
+ templateLock: "all",
48
+ },
49
+ };
50
+ /**
51
+ * Returns whether a string matches one of the supported compound preset ids.
52
+ */
53
+ export function isCompoundInnerBlocksPresetId(value) {
54
+ return COMPOUND_INNER_BLOCKS_PRESET_IDS.includes(value);
55
+ }
56
+ /**
57
+ * Parses a raw CLI or config value into a supported preset id.
58
+ *
59
+ * Returns `undefined` for non-string or empty input, and throws when the input
60
+ * is a non-empty unsupported preset id.
61
+ */
62
+ export function parseCompoundInnerBlocksPreset(value) {
63
+ if (typeof value !== "string") {
64
+ return undefined;
65
+ }
66
+ const normalizedValue = value.trim();
67
+ if (normalizedValue.length === 0) {
68
+ return undefined;
69
+ }
70
+ if (!isCompoundInnerBlocksPresetId(normalizedValue)) {
71
+ throw new Error(`Unsupported InnerBlocks preset "${value}". Expected one of: ${COMPOUND_INNER_BLOCKS_PRESET_IDS.join(", ")}.`);
72
+ }
73
+ return normalizedValue;
74
+ }
75
+ /**
76
+ * Resolves an optional preset id to a concrete preset, defaulting to
77
+ * `DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID`.
78
+ */
79
+ export function resolveCompoundInnerBlocksPreset(value) {
80
+ return value ?? DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID;
81
+ }
82
+ /**
83
+ * Looks up the preset definition for the provided preset id, applying the
84
+ * default preset when the input is omitted.
85
+ */
86
+ export function getCompoundInnerBlocksPresetDefinition(value) {
87
+ return COMPOUND_INNER_BLOCKS_PRESET_REGISTRY[resolveCompoundInnerBlocksPreset(value)];
88
+ }
@@ -10,8 +10,11 @@
10
10
  * `runAddHookedBlockCommand`,
11
11
  * `HOOKED_BLOCK_POSITION_IDS`, and `runDoctor`.
12
12
  */
13
- export { scaffoldProject, collectScaffoldAnswers, getDefaultAnswers, getTemplateVariables, resolvePackageManagerId, resolveTemplateId, } from "./scaffold.js";
13
+ export { COMPOUND_INNER_BLOCKS_PRESET_IDS, DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID, getCompoundInnerBlocksPresetDefinition, isCompoundInnerBlocksPresetId, parseCompoundInnerBlocksPreset, resolveCompoundInnerBlocksPreset, } from "./compound-inner-blocks.js";
14
+ export type { CompoundInnerBlocksPresetDefinition, CompoundInnerBlocksPresetId, CompoundInnerBlocksTemplateLock, } from "./compound-inner-blocks.js";
15
+ export { scaffoldProject, collectScaffoldAnswers, getScaffoldTemplateVariableGroups, getDefaultAnswers, getTemplateVariables, resolvePackageManagerId, resolveTemplateId, } from "./scaffold.js";
14
16
  export { BlockGeneratorService } from "./block-generator-service.js";
17
+ export type { BasicScaffoldTemplateVariableGroups, CompoundScaffoldTemplateVariableGroups, ExternalScaffoldTemplateVariableGroups, FlatScaffoldTemplateVariables, InteractivityScaffoldTemplateVariableGroups, PersistenceScaffoldTemplateVariableGroups, QueryLoopScaffoldTemplateVariableGroups, ScaffoldTemplateFamily, ScaffoldTemplateVariableGroups, } from "./scaffold.js";
15
18
  export type { ApplyBlockInput, BlockGenerationTarget, BlockSpec, PlanBlockInput, PlanBlockResult, RenderBlockInput, RenderBlockResult, ValidateBlockInput, ValidateBlockResult, } from "./block-generator-service.js";
16
19
  export { BLOCK_GENERATION_TOOL_CONTRACT_VERSION, inspectBlockGeneration, } from "./block-generator-tool-contract.js";
17
20
  export type { BlockGenerationEmittedFilePreview, BlockGenerationRenderPreview, BlockGenerationStarterManifestPreview, BlockGenerationTemplateCopyPreview, BlockGenerationToolStage, InspectBlockGenerationInput, InspectBlockGenerationPlanResult, InspectBlockGenerationRenderResult, InspectBlockGenerationResult, InspectBlockGenerationValidateResult, } from "./block-generator-tool-contract.js";
@@ -22,5 +25,6 @@ export { buildCompoundChildStarterManifestDocument, getStarterManifestFiles, str
22
25
  export type { EndpointAuthIntent, EndpointOpenApiAuthMode, EndpointOpenApiContractDocument, EndpointOpenApiDocumentOptions, EndpointOpenApiEndpointDefinition, EndpointOpenApiMethod, EndpointWordPressAuthDefinition, EndpointWordPressAuthMechanism, JsonSchemaDocument, JsonSchemaProjectionProfile, JsonSchemaObject, NormalizedEndpointAuthDefinition, OpenApiDocument, OpenApiInfo, OpenApiOperation, OpenApiParameter, OpenApiPathItem, OpenApiSecurityScheme, } from "./schema-core.js";
23
26
  export { PACKAGE_MANAGER_IDS, PACKAGE_MANAGERS, formatPackageExecCommand, formatInstallCommand, formatRunScript, getPackageManager, getPackageManagerSelectOptions, transformPackageManagerText, } from "./package-managers.js";
24
27
  export { TEMPLATE_IDS, TEMPLATE_REGISTRY, getTemplateById, getTemplateSelectOptions, listTemplates, } from "./template-registry.js";
28
+ export { STALE_TEMP_ROOT_MAX_AGE_MS, WP_TYPIA_TEMP_ROOT_PREFIX, cleanupManagedTempRoot, cleanupStaleTempRoots, createManagedTempRoot, getTrackedTempRoots, } from "./temp-roots.js";
25
29
  export { createReadlinePrompt, createCliCommandError, CliDiagnosticError, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, EDITOR_PLUGIN_SLOT_IDS, isCliDiagnosticError, runAddBindingSourceCommand, runAddBlockCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
26
30
  export type { CliDiagnosticMessage, DoctorCheck, EditorPluginSlotId, HookedBlockPositionId, ReadlinePrompt, } from "./cli-core.js";
@@ -10,7 +10,8 @@
10
10
  * `runAddHookedBlockCommand`,
11
11
  * `HOOKED_BLOCK_POSITION_IDS`, and `runDoctor`.
12
12
  */
13
- export { scaffoldProject, collectScaffoldAnswers, getDefaultAnswers, getTemplateVariables, resolvePackageManagerId, resolveTemplateId, } from "./scaffold.js";
13
+ export { COMPOUND_INNER_BLOCKS_PRESET_IDS, DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID, getCompoundInnerBlocksPresetDefinition, isCompoundInnerBlocksPresetId, parseCompoundInnerBlocksPreset, resolveCompoundInnerBlocksPreset, } from "./compound-inner-blocks.js";
14
+ export { scaffoldProject, collectScaffoldAnswers, getScaffoldTemplateVariableGroups, getDefaultAnswers, getTemplateVariables, resolvePackageManagerId, resolveTemplateId, } from "./scaffold.js";
14
15
  export { BlockGeneratorService } from "./block-generator-service.js";
15
16
  export { BLOCK_GENERATION_TOOL_CONTRACT_VERSION, inspectBlockGeneration, } from "./block-generator-tool-contract.js";
16
17
  export { formatMigrationHelpText, parseMigrationArgs, runMigrationCommand, } from "./migrations.js";
@@ -19,4 +20,5 @@ export { manifestAttributeToJsonSchema, projectJsonSchemaDocument, manifestToJso
19
20
  export { buildCompoundChildStarterManifestDocument, getStarterManifestFiles, stringifyStarterManifest, } from "./starter-manifests.js";
20
21
  export { PACKAGE_MANAGER_IDS, PACKAGE_MANAGERS, formatPackageExecCommand, formatInstallCommand, formatRunScript, getPackageManager, getPackageManagerSelectOptions, transformPackageManagerText, } from "./package-managers.js";
21
22
  export { TEMPLATE_IDS, TEMPLATE_REGISTRY, getTemplateById, getTemplateSelectOptions, listTemplates, } from "./template-registry.js";
23
+ export { STALE_TEMP_ROOT_MAX_AGE_MS, WP_TYPIA_TEMP_ROOT_PREFIX, cleanupManagedTempRoot, cleanupStaleTempRoots, createManagedTempRoot, getTrackedTempRoots, } from "./temp-roots.js";
22
24
  export { createReadlinePrompt, createCliCommandError, CliDiagnosticError, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, EDITOR_PLUGIN_SLOT_IDS, isCliDiagnosticError, runAddBindingSourceCommand, runAddBlockCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
@@ -19,6 +19,8 @@ export function formatMigrationHelpText() {
19
19
 
20
20
  Notes:
21
21
  \`migrate init\` auto-detects supported single-block and \`src/blocks/*\` multi-block layouts.
22
+ \`migrate init\` only retrofits migration support into projects that already match those layouts.
23
+ A broader project-level \`wp-typia init\` path remains future work.
22
24
  Migration versions use strict schema labels like \`v1\`, \`v2\`, and \`v3\`.
23
25
  \`migrate wizard\` is TTY-only and helps you choose one legacy migration version to preview.
24
26
  \`migrate plan\` and \`migrate wizard\` are read-only previews; they do not scaffold rules or fixtures.
@@ -4,6 +4,7 @@ interface PackageVersions {
4
4
  blockTypesPackageVersion: string;
5
5
  projectToolsPackageVersion: string;
6
6
  restPackageVersion: string;
7
+ wpTypiaPackageExactVersion: string;
7
8
  wpTypiaPackageVersion: string;
8
9
  }
9
10
  export declare function getPackageVersions(): PackageVersions;