@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
@@ -307,6 +307,461 @@ $wrapper_attributes = get_block_wrapper_attributes(
307
307
  </div>
308
308
  </div>
309
309
  `;
310
+ const PERSISTENCE_RENDER_TARGETS_TEMPLATE = `<?php
311
+ /**
312
+ * Alternate render target helpers for the {{title}} block.
313
+ *
314
+ * @package {{pascalCase}}
315
+ */
316
+
317
+ if ( ! defined( 'ABSPATH' ) ) {
318
+ exit;
319
+ }
320
+
321
+ if ( ! function_exists( '{{phpPrefix}}_{{slugSnakeCase}}_build_render_context' ) ) {
322
+ function {{phpPrefix}}_{{slugSnakeCase}}_build_render_context( $attributes, $content, $block ) {
323
+ $validator_path = __DIR__ . '/typia-validator.php';
324
+ if ( ! file_exists( $validator_path ) ) {
325
+ return null;
326
+ }
327
+
328
+ $validator = require $validator_path;
329
+ if ( ! is_object( $validator ) || ! method_exists( $validator, 'apply_defaults' ) || ! method_exists( $validator, 'validate' ) ) {
330
+ return null;
331
+ }
332
+
333
+ $normalized = $validator->apply_defaults( is_array( $attributes ) ? $attributes : array() );
334
+ $validation = $validator->validate( $normalized );
335
+ $resource_key = isset( $normalized['resourceKey'] ) ? (string) $normalized['resourceKey'] : '';
336
+
337
+ if ( empty( $validation['valid'] ) || '' === $resource_key ) {
338
+ return null;
339
+ }
340
+
341
+ $alignment = isset( $normalized['alignment'] ) ? (string) $normalized['alignment'] : 'left';
342
+ $button_label = isset( $normalized['buttonLabel'] ) ? (string) $normalized['buttonLabel'] : 'Persist Count';
343
+ $rendered_content = isset( $normalized['content'] ) ? (string) $normalized['content'] : '';
344
+ $post_id = is_object( $block ) && isset( $block->context['postId'] )
345
+ ? (int) $block->context['postId']
346
+ : (int) get_queried_object_id();
347
+ $storage_mode = '{{dataStorageMode}}';
348
+ $persistence_policy = '{{persistencePolicy}}';
349
+
350
+ {{phpPrefix}}_record_rendered_block_instance(
351
+ (int) $post_id,
352
+ '{{namespace}}/{{slugKebabCase}}',
353
+ $resource_key
354
+ );
355
+
356
+ $notice_message = 'authenticated' === $persistence_policy
357
+ ? __( 'Sign in to persist this counter.', '{{textDomain}}' )
358
+ : __( 'Public writes are temporarily unavailable.', '{{textDomain}}' );
359
+ $web_context = array(
360
+ 'bootstrapReady' => false,
361
+ 'buttonLabel' => $button_label,
362
+ 'canWrite' => false,
363
+ 'client' => array(
364
+ 'writeExpiry' => 0,
365
+ 'writeNonce' => '',
366
+ 'writeToken' => '',
367
+ ),
368
+ 'count' => 0,
369
+ 'error' => '',
370
+ 'isBootstrapping' => false,
371
+ 'isLoading' => false,
372
+ 'isSaving' => false,
373
+ 'isVisible' => ! empty( $normalized['isVisible'] ),
374
+ 'persistencePolicy' => $persistence_policy,
375
+ 'postId' => (int) $post_id,
376
+ 'resourceKey' => $resource_key,
377
+ 'storage' => $storage_mode,
378
+ );
379
+
380
+ return array(
381
+ 'alignment' => $alignment,
382
+ 'buttonLabel' => $button_label,
383
+ 'content' => $rendered_content,
384
+ 'frontendClassName' => '{{frontendCssClassName}}',
385
+ 'isVisible' => ! empty( $normalized['isVisible'] ),
386
+ 'normalized' => $normalized,
387
+ 'noticeMessage' => $notice_message,
388
+ 'postId' => (int) $post_id,
389
+ 'resourceKey' => $resource_key,
390
+ 'showCount' => ! empty( $normalized['showCount'] ),
391
+ 'title' => {{titleJson}},
392
+ 'webContext' => $web_context,
393
+ );
394
+ }
395
+ }
396
+
397
+ if ( ! function_exists( '{{phpPrefix}}_{{slugSnakeCase}}_render_target' ) ) {
398
+ function {{phpPrefix}}_{{slugSnakeCase}}_render_target( string $target, $attributes, $content = '', $block = null ): string {
399
+ $context = {{phpPrefix}}_{{slugSnakeCase}}_build_render_context( $attributes, $content, $block );
400
+ if ( null === $context || empty( $context['isVisible'] ) ) {
401
+ return '';
402
+ }
403
+
404
+ $target_context = apply_filters(
405
+ '{{phpPrefix}}_{{slugSnakeCase}}_render_target_context',
406
+ $context,
407
+ $target,
408
+ $attributes,
409
+ $block
410
+ );
411
+
412
+ $markup = '';
413
+ switch ( $target ) {
414
+ case 'email':
415
+ $parts = array(
416
+ '<div class="' . esc_attr( $target_context['frontendClassName'] ) . '-email">',
417
+ '<p style="text-align:' . esc_attr( $target_context['alignment'] ) . ';">' . esc_html( $target_context['content'] ) . '</p>',
418
+ );
419
+ if ( ! empty( $target_context['showCount'] ) ) {
420
+ $parts[] = '<p><strong>' . esc_html__( 'Count', '{{textDomain}}' ) . ':</strong> ' . esc_html( (string) $target_context['webContext']['count'] ) . '</p>';
421
+ }
422
+ $parts[] = '<p>' . esc_html( $target_context['noticeMessage'] ) . '</p>';
423
+ $parts[] = '</div>';
424
+ $markup = implode( '', $parts );
425
+ break;
426
+ case 'mjml':
427
+ $markup = '<mjml><mj-body><mj-section><mj-column><mj-text align="' . esc_attr( $target_context['alignment'] ) . '">' . esc_html( $target_context['content'] ) . '</mj-text>';
428
+ if ( ! empty( $target_context['showCount'] ) ) {
429
+ $markup .= '<mj-text>' . esc_html__( 'Count', '{{textDomain}}' ) . ': ' . esc_html( (string) $target_context['webContext']['count'] ) . '</mj-text>';
430
+ }
431
+ $markup .= '<mj-text>' . esc_html( $target_context['noticeMessage'] ) . '</mj-text></mj-column></mj-section></mj-body></mjml>';
432
+ break;
433
+ case 'plain-text':
434
+ $markup = implode(
435
+ "\\n",
436
+ array_filter(
437
+ array(
438
+ $target_context['title'],
439
+ $target_context['content'],
440
+ ! empty( $target_context['showCount'] )
441
+ ? sprintf( '%s: %s', __( 'Count', '{{textDomain}}' ), (string) $target_context['webContext']['count'] )
442
+ : null,
443
+ $target_context['noticeMessage'],
444
+ ),
445
+ static fn( $value ) => is_string( $value ) && '' !== $value
446
+ )
447
+ );
448
+ break;
449
+ case 'web':
450
+ default:
451
+ $wrapper_attributes = get_block_wrapper_attributes(
452
+ array(
453
+ 'data-wp-context' => wp_json_encode( $target_context['webContext'] ),
454
+ 'data-wp-interactive' => '{{slugKebabCase}}',
455
+ 'data-wp-init' => 'callbacks.init',
456
+ 'data-wp-run--mounted' => 'callbacks.mounted',
457
+ )
458
+ );
459
+ ob_start();
460
+ ?>
461
+ <div <?php echo $wrapper_attributes; ?>>
462
+ <div class="{{frontendCssClassName}}">
463
+ <p class="{{frontendCssClassName}}__content" style="<?php echo esc_attr( 'text-align:' . $target_context['alignment'] ); ?>">
464
+ <?php echo esc_html( $target_context['content'] ); ?>
465
+ </p>
466
+ <p
467
+ class="{{frontendCssClassName}}__notice"
468
+ data-wp-bind--hidden="!context.bootstrapReady || context.canWrite"
469
+ hidden
470
+ >
471
+ <?php echo esc_html( $target_context['noticeMessage'] ); ?>
472
+ </p>
473
+ <p
474
+ class="{{frontendCssClassName}}__error"
475
+ role="status"
476
+ aria-live="polite"
477
+ aria-atomic="true"
478
+ data-wp-bind--hidden="!context.error"
479
+ data-wp-text="context.error"
480
+ hidden
481
+ ></p>
482
+ <?php if ( ! empty( $target_context['showCount'] ) ) : ?>
483
+ <span
484
+ class="{{frontendCssClassName}}__count"
485
+ role="status"
486
+ aria-live="polite"
487
+ aria-atomic="true"
488
+ data-wp-text="context.count"
489
+ >
490
+ 0
491
+ </span>
492
+ <?php endif; ?>
493
+ <button
494
+ type="button"
495
+ disabled
496
+ data-wp-bind--disabled="!context.canWrite"
497
+ data-wp-on--click="actions.increment"
498
+ >
499
+ <?php echo esc_html( $target_context['buttonLabel'] ); ?>
500
+ </button>
501
+ </div>
502
+ </div>
503
+ <?php
504
+ $markup = (string) ob_get_clean();
505
+ break;
506
+ }
507
+
508
+ return apply_filters(
509
+ '{{phpPrefix}}_{{slugSnakeCase}}_render_target_markup',
510
+ $markup,
511
+ $target,
512
+ $target_context
513
+ );
514
+ }
515
+ }
516
+ `;
517
+ const COMPOUND_PERSISTENCE_RENDER_TARGETS_TEMPLATE = `<?php
518
+ /**
519
+ * Alternate render target helpers for the {{title}} compound parent block.
520
+ *
521
+ * @package {{pascalCase}}
522
+ */
523
+
524
+ if ( ! defined( 'ABSPATH' ) ) {
525
+ exit;
526
+ }
527
+
528
+ if ( ! function_exists( '{{phpPrefix}}_{{slugSnakeCase}}_build_render_context' ) ) {
529
+ function {{phpPrefix}}_{{slugSnakeCase}}_build_render_context( $attributes, $content, $block ) {
530
+ $validator_path = __DIR__ . '/typia-validator.php';
531
+ if ( ! file_exists( $validator_path ) ) {
532
+ return null;
533
+ }
534
+
535
+ $validator = require $validator_path;
536
+ if ( ! is_object( $validator ) || ! method_exists( $validator, 'apply_defaults' ) || ! method_exists( $validator, 'validate' ) ) {
537
+ return null;
538
+ }
539
+
540
+ $normalized = $validator->apply_defaults( is_array( $attributes ) ? $attributes : array() );
541
+ $validation = $validator->validate( $normalized );
542
+ $resource_key = isset( $normalized['resourceKey'] ) ? (string) $normalized['resourceKey'] : '';
543
+ $heading = isset( $normalized['heading'] ) ? (string) $normalized['heading'] : {{titlePhpLiteral}};
544
+ $intro = isset( $normalized['intro'] ) ? (string) $normalized['intro'] : '';
545
+ $button_label = isset( $normalized['buttonLabel'] ) ? (string) $normalized['buttonLabel'] : 'Persist Count';
546
+ $show_count = ! empty( $normalized['showCount'] );
547
+ $show_dividers = ! empty( $normalized['showDividers'] );
548
+ $post_id = is_object( $block ) && isset( $block->context['postId'] )
549
+ ? (int) $block->context['postId']
550
+ : (int) get_queried_object_id();
551
+ $storage_mode = '{{dataStorageMode}}';
552
+ $persistence_policy = '{{persistencePolicy}}';
553
+
554
+ {{phpPrefix}}_record_rendered_block_instance(
555
+ (int) $post_id,
556
+ '{{namespace}}/{{slugKebabCase}}',
557
+ $resource_key
558
+ );
559
+
560
+ $notice_message = 'authenticated' === $persistence_policy
561
+ ? __( 'Sign in to persist this counter.', '{{textDomain}}' )
562
+ : __( 'Public writes are temporarily unavailable.', '{{textDomain}}' );
563
+
564
+ if ( empty( $validation['valid'] ) || '' === $resource_key ) {
565
+ return null;
566
+ }
567
+
568
+ $web_context = array(
569
+ 'bootstrapReady' => false,
570
+ 'buttonLabel' => $button_label,
571
+ 'canWrite' => false,
572
+ 'client' => array(
573
+ 'writeExpiry' => 0,
574
+ 'writeNonce' => '',
575
+ 'writeToken' => '',
576
+ ),
577
+ 'count' => 0,
578
+ 'error' => '',
579
+ 'isBootstrapping' => false,
580
+ 'isLoading' => false,
581
+ 'isSaving' => false,
582
+ 'persistencePolicy' => $persistence_policy,
583
+ 'postId' => (int) $post_id,
584
+ 'resourceKey' => $resource_key,
585
+ 'showCount' => $show_count,
586
+ 'storage' => $storage_mode,
587
+ );
588
+
589
+ $allowed_inner_html = wp_kses_allowed_html( 'post' );
590
+
591
+ foreach ( $allowed_inner_html as &$allowed_attributes ) {
592
+ if ( ! is_array( $allowed_attributes ) ) {
593
+ continue;
594
+ }
595
+
596
+ $allowed_attributes['data-wp-bind--disabled'] = true;
597
+ $allowed_attributes['data-wp-bind--hidden'] = true;
598
+ $allowed_attributes['data-wp-bind--value'] = true;
599
+ $allowed_attributes['data-wp-class'] = true;
600
+ $allowed_attributes['data-wp-class--active'] = true;
601
+ $allowed_attributes['data-wp-context'] = true;
602
+ $allowed_attributes['data-wp-init'] = true;
603
+ $allowed_attributes['data-wp-interactive'] = true;
604
+ $allowed_attributes['data-wp-on--click'] = true;
605
+ $allowed_attributes['data-wp-on--mouseenter'] = true;
606
+ $allowed_attributes['data-wp-on--mouseleave'] = true;
607
+ $allowed_attributes['data-wp-run--mounted'] = true;
608
+ $allowed_attributes['data-wp-style--width'] = true;
609
+ $allowed_attributes['data-wp-text'] = true;
610
+ }
611
+ unset( $allowed_attributes );
612
+
613
+ return array(
614
+ 'buttonLabel' => $button_label,
615
+ 'frontendClassName' => '{{cssClassName}}',
616
+ 'heading' => $heading,
617
+ 'intro' => $intro,
618
+ 'isVisible' => true,
619
+ 'normalized' => $normalized,
620
+ 'noticeMessage' => $notice_message,
621
+ 'postId' => (int) $post_id,
622
+ 'resourceKey' => $resource_key,
623
+ 'sanitizedContent' => wp_kses( $content, $allowed_inner_html ),
624
+ 'showCount' => $show_count,
625
+ 'showDividers' => $show_dividers,
626
+ 'title' => {{titleJson}},
627
+ 'webContext' => $web_context,
628
+ );
629
+ }
630
+ }
631
+
632
+ if ( ! function_exists( '{{phpPrefix}}_{{slugSnakeCase}}_render_target' ) ) {
633
+ function {{phpPrefix}}_{{slugSnakeCase}}_render_target( string $target, $attributes, $content = '', $block = null ): string {
634
+ $context = {{phpPrefix}}_{{slugSnakeCase}}_build_render_context( $attributes, $content, $block );
635
+ if ( null === $context ) {
636
+ return '';
637
+ }
638
+
639
+ $target_context = apply_filters(
640
+ '{{phpPrefix}}_{{slugSnakeCase}}_render_target_context',
641
+ $context,
642
+ $target,
643
+ $attributes,
644
+ $block
645
+ );
646
+
647
+ $markup = '';
648
+ switch ( $target ) {
649
+ case 'email':
650
+ $parts = array(
651
+ '<div class="' . esc_attr( $target_context['frontendClassName'] ) . '-email">',
652
+ '<h3>' . esc_html( $target_context['heading'] ) . '</h3>',
653
+ );
654
+ if ( '' !== $target_context['intro'] ) {
655
+ $parts[] = '<p>' . esc_html( $target_context['intro'] ) . '</p>';
656
+ }
657
+ if ( ! empty( $target_context['showCount'] ) ) {
658
+ $parts[] = '<p><strong>' . esc_html__( 'Count', '{{textDomain}}' ) . ':</strong> ' . esc_html( (string) $target_context['webContext']['count'] ) . '</p>';
659
+ }
660
+ $parts[] = wp_kses_post( $target_context['sanitizedContent'] );
661
+ $parts[] = '<p>' . esc_html( $target_context['noticeMessage'] ) . '</p>';
662
+ $parts[] = '</div>';
663
+ $markup = implode( '', $parts );
664
+ break;
665
+ case 'mjml':
666
+ $markup = '<mjml><mj-body><mj-section><mj-column><mj-text font-weight="700">' . esc_html( $target_context['heading'] ) . '</mj-text>';
667
+ if ( '' !== $target_context['intro'] ) {
668
+ $markup .= '<mj-text>' . esc_html( $target_context['intro'] ) . '</mj-text>';
669
+ }
670
+ if ( ! empty( $target_context['showCount'] ) ) {
671
+ $markup .= '<mj-text>' . esc_html__( 'Count', '{{textDomain}}' ) . ': ' . esc_html( (string) $target_context['webContext']['count'] ) . '</mj-text>';
672
+ }
673
+ $markup .= '<mj-text>' . esc_html( wp_strip_all_tags( $target_context['sanitizedContent'] ) ) . '</mj-text>';
674
+ $markup .= '<mj-text>' . esc_html( $target_context['noticeMessage'] ) . '</mj-text></mj-column></mj-section></mj-body></mjml>';
675
+ break;
676
+ case 'plain-text':
677
+ $markup = implode(
678
+ "\\n",
679
+ array_filter(
680
+ array(
681
+ $target_context['heading'],
682
+ $target_context['intro'],
683
+ wp_strip_all_tags( $target_context['sanitizedContent'] ),
684
+ ! empty( $target_context['showCount'] )
685
+ ? sprintf( '%s: %s', __( 'Count', '{{textDomain}}' ), (string) $target_context['webContext']['count'] )
686
+ : null,
687
+ $target_context['noticeMessage'],
688
+ ),
689
+ static fn( $value ) => is_string( $value ) && '' !== $value
690
+ )
691
+ );
692
+ break;
693
+ case 'web':
694
+ default:
695
+ $wrapper_attributes = get_block_wrapper_attributes(
696
+ array(
697
+ 'class' => '{{cssClassName}}',
698
+ 'data-show-dividers' => $target_context['showDividers'] ? 'true' : 'false',
699
+ 'data-wp-context' => wp_json_encode( $target_context['webContext'] ),
700
+ 'data-wp-init' => 'callbacks.init',
701
+ 'data-wp-interactive' => '{{slugKebabCase}}',
702
+ 'data-wp-run--mounted' => 'callbacks.mounted',
703
+ )
704
+ );
705
+ ob_start();
706
+ ?>
707
+ <div <?php echo $wrapper_attributes; ?>>
708
+ <h3 class="{{cssClassName}}__heading"><?php echo esc_html( $target_context['heading'] ); ?></h3>
709
+ <?php if ( '' !== $target_context['intro'] ) : ?>
710
+ <p class="{{cssClassName}}__intro"><?php echo esc_html( $target_context['intro'] ); ?></p>
711
+ <?php endif; ?>
712
+ <p
713
+ class="{{cssClassName}}__notice"
714
+ data-wp-bind--hidden="!context.bootstrapReady || context.canWrite"
715
+ hidden
716
+ >
717
+ <?php echo esc_html( $target_context['noticeMessage'] ); ?>
718
+ </p>
719
+ <p
720
+ class="{{cssClassName}}__error"
721
+ role="status"
722
+ aria-live="polite"
723
+ aria-atomic="true"
724
+ data-wp-bind--hidden="!context.error"
725
+ data-wp-text="context.error"
726
+ hidden
727
+ ></p>
728
+ <?php if ( ! empty( $target_context['showCount'] ) ) : ?>
729
+ <div class="{{cssClassName}}__counter">
730
+ <span
731
+ class="{{cssClassName}}__count"
732
+ role="status"
733
+ aria-live="polite"
734
+ aria-atomic="true"
735
+ data-wp-text="context.count"
736
+ >0</span>
737
+ <button
738
+ type="button"
739
+ disabled
740
+ data-wp-bind--disabled="!context.canWrite"
741
+ data-wp-on--click="actions.increment"
742
+ >
743
+ <?php echo esc_html( $target_context['buttonLabel'] ); ?>
744
+ </button>
745
+ </div>
746
+ <?php endif; ?>
747
+ <div class="{{cssClassName}}__items">
748
+ <?php echo wp_kses_post( $target_context['sanitizedContent'] ); ?>
749
+ </div>
750
+ </div>
751
+ <?php
752
+ $markup = (string) ob_get_clean();
753
+ break;
754
+ }
755
+
756
+ return apply_filters(
757
+ '{{phpPrefix}}_{{slugSnakeCase}}_render_target_markup',
758
+ $markup,
759
+ $target,
760
+ $target_context
761
+ );
762
+ }
763
+ }
764
+ `;
310
765
  const COMPOUND_STYLE_TEMPLATE = `.{{cssClassName}} {
311
766
  border: 1px solid #dcdcde;
312
767
  border-radius: 12px;
@@ -346,6 +801,24 @@ function renderArtifact(relativePath, template, view) {
346
801
  source: source.endsWith("\n") ? source : `${source}\n`,
347
802
  };
348
803
  }
804
+ function buildAlternateRenderEntryArtifact(relativePath, target, variables) {
805
+ const template = `<?php
806
+ /**
807
+ * Alternate ${target} render entry for {{title}}.
808
+ *
809
+ * @package {{pascalCase}}
810
+ */
811
+
812
+ if ( ! defined( 'ABSPATH' ) ) {
813
+ exit;
814
+ }
815
+
816
+ require_once __DIR__ . '/render-targets.php';
817
+
818
+ return {{phpPrefix}}_{{slugSnakeCase}}_render_target( '${target}', $attributes, $content ?? '', $block ?? null );
819
+ `;
820
+ return renderArtifact(relativePath, template, variables);
821
+ }
349
822
  function toPhpSingleQuotedString(value) {
350
823
  return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
351
824
  }
@@ -363,10 +836,27 @@ function buildInteractivityArtifacts(variables) {
363
836
  ];
364
837
  }
365
838
  function buildPersistenceArtifacts(variables) {
366
- return [
839
+ if (variables.hasAlternateRenderTargets !== "true") {
840
+ return [
841
+ renderArtifact("src/style.scss", PERSISTENCE_STYLE_TEMPLATE, variables),
842
+ renderArtifact("src/render.php", PERSISTENCE_RENDER_TEMPLATE, variables),
843
+ ];
844
+ }
845
+ const artifacts = [
367
846
  renderArtifact("src/style.scss", PERSISTENCE_STYLE_TEMPLATE, variables),
368
- renderArtifact("src/render.php", PERSISTENCE_RENDER_TEMPLATE, variables),
847
+ renderArtifact("src/render-targets.php", PERSISTENCE_RENDER_TARGETS_TEMPLATE, variables),
848
+ buildAlternateRenderEntryArtifact("src/render.php", "web", variables),
369
849
  ];
850
+ if (variables.hasAlternateEmailRenderTarget === "true") {
851
+ artifacts.push(buildAlternateRenderEntryArtifact("src/render-email.php", "email", variables));
852
+ }
853
+ if (variables.hasAlternateMjmlRenderTarget === "true") {
854
+ artifacts.push(buildAlternateRenderEntryArtifact("src/render-mjml.php", "mjml", variables));
855
+ }
856
+ if (variables.hasAlternatePlainTextRenderTarget === "true") {
857
+ artifacts.push(buildAlternateRenderEntryArtifact("src/render-text.php", "plain-text", variables));
858
+ }
859
+ return artifacts;
370
860
  }
371
861
  function buildCompoundArtifacts(variables) {
372
862
  const artifacts = [
@@ -377,6 +867,19 @@ function buildCompoundArtifacts(variables) {
377
867
  ...variables,
378
868
  titlePhpLiteral: toPhpSingleQuotedString(variables.title),
379
869
  };
870
+ if (variables.hasAlternateRenderTargets === "true") {
871
+ artifacts.push(renderArtifact(`src/blocks/${variables.slugKebabCase}/render-targets.php`, COMPOUND_PERSISTENCE_RENDER_TARGETS_TEMPLATE, renderView), buildAlternateRenderEntryArtifact(`src/blocks/${variables.slugKebabCase}/render.php`, "web", variables));
872
+ if (variables.hasAlternateEmailRenderTarget === "true") {
873
+ artifacts.push(buildAlternateRenderEntryArtifact(`src/blocks/${variables.slugKebabCase}/render-email.php`, "email", variables));
874
+ }
875
+ if (variables.hasAlternateMjmlRenderTarget === "true") {
876
+ artifacts.push(buildAlternateRenderEntryArtifact(`src/blocks/${variables.slugKebabCase}/render-mjml.php`, "mjml", variables));
877
+ }
878
+ if (variables.hasAlternatePlainTextRenderTarget === "true") {
879
+ artifacts.push(buildAlternateRenderEntryArtifact(`src/blocks/${variables.slugKebabCase}/render-text.php`, "plain-text", variables));
880
+ }
881
+ return artifacts;
882
+ }
380
883
  const renderSource = `<?php
381
884
  /**
382
885
  * Dynamic render entry for the {{title}} compound parent block.
@@ -18,6 +18,9 @@ export declare function seedWorkspaceMigrationProject(projectDir: string, curren
18
18
  * workspace. Defaults to `process.cwd()`.
19
19
  * @param options.dataStorageMode Optional storage mode for persistence-capable
20
20
  * templates.
21
+ * @param options.innerBlocksPreset Optional compound-only InnerBlocks preset
22
+ * (`freeform`, `ordered`, `horizontal`, or `locked-structure`) that controls
23
+ * the generated authoring defaults for nested compound containers.
21
24
  * @param options.persistencePolicy Optional persistence policy for
22
25
  * persistence-capable templates.
23
26
  * @param options.templateId Built-in block family to scaffold. Defaults to
@@ -30,7 +33,7 @@ export declare function seedWorkspaceMigrationProject(projectDir: string, curren
30
33
  * workspace dependencies have not been installed yet, or target block paths
31
34
  * already exist.
32
35
  */
33
- export declare function runAddBlockCommand({ blockName, cwd, dataStorageMode, externalLayerId, externalLayerSource, persistencePolicy, selectExternalLayerId, templateId, }: RunAddBlockCommandOptions): Promise<{
36
+ export declare function runAddBlockCommand({ alternateRenderTargets, blockName, cwd, dataStorageMode, externalLayerId, externalLayerSource, innerBlocksPreset, persistencePolicy, selectExternalLayerId, templateId, }: RunAddBlockCommandOptions): Promise<{
34
37
  blockSlugs: string[];
35
38
  projectDir: string;
36
39
  templateId: AddBlockTemplateId;