@wp-typia/project-tools 0.22.4 → 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 (65) 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-anchors.js +3 -24
  18. package/dist/runtime/cli-add-workspace-ai-scaffold.js +14 -6
  19. package/dist/runtime/cli-add-workspace-assets.js +7 -50
  20. package/dist/runtime/cli-add-workspace-rest-anchors.js +3 -24
  21. package/dist/runtime/cli-doctor-workspace-bindings.js +2 -3
  22. package/dist/runtime/cli-doctor-workspace-blocks.js +2 -3
  23. package/dist/runtime/cli-doctor-workspace-features.js +6 -11
  24. package/dist/runtime/cli-doctor-workspace-shared.d.ts +8 -0
  25. package/dist/runtime/cli-doctor-workspace-shared.js +10 -0
  26. package/dist/runtime/cli-help.js +1 -1
  27. package/dist/runtime/cli-init-apply.d.ts +15 -0
  28. package/dist/runtime/cli-init-apply.js +99 -0
  29. package/dist/runtime/cli-init-package-json.d.ts +19 -0
  30. package/dist/runtime/cli-init-package-json.js +191 -0
  31. package/dist/runtime/cli-init-plan.d.ts +39 -0
  32. package/dist/runtime/cli-init-plan.js +375 -0
  33. package/dist/runtime/cli-init-templates.d.ts +27 -0
  34. package/dist/runtime/cli-init-templates.js +244 -0
  35. package/dist/runtime/cli-init-types.d.ts +84 -0
  36. package/dist/runtime/cli-init-types.js +3 -0
  37. package/dist/runtime/cli-init.d.ts +4 -100
  38. package/dist/runtime/cli-init.js +6 -878
  39. package/dist/runtime/fs-async.d.ts +28 -0
  40. package/dist/runtime/fs-async.js +53 -0
  41. package/dist/runtime/package-managers.js +1 -1
  42. package/dist/runtime/php-utils.d.ts +16 -0
  43. package/dist/runtime/php-utils.js +321 -1
  44. package/dist/runtime/scaffold-apply-utils.js +10 -20
  45. package/dist/runtime/scaffold-bootstrap.js +6 -8
  46. package/dist/runtime/scaffold-compatibility.d.ts +15 -3
  47. package/dist/runtime/scaffold-compatibility.js +42 -11
  48. package/dist/runtime/scaffold-documents.js +12 -0
  49. package/dist/runtime/scaffold-package-manager-files.js +4 -3
  50. package/dist/runtime/string-case.d.ts +5 -0
  51. package/dist/runtime/string-case.js +52 -2
  52. package/dist/runtime/template-source-cache.d.ts +19 -0
  53. package/dist/runtime/template-source-cache.js +164 -28
  54. package/dist/runtime/template-source-external.d.ts +7 -0
  55. package/dist/runtime/template-source-external.js +22 -5
  56. package/dist/runtime/template-source-normalization.d.ts +1 -1
  57. package/dist/runtime/template-source-normalization.js +12 -12
  58. package/dist/runtime/template-source-remote.d.ts +14 -0
  59. package/dist/runtime/template-source-remote.js +91 -15
  60. package/dist/runtime/template-source.js +35 -25
  61. package/dist/runtime/typia-llm.js +7 -0
  62. package/dist/runtime/version-floor.js +8 -2
  63. package/dist/runtime/workspace-inventory.d.ts +16 -14
  64. package/dist/runtime/workspace-inventory.js +310 -239
  65. package/package.json +6 -1
@@ -4,6 +4,9 @@ import { readFile, writeFile } from "node:fs/promises";
4
4
  import ts from "typescript";
5
5
  import { REST_RESOURCE_METHOD_IDS } from "./cli-add-shared.js";
6
6
  import { escapeRegex } from "./php-utils.js";
7
+ function defineInventoryEntryParser(descriptor) {
8
+ return descriptor;
9
+ }
7
10
  export const BLOCK_CONFIG_ENTRY_MARKER = "\t// wp-typia add block entries";
8
11
  export const VARIATION_CONFIG_ENTRY_MARKER = "\t// wp-typia add variation entries";
9
12
  export const BLOCK_STYLE_CONFIG_ENTRY_MARKER = "\t// wp-typia add style entries";
@@ -202,102 +205,319 @@ export const EDITOR_PLUGINS: WorkspaceEditorPluginConfig[] = [
202
205
  \t// wp-typia add editor-plugin entries
203
206
  ];
204
207
  `;
208
+ const BLOCK_INVENTORY_SECTION = {
209
+ append: {
210
+ marker: BLOCK_CONFIG_ENTRY_MARKER,
211
+ optionKey: "blockEntries",
212
+ },
213
+ parse: {
214
+ entriesKey: "blocks",
215
+ entry: defineInventoryEntryParser({
216
+ entryName: "BLOCKS",
217
+ fields: [
218
+ { key: "apiTypesFile" },
219
+ { key: "attributeTypeName" },
220
+ { key: "openApiFile" },
221
+ { key: "slug", required: true },
222
+ { key: "typesFile", required: true },
223
+ ],
224
+ }),
225
+ exportName: "BLOCKS",
226
+ required: true,
227
+ },
228
+ };
205
229
  const INVENTORY_SECTIONS = [
206
230
  {
231
+ append: {
232
+ marker: VARIATION_CONFIG_ENTRY_MARKER,
233
+ optionKey: "variationEntries",
234
+ },
207
235
  interface: {
208
236
  name: "WorkspaceVariationConfig",
209
237
  section: VARIATIONS_INTERFACE_SECTION,
210
238
  },
239
+ parse: {
240
+ entriesKey: "variations",
241
+ entry: defineInventoryEntryParser({
242
+ entryName: "VARIATIONS",
243
+ fields: [
244
+ { key: "block", required: true },
245
+ { key: "file", required: true },
246
+ { key: "slug", required: true },
247
+ ],
248
+ }),
249
+ hasSectionKey: "hasVariationsSection",
250
+ },
211
251
  value: {
212
252
  name: "VARIATIONS",
213
253
  section: VARIATIONS_CONST_SECTION,
214
254
  },
215
255
  },
216
256
  {
257
+ append: {
258
+ marker: BLOCK_STYLE_CONFIG_ENTRY_MARKER,
259
+ optionKey: "blockStyleEntries",
260
+ },
217
261
  interface: {
218
262
  name: "WorkspaceBlockStyleConfig",
219
263
  section: BLOCK_STYLES_INTERFACE_SECTION,
220
264
  },
265
+ parse: {
266
+ entriesKey: "blockStyles",
267
+ entry: defineInventoryEntryParser({
268
+ entryName: "BLOCK_STYLES",
269
+ fields: [
270
+ { key: "block", required: true },
271
+ { key: "file", required: true },
272
+ { key: "slug", required: true },
273
+ ],
274
+ }),
275
+ hasSectionKey: "hasBlockStylesSection",
276
+ },
221
277
  value: {
222
278
  name: "BLOCK_STYLES",
223
279
  section: BLOCK_STYLES_CONST_SECTION,
224
280
  },
225
281
  },
226
282
  {
283
+ append: {
284
+ marker: BLOCK_TRANSFORM_CONFIG_ENTRY_MARKER,
285
+ optionKey: "blockTransformEntries",
286
+ },
227
287
  interface: {
228
288
  name: "WorkspaceBlockTransformConfig",
229
289
  section: BLOCK_TRANSFORMS_INTERFACE_SECTION,
230
290
  },
291
+ parse: {
292
+ entriesKey: "blockTransforms",
293
+ entry: defineInventoryEntryParser({
294
+ entryName: "BLOCK_TRANSFORMS",
295
+ fields: [
296
+ { key: "block", required: true },
297
+ { key: "file", required: true },
298
+ { key: "from", required: true },
299
+ { key: "slug", required: true },
300
+ { key: "to", required: true },
301
+ ],
302
+ }),
303
+ hasSectionKey: "hasBlockTransformsSection",
304
+ },
231
305
  value: {
232
306
  name: "BLOCK_TRANSFORMS",
233
307
  section: BLOCK_TRANSFORMS_CONST_SECTION,
234
308
  },
235
309
  },
236
310
  {
311
+ append: {
312
+ marker: PATTERN_CONFIG_ENTRY_MARKER,
313
+ optionKey: "patternEntries",
314
+ },
237
315
  interface: {
238
316
  name: "WorkspacePatternConfig",
239
317
  section: PATTERNS_INTERFACE_SECTION,
240
318
  },
319
+ parse: {
320
+ entriesKey: "patterns",
321
+ entry: defineInventoryEntryParser({
322
+ entryName: "PATTERNS",
323
+ fields: [
324
+ { key: "file", required: true },
325
+ { key: "slug", required: true },
326
+ ],
327
+ }),
328
+ hasSectionKey: "hasPatternsSection",
329
+ },
241
330
  value: {
242
331
  name: "PATTERNS",
243
332
  section: PATTERNS_CONST_SECTION,
244
333
  },
245
334
  },
246
335
  {
336
+ append: {
337
+ marker: BINDING_SOURCE_CONFIG_ENTRY_MARKER,
338
+ optionKey: "bindingSourceEntries",
339
+ },
247
340
  interface: {
248
341
  name: "WorkspaceBindingSourceConfig",
249
342
  section: BINDING_SOURCES_INTERFACE_SECTION,
250
343
  },
344
+ parse: {
345
+ entriesKey: "bindingSources",
346
+ entry: defineInventoryEntryParser({
347
+ entryName: "BINDING_SOURCES",
348
+ fields: [
349
+ { key: "attribute" },
350
+ { key: "block" },
351
+ { key: "editorFile", required: true },
352
+ { key: "serverFile", required: true },
353
+ { key: "slug", required: true },
354
+ ],
355
+ }),
356
+ hasSectionKey: "hasBindingSourcesSection",
357
+ },
251
358
  value: {
252
359
  name: "BINDING_SOURCES",
253
360
  section: BINDING_SOURCES_CONST_SECTION,
254
361
  },
255
362
  },
256
363
  {
364
+ append: {
365
+ marker: REST_RESOURCE_CONFIG_ENTRY_MARKER,
366
+ optionKey: "restResourceEntries",
367
+ },
257
368
  interface: {
258
369
  name: "WorkspaceRestResourceConfig",
259
370
  section: REST_RESOURCES_INTERFACE_SECTION,
260
371
  },
372
+ parse: {
373
+ entriesKey: "restResources",
374
+ entry: defineInventoryEntryParser({
375
+ entryName: "REST_RESOURCES",
376
+ fields: [
377
+ { key: "apiFile", required: true },
378
+ { key: "clientFile", required: true },
379
+ { key: "dataFile", required: true },
380
+ {
381
+ key: "methods",
382
+ kind: "stringArray",
383
+ required: true,
384
+ validate: (value, context) => {
385
+ const methods = Array.isArray(value) ? value : [];
386
+ const invalidMethods = methods.filter((method) => !REST_RESOURCE_METHOD_IDS.includes(method));
387
+ if (invalidMethods.length > 0) {
388
+ throw new Error(`${context.entryName}[${context.elementIndex}].${context.key} includes unsupported values: ${invalidMethods.join(", ")}.`);
389
+ }
390
+ },
391
+ },
392
+ { key: "namespace", required: true },
393
+ { key: "openApiFile", required: true },
394
+ { key: "phpFile", required: true },
395
+ { key: "slug", required: true },
396
+ { key: "typesFile", required: true },
397
+ { key: "validatorsFile", required: true },
398
+ ],
399
+ }),
400
+ hasSectionKey: "hasRestResourcesSection",
401
+ },
261
402
  value: {
262
403
  name: "REST_RESOURCES",
263
404
  section: REST_RESOURCES_CONST_SECTION,
264
405
  },
265
406
  },
266
407
  {
408
+ append: {
409
+ marker: ABILITY_CONFIG_ENTRY_MARKER,
410
+ optionKey: "abilityEntries",
411
+ },
267
412
  interface: {
268
413
  name: "WorkspaceAbilityConfig",
269
414
  section: ABILITIES_INTERFACE_SECTION,
270
415
  },
416
+ parse: {
417
+ entriesKey: "abilities",
418
+ entry: defineInventoryEntryParser({
419
+ entryName: "ABILITIES",
420
+ fields: [
421
+ { key: "clientFile", required: true },
422
+ { key: "configFile", required: true },
423
+ { key: "dataFile", required: true },
424
+ { key: "inputSchemaFile", required: true },
425
+ { key: "inputTypeName", required: true },
426
+ { key: "outputSchemaFile", required: true },
427
+ { key: "outputTypeName", required: true },
428
+ { key: "phpFile", required: true },
429
+ { key: "slug", required: true },
430
+ { key: "typesFile", required: true },
431
+ ],
432
+ }),
433
+ hasSectionKey: "hasAbilitiesSection",
434
+ },
271
435
  value: {
272
436
  name: "ABILITIES",
273
437
  section: ABILITIES_CONST_SECTION,
274
438
  },
275
439
  },
276
440
  {
441
+ append: {
442
+ marker: AI_FEATURE_CONFIG_ENTRY_MARKER,
443
+ optionKey: "aiFeatureEntries",
444
+ },
277
445
  interface: {
278
446
  name: "WorkspaceAiFeatureConfig",
279
447
  section: AI_FEATURES_INTERFACE_SECTION,
280
448
  },
449
+ parse: {
450
+ entriesKey: "aiFeatures",
451
+ entry: defineInventoryEntryParser({
452
+ entryName: "AI_FEATURES",
453
+ fields: [
454
+ { key: "aiSchemaFile", required: true },
455
+ { key: "apiFile", required: true },
456
+ { key: "clientFile", required: true },
457
+ { key: "dataFile", required: true },
458
+ { key: "namespace", required: true },
459
+ { key: "openApiFile", required: true },
460
+ { key: "phpFile", required: true },
461
+ { key: "slug", required: true },
462
+ { key: "typesFile", required: true },
463
+ { key: "validatorsFile", required: true },
464
+ ],
465
+ }),
466
+ hasSectionKey: "hasAiFeaturesSection",
467
+ },
281
468
  value: {
282
469
  name: "AI_FEATURES",
283
470
  section: AI_FEATURES_CONST_SECTION,
284
471
  },
285
472
  },
286
473
  {
474
+ append: {
475
+ marker: ADMIN_VIEW_CONFIG_ENTRY_MARKER,
476
+ optionKey: "adminViewEntries",
477
+ },
287
478
  interface: {
288
479
  name: "WorkspaceAdminViewConfig",
289
480
  section: ADMIN_VIEWS_INTERFACE_SECTION,
290
481
  },
482
+ parse: {
483
+ entriesKey: "adminViews",
484
+ entry: defineInventoryEntryParser({
485
+ entryName: "ADMIN_VIEWS",
486
+ fields: [
487
+ { key: "file", required: true },
488
+ { key: "phpFile", required: true },
489
+ { key: "slug", required: true },
490
+ { key: "source" },
491
+ ],
492
+ }),
493
+ hasSectionKey: "hasAdminViewsSection",
494
+ },
291
495
  value: {
292
496
  name: "ADMIN_VIEWS",
293
497
  section: ADMIN_VIEWS_CONST_SECTION,
294
498
  },
295
499
  },
296
500
  {
501
+ append: {
502
+ marker: EDITOR_PLUGIN_CONFIG_ENTRY_MARKER,
503
+ optionKey: "editorPluginEntries",
504
+ },
297
505
  interface: {
298
506
  name: "WorkspaceEditorPluginConfig",
299
507
  section: EDITOR_PLUGINS_INTERFACE_SECTION,
300
508
  },
509
+ parse: {
510
+ entriesKey: "editorPlugins",
511
+ entry: defineInventoryEntryParser({
512
+ entryName: "EDITOR_PLUGINS",
513
+ fields: [
514
+ { key: "file", required: true },
515
+ { key: "slug", required: true },
516
+ { key: "slot", required: true },
517
+ ],
518
+ }),
519
+ hasSectionKey: "hasEditorPluginsSection",
520
+ },
301
521
  value: {
302
522
  name: "EDITOR_PLUGINS",
303
523
  section: EDITOR_PLUGINS_CONST_SECTION,
@@ -383,169 +603,60 @@ function getRequiredStringArrayProperty(entryName, elementIndex, objectLiteral,
383
603
  }
384
604
  throw new Error(`${entryName}[${elementIndex}] is missing required "${key}" in scripts/block-config.ts.`);
385
605
  }
386
- function parseBlockEntries(arrayLiteral) {
387
- return arrayLiteral.elements.map((element, elementIndex) => {
388
- if (!ts.isObjectLiteralExpression(element)) {
389
- throw new Error(`BLOCKS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
390
- }
391
- return {
392
- apiTypesFile: getOptionalStringProperty("BLOCKS", elementIndex, element, "apiTypesFile"),
393
- attributeTypeName: getOptionalStringProperty("BLOCKS", elementIndex, element, "attributeTypeName"),
394
- openApiFile: getOptionalStringProperty("BLOCKS", elementIndex, element, "openApiFile"),
395
- slug: getRequiredStringProperty("BLOCKS", elementIndex, element, "slug"),
396
- typesFile: getRequiredStringProperty("BLOCKS", elementIndex, element, "typesFile"),
397
- };
398
- });
399
- }
400
- function parseVariationEntries(arrayLiteral) {
401
- return arrayLiteral.elements.map((element, elementIndex) => {
402
- if (!ts.isObjectLiteralExpression(element)) {
403
- throw new Error(`VARIATIONS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
404
- }
405
- return {
406
- block: getRequiredStringProperty("VARIATIONS", elementIndex, element, "block"),
407
- file: getRequiredStringProperty("VARIATIONS", elementIndex, element, "file"),
408
- slug: getRequiredStringProperty("VARIATIONS", elementIndex, element, "slug"),
409
- };
410
- });
411
- }
412
- function parseBlockStyleEntries(arrayLiteral) {
413
- return arrayLiteral.elements.map((element, elementIndex) => {
414
- if (!ts.isObjectLiteralExpression(element)) {
415
- throw new Error(`BLOCK_STYLES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
416
- }
417
- return {
418
- block: getRequiredStringProperty("BLOCK_STYLES", elementIndex, element, "block"),
419
- file: getRequiredStringProperty("BLOCK_STYLES", elementIndex, element, "file"),
420
- slug: getRequiredStringProperty("BLOCK_STYLES", elementIndex, element, "slug"),
421
- };
422
- });
423
- }
424
- function parseBlockTransformEntries(arrayLiteral) {
425
- return arrayLiteral.elements.map((element, elementIndex) => {
426
- if (!ts.isObjectLiteralExpression(element)) {
427
- throw new Error(`BLOCK_TRANSFORMS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
428
- }
429
- return {
430
- block: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "block"),
431
- file: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "file"),
432
- from: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "from"),
433
- slug: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "slug"),
434
- to: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "to"),
435
- };
436
- });
437
- }
438
- function parsePatternEntries(arrayLiteral) {
439
- return arrayLiteral.elements.map((element, elementIndex) => {
440
- if (!ts.isObjectLiteralExpression(element)) {
441
- throw new Error(`PATTERNS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
442
- }
443
- return {
444
- file: getRequiredStringProperty("PATTERNS", elementIndex, element, "file"),
445
- slug: getRequiredStringProperty("PATTERNS", elementIndex, element, "slug"),
446
- };
447
- });
448
- }
449
- function parseBindingSourceEntries(arrayLiteral) {
606
+ function parseInventoryEntries(arrayLiteral, descriptor) {
450
607
  return arrayLiteral.elements.map((element, elementIndex) => {
451
608
  if (!ts.isObjectLiteralExpression(element)) {
452
- throw new Error(`BINDING_SOURCES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
609
+ throw new Error(`${descriptor.entryName}[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
453
610
  }
454
- return {
455
- attribute: getOptionalStringProperty("BINDING_SOURCES", elementIndex, element, "attribute"),
456
- block: getOptionalStringProperty("BINDING_SOURCES", elementIndex, element, "block"),
457
- editorFile: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "editorFile"),
458
- serverFile: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "serverFile"),
459
- slug: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "slug"),
460
- };
461
- });
462
- }
463
- function parseRestResourceEntries(arrayLiteral) {
464
- return arrayLiteral.elements.map((element, elementIndex) => {
465
- if (!ts.isObjectLiteralExpression(element)) {
466
- throw new Error(`REST_RESOURCES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
611
+ const entry = {};
612
+ for (const field of descriptor.fields) {
613
+ const kind = field.kind ?? "string";
614
+ const value = kind === "stringArray"
615
+ ? getRequiredStringArrayProperty(descriptor.entryName, elementIndex, element, field.key)
616
+ : field.required
617
+ ? getRequiredStringProperty(descriptor.entryName, elementIndex, element, field.key)
618
+ : getOptionalStringProperty(descriptor.entryName, elementIndex, element, field.key);
619
+ field.validate?.(value, {
620
+ elementIndex,
621
+ entryName: descriptor.entryName,
622
+ key: field.key,
623
+ });
624
+ entry[field.key] = value;
467
625
  }
468
- const methods = getRequiredStringArrayProperty("REST_RESOURCES", elementIndex, element, "methods");
469
- const invalidMethods = methods.filter((method) => !REST_RESOURCE_METHOD_IDS.includes(method));
470
- if (invalidMethods.length > 0) {
471
- throw new Error(`REST_RESOURCES[${elementIndex}].methods includes unsupported values: ${invalidMethods.join(", ")}.`);
472
- }
473
- return {
474
- apiFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "apiFile"),
475
- clientFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "clientFile"),
476
- dataFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "dataFile"),
477
- methods,
478
- namespace: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "namespace"),
479
- openApiFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "openApiFile"),
480
- phpFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "phpFile"),
481
- slug: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "slug"),
482
- typesFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "typesFile"),
483
- validatorsFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "validatorsFile"),
484
- };
626
+ return entry;
485
627
  });
486
628
  }
487
- function parseAiFeatureEntries(arrayLiteral) {
488
- return arrayLiteral.elements.map((element, elementIndex) => {
489
- if (!ts.isObjectLiteralExpression(element)) {
490
- throw new Error(`AI_FEATURES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
491
- }
629
+ function parseInventorySection(sourceFile, descriptor) {
630
+ if (!descriptor.parse) {
492
631
  return {
493
- aiSchemaFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "aiSchemaFile"),
494
- apiFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "apiFile"),
495
- clientFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "clientFile"),
496
- dataFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "dataFile"),
497
- namespace: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "namespace"),
498
- openApiFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "openApiFile"),
499
- phpFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "phpFile"),
500
- slug: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "slug"),
501
- typesFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "typesFile"),
502
- validatorsFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "validatorsFile"),
632
+ entries: [],
633
+ found: false,
503
634
  };
504
- });
505
- }
506
- function parseAbilityEntries(arrayLiteral) {
507
- return arrayLiteral.elements.map((element, elementIndex) => {
508
- if (!ts.isObjectLiteralExpression(element)) {
509
- throw new Error(`ABILITIES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
510
- }
511
- return {
512
- clientFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "clientFile"),
513
- configFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "configFile"),
514
- dataFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "dataFile"),
515
- inputSchemaFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "inputSchemaFile"),
516
- inputTypeName: getRequiredStringProperty("ABILITIES", elementIndex, element, "inputTypeName"),
517
- outputSchemaFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "outputSchemaFile"),
518
- outputTypeName: getRequiredStringProperty("ABILITIES", elementIndex, element, "outputTypeName"),
519
- phpFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "phpFile"),
520
- slug: getRequiredStringProperty("ABILITIES", elementIndex, element, "slug"),
521
- typesFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "typesFile"),
522
- };
523
- });
524
- }
525
- function parseEditorPluginEntries(arrayLiteral) {
526
- return arrayLiteral.elements.map((element, elementIndex) => {
527
- if (!ts.isObjectLiteralExpression(element)) {
528
- throw new Error(`EDITOR_PLUGINS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
635
+ }
636
+ const exportName = descriptor.parse.exportName ?? descriptor.value?.name;
637
+ if (!exportName) {
638
+ throw new Error("Inventory parser descriptor is missing an export name.");
639
+ }
640
+ const exportedArray = findExportedArrayLiteral(sourceFile, exportName);
641
+ if (!exportedArray.found) {
642
+ if (descriptor.parse.required) {
643
+ throw new Error(`scripts/block-config.ts must export a ${exportName} array.`);
529
644
  }
530
645
  return {
531
- file: getRequiredStringProperty("EDITOR_PLUGINS", elementIndex, element, "file"),
532
- slug: getRequiredStringProperty("EDITOR_PLUGINS", elementIndex, element, "slug"),
533
- slot: getRequiredStringProperty("EDITOR_PLUGINS", elementIndex, element, "slot"),
646
+ entries: [],
647
+ found: false,
534
648
  };
535
- });
536
- }
537
- function parseAdminViewEntries(arrayLiteral) {
538
- return arrayLiteral.elements.map((element, elementIndex) => {
539
- if (!ts.isObjectLiteralExpression(element)) {
540
- throw new Error(`ADMIN_VIEWS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
649
+ }
650
+ if (!exportedArray.array) {
651
+ if (descriptor.parse.required) {
652
+ throw new Error(`scripts/block-config.ts must export a ${exportName} array.`);
541
653
  }
542
- return {
543
- file: getRequiredStringProperty("ADMIN_VIEWS", elementIndex, element, "file"),
544
- phpFile: getRequiredStringProperty("ADMIN_VIEWS", elementIndex, element, "phpFile"),
545
- slug: getRequiredStringProperty("ADMIN_VIEWS", elementIndex, element, "slug"),
546
- source: getOptionalStringProperty("ADMIN_VIEWS", elementIndex, element, "source"),
547
- };
548
- });
654
+ throw new Error(`scripts/block-config.ts must export ${exportName} as an array literal.`);
655
+ }
656
+ return {
657
+ entries: parseInventoryEntries(exportedArray.array, descriptor.parse.entry),
658
+ found: true,
659
+ };
549
660
  }
550
661
  /**
551
662
  * Parse workspace inventory entries from the source of `scripts/block-config.ts`.
@@ -556,82 +667,42 @@ function parseAdminViewEntries(arrayLiteral) {
556
667
  */
557
668
  export function parseWorkspaceInventorySource(source) {
558
669
  const sourceFile = ts.createSourceFile("block-config.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
559
- const blockArray = findExportedArrayLiteral(sourceFile, "BLOCKS");
560
- if (!blockArray.found || !blockArray.array) {
561
- throw new Error("scripts/block-config.ts must export a BLOCKS array.");
562
- }
563
- const variationArray = findExportedArrayLiteral(sourceFile, "VARIATIONS");
564
- const blockStyleArray = findExportedArrayLiteral(sourceFile, "BLOCK_STYLES");
565
- const blockTransformArray = findExportedArrayLiteral(sourceFile, "BLOCK_TRANSFORMS");
566
- const patternArray = findExportedArrayLiteral(sourceFile, "PATTERNS");
567
- const bindingSourceArray = findExportedArrayLiteral(sourceFile, "BINDING_SOURCES");
568
- const restResourceArray = findExportedArrayLiteral(sourceFile, "REST_RESOURCES");
569
- const abilityArray = findExportedArrayLiteral(sourceFile, "ABILITIES");
570
- const aiFeatureArray = findExportedArrayLiteral(sourceFile, "AI_FEATURES");
571
- const adminViewArray = findExportedArrayLiteral(sourceFile, "ADMIN_VIEWS");
572
- const editorPluginArray = findExportedArrayLiteral(sourceFile, "EDITOR_PLUGINS");
573
- if (variationArray.found && !variationArray.array) {
574
- throw new Error("scripts/block-config.ts must export VARIATIONS as an array literal.");
575
- }
576
- if (blockStyleArray.found && !blockStyleArray.array) {
577
- throw new Error("scripts/block-config.ts must export BLOCK_STYLES as an array literal.");
578
- }
579
- if (blockTransformArray.found && !blockTransformArray.array) {
580
- throw new Error("scripts/block-config.ts must export BLOCK_TRANSFORMS as an array literal.");
581
- }
582
- if (patternArray.found && !patternArray.array) {
583
- throw new Error("scripts/block-config.ts must export PATTERNS as an array literal.");
584
- }
585
- if (bindingSourceArray.found && !bindingSourceArray.array) {
586
- throw new Error("scripts/block-config.ts must export BINDING_SOURCES as an array literal.");
587
- }
588
- if (restResourceArray.found && !restResourceArray.array) {
589
- throw new Error("scripts/block-config.ts must export REST_RESOURCES as an array literal.");
590
- }
591
- if (abilityArray.found && !abilityArray.array) {
592
- throw new Error("scripts/block-config.ts must export ABILITIES as an array literal.");
593
- }
594
- if (aiFeatureArray.found && !aiFeatureArray.array) {
595
- throw new Error("scripts/block-config.ts must export AI_FEATURES as an array literal.");
596
- }
597
- if (adminViewArray.found && !adminViewArray.array) {
598
- throw new Error("scripts/block-config.ts must export ADMIN_VIEWS as an array literal.");
599
- }
600
- if (editorPluginArray.found && !editorPluginArray.array) {
601
- throw new Error("scripts/block-config.ts must export EDITOR_PLUGINS as an array literal.");
602
- }
603
- return {
604
- abilities: abilityArray.array ? parseAbilityEntries(abilityArray.array) : [],
605
- adminViews: adminViewArray.array ? parseAdminViewEntries(adminViewArray.array) : [],
606
- aiFeatures: aiFeatureArray.array ? parseAiFeatureEntries(aiFeatureArray.array) : [],
607
- bindingSources: bindingSourceArray.array
608
- ? parseBindingSourceEntries(bindingSourceArray.array)
609
- : [],
610
- blockStyles: blockStyleArray.array ? parseBlockStyleEntries(blockStyleArray.array) : [],
611
- blockTransforms: blockTransformArray.array
612
- ? parseBlockTransformEntries(blockTransformArray.array)
613
- : [],
614
- blocks: parseBlockEntries(blockArray.array),
615
- hasAbilitiesSection: abilityArray.found,
616
- hasAdminViewsSection: adminViewArray.found,
617
- hasAiFeaturesSection: aiFeatureArray.found,
618
- hasBindingSourcesSection: bindingSourceArray.found,
619
- hasBlockStylesSection: blockStyleArray.found,
620
- hasBlockTransformsSection: blockTransformArray.found,
621
- hasEditorPluginsSection: editorPluginArray.found,
622
- hasPatternsSection: patternArray.found,
623
- hasRestResourcesSection: restResourceArray.found,
624
- hasVariationsSection: variationArray.found,
625
- editorPlugins: editorPluginArray.array
626
- ? parseEditorPluginEntries(editorPluginArray.array)
627
- : [],
628
- patterns: patternArray.array ? parsePatternEntries(patternArray.array) : [],
629
- restResources: restResourceArray.array
630
- ? parseRestResourceEntries(restResourceArray.array)
631
- : [],
670
+ const parsedInventory = {
671
+ abilities: [],
672
+ adminViews: [],
673
+ aiFeatures: [],
674
+ bindingSources: [],
675
+ blockStyles: [],
676
+ blockTransforms: [],
677
+ blocks: parseInventorySection(sourceFile, BLOCK_INVENTORY_SECTION).entries,
678
+ editorPlugins: [],
679
+ hasAbilitiesSection: false,
680
+ hasAdminViewsSection: false,
681
+ hasAiFeaturesSection: false,
682
+ hasBindingSourcesSection: false,
683
+ hasBlockStylesSection: false,
684
+ hasBlockTransformsSection: false,
685
+ hasEditorPluginsSection: false,
686
+ hasPatternsSection: false,
687
+ hasRestResourcesSection: false,
688
+ hasVariationsSection: false,
689
+ patterns: [],
690
+ restResources: [],
632
691
  source,
633
- variations: variationArray.array ? parseVariationEntries(variationArray.array) : [],
692
+ variations: [],
634
693
  };
694
+ const mutableInventory = parsedInventory;
695
+ for (const section of INVENTORY_SECTIONS) {
696
+ if (!section.parse) {
697
+ continue;
698
+ }
699
+ const parsedSection = parseInventorySection(sourceFile, section);
700
+ mutableInventory[section.parse.entriesKey] = parsedSection.entries;
701
+ if (section.parse.hasSectionKey) {
702
+ mutableInventory[section.parse.hasSectionKey] = parsedSection.found;
703
+ }
704
+ }
705
+ return parsedInventory;
635
706
  }
636
707
  /**
637
708
  * Read and parse the canonical workspace inventory file.
@@ -704,6 +775,16 @@ function appendEntriesAtMarker(source, marker, entries) {
704
775
  }
705
776
  return source.replace(marker, `${entries.join("\n")}\n${marker}`);
706
777
  }
778
+ function appendInventorySectionEntries(source, options) {
779
+ let nextSource = source;
780
+ for (const section of [BLOCK_INVENTORY_SECTION, ...INVENTORY_SECTIONS]) {
781
+ if (!section.append) {
782
+ continue;
783
+ }
784
+ nextSource = appendEntriesAtMarker(nextSource, section.append.marker, options[section.append.optionKey] ?? []);
785
+ }
786
+ return nextSource;
787
+ }
707
788
  function ensureInterfaceField(source, interfaceName, fieldName, fieldSource) {
708
789
  const interfacePattern = new RegExp(`(export\\s+interface\\s+${escapeRegex(interfaceName)}\\s*\\{\\r?\\n)([\\s\\S]*?)(\\r?\\n\\})`, "u");
709
790
  return source.replace(interfacePattern, (match, start, body, end) => {
@@ -762,28 +843,18 @@ function normalizeInterfaceFieldBlock(source, interfaceName, fieldName, fieldSou
762
843
  * @param options Entry lists plus an optional source transformer.
763
844
  * @returns Updated source text with all requested inventory entries appended.
764
845
  */
765
- export function updateWorkspaceInventorySource(source, { blockEntries = [], blockStyleEntries = [], blockTransformEntries = [], bindingSourceEntries = [], abilityEntries = [], adminViewEntries = [], aiFeatureEntries = [], editorPluginEntries = [], patternEntries = [], restResourceEntries = [], variationEntries = [], transformSource, } = {}) {
846
+ export function updateWorkspaceInventorySource(source, options = {}) {
766
847
  let nextSource = ensureWorkspaceInventorySections(source);
767
- if (transformSource) {
768
- nextSource = transformSource(nextSource);
848
+ if (options.transformSource) {
849
+ nextSource = options.transformSource(nextSource);
769
850
  }
770
- nextSource = appendEntriesAtMarker(nextSource, BLOCK_CONFIG_ENTRY_MARKER, blockEntries);
771
- nextSource = appendEntriesAtMarker(nextSource, VARIATION_CONFIG_ENTRY_MARKER, variationEntries);
772
- nextSource = appendEntriesAtMarker(nextSource, BLOCK_STYLE_CONFIG_ENTRY_MARKER, blockStyleEntries);
773
- nextSource = appendEntriesAtMarker(nextSource, BLOCK_TRANSFORM_CONFIG_ENTRY_MARKER, blockTransformEntries);
774
- nextSource = appendEntriesAtMarker(nextSource, PATTERN_CONFIG_ENTRY_MARKER, patternEntries);
775
- nextSource = appendEntriesAtMarker(nextSource, BINDING_SOURCE_CONFIG_ENTRY_MARKER, bindingSourceEntries);
776
- nextSource = appendEntriesAtMarker(nextSource, REST_RESOURCE_CONFIG_ENTRY_MARKER, restResourceEntries);
777
- nextSource = appendEntriesAtMarker(nextSource, ABILITY_CONFIG_ENTRY_MARKER, abilityEntries);
778
- nextSource = appendEntriesAtMarker(nextSource, AI_FEATURE_CONFIG_ENTRY_MARKER, aiFeatureEntries);
779
- nextSource = appendEntriesAtMarker(nextSource, ADMIN_VIEW_CONFIG_ENTRY_MARKER, adminViewEntries);
851
+ nextSource = appendInventorySectionEntries(nextSource, options);
780
852
  nextSource = ensureInterfaceField(nextSource, "WorkspaceBindingSourceConfig", "attribute", "\tattribute?: string;");
781
853
  nextSource = ensureInterfaceField(nextSource, "WorkspaceBindingSourceConfig", "block", "\tblock?: string;");
782
854
  nextSource = ensureInterfaceField(nextSource, "WorkspaceAbilityConfig", "compatibility", WORKSPACE_COMPATIBILITY_CONFIG_FIELD);
783
855
  nextSource = normalizeInterfaceFieldBlock(nextSource, "WorkspaceAbilityConfig", "compatibility", WORKSPACE_COMPATIBILITY_CONFIG_FIELD, ["optionalFeatureIds: string[];", "requiredFeatureIds: string[];"]);
784
856
  nextSource = ensureInterfaceField(nextSource, "WorkspaceAiFeatureConfig", "compatibility", WORKSPACE_COMPATIBILITY_CONFIG_FIELD);
785
857
  nextSource = normalizeInterfaceFieldBlock(nextSource, "WorkspaceAiFeatureConfig", "compatibility", WORKSPACE_COMPATIBILITY_CONFIG_FIELD, ["optionalFeatureIds: string[];", "requiredFeatureIds: string[];"]);
786
- nextSource = appendEntriesAtMarker(nextSource, EDITOR_PLUGIN_CONFIG_ENTRY_MARKER, editorPluginEntries);
787
858
  return nextSource;
788
859
  }
789
860
  /**