@wp-typia/project-tools 0.22.9 → 0.22.10

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.
@@ -0,0 +1,511 @@
1
+ import ts from "typescript";
2
+ import { REST_RESOURCE_METHOD_IDS } from "./cli-add-shared.js";
3
+ import { getPropertyNameText } from "./ts-property-names.js";
4
+ import { ABILITY_CONFIG_ENTRY_MARKER, ABILITIES_CONST_SECTION, ABILITIES_INTERFACE_SECTION, ADMIN_VIEW_CONFIG_ENTRY_MARKER, ADMIN_VIEWS_CONST_SECTION, ADMIN_VIEWS_INTERFACE_SECTION, AI_FEATURES_CONST_SECTION, AI_FEATURES_INTERFACE_SECTION, AI_FEATURE_CONFIG_ENTRY_MARKER, BINDING_SOURCES_CONST_SECTION, BINDING_SOURCES_INTERFACE_SECTION, BINDING_SOURCE_CONFIG_ENTRY_MARKER, BLOCK_CONFIG_ENTRY_MARKER, BLOCK_STYLES_CONST_SECTION, BLOCK_STYLES_INTERFACE_SECTION, BLOCK_STYLE_CONFIG_ENTRY_MARKER, BLOCK_TRANSFORMS_CONST_SECTION, BLOCK_TRANSFORMS_INTERFACE_SECTION, BLOCK_TRANSFORM_CONFIG_ENTRY_MARKER, EDITOR_PLUGINS_CONST_SECTION, EDITOR_PLUGINS_INTERFACE_SECTION, EDITOR_PLUGIN_CONFIG_ENTRY_MARKER, PATTERNS_CONST_SECTION, PATTERNS_INTERFACE_SECTION, PATTERN_CONFIG_ENTRY_MARKER, REST_RESOURCES_CONST_SECTION, REST_RESOURCES_INTERFACE_SECTION, REST_RESOURCE_CONFIG_ENTRY_MARKER, VARIATIONS_CONST_SECTION, VARIATIONS_INTERFACE_SECTION, VARIATION_CONFIG_ENTRY_MARKER, } from "./workspace-inventory-templates.js";
5
+ function defineInventoryEntryParser() {
6
+ return (descriptor) => descriptor;
7
+ }
8
+ export const BLOCK_INVENTORY_SECTION = {
9
+ append: {
10
+ marker: BLOCK_CONFIG_ENTRY_MARKER,
11
+ optionKey: "blockEntries",
12
+ },
13
+ parse: {
14
+ entriesKey: "blocks",
15
+ entry: defineInventoryEntryParser()({
16
+ entryName: "BLOCKS",
17
+ fields: [
18
+ { key: "apiTypesFile" },
19
+ { key: "attributeTypeName" },
20
+ { key: "openApiFile" },
21
+ { key: "slug", required: true },
22
+ { key: "typesFile", required: true },
23
+ ],
24
+ }),
25
+ exportName: "BLOCKS",
26
+ required: true,
27
+ },
28
+ };
29
+ export const INVENTORY_SECTIONS = [
30
+ {
31
+ append: {
32
+ marker: VARIATION_CONFIG_ENTRY_MARKER,
33
+ optionKey: "variationEntries",
34
+ },
35
+ interface: {
36
+ name: "WorkspaceVariationConfig",
37
+ section: VARIATIONS_INTERFACE_SECTION,
38
+ },
39
+ parse: {
40
+ entriesKey: "variations",
41
+ entry: defineInventoryEntryParser()({
42
+ entryName: "VARIATIONS",
43
+ fields: [
44
+ { key: "block", required: true },
45
+ { key: "file", required: true },
46
+ { key: "slug", required: true },
47
+ ],
48
+ }),
49
+ hasSectionKey: "hasVariationsSection",
50
+ },
51
+ value: {
52
+ name: "VARIATIONS",
53
+ section: VARIATIONS_CONST_SECTION,
54
+ },
55
+ },
56
+ {
57
+ append: {
58
+ marker: BLOCK_STYLE_CONFIG_ENTRY_MARKER,
59
+ optionKey: "blockStyleEntries",
60
+ },
61
+ interface: {
62
+ name: "WorkspaceBlockStyleConfig",
63
+ section: BLOCK_STYLES_INTERFACE_SECTION,
64
+ },
65
+ parse: {
66
+ entriesKey: "blockStyles",
67
+ entry: defineInventoryEntryParser()({
68
+ entryName: "BLOCK_STYLES",
69
+ fields: [
70
+ { key: "block", required: true },
71
+ { key: "file", required: true },
72
+ { key: "slug", required: true },
73
+ ],
74
+ }),
75
+ hasSectionKey: "hasBlockStylesSection",
76
+ },
77
+ value: {
78
+ name: "BLOCK_STYLES",
79
+ section: BLOCK_STYLES_CONST_SECTION,
80
+ },
81
+ },
82
+ {
83
+ append: {
84
+ marker: BLOCK_TRANSFORM_CONFIG_ENTRY_MARKER,
85
+ optionKey: "blockTransformEntries",
86
+ },
87
+ interface: {
88
+ name: "WorkspaceBlockTransformConfig",
89
+ section: BLOCK_TRANSFORMS_INTERFACE_SECTION,
90
+ },
91
+ parse: {
92
+ entriesKey: "blockTransforms",
93
+ entry: defineInventoryEntryParser()({
94
+ entryName: "BLOCK_TRANSFORMS",
95
+ fields: [
96
+ { key: "block", required: true },
97
+ { key: "file", required: true },
98
+ { key: "from", required: true },
99
+ { key: "slug", required: true },
100
+ { key: "to", required: true },
101
+ ],
102
+ }),
103
+ hasSectionKey: "hasBlockTransformsSection",
104
+ },
105
+ value: {
106
+ name: "BLOCK_TRANSFORMS",
107
+ section: BLOCK_TRANSFORMS_CONST_SECTION,
108
+ },
109
+ },
110
+ {
111
+ append: {
112
+ marker: PATTERN_CONFIG_ENTRY_MARKER,
113
+ optionKey: "patternEntries",
114
+ },
115
+ interface: {
116
+ name: "WorkspacePatternConfig",
117
+ section: PATTERNS_INTERFACE_SECTION,
118
+ },
119
+ parse: {
120
+ entriesKey: "patterns",
121
+ entry: defineInventoryEntryParser()({
122
+ entryName: "PATTERNS",
123
+ fields: [
124
+ { key: "file", required: true },
125
+ { key: "slug", required: true },
126
+ ],
127
+ }),
128
+ hasSectionKey: "hasPatternsSection",
129
+ },
130
+ value: {
131
+ name: "PATTERNS",
132
+ section: PATTERNS_CONST_SECTION,
133
+ },
134
+ },
135
+ {
136
+ append: {
137
+ marker: BINDING_SOURCE_CONFIG_ENTRY_MARKER,
138
+ optionKey: "bindingSourceEntries",
139
+ },
140
+ interface: {
141
+ name: "WorkspaceBindingSourceConfig",
142
+ section: BINDING_SOURCES_INTERFACE_SECTION,
143
+ },
144
+ parse: {
145
+ entriesKey: "bindingSources",
146
+ entry: defineInventoryEntryParser()({
147
+ entryName: "BINDING_SOURCES",
148
+ fields: [
149
+ { key: "attribute" },
150
+ { key: "block" },
151
+ { key: "editorFile", required: true },
152
+ { key: "serverFile", required: true },
153
+ { key: "slug", required: true },
154
+ ],
155
+ }),
156
+ hasSectionKey: "hasBindingSourcesSection",
157
+ },
158
+ value: {
159
+ name: "BINDING_SOURCES",
160
+ section: BINDING_SOURCES_CONST_SECTION,
161
+ },
162
+ },
163
+ {
164
+ append: {
165
+ marker: REST_RESOURCE_CONFIG_ENTRY_MARKER,
166
+ optionKey: "restResourceEntries",
167
+ },
168
+ interface: {
169
+ name: "WorkspaceRestResourceConfig",
170
+ section: REST_RESOURCES_INTERFACE_SECTION,
171
+ },
172
+ parse: {
173
+ entriesKey: "restResources",
174
+ entry: defineInventoryEntryParser()({
175
+ entryName: "REST_RESOURCES",
176
+ fields: [
177
+ { key: "apiFile", required: true },
178
+ { key: "clientFile", required: true },
179
+ { key: "dataFile", required: true },
180
+ {
181
+ key: "methods",
182
+ kind: "stringArray",
183
+ required: true,
184
+ validate: (value, context) => {
185
+ const methods = Array.isArray(value) ? value : [];
186
+ const invalidMethods = methods.filter((method) => !REST_RESOURCE_METHOD_IDS.includes(method));
187
+ if (invalidMethods.length > 0) {
188
+ throw new Error(`${context.entryName}[${context.elementIndex}].${context.key} includes unsupported values: ${invalidMethods.join(", ")}.`);
189
+ }
190
+ },
191
+ },
192
+ { key: "namespace", required: true },
193
+ { key: "openApiFile", required: true },
194
+ { key: "phpFile", required: true },
195
+ { key: "slug", required: true },
196
+ { key: "typesFile", required: true },
197
+ { key: "validatorsFile", required: true },
198
+ ],
199
+ }),
200
+ hasSectionKey: "hasRestResourcesSection",
201
+ },
202
+ value: {
203
+ name: "REST_RESOURCES",
204
+ section: REST_RESOURCES_CONST_SECTION,
205
+ },
206
+ },
207
+ {
208
+ append: {
209
+ marker: ABILITY_CONFIG_ENTRY_MARKER,
210
+ optionKey: "abilityEntries",
211
+ },
212
+ interface: {
213
+ name: "WorkspaceAbilityConfig",
214
+ section: ABILITIES_INTERFACE_SECTION,
215
+ },
216
+ parse: {
217
+ entriesKey: "abilities",
218
+ entry: defineInventoryEntryParser()({
219
+ entryName: "ABILITIES",
220
+ fields: [
221
+ { key: "clientFile", required: true },
222
+ { key: "configFile", required: true },
223
+ { key: "dataFile", required: true },
224
+ { key: "inputSchemaFile", required: true },
225
+ { key: "inputTypeName", required: true },
226
+ { key: "outputSchemaFile", required: true },
227
+ { key: "outputTypeName", required: true },
228
+ { key: "phpFile", required: true },
229
+ { key: "slug", required: true },
230
+ { key: "typesFile", required: true },
231
+ ],
232
+ }),
233
+ hasSectionKey: "hasAbilitiesSection",
234
+ },
235
+ value: {
236
+ name: "ABILITIES",
237
+ section: ABILITIES_CONST_SECTION,
238
+ },
239
+ },
240
+ {
241
+ append: {
242
+ marker: AI_FEATURE_CONFIG_ENTRY_MARKER,
243
+ optionKey: "aiFeatureEntries",
244
+ },
245
+ interface: {
246
+ name: "WorkspaceAiFeatureConfig",
247
+ section: AI_FEATURES_INTERFACE_SECTION,
248
+ },
249
+ parse: {
250
+ entriesKey: "aiFeatures",
251
+ entry: defineInventoryEntryParser()({
252
+ entryName: "AI_FEATURES",
253
+ fields: [
254
+ { key: "aiSchemaFile", required: true },
255
+ { key: "apiFile", required: true },
256
+ { key: "clientFile", required: true },
257
+ { key: "dataFile", required: true },
258
+ { key: "namespace", required: true },
259
+ { key: "openApiFile", required: true },
260
+ { key: "phpFile", required: true },
261
+ { key: "slug", required: true },
262
+ { key: "typesFile", required: true },
263
+ { key: "validatorsFile", required: true },
264
+ ],
265
+ }),
266
+ hasSectionKey: "hasAiFeaturesSection",
267
+ },
268
+ value: {
269
+ name: "AI_FEATURES",
270
+ section: AI_FEATURES_CONST_SECTION,
271
+ },
272
+ },
273
+ {
274
+ append: {
275
+ marker: ADMIN_VIEW_CONFIG_ENTRY_MARKER,
276
+ optionKey: "adminViewEntries",
277
+ },
278
+ interface: {
279
+ name: "WorkspaceAdminViewConfig",
280
+ section: ADMIN_VIEWS_INTERFACE_SECTION,
281
+ },
282
+ parse: {
283
+ entriesKey: "adminViews",
284
+ entry: defineInventoryEntryParser()({
285
+ entryName: "ADMIN_VIEWS",
286
+ fields: [
287
+ { key: "file", required: true },
288
+ { key: "phpFile", required: true },
289
+ { key: "slug", required: true },
290
+ { key: "source" },
291
+ ],
292
+ }),
293
+ hasSectionKey: "hasAdminViewsSection",
294
+ },
295
+ value: {
296
+ name: "ADMIN_VIEWS",
297
+ section: ADMIN_VIEWS_CONST_SECTION,
298
+ },
299
+ },
300
+ {
301
+ append: {
302
+ marker: EDITOR_PLUGIN_CONFIG_ENTRY_MARKER,
303
+ optionKey: "editorPluginEntries",
304
+ },
305
+ interface: {
306
+ name: "WorkspaceEditorPluginConfig",
307
+ section: EDITOR_PLUGINS_INTERFACE_SECTION,
308
+ },
309
+ parse: {
310
+ entriesKey: "editorPlugins",
311
+ entry: defineInventoryEntryParser()({
312
+ entryName: "EDITOR_PLUGINS",
313
+ fields: [
314
+ { key: "file", required: true },
315
+ { key: "slug", required: true },
316
+ { key: "slot", required: true },
317
+ ],
318
+ }),
319
+ hasSectionKey: "hasEditorPluginsSection",
320
+ },
321
+ value: {
322
+ name: "EDITOR_PLUGINS",
323
+ section: EDITOR_PLUGINS_CONST_SECTION,
324
+ },
325
+ },
326
+ ];
327
+ function findExportedArrayLiteral(sourceFile, exportName) {
328
+ for (const statement of sourceFile.statements) {
329
+ if (!ts.isVariableStatement(statement)) {
330
+ continue;
331
+ }
332
+ if (!statement.modifiers?.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)) {
333
+ continue;
334
+ }
335
+ for (const declaration of statement.declarationList.declarations) {
336
+ if (!ts.isIdentifier(declaration.name) ||
337
+ declaration.name.text !== exportName) {
338
+ continue;
339
+ }
340
+ if (declaration.initializer &&
341
+ ts.isArrayLiteralExpression(declaration.initializer)) {
342
+ return {
343
+ array: declaration.initializer,
344
+ found: true,
345
+ };
346
+ }
347
+ return {
348
+ array: null,
349
+ found: true,
350
+ };
351
+ }
352
+ }
353
+ return {
354
+ array: null,
355
+ found: false,
356
+ };
357
+ }
358
+ function getOptionalStringProperty(entryName, elementIndex, objectLiteral, key) {
359
+ for (const property of objectLiteral.properties) {
360
+ if (!ts.isPropertyAssignment(property)) {
361
+ continue;
362
+ }
363
+ const propertyName = getPropertyNameText(property.name);
364
+ if (propertyName !== key) {
365
+ continue;
366
+ }
367
+ if (ts.isStringLiteralLike(property.initializer)) {
368
+ return property.initializer.text;
369
+ }
370
+ throw new Error(`${entryName}[${elementIndex}] must use a string literal for "${key}" in scripts/block-config.ts.`);
371
+ }
372
+ return undefined;
373
+ }
374
+ function getOptionalStringArrayProperty(entryName, elementIndex, objectLiteral, key) {
375
+ for (const property of objectLiteral.properties) {
376
+ if (!ts.isPropertyAssignment(property)) {
377
+ continue;
378
+ }
379
+ const propertyName = getPropertyNameText(property.name);
380
+ if (propertyName !== key) {
381
+ continue;
382
+ }
383
+ if (!ts.isArrayLiteralExpression(property.initializer)) {
384
+ throw new Error(`${entryName}[${elementIndex}] must use an array literal for "${key}" in scripts/block-config.ts.`);
385
+ }
386
+ return property.initializer.elements.map((element, itemIndex) => {
387
+ if (!ts.isStringLiteralLike(element)) {
388
+ throw new Error(`${entryName}[${elementIndex}].${key}[${itemIndex}] must use a string literal in scripts/block-config.ts.`);
389
+ }
390
+ return element.text;
391
+ });
392
+ }
393
+ return undefined;
394
+ }
395
+ function isMissingRequiredInventoryValue(value) {
396
+ return (value === undefined || (typeof value === "string" && value.length === 0));
397
+ }
398
+ function formatMissingRequiredInventoryFields(keys) {
399
+ return keys.length === 1
400
+ ? `required "${keys[0]}"`
401
+ : `required fields ${keys.map((key) => `"${key}"`).join(", ")}`;
402
+ }
403
+ function assertParsedInventoryEntry(entry, descriptor, elementIndex) {
404
+ const missingRequiredKeys = descriptor.fields
405
+ .filter((field) => field.required === true &&
406
+ isMissingRequiredInventoryValue(entry[field.key]))
407
+ .map((field) => field.key);
408
+ if (missingRequiredKeys.length > 0) {
409
+ throw new Error(`${descriptor.entryName}[${elementIndex}] is missing ${formatMissingRequiredInventoryFields(missingRequiredKeys)} in scripts/block-config.ts.`);
410
+ }
411
+ }
412
+ function parseInventoryEntries(arrayLiteral, descriptor) {
413
+ return arrayLiteral.elements.map((element, elementIndex) => {
414
+ if (!ts.isObjectLiteralExpression(element)) {
415
+ throw new Error(`${descriptor.entryName}[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
416
+ }
417
+ const entry = {};
418
+ for (const field of descriptor.fields) {
419
+ const kind = field.kind ?? "string";
420
+ const value = kind === "stringArray"
421
+ ? getOptionalStringArrayProperty(descriptor.entryName, elementIndex, element, field.key)
422
+ : getOptionalStringProperty(descriptor.entryName, elementIndex, element, field.key);
423
+ field.validate?.(value, {
424
+ elementIndex,
425
+ entryName: descriptor.entryName,
426
+ key: field.key,
427
+ });
428
+ entry[field.key] = value;
429
+ }
430
+ assertParsedInventoryEntry(entry, descriptor, elementIndex);
431
+ return entry;
432
+ });
433
+ }
434
+ function parseInventorySection(sourceFile, descriptor) {
435
+ if (!descriptor.parse) {
436
+ return {
437
+ entries: [],
438
+ found: false,
439
+ };
440
+ }
441
+ const exportName = descriptor.parse.exportName ?? descriptor.value?.name;
442
+ if (!exportName) {
443
+ throw new Error("Inventory parser descriptor is missing an export name.");
444
+ }
445
+ const exportedArray = findExportedArrayLiteral(sourceFile, exportName);
446
+ if (!exportedArray.found) {
447
+ if (descriptor.parse.required) {
448
+ throw new Error(`scripts/block-config.ts must export a ${exportName} array.`);
449
+ }
450
+ return {
451
+ entries: [],
452
+ found: false,
453
+ };
454
+ }
455
+ if (!exportedArray.array) {
456
+ if (descriptor.parse.required) {
457
+ throw new Error(`scripts/block-config.ts must export a ${exportName} array.`);
458
+ }
459
+ throw new Error(`scripts/block-config.ts must export ${exportName} as an array literal.`);
460
+ }
461
+ return {
462
+ entries: parseInventoryEntries(exportedArray.array, descriptor.parse.entry),
463
+ found: true,
464
+ };
465
+ }
466
+ /**
467
+ * Parse workspace inventory entries from the source of `scripts/block-config.ts`.
468
+ *
469
+ * @param source Raw TypeScript source from `scripts/block-config.ts`.
470
+ * @returns Parsed inventory sections without the resolved `blockConfigPath`.
471
+ * @throws {Error} When `BLOCKS` is missing or any inventory entry is malformed.
472
+ */
473
+ export function parseWorkspaceInventorySource(source) {
474
+ const sourceFile = ts.createSourceFile("block-config.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
475
+ const parsedInventory = {
476
+ abilities: [],
477
+ adminViews: [],
478
+ aiFeatures: [],
479
+ bindingSources: [],
480
+ blockStyles: [],
481
+ blockTransforms: [],
482
+ blocks: parseInventorySection(sourceFile, BLOCK_INVENTORY_SECTION).entries,
483
+ editorPlugins: [],
484
+ hasAbilitiesSection: false,
485
+ hasAdminViewsSection: false,
486
+ hasAiFeaturesSection: false,
487
+ hasBindingSourcesSection: false,
488
+ hasBlockStylesSection: false,
489
+ hasBlockTransformsSection: false,
490
+ hasEditorPluginsSection: false,
491
+ hasPatternsSection: false,
492
+ hasRestResourcesSection: false,
493
+ hasVariationsSection: false,
494
+ patterns: [],
495
+ restResources: [],
496
+ source,
497
+ variations: [],
498
+ };
499
+ const mutableInventory = parsedInventory;
500
+ for (const section of INVENTORY_SECTIONS) {
501
+ if (!section.parse) {
502
+ continue;
503
+ }
504
+ const parsedSection = parseInventorySection(sourceFile, section);
505
+ mutableInventory[section.parse.entriesKey] = parsedSection.entries;
506
+ if (section.parse.hasSectionKey) {
507
+ mutableInventory[section.parse.hasSectionKey] = parsedSection.found;
508
+ }
509
+ }
510
+ return parsedInventory;
511
+ }
@@ -0,0 +1,44 @@
1
+ import type { WorkspaceBlockSelectOption, WorkspaceInventory } from "./workspace-inventory-types.js";
2
+ /**
3
+ * Synchronously read and parse the canonical workspace inventory file.
4
+ *
5
+ * This compatibility helper is intentionally sync-only for callers that expose
6
+ * synchronous APIs. Prefer `readWorkspaceInventoryAsync()` from async command
7
+ * paths so workspace reads do not block the event loop.
8
+ *
9
+ * @param projectDir Workspace root directory.
10
+ * @returns Parsed `WorkspaceInventory` including the resolved `blockConfigPath`.
11
+ * @throws {Error} When `scripts/block-config.ts` is missing or invalid.
12
+ */
13
+ export declare function readWorkspaceInventory(projectDir: string): WorkspaceInventory;
14
+ /**
15
+ * Asynchronously read and parse the canonical workspace inventory file.
16
+ *
17
+ * @param projectDir Workspace root directory.
18
+ * @returns Parsed `WorkspaceInventory` including the resolved `blockConfigPath`.
19
+ * @throws {Error} When `scripts/block-config.ts` is missing or invalid.
20
+ */
21
+ export declare function readWorkspaceInventoryAsync(projectDir: string): Promise<WorkspaceInventory>;
22
+ /**
23
+ * Synchronously return select options for the current workspace block inventory.
24
+ *
25
+ * The `description` field mirrors `block.typesFile`, while `name` and `value`
26
+ * both map to the block slug for use in interactive add flows.
27
+ *
28
+ * @deprecated Use `getWorkspaceBlockSelectOptionsAsync()` from async command
29
+ * paths. This helper intentionally remains sync-only for compatibility callers.
30
+ *
31
+ * @param projectDir Workspace root directory.
32
+ * @returns Block options for variation-target selection.
33
+ */
34
+ export declare function getWorkspaceBlockSelectOptions(projectDir: string): WorkspaceBlockSelectOption[];
35
+ /**
36
+ * Asynchronously return select options for the current workspace block inventory.
37
+ *
38
+ * The returned option shape matches `getWorkspaceBlockSelectOptions()` while
39
+ * avoiding synchronous inventory reads in interactive or async command paths.
40
+ *
41
+ * @param projectDir Workspace root directory.
42
+ * @returns Block options for variation-target selection.
43
+ */
44
+ export declare function getWorkspaceBlockSelectOptionsAsync(projectDir: string): Promise<WorkspaceBlockSelectOption[]>;
@@ -0,0 +1,91 @@
1
+ import { readFileSync } from "node:fs";
2
+ import path from "node:path";
3
+ import { readFile } from "node:fs/promises";
4
+ import { isFileNotFoundError } from "./fs-async.js";
5
+ import { parseWorkspaceInventorySource } from "./workspace-inventory-parser.js";
6
+ /**
7
+ * Synchronously read and parse the canonical workspace inventory file.
8
+ *
9
+ * This compatibility helper is intentionally sync-only for callers that expose
10
+ * synchronous APIs. Prefer `readWorkspaceInventoryAsync()` from async command
11
+ * paths so workspace reads do not block the event loop.
12
+ *
13
+ * @param projectDir Workspace root directory.
14
+ * @returns Parsed `WorkspaceInventory` including the resolved `blockConfigPath`.
15
+ * @throws {Error} When `scripts/block-config.ts` is missing or invalid.
16
+ */
17
+ export function readWorkspaceInventory(projectDir) {
18
+ const blockConfigPath = path.join(projectDir, "scripts", "block-config.ts");
19
+ let source;
20
+ try {
21
+ source = readFileSync(blockConfigPath, "utf8");
22
+ }
23
+ catch (error) {
24
+ if (isFileNotFoundError(error)) {
25
+ throw new Error(`Workspace inventory file is missing at ${blockConfigPath}. Expected scripts/block-config.ts to exist.`);
26
+ }
27
+ throw error;
28
+ }
29
+ return {
30
+ blockConfigPath,
31
+ ...parseWorkspaceInventorySource(source),
32
+ };
33
+ }
34
+ /**
35
+ * Asynchronously read and parse the canonical workspace inventory file.
36
+ *
37
+ * @param projectDir Workspace root directory.
38
+ * @returns Parsed `WorkspaceInventory` including the resolved `blockConfigPath`.
39
+ * @throws {Error} When `scripts/block-config.ts` is missing or invalid.
40
+ */
41
+ export async function readWorkspaceInventoryAsync(projectDir) {
42
+ const blockConfigPath = path.join(projectDir, "scripts", "block-config.ts");
43
+ let source;
44
+ try {
45
+ source = await readFile(blockConfigPath, "utf8");
46
+ }
47
+ catch (error) {
48
+ if (isFileNotFoundError(error)) {
49
+ throw new Error(`Workspace inventory file is missing at ${blockConfigPath}. Expected scripts/block-config.ts to exist.`);
50
+ }
51
+ throw error;
52
+ }
53
+ return {
54
+ blockConfigPath,
55
+ ...parseWorkspaceInventorySource(source),
56
+ };
57
+ }
58
+ function toWorkspaceBlockSelectOptions(blocks) {
59
+ return blocks.map((block) => ({
60
+ description: block.typesFile,
61
+ name: block.slug,
62
+ value: block.slug,
63
+ }));
64
+ }
65
+ /**
66
+ * Synchronously return select options for the current workspace block inventory.
67
+ *
68
+ * The `description` field mirrors `block.typesFile`, while `name` and `value`
69
+ * both map to the block slug for use in interactive add flows.
70
+ *
71
+ * @deprecated Use `getWorkspaceBlockSelectOptionsAsync()` from async command
72
+ * paths. This helper intentionally remains sync-only for compatibility callers.
73
+ *
74
+ * @param projectDir Workspace root directory.
75
+ * @returns Block options for variation-target selection.
76
+ */
77
+ export function getWorkspaceBlockSelectOptions(projectDir) {
78
+ return toWorkspaceBlockSelectOptions(readWorkspaceInventory(projectDir).blocks);
79
+ }
80
+ /**
81
+ * Asynchronously return select options for the current workspace block inventory.
82
+ *
83
+ * The returned option shape matches `getWorkspaceBlockSelectOptions()` while
84
+ * avoiding synchronous inventory reads in interactive or async command paths.
85
+ *
86
+ * @param projectDir Workspace root directory.
87
+ * @returns Block options for variation-target selection.
88
+ */
89
+ export async function getWorkspaceBlockSelectOptionsAsync(projectDir) {
90
+ return toWorkspaceBlockSelectOptions((await readWorkspaceInventoryAsync(projectDir)).blocks);
91
+ }
@@ -0,0 +1,35 @@
1
+ export declare const BLOCK_CONFIG_ENTRY_MARKER = "\t// wp-typia add block entries";
2
+ export declare const VARIATION_CONFIG_ENTRY_MARKER = "\t// wp-typia add variation entries";
3
+ export declare const BLOCK_STYLE_CONFIG_ENTRY_MARKER = "\t// wp-typia add style entries";
4
+ export declare const BLOCK_TRANSFORM_CONFIG_ENTRY_MARKER = "\t// wp-typia add transform entries";
5
+ export declare const PATTERN_CONFIG_ENTRY_MARKER = "\t// wp-typia add pattern entries";
6
+ export declare const BINDING_SOURCE_CONFIG_ENTRY_MARKER = "\t// wp-typia add binding-source entries";
7
+ export declare const REST_RESOURCE_CONFIG_ENTRY_MARKER = "\t// wp-typia add rest-resource entries";
8
+ export declare const ABILITY_CONFIG_ENTRY_MARKER = "\t// wp-typia add ability entries";
9
+ export declare const AI_FEATURE_CONFIG_ENTRY_MARKER = "\t// wp-typia add ai-feature entries";
10
+ export declare const ADMIN_VIEW_CONFIG_ENTRY_MARKER = "\t// wp-typia add admin-view entries";
11
+ /**
12
+ * Marker used to append generated editor-plugin entries into `EDITOR_PLUGINS`.
13
+ */
14
+ export declare const EDITOR_PLUGIN_CONFIG_ENTRY_MARKER = "\t// wp-typia add editor-plugin entries";
15
+ export declare const VARIATIONS_INTERFACE_SECTION = "\n\nexport interface WorkspaceVariationConfig {\n\tblock: string;\n\tfile: string;\n\tslug: string;\n}\n";
16
+ export declare const VARIATIONS_CONST_SECTION = "\n\nexport const VARIATIONS: WorkspaceVariationConfig[] = [\n\t// wp-typia add variation entries\n];\n";
17
+ export declare const BLOCK_STYLES_INTERFACE_SECTION = "\n\nexport interface WorkspaceBlockStyleConfig {\n\tblock: string;\n\tfile: string;\n\tslug: string;\n}\n";
18
+ export declare const BLOCK_STYLES_CONST_SECTION = "\n\nexport const BLOCK_STYLES: WorkspaceBlockStyleConfig[] = [\n\t// wp-typia add style entries\n];\n";
19
+ export declare const BLOCK_TRANSFORMS_INTERFACE_SECTION = "\n\nexport interface WorkspaceBlockTransformConfig {\n\tblock: string;\n\tfile: string;\n\tfrom: string;\n\tslug: string;\n\tto: string;\n}\n";
20
+ export declare const BLOCK_TRANSFORMS_CONST_SECTION = "\n\nexport const BLOCK_TRANSFORMS: WorkspaceBlockTransformConfig[] = [\n\t// wp-typia add transform entries\n];\n";
21
+ export declare const PATTERNS_INTERFACE_SECTION = "\n\nexport interface WorkspacePatternConfig {\n\tfile: string;\n\tslug: string;\n}\n";
22
+ export declare const PATTERNS_CONST_SECTION = "\n\nexport const PATTERNS: WorkspacePatternConfig[] = [\n\t// wp-typia add pattern entries\n];\n";
23
+ export declare const BINDING_SOURCES_INTERFACE_SECTION = "\n\nexport interface WorkspaceBindingSourceConfig {\n\tattribute?: string;\n\tblock?: string;\n\teditorFile: string;\n\tserverFile: string;\n\tslug: string;\n}\n";
24
+ export declare const BINDING_SOURCES_CONST_SECTION = "\n\nexport const BINDING_SOURCES: WorkspaceBindingSourceConfig[] = [\n\t// wp-typia add binding-source entries\n];\n";
25
+ export declare const REST_RESOURCES_INTERFACE_SECTION = "\n\nexport interface WorkspaceRestResourceConfig {\n\tapiFile: string;\n\tclientFile: string;\n\tdataFile: string;\n\tmethods: Array< 'list' | 'read' | 'create' | 'update' | 'delete' >;\n\tnamespace: string;\n\topenApiFile: string;\n\tphpFile: string;\n\trestManifest?: ReturnType<\n\t\ttypeof import( '@wp-typia/block-runtime/metadata-core' ).defineEndpointManifest\n\t>;\n\tslug: string;\n\ttypesFile: string;\n\tvalidatorsFile: string;\n}\n";
26
+ export declare const REST_RESOURCES_CONST_SECTION = "\n\nexport const REST_RESOURCES: WorkspaceRestResourceConfig[] = [\n\t// wp-typia add rest-resource entries\n];\n";
27
+ export declare const WORKSPACE_COMPATIBILITY_CONFIG_FIELD = "\tcompatibility?: {\n\t\thardMinimums: {\n\t\t\tphp?: string;\n\t\t\twordpress?: string;\n\t\t};\n\t\tmode: 'baseline' | 'optional' | 'required';\n\t\toptionalFeatureIds: string[];\n\t\toptionalFeatures: string[];\n\t\trequiredFeatureIds: string[];\n\t\trequiredFeatures: string[];\n\t\truntimeGates: string[];\n\t};\n";
28
+ export declare const ABILITIES_INTERFACE_SECTION = "\n\nexport interface WorkspaceAbilityConfig {\n\tclientFile: string;\n\tcompatibility?: {\n\t\thardMinimums: {\n\t\t\tphp?: string;\n\t\t\twordpress?: string;\n\t\t};\n\t\tmode: 'baseline' | 'optional' | 'required';\n\t\toptionalFeatureIds: string[];\n\t\toptionalFeatures: string[];\n\t\trequiredFeatureIds: string[];\n\t\trequiredFeatures: string[];\n\t\truntimeGates: string[];\n\t};\n\tconfigFile: string;\n\tdataFile: string;\n\tinputSchemaFile: string;\n\tinputTypeName: string;\n\toutputSchemaFile: string;\n\toutputTypeName: string;\n\tphpFile: string;\n\tslug: string;\n\ttypesFile: string;\n}\n";
29
+ export declare const ABILITIES_CONST_SECTION = "\n\nexport const ABILITIES: WorkspaceAbilityConfig[] = [\n\t// wp-typia add ability entries\n];\n";
30
+ export declare const AI_FEATURES_INTERFACE_SECTION = "\n\nexport interface WorkspaceAiFeatureConfig {\n\taiSchemaFile: string;\n\tapiFile: string;\n\tclientFile: string;\n\tcompatibility?: {\n\t\thardMinimums: {\n\t\t\tphp?: string;\n\t\t\twordpress?: string;\n\t\t};\n\t\tmode: 'baseline' | 'optional' | 'required';\n\t\toptionalFeatureIds: string[];\n\t\toptionalFeatures: string[];\n\t\trequiredFeatureIds: string[];\n\t\trequiredFeatures: string[];\n\t\truntimeGates: string[];\n\t};\n\tdataFile: string;\n\tnamespace: string;\n\topenApiFile: string;\n\tphpFile: string;\n\trestManifest?: ReturnType<\n\t\ttypeof import( '@wp-typia/block-runtime/metadata-core' ).defineEndpointManifest\n\t>;\n\tslug: string;\n\ttypesFile: string;\n\tvalidatorsFile: string;\n}\n";
31
+ export declare const AI_FEATURES_CONST_SECTION = "\n\nexport const AI_FEATURES: WorkspaceAiFeatureConfig[] = [\n\t// wp-typia add ai-feature entries\n];\n";
32
+ export declare const ADMIN_VIEWS_INTERFACE_SECTION = "\n\nexport interface WorkspaceAdminViewConfig {\n\tfile: string;\n\tphpFile: string;\n\tslug: string;\n\tsource?: string;\n}\n";
33
+ export declare const ADMIN_VIEWS_CONST_SECTION = "\n\nexport const ADMIN_VIEWS: WorkspaceAdminViewConfig[] = [\n\t// wp-typia add admin-view entries\n];\n";
34
+ export declare const EDITOR_PLUGINS_INTERFACE_SECTION = "\n\nexport interface WorkspaceEditorPluginConfig {\n\tfile: string;\n\tslug: string;\n\tslot: string;\n}\n";
35
+ export declare const EDITOR_PLUGINS_CONST_SECTION = "\n\nexport const EDITOR_PLUGINS: WorkspaceEditorPluginConfig[] = [\n\t// wp-typia add editor-plugin entries\n];\n";