@wp-typia/project-tools 0.22.5 → 0.22.6

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/ai-feature-capability.js +20 -0
  2. package/dist/runtime/cli-add-block.js +16 -11
  3. package/dist/runtime/cli-add-collision.js +213 -136
  4. package/dist/runtime/cli-add-help.js +1 -1
  5. package/dist/runtime/cli-add-kind-ids.d.ts +11 -0
  6. package/dist/runtime/cli-add-kind-ids.js +20 -0
  7. package/dist/runtime/cli-add-types.d.ts +2 -8
  8. package/dist/runtime/cli-add-types.js +1 -17
  9. package/dist/runtime/cli-add-workspace-ability-scaffold.d.ts +3 -1
  10. package/dist/runtime/cli-add-workspace-ability-scaffold.js +22 -5
  11. package/dist/runtime/cli-add-workspace-ability.d.ts +4 -0
  12. package/dist/runtime/cli-add-workspace-ability.js +5 -1
  13. package/dist/runtime/cli-add-workspace-admin-view-source.d.ts +7 -0
  14. package/dist/runtime/cli-add-workspace-admin-view-source.js +9 -10
  15. package/dist/runtime/cli-add-workspace-admin-view-types.d.ts +0 -2
  16. package/dist/runtime/cli-add-workspace-admin-view-types.js +0 -3
  17. package/dist/runtime/cli-add-workspace-ai-scaffold.js +14 -6
  18. package/dist/runtime/cli-doctor-workspace-bindings.js +2 -3
  19. package/dist/runtime/cli-doctor-workspace-blocks.js +2 -3
  20. package/dist/runtime/cli-doctor-workspace-features.js +6 -11
  21. package/dist/runtime/cli-doctor-workspace-shared.d.ts +8 -0
  22. package/dist/runtime/cli-doctor-workspace-shared.js +10 -0
  23. package/dist/runtime/cli-help.js +1 -1
  24. package/dist/runtime/cli-init-apply.d.ts +15 -0
  25. package/dist/runtime/cli-init-apply.js +99 -0
  26. package/dist/runtime/cli-init-package-json.d.ts +19 -0
  27. package/dist/runtime/cli-init-package-json.js +191 -0
  28. package/dist/runtime/cli-init-plan.d.ts +39 -0
  29. package/dist/runtime/cli-init-plan.js +375 -0
  30. package/dist/runtime/cli-init-templates.d.ts +27 -0
  31. package/dist/runtime/cli-init-templates.js +244 -0
  32. package/dist/runtime/cli-init-types.d.ts +84 -0
  33. package/dist/runtime/cli-init-types.js +3 -0
  34. package/dist/runtime/cli-init.d.ts +4 -100
  35. package/dist/runtime/cli-init.js +6 -878
  36. package/dist/runtime/fs-async.d.ts +28 -0
  37. package/dist/runtime/fs-async.js +53 -0
  38. package/dist/runtime/package-managers.js +1 -1
  39. package/dist/runtime/php-utils.d.ts +16 -0
  40. package/dist/runtime/php-utils.js +321 -1
  41. package/dist/runtime/scaffold-apply-utils.js +10 -20
  42. package/dist/runtime/scaffold-bootstrap.js +6 -8
  43. package/dist/runtime/scaffold-compatibility.d.ts +15 -3
  44. package/dist/runtime/scaffold-compatibility.js +42 -11
  45. package/dist/runtime/scaffold-documents.js +12 -0
  46. package/dist/runtime/scaffold-package-manager-files.js +4 -3
  47. package/dist/runtime/string-case.d.ts +5 -0
  48. package/dist/runtime/string-case.js +52 -2
  49. package/dist/runtime/template-source-cache.d.ts +19 -0
  50. package/dist/runtime/template-source-cache.js +164 -28
  51. package/dist/runtime/template-source-external.d.ts +7 -0
  52. package/dist/runtime/template-source-external.js +22 -5
  53. package/dist/runtime/template-source-normalization.d.ts +1 -1
  54. package/dist/runtime/template-source-normalization.js +12 -12
  55. package/dist/runtime/template-source-remote.d.ts +14 -0
  56. package/dist/runtime/template-source-remote.js +91 -15
  57. package/dist/runtime/template-source.js +35 -25
  58. package/dist/runtime/typia-llm.js +7 -0
  59. package/dist/runtime/version-floor.js +8 -2
  60. package/dist/runtime/workspace-inventory.d.ts +16 -14
  61. package/dist/runtime/workspace-inventory.js +58 -14
  62. package/package.json +6 -1
@@ -74,6 +74,25 @@ function normalizeSelections(selections) {
74
74
  }
75
75
  return [...normalized.values()];
76
76
  }
77
+ function validateFeatureMinimumVersions(definition) {
78
+ for (const [platform, value] of [
79
+ ['wordpress', definition.minimumVersions?.wordpress],
80
+ ['php', definition.minimumVersions?.php],
81
+ ]) {
82
+ if (value === undefined) {
83
+ continue;
84
+ }
85
+ try {
86
+ pickHigherVersionFloor(value, undefined);
87
+ }
88
+ catch (error) {
89
+ throw new Error([
90
+ `Invalid ${platform} minimum version floor for AI feature "${definition.id}": "${value}".`,
91
+ 'Expected dotted numeric segments such as "6.7" or "8.1.2".',
92
+ ].join(' '), { cause: error });
93
+ }
94
+ }
95
+ }
77
96
  /**
78
97
  * Resolves a normalized AI feature capability plan from a list of selections.
79
98
  *
@@ -96,6 +115,7 @@ export function resolveAiFeatureCapabilityPlan(selections, registry = DEFAULT_AI
96
115
  if (!definition) {
97
116
  throw new Error(`Unknown AI feature capability "${selection.featureId}".`);
98
117
  }
118
+ validateFeatureMinimumVersions(definition);
99
119
  const resolvedDefinition = {
100
120
  ...definition,
101
121
  mode: selection.mode,
@@ -1,4 +1,3 @@
1
- import fs from "node:fs";
2
1
  import { promises as fsp } from "node:fs";
3
2
  import path from "node:path";
4
3
  import { syncBlockMetadata, } from "@wp-typia/block-runtime/metadata-core";
@@ -21,6 +20,7 @@ import { parseCompoundInnerBlocksPreset } from "./compound-inner-blocks.js";
21
20
  import { resolveOptionalInteractiveExternalLayerId, } from "./external-layer-selection.js";
22
21
  import { parseAlternateRenderTargets } from "./alternate-render-targets.js";
23
22
  import { assertExternalLayerCompositionOptions, normalizeOptionalCliString, resolveLocalCliPathOption, } from "./cli-validation.js";
23
+ import { pathExists } from "./fs-async.js";
24
24
  const COLLECTION_IMPORT_LINE = "import '../../collection';";
25
25
  // This is a lightweight preflight heuristic for the common install layouts:
26
26
  // node_modules for npm/pnpm/bun/yarn-classic and Yarn PnP marker files.
@@ -65,11 +65,16 @@ async function renderWorkspacePersistenceServerModule(projectDir, variables) {
65
65
  const templateDir = buildServerTemplateRoot(variables.persistencePolicy);
66
66
  await copyInterpolatedDirectory(templateDir, targetDir, variables);
67
67
  }
68
- function hasInstalledWorkspaceDependencies(projectDir) {
69
- return WORKSPACE_INSTALL_MARKERS.some((marker) => fs.existsSync(path.join(projectDir, marker)));
68
+ async function hasInstalledWorkspaceDependencies(projectDir) {
69
+ for (const marker of WORKSPACE_INSTALL_MARKERS) {
70
+ if (await pathExists(path.join(projectDir, marker))) {
71
+ return true;
72
+ }
73
+ }
74
+ return false;
70
75
  }
71
- function assertWorkspaceDependenciesInstalled(workspace) {
72
- if (hasInstalledWorkspaceDependencies(workspace.projectDir)) {
76
+ async function assertWorkspaceDependenciesInstalled(workspace) {
77
+ if (await hasInstalledWorkspaceDependencies(workspace.projectDir)) {
73
78
  return;
74
79
  }
75
80
  throw new Error(`Workspace dependencies have not been installed yet. Run \`${formatInstallCommand(workspace.packageManager)}\` from the workspace root before using \`wp-typia add block ...\`.`);
@@ -139,19 +144,19 @@ function collectWorkspaceBlockPaths(projectDir, templateId, variables) {
139
144
  }
140
145
  return [path.join(projectDir, "src", "blocks", variables.slugKebabCase)];
141
146
  }
142
- function assertBlockTargetsDoNotExist(projectDir, templateId, variables) {
147
+ async function assertBlockTargetsDoNotExist(projectDir, templateId, variables) {
143
148
  for (const targetPath of collectWorkspaceBlockPaths(projectDir, templateId, variables)) {
144
- if (fs.existsSync(targetPath)) {
149
+ if (await pathExists(targetPath)) {
145
150
  throw new Error(`A block already exists at ${path.relative(projectDir, targetPath)}. Choose a different name.`);
146
151
  }
147
152
  }
148
153
  }
149
154
  async function updateWorkspaceMigrationConfigIfPresent(projectDir, newBlocks) {
150
155
  const configPath = path.join(projectDir, "src", "migrations", "config.ts");
151
- if (!fs.existsSync(configPath)) {
156
+ const configSource = await readOptionalFile(configPath);
157
+ if (configSource === null) {
152
158
  return;
153
159
  }
154
- const configSource = await fsp.readFile(configPath, "utf8");
155
160
  const config = parseMigrationConfig(configSource);
156
161
  const existingBlocks = Array.isArray(config.blocks) ? config.blocks : [];
157
162
  const nextBlocks = [
@@ -292,7 +297,7 @@ export async function runAddBlockCommand({ alternateRenderTargets, blockName, cw
292
297
  assertCompoundInnerBlocksPresetAllowed(resolvedTemplateId, innerBlocksPreset);
293
298
  const resolvedInnerBlocksPreset = parseCompoundInnerBlocksPreset(innerBlocksPreset);
294
299
  const workspace = resolveWorkspaceProject(cwd);
295
- assertWorkspaceDependenciesInstalled(workspace);
300
+ await assertWorkspaceDependenciesInstalled(workspace);
296
301
  const normalizedExternalLayerId = normalizeOptionalCliString(externalLayerId);
297
302
  const normalizedExternalLayerSource = resolveLocalCliPathOption({
298
303
  cwd,
@@ -367,7 +372,7 @@ export async function runAddBlockCommand({ alternateRenderTargets, blockName, cw
367
372
  });
368
373
  return scaffoldResult;
369
374
  })();
370
- assertBlockTargetsDoNotExist(workspace.projectDir, resolvedTemplateId, result.variables);
375
+ await assertBlockTargetsDoNotExist(workspace.projectDir, resolvedTemplateId, result.variables);
371
376
  const mutationSnapshot = {
372
377
  fileSources: await snapshotWorkspaceFiles([
373
378
  blockConfigPath,
@@ -18,6 +18,179 @@ export function assertScaffoldDoesNotExist(options) {
18
18
  throw new Error(options.inventoryCollision.message);
19
19
  }
20
20
  }
21
+ /**
22
+ * Run descriptor-backed add-kind collision checks.
23
+ *
24
+ * Use descriptors when an add kind only needs predictable filesystem and
25
+ * inventory targets. Keep custom checks for add kinds that depend on rendered
26
+ * template outputs, compound scaffolds, or other command-specific state.
27
+ *
28
+ * @param options Descriptor, context, inventory, and project root for the check.
29
+ * @throws {Error} When any descriptor-backed target already exists.
30
+ */
31
+ function assertAddKindScaffoldDoesNotExist(options) {
32
+ const inventoryCollision = options.descriptor.inventoryCollision;
33
+ assertScaffoldDoesNotExist({
34
+ filesystemCollisions: options.descriptor.filesystemCollisions.map((collision) => ({
35
+ label: collision.label,
36
+ relativePath: collision.relativePath(options.context),
37
+ })),
38
+ inventoryCollision: inventoryCollision
39
+ ? {
40
+ entries: inventoryCollision.entries(options.inventory),
41
+ exists: (entry) => inventoryCollision.exists(entry, options.context),
42
+ message: inventoryCollision.message(options.context),
43
+ }
44
+ : undefined,
45
+ projectDir: options.projectDir,
46
+ });
47
+ }
48
+ const VARIATION_COLLISION_DESCRIPTOR = {
49
+ filesystemCollisions: [
50
+ {
51
+ label: "A variation",
52
+ relativePath: ({ blockSlug, slug }) => path.join("src", "blocks", blockSlug, "variations", `${slug}.ts`),
53
+ },
54
+ ],
55
+ inventoryCollision: {
56
+ entries: (inventory) => inventory.variations,
57
+ exists: (entry, { blockSlug, slug }) => entry.block === blockSlug && entry.slug === slug,
58
+ message: ({ blockSlug, slug }) => `A variation inventory entry already exists for ${blockSlug}/${slug}. Choose a different name.`,
59
+ },
60
+ };
61
+ const BLOCK_STYLE_COLLISION_DESCRIPTOR = {
62
+ filesystemCollisions: [
63
+ {
64
+ label: "A block style",
65
+ relativePath: ({ blockSlug, slug }) => path.join("src", "blocks", blockSlug, "styles", `${slug}.ts`),
66
+ },
67
+ ],
68
+ inventoryCollision: {
69
+ entries: (inventory) => inventory.blockStyles,
70
+ exists: (entry, { blockSlug, slug }) => entry.block === blockSlug && entry.slug === slug,
71
+ message: ({ blockSlug, slug }) => `A block style inventory entry already exists for ${blockSlug}/${slug}. Choose a different name.`,
72
+ },
73
+ };
74
+ const BLOCK_TRANSFORM_COLLISION_DESCRIPTOR = {
75
+ filesystemCollisions: [
76
+ {
77
+ label: "A block transform",
78
+ relativePath: ({ blockSlug, slug }) => path.join("src", "blocks", blockSlug, "transforms", `${slug}.ts`),
79
+ },
80
+ ],
81
+ inventoryCollision: {
82
+ entries: (inventory) => inventory.blockTransforms,
83
+ exists: (entry, { blockSlug, slug }) => entry.block === blockSlug && entry.slug === slug,
84
+ message: ({ blockSlug, slug }) => `A block transform inventory entry already exists for ${blockSlug}/${slug}. Choose a different name.`,
85
+ },
86
+ };
87
+ const PATTERN_COLLISION_DESCRIPTOR = {
88
+ filesystemCollisions: [
89
+ {
90
+ label: "A pattern",
91
+ relativePath: ({ slug }) => path.join("src", "patterns", `${slug}.php`),
92
+ },
93
+ ],
94
+ inventoryCollision: {
95
+ entries: (inventory) => inventory.patterns,
96
+ exists: (entry, { slug }) => entry.slug === slug,
97
+ message: ({ slug }) => `A pattern inventory entry already exists for ${slug}. Choose a different name.`,
98
+ },
99
+ };
100
+ const BINDING_SOURCE_COLLISION_DESCRIPTOR = {
101
+ filesystemCollisions: [
102
+ {
103
+ label: "A binding source",
104
+ relativePath: ({ slug }) => path.join("src", "bindings", slug),
105
+ },
106
+ ],
107
+ inventoryCollision: {
108
+ entries: (inventory) => inventory.bindingSources,
109
+ exists: (entry, { slug }) => entry.slug === slug,
110
+ message: ({ slug }) => `A binding source inventory entry already exists for ${slug}. Choose a different name.`,
111
+ },
112
+ };
113
+ const REST_RESOURCE_COLLISION_DESCRIPTOR = {
114
+ filesystemCollisions: [
115
+ {
116
+ label: "A REST resource",
117
+ relativePath: ({ slug }) => path.join("src", "rest", slug),
118
+ },
119
+ {
120
+ label: "A REST resource bootstrap",
121
+ relativePath: ({ slug }) => path.join("inc", "rest", `${slug}.php`),
122
+ },
123
+ ],
124
+ inventoryCollision: {
125
+ entries: (inventory) => inventory.restResources,
126
+ exists: (entry, { slug }) => entry.slug === slug,
127
+ message: ({ slug }) => `A REST resource inventory entry already exists for ${slug}. Choose a different name.`,
128
+ },
129
+ };
130
+ const ADMIN_VIEW_COLLISION_DESCRIPTOR = {
131
+ filesystemCollisions: [
132
+ {
133
+ label: "An admin view",
134
+ relativePath: ({ slug }) => path.join("src", "admin-views", slug),
135
+ },
136
+ {
137
+ label: "An admin view bootstrap",
138
+ relativePath: ({ slug }) => path.join("inc", "admin-views", `${slug}.php`),
139
+ },
140
+ ],
141
+ inventoryCollision: {
142
+ entries: (inventory) => inventory.adminViews,
143
+ exists: (entry, { slug }) => entry.slug === slug,
144
+ message: ({ slug }) => `An admin view inventory entry already exists for ${slug}. Choose a different name.`,
145
+ },
146
+ };
147
+ const ABILITY_COLLISION_DESCRIPTOR = {
148
+ filesystemCollisions: [
149
+ {
150
+ label: "An ability scaffold",
151
+ relativePath: ({ slug }) => path.join("src", "abilities", slug),
152
+ },
153
+ {
154
+ label: "An ability bootstrap",
155
+ relativePath: ({ slug }) => path.join("inc", "abilities", `${slug}.php`),
156
+ },
157
+ ],
158
+ inventoryCollision: {
159
+ entries: (inventory) => inventory.abilities,
160
+ exists: (entry, { slug }) => entry.slug === slug,
161
+ message: ({ slug }) => `An ability inventory entry already exists for ${slug}. Choose a different name.`,
162
+ },
163
+ };
164
+ const AI_FEATURE_COLLISION_DESCRIPTOR = {
165
+ filesystemCollisions: [
166
+ {
167
+ label: "An AI feature",
168
+ relativePath: ({ slug }) => path.join("src", "ai-features", slug),
169
+ },
170
+ {
171
+ label: "An AI feature bootstrap",
172
+ relativePath: ({ slug }) => path.join("inc", "ai-features", `${slug}.php`),
173
+ },
174
+ ],
175
+ inventoryCollision: {
176
+ entries: (inventory) => inventory.aiFeatures,
177
+ exists: (entry, { slug }) => entry.slug === slug,
178
+ message: ({ slug }) => `An AI feature inventory entry already exists for ${slug}. Choose a different name.`,
179
+ },
180
+ };
181
+ const EDITOR_PLUGIN_COLLISION_DESCRIPTOR = {
182
+ filesystemCollisions: [
183
+ {
184
+ label: "An editor plugin",
185
+ relativePath: ({ slug }) => path.join("src", "editor-plugins", slug),
186
+ },
187
+ ],
188
+ inventoryCollision: {
189
+ entries: (inventory) => inventory.editorPlugins,
190
+ exists: (entry, { slug }) => entry.slug === slug,
191
+ message: ({ slug }) => `An editor plugin inventory entry already exists for ${slug}. Choose a different name.`,
192
+ },
193
+ };
21
194
  /**
22
195
  * Ensure a block variation scaffold does not already exist.
23
196
  *
@@ -28,18 +201,10 @@ export function assertScaffoldDoesNotExist(options) {
28
201
  * @throws {Error} When the variation file or inventory entry already exists.
29
202
  */
30
203
  export function assertVariationDoesNotExist(projectDir, blockSlug, variationSlug, inventory) {
31
- assertScaffoldDoesNotExist({
32
- filesystemCollisions: [
33
- {
34
- label: "A variation",
35
- relativePath: path.join("src", "blocks", blockSlug, "variations", `${variationSlug}.ts`),
36
- },
37
- ],
38
- inventoryCollision: {
39
- entries: inventory.variations,
40
- exists: (entry) => entry.block === blockSlug && entry.slug === variationSlug,
41
- message: `A variation inventory entry already exists for ${blockSlug}/${variationSlug}. Choose a different name.`,
42
- },
204
+ assertAddKindScaffoldDoesNotExist({
205
+ context: { blockSlug, slug: variationSlug },
206
+ descriptor: VARIATION_COLLISION_DESCRIPTOR,
207
+ inventory,
43
208
  projectDir,
44
209
  });
45
210
  }
@@ -53,18 +218,10 @@ export function assertVariationDoesNotExist(projectDir, blockSlug, variationSlug
53
218
  * @throws {Error} When the style file or inventory entry already exists.
54
219
  */
55
220
  export function assertBlockStyleDoesNotExist(projectDir, blockSlug, styleSlug, inventory) {
56
- assertScaffoldDoesNotExist({
57
- filesystemCollisions: [
58
- {
59
- label: "A block style",
60
- relativePath: path.join("src", "blocks", blockSlug, "styles", `${styleSlug}.ts`),
61
- },
62
- ],
63
- inventoryCollision: {
64
- entries: inventory.blockStyles,
65
- exists: (entry) => entry.block === blockSlug && entry.slug === styleSlug,
66
- message: `A block style inventory entry already exists for ${blockSlug}/${styleSlug}. Choose a different name.`,
67
- },
221
+ assertAddKindScaffoldDoesNotExist({
222
+ context: { blockSlug, slug: styleSlug },
223
+ descriptor: BLOCK_STYLE_COLLISION_DESCRIPTOR,
224
+ inventory,
68
225
  projectDir,
69
226
  });
70
227
  }
@@ -78,18 +235,10 @@ export function assertBlockStyleDoesNotExist(projectDir, blockSlug, styleSlug, i
78
235
  * @throws {Error} When the transform file or inventory entry already exists.
79
236
  */
80
237
  export function assertBlockTransformDoesNotExist(projectDir, blockSlug, transformSlug, inventory) {
81
- assertScaffoldDoesNotExist({
82
- filesystemCollisions: [
83
- {
84
- label: "A block transform",
85
- relativePath: path.join("src", "blocks", blockSlug, "transforms", `${transformSlug}.ts`),
86
- },
87
- ],
88
- inventoryCollision: {
89
- entries: inventory.blockTransforms,
90
- exists: (entry) => entry.block === blockSlug && entry.slug === transformSlug,
91
- message: `A block transform inventory entry already exists for ${blockSlug}/${transformSlug}. Choose a different name.`,
92
- },
238
+ assertAddKindScaffoldDoesNotExist({
239
+ context: { blockSlug, slug: transformSlug },
240
+ descriptor: BLOCK_TRANSFORM_COLLISION_DESCRIPTOR,
241
+ inventory,
93
242
  projectDir,
94
243
  });
95
244
  }
@@ -104,18 +253,10 @@ export function assertBlockTransformDoesNotExist(projectDir, blockSlug, transfor
104
253
  * @throws {Error} When the pattern file or inventory entry already exists.
105
254
  */
106
255
  export function assertPatternDoesNotExist(projectDir, patternSlug, inventory) {
107
- assertScaffoldDoesNotExist({
108
- filesystemCollisions: [
109
- {
110
- label: "A pattern",
111
- relativePath: path.join("src", "patterns", `${patternSlug}.php`),
112
- },
113
- ],
114
- inventoryCollision: {
115
- entries: inventory.patterns,
116
- exists: (entry) => entry.slug === patternSlug,
117
- message: `A pattern inventory entry already exists for ${patternSlug}. Choose a different name.`,
118
- },
256
+ assertAddKindScaffoldDoesNotExist({
257
+ context: { slug: patternSlug },
258
+ descriptor: PATTERN_COLLISION_DESCRIPTOR,
259
+ inventory,
119
260
  projectDir,
120
261
  });
121
262
  }
@@ -130,18 +271,10 @@ export function assertPatternDoesNotExist(projectDir, patternSlug, inventory) {
130
271
  * @throws {Error} When the binding directory or inventory entry already exists.
131
272
  */
132
273
  export function assertBindingSourceDoesNotExist(projectDir, bindingSourceSlug, inventory) {
133
- assertScaffoldDoesNotExist({
134
- filesystemCollisions: [
135
- {
136
- label: "A binding source",
137
- relativePath: path.join("src", "bindings", bindingSourceSlug),
138
- },
139
- ],
140
- inventoryCollision: {
141
- entries: inventory.bindingSources,
142
- exists: (entry) => entry.slug === bindingSourceSlug,
143
- message: `A binding source inventory entry already exists for ${bindingSourceSlug}. Choose a different name.`,
144
- },
274
+ assertAddKindScaffoldDoesNotExist({
275
+ context: { slug: bindingSourceSlug },
276
+ descriptor: BINDING_SOURCE_COLLISION_DESCRIPTOR,
277
+ inventory,
145
278
  projectDir,
146
279
  });
147
280
  }
@@ -156,22 +289,10 @@ export function assertBindingSourceDoesNotExist(projectDir, bindingSourceSlug, i
156
289
  * @throws {Error} When REST resource files or inventory entry already exist.
157
290
  */
158
291
  export function assertRestResourceDoesNotExist(projectDir, restResourceSlug, inventory) {
159
- assertScaffoldDoesNotExist({
160
- filesystemCollisions: [
161
- {
162
- label: "A REST resource",
163
- relativePath: path.join("src", "rest", restResourceSlug),
164
- },
165
- {
166
- label: "A REST resource bootstrap",
167
- relativePath: path.join("inc", "rest", `${restResourceSlug}.php`),
168
- },
169
- ],
170
- inventoryCollision: {
171
- entries: inventory.restResources,
172
- exists: (entry) => entry.slug === restResourceSlug,
173
- message: `A REST resource inventory entry already exists for ${restResourceSlug}. Choose a different name.`,
174
- },
292
+ assertAddKindScaffoldDoesNotExist({
293
+ context: { slug: restResourceSlug },
294
+ descriptor: REST_RESOURCE_COLLISION_DESCRIPTOR,
295
+ inventory,
175
296
  projectDir,
176
297
  });
177
298
  }
@@ -185,22 +306,10 @@ export function assertRestResourceDoesNotExist(projectDir, restResourceSlug, inv
185
306
  * @throws {Error} When the directory, PHP bootstrap, or inventory entry already exists.
186
307
  */
187
308
  export function assertAdminViewDoesNotExist(projectDir, adminViewSlug, inventory) {
188
- assertScaffoldDoesNotExist({
189
- filesystemCollisions: [
190
- {
191
- label: "An admin view",
192
- relativePath: path.join("src", "admin-views", adminViewSlug),
193
- },
194
- {
195
- label: "An admin view bootstrap",
196
- relativePath: path.join("inc", "admin-views", `${adminViewSlug}.php`),
197
- },
198
- ],
199
- inventoryCollision: {
200
- entries: inventory.adminViews,
201
- exists: (entry) => entry.slug === adminViewSlug,
202
- message: `An admin view inventory entry already exists for ${adminViewSlug}. Choose a different name.`,
203
- },
309
+ assertAddKindScaffoldDoesNotExist({
310
+ context: { slug: adminViewSlug },
311
+ descriptor: ADMIN_VIEW_COLLISION_DESCRIPTOR,
312
+ inventory,
204
313
  projectDir,
205
314
  });
206
315
  }
@@ -217,22 +326,10 @@ export function assertAdminViewDoesNotExist(projectDir, adminViewSlug, inventory
217
326
  * @throws {Error} When the ability directory, PHP bootstrap, or inventory entry already exists.
218
327
  */
219
328
  export function assertAbilityDoesNotExist(projectDir, abilitySlug, inventory) {
220
- assertScaffoldDoesNotExist({
221
- filesystemCollisions: [
222
- {
223
- label: "An ability scaffold",
224
- relativePath: path.join("src", "abilities", abilitySlug),
225
- },
226
- {
227
- label: "An ability bootstrap",
228
- relativePath: path.join("inc", "abilities", `${abilitySlug}.php`),
229
- },
230
- ],
231
- inventoryCollision: {
232
- entries: inventory.abilities,
233
- exists: (entry) => entry.slug === abilitySlug,
234
- message: `An ability inventory entry already exists for ${abilitySlug}. Choose a different name.`,
235
- },
329
+ assertAddKindScaffoldDoesNotExist({
330
+ context: { slug: abilitySlug },
331
+ descriptor: ABILITY_COLLISION_DESCRIPTOR,
332
+ inventory,
236
333
  projectDir,
237
334
  });
238
335
  }
@@ -247,22 +344,10 @@ export function assertAbilityDoesNotExist(projectDir, abilitySlug, inventory) {
247
344
  * @throws {Error} When AI feature files or inventory entry already exist.
248
345
  */
249
346
  export function assertAiFeatureDoesNotExist(projectDir, aiFeatureSlug, inventory) {
250
- assertScaffoldDoesNotExist({
251
- filesystemCollisions: [
252
- {
253
- label: "An AI feature",
254
- relativePath: path.join("src", "ai-features", aiFeatureSlug),
255
- },
256
- {
257
- label: "An AI feature bootstrap",
258
- relativePath: path.join("inc", "ai-features", `${aiFeatureSlug}.php`),
259
- },
260
- ],
261
- inventoryCollision: {
262
- entries: inventory.aiFeatures,
263
- exists: (entry) => entry.slug === aiFeatureSlug,
264
- message: `An AI feature inventory entry already exists for ${aiFeatureSlug}. Choose a different name.`,
265
- },
347
+ assertAddKindScaffoldDoesNotExist({
348
+ context: { slug: aiFeatureSlug },
349
+ descriptor: AI_FEATURE_COLLISION_DESCRIPTOR,
350
+ inventory,
266
351
  projectDir,
267
352
  });
268
353
  }
@@ -276,18 +361,10 @@ export function assertAiFeatureDoesNotExist(projectDir, aiFeatureSlug, inventory
276
361
  * @throws {Error} When the directory or inventory entry already exists.
277
362
  */
278
363
  export function assertEditorPluginDoesNotExist(projectDir, editorPluginSlug, inventory) {
279
- assertScaffoldDoesNotExist({
280
- filesystemCollisions: [
281
- {
282
- label: "An editor plugin",
283
- relativePath: path.join("src", "editor-plugins", editorPluginSlug),
284
- },
285
- ],
286
- inventoryCollision: {
287
- entries: inventory.editorPlugins,
288
- exists: (entry) => entry.slug === editorPluginSlug,
289
- message: `An editor plugin inventory entry already exists for ${editorPluginSlug}. Choose a different name.`,
290
- },
364
+ assertAddKindScaffoldDoesNotExist({
365
+ context: { slug: editorPluginSlug },
366
+ descriptor: EDITOR_PLUGIN_COLLISION_DESCRIPTOR,
367
+ inventory,
291
368
  projectDir,
292
369
  });
293
370
  }
@@ -26,7 +26,7 @@ Notes:
26
26
  \`add admin-view\` scaffolds an opt-in DataViews-powered WordPress admin screen under \`src/admin-views/\`.
27
27
  Pass \`--source rest-resource:<slug>\` to reuse a list-capable REST resource.
28
28
  Pass \`--source core-data:postType/post\` or \`--source core-data:taxonomy/category\` to bind a WordPress-owned entity collection.
29
- Public installs currently gate this workflow until \`@wp-typia/dataviews\` is published to npm.
29
+ Generated admin-view workspaces add \`@wp-typia/dataviews\` and the needed WordPress DataViews packages as opt-in dependencies.
30
30
  \`query-loop\` is a create-time scaffold family. Use \`wp-typia create <project-dir> --template query-loop\` instead of \`wp-typia add block\`.
31
31
  \`add variation\` targets an existing block slug from \`scripts/block-config.ts\`.
32
32
  \`add style\` registers a Block Styles option for an existing generated block.
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Canonical top-level `wp-typia add` kind ids shared by the CLI command
3
+ * registry, routing metadata generation, and project-tools runtime helpers.
4
+ *
5
+ * Keep this order stable because it drives help output and command metadata.
6
+ */
7
+ export declare const ADD_KIND_IDS: readonly ["admin-view", "block", "variation", "style", "transform", "pattern", "binding-source", "rest-resource", "ability", "ai-feature", "hooked-block", "editor-plugin"];
8
+ /**
9
+ * Union of supported top-level `wp-typia add` kind ids.
10
+ */
11
+ export type AddKindId = (typeof ADD_KIND_IDS)[number];
@@ -0,0 +1,20 @@
1
+ /**
2
+ * Canonical top-level `wp-typia add` kind ids shared by the CLI command
3
+ * registry, routing metadata generation, and project-tools runtime helpers.
4
+ *
5
+ * Keep this order stable because it drives help output and command metadata.
6
+ */
7
+ export const ADD_KIND_IDS = [
8
+ "admin-view",
9
+ "block",
10
+ "variation",
11
+ "style",
12
+ "transform",
13
+ "pattern",
14
+ "binding-source",
15
+ "rest-resource",
16
+ "ability",
17
+ "ai-feature",
18
+ "hooked-block",
19
+ "editor-plugin",
20
+ ];
@@ -1,11 +1,5 @@
1
- /**
2
- * Supported top-level `wp-typia add` kinds exposed by the canonical CLI.
3
- */
4
- export declare const ADD_KIND_IDS: readonly ["admin-view", "block", "variation", "style", "transform", "pattern", "binding-source", "rest-resource", "ability", "ai-feature", "hooked-block", "editor-plugin"];
5
- /**
6
- * Union of supported top-level `wp-typia add` kind ids.
7
- */
8
- export type AddKindId = (typeof ADD_KIND_IDS)[number];
1
+ export { ADD_KIND_IDS } from "./cli-add-kind-ids.js";
2
+ export type { AddKindId } from "./cli-add-kind-ids.js";
9
3
  /**
10
4
  * Supported plugin-level REST resource methods accepted by
11
5
  * `wp-typia add rest-resource --methods`.
@@ -1,20 +1,4 @@
1
- /**
2
- * Supported top-level `wp-typia add` kinds exposed by the canonical CLI.
3
- */
4
- export const ADD_KIND_IDS = [
5
- "admin-view",
6
- "block",
7
- "variation",
8
- "style",
9
- "transform",
10
- "pattern",
11
- "binding-source",
12
- "rest-resource",
13
- "ability",
14
- "ai-feature",
15
- "hooked-block",
16
- "editor-plugin",
17
- ];
1
+ export { ADD_KIND_IDS } from "./cli-add-kind-ids.js";
18
2
  /**
19
3
  * Supported plugin-level REST resource methods accepted by
20
4
  * `wp-typia add rest-resource --methods`.
@@ -2,4 +2,6 @@ import { type ScaffoldAbilityWorkspaceOptions } from "./cli-add-workspace-abilit
2
2
  /**
3
3
  * Write generated workflow ability sources and patch shared workspace anchors.
4
4
  */
5
- export declare function scaffoldAbilityWorkspace({ abilitySlug, compatibilityPolicy, workspace, }: ScaffoldAbilityWorkspaceOptions): Promise<void>;
5
+ export declare function scaffoldAbilityWorkspace({ abilitySlug, compatibilityPolicy, workspace, }: ScaffoldAbilityWorkspaceOptions): Promise<{
6
+ warnings: string[];
7
+ }>;