@wp-typia/project-tools 0.22.3 → 0.22.5

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 (43) hide show
  1. package/dist/runtime/cli-add-block-json.d.ts +31 -0
  2. package/dist/runtime/cli-add-block-json.js +65 -0
  3. package/dist/runtime/cli-add-collision.d.ts +129 -0
  4. package/dist/runtime/cli-add-collision.js +293 -0
  5. package/dist/runtime/cli-add-filesystem.d.ts +29 -0
  6. package/dist/runtime/cli-add-filesystem.js +77 -0
  7. package/dist/runtime/cli-add-help.d.ts +4 -0
  8. package/dist/runtime/cli-add-help.js +41 -0
  9. package/dist/runtime/cli-add-shared.d.ts +6 -304
  10. package/dist/runtime/cli-add-shared.js +6 -524
  11. package/dist/runtime/cli-add-types.d.ts +247 -0
  12. package/dist/runtime/cli-add-types.js +64 -0
  13. package/dist/runtime/cli-add-validation.d.ts +87 -0
  14. package/dist/runtime/cli-add-validation.js +147 -0
  15. package/dist/runtime/cli-add-workspace-ability-scaffold.js +46 -72
  16. package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +35 -61
  17. package/dist/runtime/cli-add-workspace-ai-anchors.js +3 -24
  18. package/dist/runtime/cli-add-workspace-ai-scaffold.js +53 -57
  19. package/dist/runtime/cli-add-workspace-ai-templates.js +2 -0
  20. package/dist/runtime/cli-add-workspace-assets.js +7 -50
  21. package/dist/runtime/cli-add-workspace-mutation.d.ts +30 -0
  22. package/dist/runtime/cli-add-workspace-mutation.js +60 -0
  23. package/dist/runtime/cli-add-workspace-rest-anchors.js +3 -24
  24. package/dist/runtime/cli-add-workspace.js +1 -79
  25. package/dist/runtime/cli-add.d.ts +2 -2
  26. package/dist/runtime/cli-add.js +2 -2
  27. package/dist/runtime/cli-doctor-workspace-blocks.js +1 -66
  28. package/dist/runtime/index.d.ts +2 -0
  29. package/dist/runtime/index.js +1 -0
  30. package/dist/runtime/migration-utils.d.ts +2 -1
  31. package/dist/runtime/migration-utils.js +3 -11
  32. package/dist/runtime/package-managers.d.ts +19 -0
  33. package/dist/runtime/package-managers.js +62 -0
  34. package/dist/runtime/template-source-cache.d.ts +59 -0
  35. package/dist/runtime/template-source-cache.js +160 -0
  36. package/dist/runtime/ts-source-masking.d.ts +28 -0
  37. package/dist/runtime/ts-source-masking.js +104 -0
  38. package/dist/runtime/typia-llm.d.ts +9 -1
  39. package/dist/runtime/typia-llm.js +20 -5
  40. package/dist/runtime/workspace-inventory.js +368 -284
  41. package/dist/runtime/workspace-project.d.ts +1 -1
  42. package/dist/runtime/workspace-project.js +2 -10
  43. package/package.json +2 -2
@@ -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,6 +205,281 @@ export const EDITOR_PLUGINS: WorkspaceEditorPluginConfig[] = [
202
205
  \t// wp-typia add editor-plugin entries
203
206
  ];
204
207
  `;
208
+ const BLOCK_INVENTORY_SECTION = {
209
+ parse: {
210
+ entriesKey: "blocks",
211
+ entry: defineInventoryEntryParser({
212
+ entryName: "BLOCKS",
213
+ fields: [
214
+ { key: "apiTypesFile" },
215
+ { key: "attributeTypeName" },
216
+ { key: "openApiFile" },
217
+ { key: "slug", required: true },
218
+ { key: "typesFile", required: true },
219
+ ],
220
+ }),
221
+ exportName: "BLOCKS",
222
+ required: true,
223
+ },
224
+ };
225
+ const INVENTORY_SECTIONS = [
226
+ {
227
+ interface: {
228
+ name: "WorkspaceVariationConfig",
229
+ section: VARIATIONS_INTERFACE_SECTION,
230
+ },
231
+ parse: {
232
+ entriesKey: "variations",
233
+ entry: defineInventoryEntryParser({
234
+ entryName: "VARIATIONS",
235
+ fields: [
236
+ { key: "block", required: true },
237
+ { key: "file", required: true },
238
+ { key: "slug", required: true },
239
+ ],
240
+ }),
241
+ hasSectionKey: "hasVariationsSection",
242
+ },
243
+ value: {
244
+ name: "VARIATIONS",
245
+ section: VARIATIONS_CONST_SECTION,
246
+ },
247
+ },
248
+ {
249
+ interface: {
250
+ name: "WorkspaceBlockStyleConfig",
251
+ section: BLOCK_STYLES_INTERFACE_SECTION,
252
+ },
253
+ parse: {
254
+ entriesKey: "blockStyles",
255
+ entry: defineInventoryEntryParser({
256
+ entryName: "BLOCK_STYLES",
257
+ fields: [
258
+ { key: "block", required: true },
259
+ { key: "file", required: true },
260
+ { key: "slug", required: true },
261
+ ],
262
+ }),
263
+ hasSectionKey: "hasBlockStylesSection",
264
+ },
265
+ value: {
266
+ name: "BLOCK_STYLES",
267
+ section: BLOCK_STYLES_CONST_SECTION,
268
+ },
269
+ },
270
+ {
271
+ interface: {
272
+ name: "WorkspaceBlockTransformConfig",
273
+ section: BLOCK_TRANSFORMS_INTERFACE_SECTION,
274
+ },
275
+ parse: {
276
+ entriesKey: "blockTransforms",
277
+ entry: defineInventoryEntryParser({
278
+ entryName: "BLOCK_TRANSFORMS",
279
+ fields: [
280
+ { key: "block", required: true },
281
+ { key: "file", required: true },
282
+ { key: "from", required: true },
283
+ { key: "slug", required: true },
284
+ { key: "to", required: true },
285
+ ],
286
+ }),
287
+ hasSectionKey: "hasBlockTransformsSection",
288
+ },
289
+ value: {
290
+ name: "BLOCK_TRANSFORMS",
291
+ section: BLOCK_TRANSFORMS_CONST_SECTION,
292
+ },
293
+ },
294
+ {
295
+ interface: {
296
+ name: "WorkspacePatternConfig",
297
+ section: PATTERNS_INTERFACE_SECTION,
298
+ },
299
+ parse: {
300
+ entriesKey: "patterns",
301
+ entry: defineInventoryEntryParser({
302
+ entryName: "PATTERNS",
303
+ fields: [
304
+ { key: "file", required: true },
305
+ { key: "slug", required: true },
306
+ ],
307
+ }),
308
+ hasSectionKey: "hasPatternsSection",
309
+ },
310
+ value: {
311
+ name: "PATTERNS",
312
+ section: PATTERNS_CONST_SECTION,
313
+ },
314
+ },
315
+ {
316
+ interface: {
317
+ name: "WorkspaceBindingSourceConfig",
318
+ section: BINDING_SOURCES_INTERFACE_SECTION,
319
+ },
320
+ parse: {
321
+ entriesKey: "bindingSources",
322
+ entry: defineInventoryEntryParser({
323
+ entryName: "BINDING_SOURCES",
324
+ fields: [
325
+ { key: "attribute" },
326
+ { key: "block" },
327
+ { key: "editorFile", required: true },
328
+ { key: "serverFile", required: true },
329
+ { key: "slug", required: true },
330
+ ],
331
+ }),
332
+ hasSectionKey: "hasBindingSourcesSection",
333
+ },
334
+ value: {
335
+ name: "BINDING_SOURCES",
336
+ section: BINDING_SOURCES_CONST_SECTION,
337
+ },
338
+ },
339
+ {
340
+ interface: {
341
+ name: "WorkspaceRestResourceConfig",
342
+ section: REST_RESOURCES_INTERFACE_SECTION,
343
+ },
344
+ parse: {
345
+ entriesKey: "restResources",
346
+ entry: defineInventoryEntryParser({
347
+ entryName: "REST_RESOURCES",
348
+ fields: [
349
+ { key: "apiFile", required: true },
350
+ { key: "clientFile", required: true },
351
+ { key: "dataFile", required: true },
352
+ {
353
+ key: "methods",
354
+ kind: "stringArray",
355
+ required: true,
356
+ validate: (value, context) => {
357
+ const methods = Array.isArray(value) ? value : [];
358
+ const invalidMethods = methods.filter((method) => !REST_RESOURCE_METHOD_IDS.includes(method));
359
+ if (invalidMethods.length > 0) {
360
+ throw new Error(`${context.entryName}[${context.elementIndex}].${context.key} includes unsupported values: ${invalidMethods.join(", ")}.`);
361
+ }
362
+ },
363
+ },
364
+ { key: "namespace", required: true },
365
+ { key: "openApiFile", required: true },
366
+ { key: "phpFile", required: true },
367
+ { key: "slug", required: true },
368
+ { key: "typesFile", required: true },
369
+ { key: "validatorsFile", required: true },
370
+ ],
371
+ }),
372
+ hasSectionKey: "hasRestResourcesSection",
373
+ },
374
+ value: {
375
+ name: "REST_RESOURCES",
376
+ section: REST_RESOURCES_CONST_SECTION,
377
+ },
378
+ },
379
+ {
380
+ interface: {
381
+ name: "WorkspaceAbilityConfig",
382
+ section: ABILITIES_INTERFACE_SECTION,
383
+ },
384
+ parse: {
385
+ entriesKey: "abilities",
386
+ entry: defineInventoryEntryParser({
387
+ entryName: "ABILITIES",
388
+ fields: [
389
+ { key: "clientFile", required: true },
390
+ { key: "configFile", required: true },
391
+ { key: "dataFile", required: true },
392
+ { key: "inputSchemaFile", required: true },
393
+ { key: "inputTypeName", required: true },
394
+ { key: "outputSchemaFile", required: true },
395
+ { key: "outputTypeName", required: true },
396
+ { key: "phpFile", required: true },
397
+ { key: "slug", required: true },
398
+ { key: "typesFile", required: true },
399
+ ],
400
+ }),
401
+ hasSectionKey: "hasAbilitiesSection",
402
+ },
403
+ value: {
404
+ name: "ABILITIES",
405
+ section: ABILITIES_CONST_SECTION,
406
+ },
407
+ },
408
+ {
409
+ interface: {
410
+ name: "WorkspaceAiFeatureConfig",
411
+ section: AI_FEATURES_INTERFACE_SECTION,
412
+ },
413
+ parse: {
414
+ entriesKey: "aiFeatures",
415
+ entry: defineInventoryEntryParser({
416
+ entryName: "AI_FEATURES",
417
+ fields: [
418
+ { key: "aiSchemaFile", required: true },
419
+ { key: "apiFile", required: true },
420
+ { key: "clientFile", required: true },
421
+ { key: "dataFile", required: true },
422
+ { key: "namespace", required: true },
423
+ { key: "openApiFile", required: true },
424
+ { key: "phpFile", required: true },
425
+ { key: "slug", required: true },
426
+ { key: "typesFile", required: true },
427
+ { key: "validatorsFile", required: true },
428
+ ],
429
+ }),
430
+ hasSectionKey: "hasAiFeaturesSection",
431
+ },
432
+ value: {
433
+ name: "AI_FEATURES",
434
+ section: AI_FEATURES_CONST_SECTION,
435
+ },
436
+ },
437
+ {
438
+ interface: {
439
+ name: "WorkspaceAdminViewConfig",
440
+ section: ADMIN_VIEWS_INTERFACE_SECTION,
441
+ },
442
+ parse: {
443
+ entriesKey: "adminViews",
444
+ entry: defineInventoryEntryParser({
445
+ entryName: "ADMIN_VIEWS",
446
+ fields: [
447
+ { key: "file", required: true },
448
+ { key: "phpFile", required: true },
449
+ { key: "slug", required: true },
450
+ { key: "source" },
451
+ ],
452
+ }),
453
+ hasSectionKey: "hasAdminViewsSection",
454
+ },
455
+ value: {
456
+ name: "ADMIN_VIEWS",
457
+ section: ADMIN_VIEWS_CONST_SECTION,
458
+ },
459
+ },
460
+ {
461
+ interface: {
462
+ name: "WorkspaceEditorPluginConfig",
463
+ section: EDITOR_PLUGINS_INTERFACE_SECTION,
464
+ },
465
+ parse: {
466
+ entriesKey: "editorPlugins",
467
+ entry: defineInventoryEntryParser({
468
+ entryName: "EDITOR_PLUGINS",
469
+ fields: [
470
+ { key: "file", required: true },
471
+ { key: "slug", required: true },
472
+ { key: "slot", required: true },
473
+ ],
474
+ }),
475
+ hasSectionKey: "hasEditorPluginsSection",
476
+ },
477
+ value: {
478
+ name: "EDITOR_PLUGINS",
479
+ section: EDITOR_PLUGINS_CONST_SECTION,
480
+ },
481
+ },
482
+ ];
205
483
  function getPropertyNameText(name) {
206
484
  if (ts.isIdentifier(name) || ts.isStringLiteral(name)) {
207
485
  return name.text;
@@ -281,169 +559,60 @@ function getRequiredStringArrayProperty(entryName, elementIndex, objectLiteral,
281
559
  }
282
560
  throw new Error(`${entryName}[${elementIndex}] is missing required "${key}" in scripts/block-config.ts.`);
283
561
  }
284
- function parseBlockEntries(arrayLiteral) {
285
- return arrayLiteral.elements.map((element, elementIndex) => {
286
- if (!ts.isObjectLiteralExpression(element)) {
287
- throw new Error(`BLOCKS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
288
- }
289
- return {
290
- apiTypesFile: getOptionalStringProperty("BLOCKS", elementIndex, element, "apiTypesFile"),
291
- attributeTypeName: getOptionalStringProperty("BLOCKS", elementIndex, element, "attributeTypeName"),
292
- openApiFile: getOptionalStringProperty("BLOCKS", elementIndex, element, "openApiFile"),
293
- slug: getRequiredStringProperty("BLOCKS", elementIndex, element, "slug"),
294
- typesFile: getRequiredStringProperty("BLOCKS", elementIndex, element, "typesFile"),
295
- };
296
- });
297
- }
298
- function parseVariationEntries(arrayLiteral) {
299
- return arrayLiteral.elements.map((element, elementIndex) => {
300
- if (!ts.isObjectLiteralExpression(element)) {
301
- throw new Error(`VARIATIONS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
302
- }
303
- return {
304
- block: getRequiredStringProperty("VARIATIONS", elementIndex, element, "block"),
305
- file: getRequiredStringProperty("VARIATIONS", elementIndex, element, "file"),
306
- slug: getRequiredStringProperty("VARIATIONS", elementIndex, element, "slug"),
307
- };
308
- });
309
- }
310
- function parseBlockStyleEntries(arrayLiteral) {
311
- return arrayLiteral.elements.map((element, elementIndex) => {
312
- if (!ts.isObjectLiteralExpression(element)) {
313
- throw new Error(`BLOCK_STYLES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
314
- }
315
- return {
316
- block: getRequiredStringProperty("BLOCK_STYLES", elementIndex, element, "block"),
317
- file: getRequiredStringProperty("BLOCK_STYLES", elementIndex, element, "file"),
318
- slug: getRequiredStringProperty("BLOCK_STYLES", elementIndex, element, "slug"),
319
- };
320
- });
321
- }
322
- function parseBlockTransformEntries(arrayLiteral) {
323
- return arrayLiteral.elements.map((element, elementIndex) => {
324
- if (!ts.isObjectLiteralExpression(element)) {
325
- throw new Error(`BLOCK_TRANSFORMS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
326
- }
327
- return {
328
- block: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "block"),
329
- file: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "file"),
330
- from: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "from"),
331
- slug: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "slug"),
332
- to: getRequiredStringProperty("BLOCK_TRANSFORMS", elementIndex, element, "to"),
333
- };
334
- });
335
- }
336
- function parsePatternEntries(arrayLiteral) {
337
- return arrayLiteral.elements.map((element, elementIndex) => {
338
- if (!ts.isObjectLiteralExpression(element)) {
339
- throw new Error(`PATTERNS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
340
- }
341
- return {
342
- file: getRequiredStringProperty("PATTERNS", elementIndex, element, "file"),
343
- slug: getRequiredStringProperty("PATTERNS", elementIndex, element, "slug"),
344
- };
345
- });
346
- }
347
- function parseBindingSourceEntries(arrayLiteral) {
348
- return arrayLiteral.elements.map((element, elementIndex) => {
349
- if (!ts.isObjectLiteralExpression(element)) {
350
- throw new Error(`BINDING_SOURCES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
351
- }
352
- return {
353
- attribute: getOptionalStringProperty("BINDING_SOURCES", elementIndex, element, "attribute"),
354
- block: getOptionalStringProperty("BINDING_SOURCES", elementIndex, element, "block"),
355
- editorFile: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "editorFile"),
356
- serverFile: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "serverFile"),
357
- slug: getRequiredStringProperty("BINDING_SOURCES", elementIndex, element, "slug"),
358
- };
359
- });
360
- }
361
- function parseRestResourceEntries(arrayLiteral) {
562
+ function parseInventoryEntries(arrayLiteral, descriptor) {
362
563
  return arrayLiteral.elements.map((element, elementIndex) => {
363
564
  if (!ts.isObjectLiteralExpression(element)) {
364
- throw new Error(`REST_RESOURCES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
565
+ throw new Error(`${descriptor.entryName}[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
365
566
  }
366
- const methods = getRequiredStringArrayProperty("REST_RESOURCES", elementIndex, element, "methods");
367
- const invalidMethods = methods.filter((method) => !REST_RESOURCE_METHOD_IDS.includes(method));
368
- if (invalidMethods.length > 0) {
369
- throw new Error(`REST_RESOURCES[${elementIndex}].methods includes unsupported values: ${invalidMethods.join(", ")}.`);
370
- }
371
- return {
372
- apiFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "apiFile"),
373
- clientFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "clientFile"),
374
- dataFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "dataFile"),
375
- methods,
376
- namespace: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "namespace"),
377
- openApiFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "openApiFile"),
378
- phpFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "phpFile"),
379
- slug: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "slug"),
380
- typesFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "typesFile"),
381
- validatorsFile: getRequiredStringProperty("REST_RESOURCES", elementIndex, element, "validatorsFile"),
382
- };
383
- });
384
- }
385
- function parseAiFeatureEntries(arrayLiteral) {
386
- return arrayLiteral.elements.map((element, elementIndex) => {
387
- if (!ts.isObjectLiteralExpression(element)) {
388
- throw new Error(`AI_FEATURES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
567
+ const entry = {};
568
+ for (const field of descriptor.fields) {
569
+ const kind = field.kind ?? "string";
570
+ const value = kind === "stringArray"
571
+ ? getRequiredStringArrayProperty(descriptor.entryName, elementIndex, element, field.key)
572
+ : field.required
573
+ ? getRequiredStringProperty(descriptor.entryName, elementIndex, element, field.key)
574
+ : getOptionalStringProperty(descriptor.entryName, elementIndex, element, field.key);
575
+ field.validate?.(value, {
576
+ elementIndex,
577
+ entryName: descriptor.entryName,
578
+ key: field.key,
579
+ });
580
+ entry[field.key] = value;
389
581
  }
390
- return {
391
- aiSchemaFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "aiSchemaFile"),
392
- apiFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "apiFile"),
393
- clientFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "clientFile"),
394
- dataFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "dataFile"),
395
- namespace: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "namespace"),
396
- openApiFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "openApiFile"),
397
- phpFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "phpFile"),
398
- slug: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "slug"),
399
- typesFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "typesFile"),
400
- validatorsFile: getRequiredStringProperty("AI_FEATURES", elementIndex, element, "validatorsFile"),
401
- };
582
+ return entry;
402
583
  });
403
584
  }
404
- function parseAbilityEntries(arrayLiteral) {
405
- return arrayLiteral.elements.map((element, elementIndex) => {
406
- if (!ts.isObjectLiteralExpression(element)) {
407
- throw new Error(`ABILITIES[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
408
- }
585
+ function parseInventorySection(sourceFile, descriptor) {
586
+ if (!descriptor.parse) {
409
587
  return {
410
- clientFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "clientFile"),
411
- configFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "configFile"),
412
- dataFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "dataFile"),
413
- inputSchemaFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "inputSchemaFile"),
414
- inputTypeName: getRequiredStringProperty("ABILITIES", elementIndex, element, "inputTypeName"),
415
- outputSchemaFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "outputSchemaFile"),
416
- outputTypeName: getRequiredStringProperty("ABILITIES", elementIndex, element, "outputTypeName"),
417
- phpFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "phpFile"),
418
- slug: getRequiredStringProperty("ABILITIES", elementIndex, element, "slug"),
419
- typesFile: getRequiredStringProperty("ABILITIES", elementIndex, element, "typesFile"),
588
+ entries: [],
589
+ found: false,
420
590
  };
421
- });
422
- }
423
- function parseEditorPluginEntries(arrayLiteral) {
424
- return arrayLiteral.elements.map((element, elementIndex) => {
425
- if (!ts.isObjectLiteralExpression(element)) {
426
- throw new Error(`EDITOR_PLUGINS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
591
+ }
592
+ const exportName = descriptor.parse.exportName ?? descriptor.value?.name;
593
+ if (!exportName) {
594
+ throw new Error("Inventory parser descriptor is missing an export name.");
595
+ }
596
+ const exportedArray = findExportedArrayLiteral(sourceFile, exportName);
597
+ if (!exportedArray.found) {
598
+ if (descriptor.parse.required) {
599
+ throw new Error(`scripts/block-config.ts must export a ${exportName} array.`);
427
600
  }
428
601
  return {
429
- file: getRequiredStringProperty("EDITOR_PLUGINS", elementIndex, element, "file"),
430
- slug: getRequiredStringProperty("EDITOR_PLUGINS", elementIndex, element, "slug"),
431
- slot: getRequiredStringProperty("EDITOR_PLUGINS", elementIndex, element, "slot"),
602
+ entries: [],
603
+ found: false,
432
604
  };
433
- });
434
- }
435
- function parseAdminViewEntries(arrayLiteral) {
436
- return arrayLiteral.elements.map((element, elementIndex) => {
437
- if (!ts.isObjectLiteralExpression(element)) {
438
- throw new Error(`ADMIN_VIEWS[${elementIndex}] must be an object literal in scripts/block-config.ts.`);
605
+ }
606
+ if (!exportedArray.array) {
607
+ if (descriptor.parse.required) {
608
+ throw new Error(`scripts/block-config.ts must export a ${exportName} array.`);
439
609
  }
440
- return {
441
- file: getRequiredStringProperty("ADMIN_VIEWS", elementIndex, element, "file"),
442
- phpFile: getRequiredStringProperty("ADMIN_VIEWS", elementIndex, element, "phpFile"),
443
- slug: getRequiredStringProperty("ADMIN_VIEWS", elementIndex, element, "slug"),
444
- source: getOptionalStringProperty("ADMIN_VIEWS", elementIndex, element, "source"),
445
- };
446
- });
610
+ throw new Error(`scripts/block-config.ts must export ${exportName} as an array literal.`);
611
+ }
612
+ return {
613
+ entries: parseInventoryEntries(exportedArray.array, descriptor.parse.entry),
614
+ found: true,
615
+ };
447
616
  }
448
617
  /**
449
618
  * Parse workspace inventory entries from the source of `scripts/block-config.ts`.
@@ -454,82 +623,42 @@ function parseAdminViewEntries(arrayLiteral) {
454
623
  */
455
624
  export function parseWorkspaceInventorySource(source) {
456
625
  const sourceFile = ts.createSourceFile("block-config.ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
457
- const blockArray = findExportedArrayLiteral(sourceFile, "BLOCKS");
458
- if (!blockArray.found || !blockArray.array) {
459
- throw new Error("scripts/block-config.ts must export a BLOCKS array.");
460
- }
461
- const variationArray = findExportedArrayLiteral(sourceFile, "VARIATIONS");
462
- const blockStyleArray = findExportedArrayLiteral(sourceFile, "BLOCK_STYLES");
463
- const blockTransformArray = findExportedArrayLiteral(sourceFile, "BLOCK_TRANSFORMS");
464
- const patternArray = findExportedArrayLiteral(sourceFile, "PATTERNS");
465
- const bindingSourceArray = findExportedArrayLiteral(sourceFile, "BINDING_SOURCES");
466
- const restResourceArray = findExportedArrayLiteral(sourceFile, "REST_RESOURCES");
467
- const abilityArray = findExportedArrayLiteral(sourceFile, "ABILITIES");
468
- const aiFeatureArray = findExportedArrayLiteral(sourceFile, "AI_FEATURES");
469
- const adminViewArray = findExportedArrayLiteral(sourceFile, "ADMIN_VIEWS");
470
- const editorPluginArray = findExportedArrayLiteral(sourceFile, "EDITOR_PLUGINS");
471
- if (variationArray.found && !variationArray.array) {
472
- throw new Error("scripts/block-config.ts must export VARIATIONS as an array literal.");
473
- }
474
- if (blockStyleArray.found && !blockStyleArray.array) {
475
- throw new Error("scripts/block-config.ts must export BLOCK_STYLES as an array literal.");
476
- }
477
- if (blockTransformArray.found && !blockTransformArray.array) {
478
- throw new Error("scripts/block-config.ts must export BLOCK_TRANSFORMS as an array literal.");
479
- }
480
- if (patternArray.found && !patternArray.array) {
481
- throw new Error("scripts/block-config.ts must export PATTERNS as an array literal.");
482
- }
483
- if (bindingSourceArray.found && !bindingSourceArray.array) {
484
- throw new Error("scripts/block-config.ts must export BINDING_SOURCES as an array literal.");
485
- }
486
- if (restResourceArray.found && !restResourceArray.array) {
487
- throw new Error("scripts/block-config.ts must export REST_RESOURCES as an array literal.");
488
- }
489
- if (abilityArray.found && !abilityArray.array) {
490
- throw new Error("scripts/block-config.ts must export ABILITIES as an array literal.");
491
- }
492
- if (aiFeatureArray.found && !aiFeatureArray.array) {
493
- throw new Error("scripts/block-config.ts must export AI_FEATURES as an array literal.");
494
- }
495
- if (adminViewArray.found && !adminViewArray.array) {
496
- throw new Error("scripts/block-config.ts must export ADMIN_VIEWS as an array literal.");
497
- }
498
- if (editorPluginArray.found && !editorPluginArray.array) {
499
- throw new Error("scripts/block-config.ts must export EDITOR_PLUGINS as an array literal.");
500
- }
501
- return {
502
- abilities: abilityArray.array ? parseAbilityEntries(abilityArray.array) : [],
503
- adminViews: adminViewArray.array ? parseAdminViewEntries(adminViewArray.array) : [],
504
- aiFeatures: aiFeatureArray.array ? parseAiFeatureEntries(aiFeatureArray.array) : [],
505
- bindingSources: bindingSourceArray.array
506
- ? parseBindingSourceEntries(bindingSourceArray.array)
507
- : [],
508
- blockStyles: blockStyleArray.array ? parseBlockStyleEntries(blockStyleArray.array) : [],
509
- blockTransforms: blockTransformArray.array
510
- ? parseBlockTransformEntries(blockTransformArray.array)
511
- : [],
512
- blocks: parseBlockEntries(blockArray.array),
513
- hasAbilitiesSection: abilityArray.found,
514
- hasAdminViewsSection: adminViewArray.found,
515
- hasAiFeaturesSection: aiFeatureArray.found,
516
- hasBindingSourcesSection: bindingSourceArray.found,
517
- hasBlockStylesSection: blockStyleArray.found,
518
- hasBlockTransformsSection: blockTransformArray.found,
519
- hasEditorPluginsSection: editorPluginArray.found,
520
- hasPatternsSection: patternArray.found,
521
- hasRestResourcesSection: restResourceArray.found,
522
- hasVariationsSection: variationArray.found,
523
- editorPlugins: editorPluginArray.array
524
- ? parseEditorPluginEntries(editorPluginArray.array)
525
- : [],
526
- patterns: patternArray.array ? parsePatternEntries(patternArray.array) : [],
527
- restResources: restResourceArray.array
528
- ? parseRestResourceEntries(restResourceArray.array)
529
- : [],
626
+ const parsedInventory = {
627
+ abilities: [],
628
+ adminViews: [],
629
+ aiFeatures: [],
630
+ bindingSources: [],
631
+ blockStyles: [],
632
+ blockTransforms: [],
633
+ blocks: parseInventorySection(sourceFile, BLOCK_INVENTORY_SECTION).entries,
634
+ editorPlugins: [],
635
+ hasAbilitiesSection: false,
636
+ hasAdminViewsSection: false,
637
+ hasAiFeaturesSection: false,
638
+ hasBindingSourcesSection: false,
639
+ hasBlockStylesSection: false,
640
+ hasBlockTransformsSection: false,
641
+ hasEditorPluginsSection: false,
642
+ hasPatternsSection: false,
643
+ hasRestResourcesSection: false,
644
+ hasVariationsSection: false,
645
+ patterns: [],
646
+ restResources: [],
530
647
  source,
531
- variations: variationArray.array ? parseVariationEntries(variationArray.array) : [],
648
+ variations: [],
532
649
  };
650
+ const mutableInventory = parsedInventory;
651
+ for (const section of INVENTORY_SECTIONS) {
652
+ if (!section.parse) {
653
+ continue;
654
+ }
655
+ const parsedSection = parseInventorySection(sourceFile, section);
656
+ mutableInventory[section.parse.entriesKey] = parsedSection.entries;
657
+ if (section.parse.hasSectionKey) {
658
+ mutableInventory[section.parse.hasSectionKey] = parsedSection.found;
659
+ }
660
+ }
661
+ return parsedInventory;
533
662
  }
534
663
  /**
535
664
  * Read and parse the canonical workspace inventory file.
@@ -576,68 +705,23 @@ export function getWorkspaceBlockSelectOptions(projectDir) {
576
705
  }
577
706
  function ensureWorkspaceInventorySections(source) {
578
707
  let nextSource = source.trimEnd();
579
- if (!/export\s+interface\s+WorkspaceVariationConfig\b/u.test(nextSource)) {
580
- nextSource += VARIATIONS_INTERFACE_SECTION;
581
- }
582
- if (!/export\s+const\s+VARIATIONS\b/u.test(nextSource)) {
583
- nextSource += VARIATIONS_CONST_SECTION;
584
- }
585
- if (!/export\s+interface\s+WorkspaceBlockStyleConfig\b/u.test(nextSource)) {
586
- nextSource += BLOCK_STYLES_INTERFACE_SECTION;
587
- }
588
- if (!/export\s+const\s+BLOCK_STYLES\b/u.test(nextSource)) {
589
- nextSource += BLOCK_STYLES_CONST_SECTION;
590
- }
591
- if (!/export\s+interface\s+WorkspaceBlockTransformConfig\b/u.test(nextSource)) {
592
- nextSource += BLOCK_TRANSFORMS_INTERFACE_SECTION;
593
- }
594
- if (!/export\s+const\s+BLOCK_TRANSFORMS\b/u.test(nextSource)) {
595
- nextSource += BLOCK_TRANSFORMS_CONST_SECTION;
596
- }
597
- if (!/export\s+interface\s+WorkspacePatternConfig\b/u.test(nextSource)) {
598
- nextSource += PATTERNS_INTERFACE_SECTION;
599
- }
600
- if (!/export\s+const\s+PATTERNS\b/u.test(nextSource)) {
601
- nextSource += PATTERNS_CONST_SECTION;
602
- }
603
- if (!/export\s+interface\s+WorkspaceBindingSourceConfig\b/u.test(nextSource)) {
604
- nextSource += BINDING_SOURCES_INTERFACE_SECTION;
605
- }
606
- if (!/export\s+const\s+BINDING_SOURCES\b/u.test(nextSource)) {
607
- nextSource += BINDING_SOURCES_CONST_SECTION;
608
- }
609
- if (!/export\s+interface\s+WorkspaceRestResourceConfig\b/u.test(nextSource)) {
610
- nextSource += REST_RESOURCES_INTERFACE_SECTION;
611
- }
612
- if (!/export\s+const\s+REST_RESOURCES\b/u.test(nextSource)) {
613
- nextSource += REST_RESOURCES_CONST_SECTION;
614
- }
615
- if (!/export\s+interface\s+WorkspaceAbilityConfig\b/u.test(nextSource)) {
616
- nextSource += ABILITIES_INTERFACE_SECTION;
617
- }
618
- if (!/export\s+const\s+ABILITIES\b/u.test(nextSource)) {
619
- nextSource += ABILITIES_CONST_SECTION;
620
- }
621
- if (!/export\s+interface\s+WorkspaceAiFeatureConfig\b/u.test(nextSource)) {
622
- nextSource += AI_FEATURES_INTERFACE_SECTION;
623
- }
624
- if (!/export\s+const\s+AI_FEATURES\b/u.test(nextSource)) {
625
- nextSource += AI_FEATURES_CONST_SECTION;
626
- }
627
- if (!/export\s+interface\s+WorkspaceAdminViewConfig\b/u.test(nextSource)) {
628
- nextSource += ADMIN_VIEWS_INTERFACE_SECTION;
629
- }
630
- if (!/export\s+const\s+ADMIN_VIEWS\b/u.test(nextSource)) {
631
- nextSource += ADMIN_VIEWS_CONST_SECTION;
632
- }
633
- if (!/export\s+interface\s+WorkspaceEditorPluginConfig\b/u.test(nextSource)) {
634
- nextSource += EDITOR_PLUGINS_INTERFACE_SECTION;
635
- }
636
- if (!/export\s+const\s+EDITOR_PLUGINS\b/u.test(nextSource)) {
637
- nextSource += EDITOR_PLUGINS_CONST_SECTION;
708
+ for (const section of INVENTORY_SECTIONS) {
709
+ if (section.interface &&
710
+ !hasExportedInterface(nextSource, section.interface.name)) {
711
+ nextSource += section.interface.section;
712
+ }
713
+ if (section.value && !hasExportedConst(nextSource, section.value.name)) {
714
+ nextSource += section.value.section;
715
+ }
638
716
  }
639
717
  return `${nextSource}\n`;
640
718
  }
719
+ function hasExportedInterface(source, interfaceName) {
720
+ return new RegExp(`export\\s+interface\\s+${escapeRegex(interfaceName)}\\b`, "u").test(source);
721
+ }
722
+ function hasExportedConst(source, constName) {
723
+ return new RegExp(`export\\s+const\\s+${escapeRegex(constName)}\\b`, "u").test(source);
724
+ }
641
725
  function appendEntriesAtMarker(source, marker, entries) {
642
726
  if (entries.length === 0) {
643
727
  return source;