@wp-typia/project-tools 0.18.0 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/dist/runtime/alternate-render-targets.d.ts +5 -0
  2. package/dist/runtime/alternate-render-targets.js +29 -0
  3. package/dist/runtime/block-generator-service-core.d.ts +1 -1
  4. package/dist/runtime/block-generator-service-core.js +11 -7
  5. package/dist/runtime/block-generator-service-spec.d.ts +8 -1
  6. package/dist/runtime/block-generator-service-spec.js +248 -2
  7. package/dist/runtime/built-in-block-artifacts.js +3 -1
  8. package/dist/runtime/built-in-block-code-artifacts.js +3 -1
  9. package/dist/runtime/built-in-block-code-templates/compound-child.d.ts +1 -1
  10. package/dist/runtime/built-in-block-code-templates/compound-child.js +14 -9
  11. package/dist/runtime/built-in-block-code-templates/compound-parent.d.ts +2 -2
  12. package/dist/runtime/built-in-block-code-templates/compound-parent.js +100 -43
  13. package/dist/runtime/built-in-block-code-templates/compound-persistence.d.ts +1 -1
  14. package/dist/runtime/built-in-block-code-templates/compound-persistence.js +11 -8
  15. package/dist/runtime/built-in-block-non-ts-artifacts.js +505 -2
  16. package/dist/runtime/cli-add-block.d.ts +4 -1
  17. package/dist/runtime/cli-add-block.js +66 -31
  18. package/dist/runtime/cli-add-shared.d.ts +3 -1
  19. package/dist/runtime/cli-add-shared.js +12 -12
  20. package/dist/runtime/cli-core.d.ts +2 -0
  21. package/dist/runtime/cli-core.js +1 -0
  22. package/dist/runtime/cli-diagnostics.d.ts +26 -0
  23. package/dist/runtime/cli-diagnostics.js +107 -0
  24. package/dist/runtime/cli-doctor-workspace.js +4 -4
  25. package/dist/runtime/cli-help.js +4 -3
  26. package/dist/runtime/cli-scaffold.d.ts +3 -1
  27. package/dist/runtime/cli-scaffold.js +91 -15
  28. package/dist/runtime/cli-templates.js +26 -1
  29. package/dist/runtime/cli-validation.d.ts +66 -0
  30. package/dist/runtime/cli-validation.js +92 -0
  31. package/dist/runtime/compound-inner-blocks.d.ts +78 -0
  32. package/dist/runtime/compound-inner-blocks.js +88 -0
  33. package/dist/runtime/index.d.ts +5 -1
  34. package/dist/runtime/index.js +3 -1
  35. package/dist/runtime/migration-command-surface.js +2 -0
  36. package/dist/runtime/package-versions.d.ts +1 -0
  37. package/dist/runtime/package-versions.js +12 -0
  38. package/dist/runtime/scaffold-answer-resolution.js +10 -6
  39. package/dist/runtime/scaffold-bootstrap.js +5 -1
  40. package/dist/runtime/scaffold-documents.js +29 -6
  41. package/dist/runtime/scaffold-identifiers.d.ts +17 -0
  42. package/dist/runtime/scaffold-identifiers.js +22 -0
  43. package/dist/runtime/scaffold-onboarding.js +21 -13
  44. package/dist/runtime/scaffold-template-variable-groups.d.ts +154 -0
  45. package/dist/runtime/scaffold-template-variable-groups.js +13 -0
  46. package/dist/runtime/scaffold-template-variables.js +80 -1
  47. package/dist/runtime/scaffold.d.ts +21 -2
  48. package/dist/runtime/scaffold.js +12 -5
  49. package/dist/runtime/temp-roots.d.ts +44 -0
  50. package/dist/runtime/temp-roots.js +129 -0
  51. package/dist/runtime/template-builtins.js +4 -6
  52. package/dist/runtime/template-registry.d.ts +8 -0
  53. package/dist/runtime/template-registry.js +34 -1
  54. package/dist/runtime/template-source-external.d.ts +1 -0
  55. package/dist/runtime/template-source-external.js +4 -7
  56. package/dist/runtime/template-source-remote.js +44 -23
  57. package/dist/runtime/template-source-seeds.js +3 -9
  58. package/dist/runtime/template-source.d.ts +2 -3
  59. package/dist/runtime/template-source.js +13 -5
  60. package/dist/runtime/workspace-project.js +1 -1
  61. package/package.json +12 -2
  62. package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +318 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wp-typia/project-tools",
3
- "version": "0.18.0",
3
+ "version": "0.19.1",
4
4
  "description": "Project orchestration and programmatic tooling for wp-typia",
5
5
  "packageManager": "bun@1.3.11",
6
6
  "type": "module",
@@ -37,6 +37,11 @@
37
37
  "import": "./dist/runtime/cli-scaffold.js",
38
38
  "default": "./dist/runtime/cli-scaffold.js"
39
39
  },
40
+ "./compound-inner-blocks": {
41
+ "types": "./dist/runtime/compound-inner-blocks.d.ts",
42
+ "import": "./dist/runtime/compound-inner-blocks.js",
43
+ "default": "./dist/runtime/compound-inner-blocks.js"
44
+ },
40
45
  "./cli-templates": {
41
46
  "types": "./dist/runtime/cli-templates.d.ts",
42
47
  "import": "./dist/runtime/cli-templates.js",
@@ -62,6 +67,11 @@
62
67
  "import": "./dist/runtime/schema-core.js",
63
68
  "default": "./dist/runtime/schema-core.js"
64
69
  },
70
+ "./temp-roots": {
71
+ "types": "./dist/runtime/temp-roots.d.ts",
72
+ "import": "./dist/runtime/temp-roots.js",
73
+ "default": "./dist/runtime/temp-roots.js"
74
+ },
65
75
  "./workspace-project": {
66
76
  "types": "./dist/runtime/workspace-project.d.ts",
67
77
  "import": "./dist/runtime/workspace-project.js",
@@ -86,7 +96,7 @@
86
96
  "test:migration-planning": "bun run build && bun test tests/migration-init.test.ts tests/migration-config.test.ts tests/migration-plan-wizard.test.ts",
87
97
  "test:migration-execution": "bun run build && bun test tests/migration-scaffold-diff.test.ts tests/migration-doctor.test.ts tests/migration-fixtures-fuzz.test.ts",
88
98
  "test:project-tools": "bun run test:scaffold-core && bun run test:workspace && bun run test:compound && bun run test:migration-planning && bun run test:migration-execution",
89
- "test:coverage": "bun run build && bun test tests/*.test.ts --coverage --coverage-reporter=lcov --coverage-dir=coverage",
99
+ "test:coverage": "bun run build && bun run --filter wp-typia build && bun test tests/*.test.ts --coverage --coverage-reporter=lcov --coverage-dir=coverage",
90
100
  "clean": "rm -rf dist",
91
101
  "prepublishOnly": "bun run build"
92
102
  },
@@ -28,25 +28,45 @@ type CompoundParentConfig = {
28
28
  };
29
29
 
30
30
  type ExistingCompoundChild = {
31
+ ancestorBlockNames: string[];
31
32
  blockJsonPath: string;
32
33
  blockName: string;
34
+ container: boolean;
35
+ directAllowedBlocks: string[];
33
36
  folderSlug: string;
34
37
  key: string;
38
+ parentBlockNames: string[];
39
+ placement: 'nested' | 'root';
40
+ supportsInserter: boolean;
41
+ title: string;
35
42
  };
36
43
 
37
44
  type ParsedArgs = {
38
45
  ancestorValues: string[];
39
46
  container: boolean;
47
+ dryRun: boolean;
40
48
  inserter?: 'hidden' | 'visible';
41
49
  slug?: string;
42
50
  title?: string;
43
51
  };
44
52
 
53
+ type CompoundChildGraphNode = {
54
+ blockName: string;
55
+ container: boolean;
56
+ directParentBlockName: string;
57
+ isProspective: boolean;
58
+ key: string;
59
+ placement: 'nested' | 'root';
60
+ supportsInserter: boolean;
61
+ title: string;
62
+ };
63
+
45
64
  function parseArgs() {
46
65
  const args = process.argv.slice( 2 );
47
66
  const parsed: ParsedArgs = {
48
67
  ancestorValues: [],
49
68
  container: false,
69
+ dryRun: false,
50
70
  };
51
71
 
52
72
  for ( let index = 0; index < args.length; index += 1 ) {
@@ -86,6 +106,11 @@ function parseArgs() {
86
106
  continue;
87
107
  }
88
108
 
109
+ if ( arg === '--dry-run' ) {
110
+ parsed.dryRun = true;
111
+ continue;
112
+ }
113
+
89
114
  if ( arg === '--inserter' ) {
90
115
  const value = args[ index + 1 ];
91
116
  if ( value !== 'hidden' && value !== 'visible' ) {
@@ -95,6 +120,10 @@ function parseArgs() {
95
120
  index += 1;
96
121
  continue;
97
122
  }
123
+
124
+ if ( arg.startsWith( '--' ) ) {
125
+ throw new Error( `Unknown option: ${ arg }.` );
126
+ }
98
127
  }
99
128
 
100
129
  return parsed;
@@ -395,16 +424,149 @@ function listExistingCompoundChildren(): ExistingCompoundChild[] {
395
424
  return null;
396
425
  }
397
426
 
427
+ const ancestorBlockNames = Array.isArray( blockJson.ancestor )
428
+ ? blockJson.ancestor.filter(
429
+ ( value ): value is string => typeof value === 'string'
430
+ )
431
+ : [];
432
+ const parentBlockNames = Array.isArray( blockJson.parent )
433
+ ? blockJson.parent.filter(
434
+ ( value ): value is string => typeof value === 'string'
435
+ )
436
+ : [];
437
+ const directAllowedBlocks = Array.isArray( blockJson.allowedBlocks )
438
+ ? blockJson.allowedBlocks.filter(
439
+ ( value ): value is string => typeof value === 'string'
440
+ )
441
+ : [];
442
+ const supports =
443
+ typeof blockJson.supports === 'object' &&
444
+ blockJson.supports &&
445
+ ! Array.isArray( blockJson.supports )
446
+ ? blockJson.supports
447
+ : null;
448
+ const supportsInserter =
449
+ supports && typeof supports.inserter === 'boolean'
450
+ ? supports.inserter
451
+ : true;
452
+ const title =
453
+ typeof blockJson.title === 'string' &&
454
+ blockJson.title.trim().length > 0
455
+ ? blockJson.title.trim()
456
+ : toTitleCase( deriveChildKey( folderSlug ) );
457
+
398
458
  return {
459
+ ancestorBlockNames,
399
460
  blockJsonPath,
400
461
  blockName,
462
+ container: Object.prototype.hasOwnProperty.call(
463
+ blockJson,
464
+ 'allowedBlocks'
465
+ ),
466
+ directAllowedBlocks,
401
467
  folderSlug,
402
468
  key: deriveChildKey( folderSlug ),
469
+ parentBlockNames,
470
+ placement: ancestorBlockNames.length > 0 ? 'nested' : 'root',
471
+ supportsInserter,
472
+ title,
403
473
  } satisfies ExistingCompoundChild;
404
474
  } )
405
475
  .filter( ( child ): child is ExistingCompoundChild => child !== null );
406
476
  }
407
477
 
478
+ function buildCompoundChildGraphMap(
479
+ existingChildren: ExistingCompoundChild[]
480
+ ): Map< string, ExistingCompoundChild > {
481
+ return new Map(
482
+ existingChildren.map( ( child ) => [ child.blockName, child ] )
483
+ );
484
+ }
485
+
486
+ function resolveDirectParentBlockName( child: ExistingCompoundChild ): string {
487
+ return (
488
+ child.ancestorBlockNames[ child.ancestorBlockNames.length - 1 ] ??
489
+ child.parentBlockNames[ 0 ] ??
490
+ PARENT_BLOCK_NAME
491
+ );
492
+ }
493
+
494
+ function validateExistingCompoundChildGraph(
495
+ existingChildren: ExistingCompoundChild[]
496
+ ) {
497
+ const seenKeys = new Set< string >();
498
+ const seenBlockNames = new Set< string >();
499
+ const childByBlockName = buildCompoundChildGraphMap( existingChildren );
500
+
501
+ for ( const child of existingChildren ) {
502
+ if ( seenKeys.has( child.key ) ) {
503
+ throw new Error(
504
+ `Existing compound child graph is invalid: child key "${ child.key }" is declared more than once.`
505
+ );
506
+ }
507
+
508
+ if ( seenBlockNames.has( child.blockName ) ) {
509
+ throw new Error(
510
+ `Existing compound child graph is invalid: ${ child.blockName } is declared more than once.`
511
+ );
512
+ }
513
+
514
+ seenKeys.add( child.key );
515
+ seenBlockNames.add( child.blockName );
516
+
517
+ if ( child.ancestorBlockNames.length === 0 ) {
518
+ if ( child.parentBlockNames.length === 0 ) {
519
+ throw new Error(
520
+ `Existing compound child graph is invalid: ${ child.blockName } must declare a parent block.`
521
+ );
522
+ }
523
+ continue;
524
+ }
525
+
526
+ for ( let index = 0; index < child.ancestorBlockNames.length; index += 1 ) {
527
+ const ancestorBlockName = child.ancestorBlockNames[ index ];
528
+ const ancestorChild = childByBlockName.get( ancestorBlockName );
529
+
530
+ if ( ! ancestorChild ) {
531
+ throw new Error(
532
+ `Existing compound child graph is invalid: ${ child.blockName } references missing ancestor ${ ancestorBlockName }.`
533
+ );
534
+ }
535
+
536
+ if ( ! ancestorChild.container ) {
537
+ throw new Error(
538
+ `Existing compound child graph is invalid: ${ ancestorChild.blockName } is not declared as a container child but has nested descendants.`
539
+ );
540
+ }
541
+
542
+ const expectedAncestorRoute = child.ancestorBlockNames.slice( 0, index );
543
+ const ancestorRouteMatches =
544
+ ancestorChild.ancestorBlockNames.length === expectedAncestorRoute.length &&
545
+ expectedAncestorRoute.every(
546
+ ( expectedAncestorBlockName, expectedIndex ) =>
547
+ ancestorChild.ancestorBlockNames[ expectedIndex ] ===
548
+ expectedAncestorBlockName
549
+ );
550
+
551
+ if ( ! ancestorRouteMatches ) {
552
+ throw new Error(
553
+ `Existing compound child graph is invalid: ${ ancestorChild.blockName } is not on the declared ancestor route for ${ child.blockName }.`
554
+ );
555
+ }
556
+
557
+ const nextBlockName =
558
+ child.ancestorBlockNames[ index + 1 ] ?? child.blockName;
559
+ if ( ancestorChild.directAllowedBlocks.includes( nextBlockName ) ) {
560
+ continue;
561
+ }
562
+
563
+ throw new Error(
564
+ `Existing compound child graph is invalid: ${ ancestorChild.blockName } does not currently allow ${ nextBlockName } as a direct child.`
565
+ );
566
+ }
567
+ }
568
+ }
569
+
408
570
  function resolveExistingCompoundChild(
409
571
  value: string,
410
572
  existingChildren: ExistingCompoundChild[]
@@ -457,14 +619,8 @@ function validateAncestorChain(
457
619
  for ( let index = 0; index < ancestorChain.length - 1; index += 1 ) {
458
620
  const currentAncestor = ancestorChain[ index ];
459
621
  const nextAncestor = ancestorChain[ index + 1 ];
460
- const blockJson = readBlockJsonDocument( currentAncestor.blockJsonPath );
461
- const allowedBlocks = Array.isArray( blockJson.allowedBlocks )
462
- ? blockJson.allowedBlocks.filter(
463
- ( value ): value is string => typeof value === 'string'
464
- )
465
- : [];
466
-
467
- if ( allowedBlocks.includes( nextAncestor.blockName ) ) {
622
+
623
+ if ( currentAncestor.directAllowedBlocks.includes( nextAncestor.blockName ) ) {
468
624
  continue;
469
625
  }
470
626
 
@@ -474,6 +630,22 @@ function validateAncestorChain(
474
630
  }
475
631
  }
476
632
 
633
+ function validateNestedAncestorTarget( ancestorChain: ExistingCompoundChild[] ) {
634
+ const directAncestor = ancestorChain[ ancestorChain.length - 1 ];
635
+
636
+ if ( ! directAncestor ) {
637
+ return;
638
+ }
639
+
640
+ if ( directAncestor.container ) {
641
+ return;
642
+ }
643
+
644
+ throw new Error(
645
+ `Cannot nest descendants under ${ directAncestor.blockName } because it is not declared as a container child. Re-add that child with --container or target an existing container child.`
646
+ );
647
+ }
648
+
477
649
  function findCompoundChildSpecSource(
478
650
  childrenRegistrySource: string,
479
651
  childKey: string
@@ -528,6 +700,86 @@ function validateAncestorInstantiability(
528
700
  }
529
701
  }
530
702
 
703
+ function formatProjectRelativePath( filePath: string ): string {
704
+ return path.relative( PROJECT_ROOT, filePath ) || '.';
705
+ }
706
+
707
+ function buildCompoundChildGraphNodes(
708
+ existingChildren: ExistingCompoundChild[],
709
+ prospectiveChild: CompoundChildGraphNode
710
+ ): CompoundChildGraphNode[] {
711
+ return [
712
+ ...existingChildren.map( ( child ) => ( {
713
+ blockName: child.blockName,
714
+ container: child.container,
715
+ directParentBlockName: resolveDirectParentBlockName( child ),
716
+ isProspective: false,
717
+ key: child.key,
718
+ placement: child.placement,
719
+ supportsInserter: child.supportsInserter,
720
+ title: child.title,
721
+ } ) ),
722
+ prospectiveChild,
723
+ ];
724
+ }
725
+
726
+ function renderCompoundChildGraphPreview(
727
+ graphNodes: CompoundChildGraphNode[],
728
+ plannedWritePaths: string[],
729
+ options: {
730
+ dryRun: boolean;
731
+ }
732
+ ): string {
733
+ const childrenByParent = new Map< string, CompoundChildGraphNode[] >();
734
+
735
+ for ( const graphNode of graphNodes ) {
736
+ const existingChildren = childrenByParent.get( graphNode.directParentBlockName ) ?? [];
737
+ existingChildren.push( graphNode );
738
+ childrenByParent.set( graphNode.directParentBlockName, existingChildren );
739
+ }
740
+
741
+ const renderChildLines = (
742
+ parentBlockName: string,
743
+ indent: string
744
+ ): string[] => {
745
+ const directChildren = [ ...( childrenByParent.get( parentBlockName ) ?? [] ) ].sort(
746
+ ( left, right ) => left.key.localeCompare( right.key )
747
+ );
748
+
749
+ return directChildren.flatMap( ( child ) => {
750
+ const labels = [
751
+ child.isProspective ? 'new' : 'existing',
752
+ child.placement === 'root' ? 'root' : 'nested',
753
+ child.container ? 'container' : 'leaf',
754
+ child.supportsInserter ? 'visible' : 'hidden',
755
+ ];
756
+ const line = `${ indent }- ${ child.key } -> ${ child.blockName } [${ labels.join( ', ' ) }]`;
757
+ return [ line, ...renderChildLines( child.blockName, `${ indent } ` ) ];
758
+ } );
759
+ };
760
+
761
+ return [
762
+ 'Compound child graph preview',
763
+ `Parent block: ${ PARENT_BLOCK_NAME }`,
764
+ ...renderChildLines( PARENT_BLOCK_NAME, '' ),
765
+ '',
766
+ 'Planned writes',
767
+ ...plannedWritePaths.map( ( plannedWritePath ) => `- ${ plannedWritePath }` ),
768
+ options.dryRun ? '' : '',
769
+ options.dryRun
770
+ ? 'Dry run only; no files were written.'
771
+ : 'Applying these updates now.',
772
+ ]
773
+ .filter( ( line, index, lines ) => {
774
+ if ( line.length > 0 ) {
775
+ return true;
776
+ }
777
+
778
+ return index > 0 && lines[ index - 1 ].length > 0;
779
+ } )
780
+ .join( '\n' );
781
+ }
782
+
531
783
  function updateAllowedBlocks(
532
784
  filePath: string,
533
785
  blockName: string
@@ -756,8 +1008,7 @@ import { __ } from '@wordpress/i18n';
756
1008
 
757
1009
  import metadata from './block-metadata';
758
1010
  import {
759
- \tgetChildAllowedBlocks,
760
- \tgetChildTemplate,
1011
+ \tgetChildInnerBlocksPropsOptions,
761
1012
  \thasNestedChildBlocks,
762
1013
  } from '../${ PARENT_BLOCK_SLUG }/children';
763
1014
  import { useTypiaValidation } from './hooks';
@@ -768,6 +1019,14 @@ import {
768
1019
  } from './validators';
769
1020
 
770
1021
  type EditProps = BlockEditProps< ${ childTypeName } >;
1022
+ type CompoundInnerBlocksProps = Parameters< typeof InnerBlocks >[ 0 ] & {
1023
+ \tdefaultBlock?: [ string, Record< string, unknown > ];
1024
+ \tdirectInsert?: boolean;
1025
+ };
1026
+
1027
+ const TypedInnerBlocks = InnerBlocks as unknown as (
1028
+ \tprops: CompoundInnerBlocksProps
1029
+ ) => ReturnType< typeof InnerBlocks >;
771
1030
 
772
1031
  export default function Edit( {
773
1032
  \tattributes,
@@ -778,8 +1037,9 @@ export default function Edit( {
778
1037
  \t\tattributes,
779
1038
  \t\tvalidate${ childInterfaceName }
780
1039
  \t);
781
- \tconst nestedAllowedBlocks = getChildAllowedBlocks( metadata.name );
782
- \tconst nestedTemplate = getChildTemplate( metadata.name );
1040
+ \tconst nestedInnerBlocksPropsOptions = getChildInnerBlocksPropsOptions(
1041
+ \t\tmetadata.name
1042
+ \t);
783
1043
  \tconst showsNestedChildren = hasNestedChildBlocks( metadata.name );
784
1044
 
785
1045
  \treturn (
@@ -809,11 +1069,8 @@ export default function Edit( {
809
1069
  \t\t\t) }
810
1070
  \t\t\t{ showsNestedChildren && (
811
1071
  \t\t\t\t<div className="${ childCssClassName }__children">
812
- \t\t\t\t\t<InnerBlocks
813
- \t\t\t\t\t\tallowedBlocks={ nestedAllowedBlocks }
814
- \t\t\t\t\t\trenderAppender={ InnerBlocks.ButtonBlockAppender }
815
- \t\t\t\t\t\ttemplate={ nestedTemplate }
816
- \t\t\t\t\t\ttemplateLock={ false }
1072
+ \t\t\t\t\t<TypedInnerBlocks
1073
+ \t\t\t\t\t\t{ ...( nestedInnerBlocksPropsOptions ?? {} ) }
817
1074
  \t\t\t\t\t/>
818
1075
  \t\t\t\t</div>
819
1076
  \t\t\t) }
@@ -936,6 +1193,7 @@ function main() {
936
1193
  const {
937
1194
  ancestorValues,
938
1195
  container,
1196
+ dryRun,
939
1197
  inserter,
940
1198
  slug,
941
1199
  title,
@@ -947,6 +1205,7 @@ function main() {
947
1205
  }
948
1206
 
949
1207
  const existingChildren = listExistingCompoundChildren();
1208
+ validateExistingCompoundChildGraph( existingChildren );
950
1209
  const ancestorChain = ensureUniqueAncestorChain(
951
1210
  ancestorValues.map( ( value ) =>
952
1211
  resolveExistingCompoundChild( value, existingChildren )
@@ -984,7 +1243,7 @@ function main() {
984
1243
  }
985
1244
 
986
1245
  validateAncestorInstantiability( childrenFile, ancestorChain );
987
-
1246
+ validateNestedAncestorTarget( ancestorChain );
988
1247
  const supportsInserter =
989
1248
  inserter === 'visible'
990
1249
  ? true
@@ -994,6 +1253,47 @@ function main() {
994
1253
  const placement = ancestorChain.length > 0 ? 'nested' : 'root';
995
1254
  const seedTemplate = supportsInserter || container || ancestorChain.length > 0;
996
1255
  const directAllowedBlocks: string[] = [];
1256
+ const directAncestor = ancestorChain[ ancestorChain.length - 1 ];
1257
+ const plannedWritePaths = [
1258
+ formatProjectRelativePath( path.join( childDir, 'block.json' ) ),
1259
+ formatProjectRelativePath( path.join( childDir, 'types.ts' ) ),
1260
+ formatProjectRelativePath( path.join( childDir, 'typia.manifest.json' ) ),
1261
+ formatProjectRelativePath( path.join( childDir, 'block-metadata.ts' ) ),
1262
+ formatProjectRelativePath( path.join( childDir, 'manifest-document.ts' ) ),
1263
+ formatProjectRelativePath( path.join( childDir, 'manifest-defaults-document.ts' ) ),
1264
+ formatProjectRelativePath( path.join( childDir, 'hooks.ts' ) ),
1265
+ formatProjectRelativePath( path.join( childDir, 'validators.ts' ) ),
1266
+ formatProjectRelativePath( path.join( childDir, 'edit.tsx' ) ),
1267
+ formatProjectRelativePath( path.join( childDir, 'save.tsx' ) ),
1268
+ formatProjectRelativePath( path.join( childDir, 'index.tsx' ) ),
1269
+ formatProjectRelativePath( childrenFile ),
1270
+ formatProjectRelativePath( blockConfigFile ),
1271
+ formatProjectRelativePath(
1272
+ placement === 'root' ? PARENT_BLOCK_JSON_PATH : directAncestor.blockJsonPath
1273
+ ),
1274
+ ];
1275
+
1276
+ console.log(
1277
+ renderCompoundChildGraphPreview(
1278
+ buildCompoundChildGraphNodes( existingChildren, {
1279
+ blockName: childBlockName,
1280
+ container,
1281
+ directParentBlockName:
1282
+ directAncestor?.blockName ?? PARENT_BLOCK_NAME,
1283
+ isProspective: true,
1284
+ key: normalizedSlug,
1285
+ placement,
1286
+ supportsInserter,
1287
+ title: childTitle,
1288
+ } ),
1289
+ plannedWritePaths,
1290
+ { dryRun }
1291
+ )
1292
+ );
1293
+
1294
+ if ( dryRun ) {
1295
+ return;
1296
+ }
997
1297
 
998
1298
  fs.mkdirSync( childDir, { recursive: true } );
999
1299