wp-typia 0.21.0 → 0.22.0

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.
@@ -36394,7 +36394,7 @@ function assertEditorPluginDoesNotExist(projectDir, editorPluginSlug, inventory)
36394
36394
  }
36395
36395
  function formatAddHelpText() {
36396
36396
  return `Usage:
36397
- wp-typia add admin-view <name> [--source <rest-resource:slug>] [--dry-run]
36397
+ wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>] [--dry-run]
36398
36398
  wp-typia add block <name> [--template <${ADD_BLOCK_TEMPLATE_IDS.join("|")}>] [--external-layer-source <./path|github:owner/repo/path[#ref]|npm-package>] [--external-layer-id <layer-id>] [--inner-blocks-preset <freeform|ordered|horizontal|locked-structure>] [--alternate-render-targets <email,mjml,plain-text>] [--data-storage <post-meta|custom-table>] [--persistence-policy <authenticated|public>] [--dry-run]
36399
36399
  wp-typia add variation <name> --block <block-slug> [--dry-run]
36400
36400
  wp-typia add style <name> --block <block-slug> [--dry-run]
@@ -36411,7 +36411,10 @@ Notes:
36411
36411
  \`wp-typia add\` runs only inside official ${WORKSPACE_TEMPLATE_PACKAGE} workspaces scaffolded via \`wp-typia create <project-dir> --template workspace\`.
36412
36412
  Pass \`--dry-run\` to preview the workspace files that would change without writing them.
36413
36413
  Interactive add flows let you choose a template when \`--template\` is omitted; non-interactive runs default to \`basic\`.
36414
- \`add admin-view\` scaffolds an opt-in DataViews-powered WordPress admin screen under \`src/admin-views/\`; pass \`--source rest-resource:<slug>\` to reuse a list-capable REST resource.
36414
+ \`add admin-view\` scaffolds an opt-in DataViews-powered WordPress admin screen under \`src/admin-views/\`.
36415
+ Pass \`--source rest-resource:<slug>\` to reuse a list-capable REST resource.
36416
+ Pass \`--source core-data:postType/post\` or \`--source core-data:taxonomy/category\` to bind a WordPress-owned entity collection.
36417
+ Public installs currently gate this workflow until \`@wp-typia/dataviews\` is published to npm.
36415
36418
  \`query-loop\` is a create-time scaffold family. Use \`wp-typia create <project-dir> --template query-loop\` instead of \`wp-typia add block\`.
36416
36419
  \`add variation\` targets an existing block slug from \`scripts/block-config.ts\`.
36417
36420
  \`add style\` registers a Block Styles option for an existing generated block.
@@ -213343,7 +213346,7 @@ function getPackageVersions() {
213343
213346
  };
213344
213347
  return versions2;
213345
213348
  }
213346
- var require2, DEFAULT_VERSION_RANGE = "^0.0.0", DEFAULT_EXACT_VERSION = "0.0.0", DEFAULT_TSX_PACKAGE_VERSION = "^4.20.5", DEFAULT_TYPIA_UNPLUGIN_PACKAGE_VERSION = "^12.0.1", cachedPackageVersions = null;
213349
+ var require2, DEFAULT_VERSION_RANGE = "^0.0.0", DEFAULT_EXACT_VERSION = "0.0.0", DEFAULT_TSX_PACKAGE_VERSION = "^4.20.5", DEFAULT_TYPIA_UNPLUGIN_PACKAGE_VERSION = "^12.0.1", DEFAULT_WORDPRESS_ABILITIES_VERSION = "^0.10.0", DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION = "^0.9.0", DEFAULT_WORDPRESS_CORE_DATA_VERSION = "^7.44.0", DEFAULT_WORDPRESS_DATA_VERSION = "^9.28.0", DEFAULT_WORDPRESS_DATAVIEWS_VERSION = "^14.1.0", DEFAULT_WP_TYPIA_DATAVIEWS_VERSION = "^0.1.0", cachedPackageVersions = null;
213347
213350
  var init_package_versions = __esm(() => {
213348
213351
  init_template_registry();
213349
213352
  require2 = createRequire(import.meta.url);
@@ -214611,6 +214614,17 @@ function buildInteractivityTypesSource(variables, attributes) {
214611
214614
  { name: "maxClicks", typeExpression: "number" }
214612
214615
  ],
214613
214616
  name: `${variables.pascalCase}Context`
214617
+ },
214618
+ {
214619
+ members: [
214620
+ { name: "clicks", typeExpression: "number" },
214621
+ { name: "isAnimating", typeExpression: "boolean" },
214622
+ { name: "isVisible", typeExpression: "boolean" },
214623
+ { name: "progress", typeExpression: "number" },
214624
+ { name: "clampedClicks", typeExpression: "number" },
214625
+ { name: "isComplete", typeExpression: "boolean" }
214626
+ ],
214627
+ name: `${variables.pascalCase}State`
214614
214628
  }
214615
214629
  ],
214616
214630
  typeAliases: [
@@ -224413,10 +224427,10 @@ var init_compound_inner_blocks = __esm(() => {
224413
224427
  };
224414
224428
  });
224415
224429
 
224416
- // ../wp-typia-project-tools/src/runtime/ai-feature-capability.ts
224430
+ // ../wp-typia-project-tools/src/runtime/version-floor.ts
224417
224431
  function parseVersionFloorParts(value2) {
224418
224432
  return value2.split(".").map((part, index) => {
224419
- if (!/^\d+$/.test(part)) {
224433
+ if (!/^\d+$/u.test(part)) {
224420
224434
  throw new Error(`parseVersionFloorParts received an invalid version floor "${value2}" at segment ${index + 1}.`);
224421
224435
  }
224422
224436
  return Number.parseInt(part, 10);
@@ -224447,6 +224461,8 @@ function pickHigherVersionFloor(current, candidate) {
224447
224461
  }
224448
224462
  return compareVersionFloors(current, candidate) >= 0 ? current : candidate;
224449
224463
  }
224464
+
224465
+ // ../wp-typia-project-tools/src/runtime/ai-feature-capability.ts
224450
224466
  function normalizeSelections(selections) {
224451
224467
  const normalized = new Map;
224452
224468
  for (const selection of selections) {
@@ -224556,35 +224572,8 @@ var init_ai_feature_capability = __esm(() => {
224556
224572
  });
224557
224573
 
224558
224574
  // ../wp-typia-project-tools/src/runtime/scaffold-compatibility.ts
224559
- function parseVersionFloorParts2(value2) {
224560
- return value2.split(".").map((part, index) => {
224561
- if (!/^\d+$/u.test(part)) {
224562
- throw new Error(`parseVersionFloorParts received an invalid version floor "${value2}" at segment ${index + 1}.`);
224563
- }
224564
- return Number.parseInt(part, 10);
224565
- });
224566
- }
224567
- function compareVersionFloors2(left, right) {
224568
- const leftParts = parseVersionFloorParts2(left);
224569
- const rightParts = parseVersionFloorParts2(right);
224570
- const length = Math.max(leftParts.length, rightParts.length);
224571
- for (let index = 0;index < length; index += 1) {
224572
- const leftValue = leftParts[index] ?? 0;
224573
- const rightValue = rightParts[index] ?? 0;
224574
- if (leftValue > rightValue) {
224575
- return 1;
224576
- }
224577
- if (leftValue < rightValue) {
224578
- return -1;
224579
- }
224580
- }
224581
- return 0;
224582
- }
224583
- function pickHigherVersionFloor2(current, candidate) {
224584
- if (!candidate) {
224585
- return current;
224586
- }
224587
- return compareVersionFloors2(current, candidate) >= 0 ? current : candidate;
224575
+ function pickHigherScaffoldVersionFloor(current, candidate) {
224576
+ return pickHigherVersionFloor(current, candidate) ?? current;
224588
224577
  }
224589
224578
  function pickHigherHeaderVersionFloor(policyValue, currentValue) {
224590
224579
  const normalizedCurrentValue = currentValue.trim();
@@ -224592,7 +224581,7 @@ function pickHigherHeaderVersionFloor(policyValue, currentValue) {
224592
224581
  return policyValue;
224593
224582
  }
224594
224583
  try {
224595
- return pickHigherVersionFloor2(policyValue, normalizedCurrentValue);
224584
+ return pickHigherScaffoldVersionFloor(policyValue, normalizedCurrentValue);
224596
224585
  } catch {
224597
224586
  return policyValue;
224598
224587
  }
@@ -224613,9 +224602,9 @@ function resolveScaffoldCompatibilityPolicy(selections, {
224613
224602
  baseline = DEFAULT_SCAFFOLD_COMPATIBILITY
224614
224603
  } = {}) {
224615
224604
  const capabilityPlan = resolveAiFeatureCapabilityPlan(selections);
224616
- const requiresAtLeast = pickHigherVersionFloor2(baseline.requiresAtLeast, capabilityPlan.hardMinimums.wordpress);
224617
- const requiresPhp = pickHigherVersionFloor2(baseline.requiresPhp, capabilityPlan.hardMinimums.php);
224618
- const testedUpTo = pickHigherVersionFloor2(baseline.testedUpTo, requiresAtLeast);
224605
+ const requiresAtLeast = pickHigherScaffoldVersionFloor(baseline.requiresAtLeast, capabilityPlan.hardMinimums.wordpress);
224606
+ const requiresPhp = pickHigherScaffoldVersionFloor(baseline.requiresPhp, capabilityPlan.hardMinimums.php);
224607
+ const testedUpTo = pickHigherScaffoldVersionFloor(baseline.testedUpTo, requiresAtLeast);
224619
224608
  return {
224620
224609
  capabilityPlan,
224621
224610
  pluginHeader: {
@@ -226451,6 +226440,7 @@ import { useBlockProps, InspectorControls, RichText, BlockControls, AlignmentToo
226451
226440
  import { PanelBody, RangeControl, Button, Notice } from '@wordpress/components';
226452
226441
  import { useState } from '@wordpress/element';
226453
226442
  import currentManifest from './manifest-document';
226443
+ import { {{slugCamelCase}}Store } from './interactivity-store';
226454
226444
  import {
226455
226445
  InspectorFromManifest,
226456
226446
  useEditorFields,
@@ -226531,17 +226521,22 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
226531
226521
 
226532
226522
  const blockProps = useBlockProps({
226533
226523
  className: \`{{cssClassName}} {{cssClassName}}--\${interactiveMode}\`,
226534
- 'data-wp-interactive': '{{slugKebabCase}}',
226535
- 'data-wp-context': JSON.stringify({
226536
- clicks: clickCount,
226537
- isAnimating,
226538
- isVisible,
226539
- animation,
226540
- maxClicks,
226541
- })
226524
+ 'data-wp-interactive': {{slugCamelCase}}Store.directive.interactive,
226525
+ 'data-wp-context': JSON.stringify(
226526
+ {{slugCamelCase}}Store.createContext({
226527
+ clicks: clickCount,
226528
+ isAnimating,
226529
+ isVisible,
226530
+ animation,
226531
+ maxClicks,
226532
+ })
226533
+ )
226542
226534
  });
226543
226535
  const previewContentStyle = { textAlign: alignmentValue };
226544
226536
  const progressBarStyle = { width: \`\${(clickCount / maxClicks) * 100}%\` };
226537
+ const clicksDirective = {{slugCamelCase}}Store.directive.state('clicks');
226538
+ const isAnimatingDirective = {{slugCamelCase}}Store.directive.state('isAnimating');
226539
+ const progressDirective = {{slugCamelCase}}Store.directive.state('progress') + " + '%'";
226545
226540
 
226546
226541
  const resetCounter = () => {
226547
226542
  updateField('clickCount', 0);
@@ -226638,9 +226633,9 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
226638
226633
  <div
226639
226634
  className={\`{{cssClassName}}__content \${isAnimating ? 'is-animating' : ''}\`}
226640
226635
  style={previewContentStyle}
226641
- data-wp-on--click={isPreviewing ? 'actions.handleClick' : undefined}
226642
- data-wp-on--mouseenter={isPreviewing && interactiveMode === 'hover' ? 'actions.handleMouseEnter' : undefined}
226643
- data-wp-on--mouseleave={isPreviewing && interactiveMode === 'hover' ? 'actions.handleMouseLeave' : undefined}
226636
+ data-wp-on--click={isPreviewing ? {{slugCamelCase}}Store.directive.action('handleClick') : undefined}
226637
+ data-wp-on--mouseenter={isPreviewing && interactiveMode === 'hover' ? {{slugCamelCase}}Store.directive.action('handleMouseEnter') : undefined}
226638
+ data-wp-on--mouseleave={isPreviewing && interactiveMode === 'hover' ? {{slugCamelCase}}Store.directive.action('handleMouseLeave') : undefined}
226644
226639
  >
226645
226640
  <RichText
226646
226641
  tagName="p"
@@ -226669,7 +226664,7 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
226669
226664
  </span>
226670
226665
  <span
226671
226666
  className="{{cssClassName}}__counter-value"
226672
- data-wp-text="state.clicks"
226667
+ data-wp-text={clicksDirective}
226673
226668
  >
226674
226669
  {clickCount}
226675
226670
  </span>
@@ -226681,7 +226676,7 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
226681
226676
  <div
226682
226677
  className="{{cssClassName}}__progress-bar"
226683
226678
  style={progressBarStyle}
226684
- data-wp-style--width="state.progress + '%'"
226679
+ data-wp-style--width={progressDirective}
226685
226680
  />
226686
226681
  </div>
226687
226682
  )}
@@ -226689,7 +226684,7 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
226689
226684
  {animation !== 'none' && (
226690
226685
  <div
226691
226686
  className={\`{{cssClassName}}__animation \${isAnimating ? 'is-active' : ''}\`}
226692
- data-wp-class--is-active="state.isAnimating"
226687
+ data-wp-class--is-active={isAnimatingDirective}
226693
226688
  >
226694
226689
  {animation}
226695
226690
  </div>
@@ -226701,6 +226696,7 @@ export default function Edit({ attributes, setAttributes, isSelected }: EditProp
226701
226696
  }
226702
226697
  `, INTERACTIVITY_SAVE_TEMPLATE = `import { useBlockProps, RichText } from '@wordpress/block-editor';
226703
226698
  import { __ } from '@wordpress/i18n';
226699
+ import { {{slugCamelCase}}Store } from './interactivity-store';
226704
226700
  import type { {{pascalCase}}Attributes } from './types';
226705
226701
 
226706
226702
  export default function Save({ attributes }: { attributes: {{pascalCase}}Attributes }) {
@@ -226712,27 +226708,41 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
226712
226708
  const maxClicks = attributes.maxClicks ?? 0;
226713
226709
  const showCounter = attributes.showCounter ?? true;
226714
226710
  const contentStyle = { textAlign: attributes.alignment };
226711
+ const clickActionDirective = {{slugCamelCase}}Store.directive.action('handleClick');
226712
+ const visibilityHiddenDirective = {{slugCamelCase}}Store.directive.negate(
226713
+ {{slugCamelCase}}Store.directive.state('isVisible')
226714
+ );
226715
+ const clicksDirective = {{slugCamelCase}}Store.directive.state('clicks');
226716
+ const clampedClicksDirective = {{slugCamelCase}}Store.directive.state('clampedClicks');
226717
+ const isAnimatingDirective = {{slugCamelCase}}Store.directive.state('isAnimating');
226718
+ const completionHiddenDirective = {{slugCamelCase}}Store.directive.negate(
226719
+ {{slugCamelCase}}Store.directive.state('isComplete')
226720
+ );
226721
+ const resetActionDirective = {{slugCamelCase}}Store.directive.action('reset');
226715
226722
  const blockProps = useBlockProps.save({
226716
226723
  className: \`{{cssClassName}} {{cssClassName}}--\${interactiveMode}\`,
226717
- 'data-wp-interactive': '{{slugKebabCase}}',
226718
- 'data-wp-context': JSON.stringify({
226719
- clicks: clickCount,
226720
- isAnimating,
226721
- isVisible,
226722
- animation,
226723
- maxClicks,
226724
- })
226724
+ 'data-wp-interactive': {{slugCamelCase}}Store.directive.interactive,
226725
+ 'data-wp-context': JSON.stringify(
226726
+ {{slugCamelCase}}Store.createContext({
226727
+ clicks: clickCount,
226728
+ isAnimating,
226729
+ isVisible,
226730
+ animation,
226731
+ maxClicks,
226732
+ })
226733
+ )
226725
226734
  });
226735
+ const progressDirective = {{slugCamelCase}}Store.directive.state('progress') + " + '%'";
226726
226736
 
226727
226737
  return (
226728
226738
  <div {...blockProps}>
226729
226739
  <div
226730
226740
  className={\`{{cssClassName}}__content \${isAnimating ? 'is-animating' : ''}\`}
226731
226741
  style={contentStyle}
226732
- data-wp-on--click="actions.handleClick"
226733
- data-wp-on--mouseenter={interactiveMode === 'hover' ? 'actions.handleMouseEnter' : undefined}
226734
- data-wp-on--mouseleave={interactiveMode === 'hover' ? 'actions.handleMouseLeave' : undefined}
226735
- data-wp-bind--hidden="!state.isVisible"
226742
+ data-wp-on--click={clickActionDirective}
226743
+ data-wp-on--mouseenter={interactiveMode === 'hover' ? {{slugCamelCase}}Store.directive.action('handleMouseEnter') : undefined}
226744
+ data-wp-on--mouseleave={interactiveMode === 'hover' ? {{slugCamelCase}}Store.directive.action('handleMouseLeave') : undefined}
226745
+ data-wp-bind--hidden={visibilityHiddenDirective}
226736
226746
  >
226737
226747
  <RichText.Content
226738
226748
  tagName="p"
@@ -226752,7 +226762,7 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
226752
226762
  </span>
226753
226763
  <span
226754
226764
  className="{{cssClassName}}__counter-value"
226755
- data-wp-text="state.clicks"
226765
+ data-wp-text={clicksDirective}
226756
226766
  >
226757
226767
  {clickCount}
226758
226768
  </span>
@@ -226768,8 +226778,8 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
226768
226778
  aria-valuemin={0}
226769
226779
  aria-valuemax={maxClicks}
226770
226780
  aria-valuenow={Math.min(clickCount, maxClicks)}
226771
- data-wp-bind--aria-valuenow="state.clampedClicks"
226772
- data-wp-style--width="state.progress + '%'"
226781
+ data-wp-bind--aria-valuenow={clampedClicksDirective}
226782
+ data-wp-style--width={progressDirective}
226773
226783
  />
226774
226784
  </div>
226775
226785
  )}
@@ -226777,7 +226787,7 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
226777
226787
  <div
226778
226788
  className={\`{{cssClassName}}__animation \${animation}\`}
226779
226789
  aria-hidden="true"
226780
- data-wp-class--is-active="state.isAnimating"
226790
+ data-wp-class--is-active={isAnimatingDirective}
226781
226791
  />
226782
226792
 
226783
226793
  {maxClicks > 0 && (
@@ -226786,7 +226796,7 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
226786
226796
  role="status"
226787
226797
  aria-live="polite"
226788
226798
  aria-atomic="true"
226789
- data-wp-bind--hidden="!state.isComplete"
226799
+ data-wp-bind--hidden={completionHiddenDirective}
226790
226800
  >
226791
226801
  { __( '\uD83C\uDF89 Complete!', '{{textDomain}}' ) }
226792
226802
  </div>
@@ -226794,7 +226804,7 @@ export default function Save({ attributes }: { attributes: {{pascalCase}}Attribu
226794
226804
 
226795
226805
  <button
226796
226806
  className="{{cssClassName}}__reset"
226797
- data-wp-on--click="actions.reset"
226807
+ data-wp-on--click={resetActionDirective}
226798
226808
  aria-label={ __( 'Reset counter', '{{textDomain}}' ) }
226799
226809
  >
226800
226810
  <span aria-hidden="true">\u21BB</span>
@@ -226842,20 +226852,213 @@ const registration = buildScaffoldBlockRegistration(
226842
226852
  );
226843
226853
 
226844
226854
  registerScaffoldBlockType(registration.name, registration.settings);
226855
+ `, INTERACTIVITY_STORE_TEMPLATE = `import type {
226856
+ {{pascalCase}}Context,
226857
+ {{pascalCase}}State,
226858
+ } from './types';
226859
+
226860
+ type InteractivityActionShape = object;
226861
+ type InteractivityCallbackShape = object;
226862
+ type InteractivityContextShape = object;
226863
+ type InteractivityStateShape = object;
226864
+ type InteractivityCallable = Function;
226865
+ type InteractivityKey<T extends object> = Extract<keyof T, string>;
226866
+ type InteractivityMethodKey<T extends object> = {
226867
+ [Key in InteractivityKey<T>]: T[Key] extends InteractivityCallable ? Key : never;
226868
+ }[InteractivityKey<T>];
226869
+
226870
+ type InteractivityDirectivePath<
226871
+ Root extends string,
226872
+ Key extends string,
226873
+ > = \`\${Root}.\${Key}\`;
226874
+
226875
+ type NegatedInteractivityDirectivePath<Path extends string> = \`!\${Path}\`;
226876
+
226877
+ export interface TypedInteractivityDirectiveHelpers<
226878
+ State extends InteractivityStateShape,
226879
+ Context extends InteractivityContextShape,
226880
+ Actions extends InteractivityActionShape,
226881
+ Callbacks extends InteractivityCallbackShape,
226882
+ Namespace extends string,
226883
+ > {
226884
+ readonly interactive: Namespace;
226885
+ action<Key extends InteractivityMethodKey<Actions>>(
226886
+ key: Key,
226887
+ ): InteractivityDirectivePath<'actions', Key>;
226888
+ callback<Key extends InteractivityMethodKey<Callbacks>>(
226889
+ key: Key,
226890
+ ): InteractivityDirectivePath<'callbacks', Key>;
226891
+ state<Key extends InteractivityKey<State>>(
226892
+ key: Key,
226893
+ ): InteractivityDirectivePath<'state', Key>;
226894
+ context<Key extends InteractivityKey<Context>>(
226895
+ key: Key,
226896
+ ): InteractivityDirectivePath<'context', Key>;
226897
+ negate<Path extends string>(
226898
+ path: Path,
226899
+ ): NegatedInteractivityDirectivePath<Path>;
226900
+ }
226901
+
226902
+ export interface TypedInteractivityStore<
226903
+ Namespace extends string,
226904
+ State extends InteractivityStateShape,
226905
+ Context extends InteractivityContextShape,
226906
+ Actions extends InteractivityActionShape,
226907
+ Callbacks extends InteractivityCallbackShape,
226908
+ > {
226909
+ readonly namespace: Namespace;
226910
+ readonly state: State;
226911
+ readonly context: Context;
226912
+ readonly actions: Actions;
226913
+ readonly callbacks: Callbacks;
226914
+ readonly directive: TypedInteractivityDirectiveHelpers<
226915
+ State,
226916
+ Context,
226917
+ Actions,
226918
+ Callbacks,
226919
+ Namespace
226920
+ >;
226921
+ createContext(value: Context): Context;
226922
+ }
226923
+
226924
+ export function defineInteractivityStore<
226925
+ Namespace extends string,
226926
+ State extends InteractivityStateShape,
226927
+ Context extends InteractivityContextShape,
226928
+ Actions extends InteractivityActionShape,
226929
+ Callbacks extends InteractivityCallbackShape,
226930
+ >(config: {
226931
+ readonly namespace: Namespace;
226932
+ readonly state: State;
226933
+ readonly context: Context;
226934
+ readonly actions: Actions;
226935
+ readonly callbacks: Callbacks;
226936
+ }): TypedInteractivityStore<Namespace, State, Context, Actions, Callbacks> {
226937
+ return {
226938
+ namespace: config.namespace,
226939
+ state: config.state,
226940
+ context: config.context,
226941
+ actions: config.actions,
226942
+ callbacks: config.callbacks,
226943
+ directive: {
226944
+ interactive: config.namespace,
226945
+ action<Key extends InteractivityMethodKey<Actions>>(key: Key) {
226946
+ return \`actions.\${key}\` as InteractivityDirectivePath<'actions', Key>;
226947
+ },
226948
+ callback<Key extends InteractivityMethodKey<Callbacks>>(key: Key) {
226949
+ return \`callbacks.\${key}\` as InteractivityDirectivePath<'callbacks', Key>;
226950
+ },
226951
+ state<Key extends InteractivityKey<State>>(key: Key) {
226952
+ return \`state.\${key}\` as InteractivityDirectivePath<'state', Key>;
226953
+ },
226954
+ context<Key extends InteractivityKey<Context>>(key: Key) {
226955
+ return \`context.\${key}\` as InteractivityDirectivePath<'context', Key>;
226956
+ },
226957
+ negate<Path extends string>(path: Path) {
226958
+ return \`!\${path}\` as NegatedInteractivityDirectivePath<Path>;
226959
+ },
226960
+ },
226961
+ createContext(value) {
226962
+ return value;
226963
+ },
226964
+ };
226965
+ }
226966
+
226967
+ type InteractivityActionHandler = Function;
226968
+
226969
+ export interface {{pascalCase}}StoreActions {
226970
+ handleClick: InteractivityActionHandler;
226971
+ handleMouseEnter: InteractivityActionHandler;
226972
+ handleMouseLeave: InteractivityActionHandler;
226973
+ reset: InteractivityActionHandler;
226974
+ }
226975
+
226976
+ export interface {{pascalCase}}StoreCallbacks {}
226977
+
226978
+ export const {{slugCamelCase}}Store = defineInteractivityStore({
226979
+ namespace: '{{slugKebabCase}}',
226980
+ state: {} as {{pascalCase}}State,
226981
+ context: {} as {{pascalCase}}Context,
226982
+ actions: {} as {{pascalCase}}StoreActions,
226983
+ callbacks: {} as {{pascalCase}}StoreCallbacks,
226984
+ });
226845
226985
  `, INTERACTIVITY_SCRIPT_TEMPLATE = `/**
226846
226986
  * WordPress Interactivity API implementation for {{title}} block
226847
226987
  */
226848
226988
  import { store, getContext, getElement, withSyncEvent } from '@wordpress/interactivity';
226849
- import type { {{pascalCase}}Context } from './types';
226989
+ import {
226990
+ {{slugCamelCase}}Store,
226991
+ type {{pascalCase}}StoreActions,
226992
+ } from './interactivity-store';
226993
+ import type { {{pascalCase}}Context, {{pascalCase}}State } from './types';
226850
226994
 
226851
226995
  function getBlockContext() {
226852
226996
  return getContext<{{pascalCase}}Context>();
226853
226997
  }
226854
226998
 
226855
- // Store configuration
226856
- store('{{slugKebabCase}}', {
226857
- // State - reactive data that updates the UI
226858
- state: {
226999
+ const actions: {{pascalCase}}StoreActions = {
227000
+ // Handle block click
227001
+ handleClick: () => {
227002
+ const context = getBlockContext();
227003
+ const { ref } = getElement();
227004
+
227005
+ if (!ref) {
227006
+ return;
227007
+ }
227008
+
227009
+ if (context.maxClicks > 0 && context.clicks >= context.maxClicks) {
227010
+ return;
227011
+ }
227012
+
227013
+ const previousClicks = context.clicks;
227014
+
227015
+ // Increment click counter
227016
+ context.clicks += 1;
227017
+
227018
+ // Trigger animation
227019
+ if (context.animation !== 'none') {
227020
+ context.isAnimating = true;
227021
+ setTimeout(() => {
227022
+ context.isAnimating = false;
227023
+ }, 1000);
227024
+ }
227025
+
227026
+ // Emit custom event
227027
+ ref.dispatchEvent(new CustomEvent('{{slugKebabCase}}:click', {
227028
+ detail: { clicks: context.clicks }
227029
+ }));
227030
+
227031
+ // Check if max clicks reached
227032
+ if (context.maxClicks > 0 && previousClicks < context.maxClicks && context.clicks === context.maxClicks) {
227033
+ ref.dispatchEvent(new CustomEvent('{{slugKebabCase}}:complete', {
227034
+ detail: { totalClicks: context.clicks }
227035
+ }));
227036
+ }
227037
+ },
227038
+
227039
+ // Handle hover events
227040
+ handleMouseEnter: () => {
227041
+ const context = getBlockContext();
227042
+ if (context.animation === 'none') return;
227043
+ context.isAnimating = true;
227044
+ },
227045
+
227046
+ handleMouseLeave: () => {
227047
+ const context = getBlockContext();
227048
+ if (context.animation === 'none') return;
227049
+ context.isAnimating = false;
227050
+ },
227051
+
227052
+ // Reset counter
227053
+ reset: withSyncEvent((event: Event) => {
227054
+ event.stopPropagation();
227055
+ const context = getBlockContext();
227056
+ context.clicks = 0;
227057
+ context.isAnimating = false;
227058
+ })
227059
+ };
227060
+
227061
+ const state = {
226859
227062
  get clicks() {
226860
227063
  return getBlockContext().clicks;
226861
227064
  },
@@ -226883,70 +227086,14 @@ store('{{slugKebabCase}}', {
226883
227086
  const context = getBlockContext();
226884
227087
  return context.clicks >= context.maxClicks && context.maxClicks > 0;
226885
227088
  }
226886
- },
226887
-
226888
- // Actions - user interactions
226889
- actions: {
226890
- // Handle block click
226891
- handleClick: () => {
226892
- const context = getBlockContext();
226893
- const { ref } = getElement();
226894
-
226895
- if (!ref) {
226896
- return;
226897
- }
226898
-
226899
- if (context.maxClicks > 0 && context.clicks >= context.maxClicks) {
226900
- return;
226901
- }
226902
-
226903
- const previousClicks = context.clicks;
227089
+ } satisfies {{pascalCase}}State;
226904
227090
 
226905
- // Increment click counter
226906
- context.clicks += 1;
226907
-
226908
- // Trigger animation
226909
- if (context.animation !== 'none') {
226910
- context.isAnimating = true;
226911
- setTimeout(() => {
226912
- context.isAnimating = false;
226913
- }, 1000);
226914
- }
226915
-
226916
- // Emit custom event
226917
- ref.dispatchEvent(new CustomEvent('{{slugKebabCase}}:click', {
226918
- detail: { clicks: context.clicks }
226919
- }));
226920
-
226921
- // Check if max clicks reached
226922
- if (context.maxClicks > 0 && previousClicks < context.maxClicks && context.clicks === context.maxClicks) {
226923
- ref.dispatchEvent(new CustomEvent('{{slugKebabCase}}:complete', {
226924
- detail: { totalClicks: context.clicks }
226925
- }));
226926
- }
226927
- },
226928
-
226929
- // Handle hover events
226930
- handleMouseEnter: () => {
226931
- const context = getBlockContext();
226932
- if (context.animation === 'none') return;
226933
- context.isAnimating = true;
226934
- },
226935
-
226936
- handleMouseLeave: () => {
226937
- const context = getBlockContext();
226938
- if (context.animation === 'none') return;
226939
- context.isAnimating = false;
226940
- },
226941
-
226942
- // Reset counter
226943
- reset: withSyncEvent((event: Event) => {
226944
- event.stopPropagation();
226945
- const context = getBlockContext();
226946
- context.clicks = 0;
226947
- context.isAnimating = false;
226948
- })
226949
- }
227091
+ // Store configuration
227092
+ store({{slugCamelCase}}Store.namespace, {
227093
+ // State - reactive data that updates the UI
227094
+ state,
227095
+ actions,
227096
+ callbacks: {{slugCamelCase}}Store.callbacks,
226950
227097
  });
226951
227098
  `, INTERACTIVITY_VALIDATORS_TEMPLATE = `import typia from 'typia';
226952
227099
  import currentManifest from "./manifest-defaults-document";
@@ -228757,6 +228904,10 @@ function buildInteractivityCodeArtifacts(variables) {
228757
228904
  relativePath: "src/interactivity.ts",
228758
228905
  template: INTERACTIVITY_SCRIPT_TEMPLATE
228759
228906
  },
228907
+ {
228908
+ relativePath: "src/interactivity-store.ts",
228909
+ template: INTERACTIVITY_STORE_TEMPLATE
228910
+ },
228760
228911
  {
228761
228912
  relativePath: "src/validators.ts",
228762
228913
  template: INTERACTIVITY_VALIDATORS_TEMPLATE
@@ -230133,6 +230284,8 @@ async function resolveOptionalInteractiveExternalLayerId({
230133
230284
  callerCwd,
230134
230285
  externalLayerId,
230135
230286
  externalLayerSource,
230287
+ listExternalTemplateLayers = listSelectableExternalTemplateLayers,
230288
+ resolveExternalTemplateSeed = resolveTemplateSeed,
230136
230289
  selectExternalLayerId
230137
230290
  }) {
230138
230291
  if (!externalLayerSource || externalLayerId || !selectExternalLayerId) {
@@ -230141,9 +230294,9 @@ async function resolveOptionalInteractiveExternalLayerId({
230141
230294
  externalLayerSource
230142
230295
  };
230143
230296
  }
230144
- const layerSeed = await resolveTemplateSeed(parseTemplateLocator(externalLayerSource), callerCwd);
230297
+ const layerSeed = await resolveExternalTemplateSeed(parseTemplateLocator(externalLayerSource), callerCwd);
230145
230298
  try {
230146
- const selectableLayers = await listSelectableExternalTemplateLayers(layerSeed.rootDir);
230299
+ const selectableLayers = await listExternalTemplateLayers(layerSeed.rootDir);
230147
230300
  if (selectableLayers.length <= 1) {
230148
230301
  await layerSeed.cleanup?.();
230149
230302
  return {
@@ -230159,7 +230312,6 @@ async function resolveOptionalInteractiveExternalLayerId({
230159
230312
  externalLayerSource: layerSeed.rootDir
230160
230313
  };
230161
230314
  }
230162
- await layerSeed.cleanup?.();
230163
230315
  throw new Error(`Unknown external layer "${selectedLayerId}". Expected one of: ${selectableLayers.map((layer) => layer.id).join(", ")}`);
230164
230316
  } catch (error48) {
230165
230317
  await layerSeed.cleanup?.();
@@ -230561,14 +230713,25 @@ function normalizeVersionRange2(value2, fallback) {
230561
230713
  }
230562
230714
  return /^[~^<>=]/u.test(trimmed) ? trimmed : `^${trimmed}`;
230563
230715
  }
230564
- function readPackageManifestVersion(packageJsonPath) {
230716
+ function readPackageManifest2(packageJsonPath) {
230565
230717
  try {
230566
- const packageJson = JSON.parse(fs42.readFileSync(packageJsonPath, "utf8"));
230567
- return packageJson.version;
230718
+ return JSON.parse(fs42.readFileSync(packageJsonPath, "utf8"));
230568
230719
  } catch {
230569
230720
  return;
230570
230721
  }
230571
230722
  }
230723
+ function readPackageManifestVersion(packageJsonPath) {
230724
+ return readPackageManifest2(packageJsonPath)?.version;
230725
+ }
230726
+ function isAdminViewUnpublishedDataViewsOverrideEnabled() {
230727
+ return process.env[ADMIN_VIEW_ALLOW_UNPUBLISHED_DATAVIEWS_ENV]?.trim() === "1";
230728
+ }
230729
+ function assertAdminViewPackageAvailability() {
230730
+ if (isAdminViewUnpublishedDataViewsOverrideEnabled() || ADMIN_VIEW_PUBLIC_INSTALLS_ENABLED) {
230731
+ return;
230732
+ }
230733
+ throw createCliDiagnosticCodeError(CLI_DIAGNOSTIC_CODES.INVALID_ARGUMENT, "`wp-typia add admin-view` is temporarily unavailable because `@wp-typia/dataviews` is not published to npm for public installs yet.");
230734
+ }
230572
230735
  function detectJsonIndent(source) {
230573
230736
  const indentMatch = /\n([ \t]+)"/u.exec(source);
230574
230737
  return indentMatch?.[1] ?? 2;
@@ -230593,22 +230756,77 @@ function getAdminViewRelativeModuleSpecifier(adminViewSlug, workspaceFile) {
230593
230756
  const relativeModulePath = path51.posix.relative(adminViewDir, modulePath);
230594
230757
  return relativeModulePath.startsWith(".") ? relativeModulePath : `./${relativeModulePath}`;
230595
230758
  }
230759
+ function isAdminViewCoreDataSource(source) {
230760
+ return source?.kind === ADMIN_VIEW_CORE_DATA_SOURCE_KIND;
230761
+ }
230762
+ function isAdminViewRestResourceSource(source) {
230763
+ return source?.kind === ADMIN_VIEW_REST_SOURCE_KIND;
230764
+ }
230765
+ function assertValidCoreDataEntitySegment(label, value2) {
230766
+ const trimmed = value2.trim();
230767
+ if (!trimmed) {
230768
+ throw new Error(`${label} is required. Use \`${ADMIN_VIEW_SOURCE_USAGE}\`.`);
230769
+ }
230770
+ if (!ADMIN_VIEW_CORE_DATA_ENTITY_SEGMENT_PATTERN.test(trimmed)) {
230771
+ throw new Error(`${label} must start with a letter and contain only letters, numbers, underscores, or hyphens.`);
230772
+ }
230773
+ return trimmed;
230774
+ }
230775
+ function assertValidCoreDataEntityName(value2) {
230776
+ const normalized = value2.trim();
230777
+ if (!normalized) {
230778
+ throw new Error(`Admin view source entity name is required. Use \`${ADMIN_VIEW_SOURCE_USAGE}\`.`);
230779
+ }
230780
+ if (!ADMIN_VIEW_CORE_DATA_ENTITY_NAME_PATTERN.test(normalized)) {
230781
+ throw new Error("Admin view source entity name must start with a lowercase letter or number and contain only lowercase letters, numbers, underscores, or hyphens.");
230782
+ }
230783
+ return normalized;
230784
+ }
230785
+ function assertValidCoreDataEntityKind(value2) {
230786
+ const normalized = assertValidCoreDataEntitySegment("Admin view source entity kind", value2);
230787
+ if (!ADMIN_VIEW_CORE_DATA_ENTITY_KIND_IDS.includes(normalized)) {
230788
+ throw new Error(`Admin view core-data sources currently support only: ${ADMIN_VIEW_CORE_DATA_ENTITY_KIND_IDS.join(", ")}.`);
230789
+ }
230790
+ return normalized;
230791
+ }
230792
+ function formatAdminViewSourceLocator(source) {
230793
+ if (isAdminViewCoreDataSource(source)) {
230794
+ return `${source.kind}:${source.entityKind}/${source.entityName}`;
230795
+ }
230796
+ return `${source.kind}:${source.slug}`;
230797
+ }
230596
230798
  function parseAdminViewSource(source) {
230597
230799
  const trimmed = source?.trim();
230598
230800
  if (!trimmed) {
230599
230801
  return;
230600
230802
  }
230601
- const [kind, slug, extra] = trimmed.split(":");
230602
- if (kind !== ADMIN_VIEW_SOURCE_KIND || !slug || extra !== undefined) {
230603
- throw new Error("Admin view source must use `rest-resource:<slug>` for now.");
230803
+ const separatorIndex = trimmed.indexOf(":");
230804
+ const kind = separatorIndex === -1 ? trimmed : trimmed.slice(0, separatorIndex);
230805
+ const locator = separatorIndex === -1 ? "" : trimmed.slice(separatorIndex + 1);
230806
+ if (!locator) {
230807
+ throw new Error("Admin view source must use `rest-resource:<slug>` or `core-data:<kind>/<name>`.");
230604
230808
  }
230605
- return {
230606
- kind,
230607
- slug: assertValidGeneratedSlug("Admin view source slug", normalizeBlockSlug(slug), "wp-typia add admin-view <name> --source rest-resource:<slug>")
230608
- };
230809
+ if (kind === ADMIN_VIEW_REST_SOURCE_KIND) {
230810
+ return {
230811
+ kind,
230812
+ slug: assertValidGeneratedSlug("Admin view source slug", locator, ADMIN_VIEW_SOURCE_USAGE)
230813
+ };
230814
+ }
230815
+ if (kind === ADMIN_VIEW_CORE_DATA_SOURCE_KIND) {
230816
+ const [entityKind, entityName, extra] = locator.split("/");
230817
+ if (!entityKind || !entityName || extra !== undefined) {
230818
+ throw new Error("Admin view core-data sources must use `core-data:<kind>/<name>`, for example `core-data:postType/post`.");
230819
+ }
230820
+ return {
230821
+ entityKind: assertValidCoreDataEntityKind(entityKind),
230822
+ entityName: assertValidCoreDataEntityName(entityName),
230823
+ kind
230824
+ };
230825
+ }
230826
+ throw new Error("Admin view source must use `rest-resource:<slug>` or `core-data:<kind>/<name>`.");
230609
230827
  }
230610
230828
  function resolveRestResourceSource(restResources, source) {
230611
- if (!source) {
230829
+ if (!isAdminViewRestResourceSource(source)) {
230612
230830
  return;
230613
230831
  }
230614
230832
  const restResource = restResources.find((entry) => entry.slug === source.slug);
@@ -230626,7 +230844,7 @@ function buildAdminViewConfigEntry(adminViewSlug, source) {
230626
230844
  ` file: ${quoteTsString(`src/admin-views/${adminViewSlug}/index.tsx`)},`,
230627
230845
  ` phpFile: ${quoteTsString(`inc/admin-views/${adminViewSlug}.php`)},`,
230628
230846
  ` slug: ${quoteTsString(adminViewSlug)},`,
230629
- source ? ` source: ${quoteTsString(`${source.kind}:${source.slug}`)},` : null,
230847
+ source ? ` source: ${quoteTsString(formatAdminViewSourceLocator(source))},` : null,
230630
230848
  "\t},"
230631
230849
  ].filter((line) => typeof line === "string").join(`
230632
230850
  `);
@@ -230639,8 +230857,9 @@ function buildAdminViewRegistrySource(adminViewSlugs) {
230639
230857
  ` : ""}// wp-typia add admin-view entries
230640
230858
  `;
230641
230859
  }
230642
- function buildAdminViewTypesSource(adminViewSlug, restResource) {
230860
+ function buildAdminViewTypesSource(adminViewSlug, restResource, coreDataSource) {
230643
230861
  const pascalName = toPascalCase(adminViewSlug);
230862
+ const coreDataRecordTypeName = `${pascalName}CoreDataRecord`;
230644
230863
  const itemTypeName = `${pascalName}AdminViewItem`;
230645
230864
  const dataSetTypeName = `${pascalName}AdminViewDataSet`;
230646
230865
  if (restResource) {
@@ -230650,6 +230869,74 @@ function buildAdminViewTypesSource(adminViewSlug, restResource) {
230650
230869
 
230651
230870
  export type ${itemTypeName} = ${restPascalName}Record;
230652
230871
 
230872
+ export interface ${dataSetTypeName} {
230873
+ items: ${itemTypeName}[];
230874
+ paginationInfo: {
230875
+ totalItems: number;
230876
+ totalPages: number;
230877
+ };
230878
+ }
230879
+ `;
230880
+ }
230881
+ if (coreDataSource) {
230882
+ if (coreDataSource.entityKind === "taxonomy") {
230883
+ return `export interface ${coreDataRecordTypeName} {
230884
+ count?: number;
230885
+ description?: string;
230886
+ id: number;
230887
+ link?: string;
230888
+ meta?: Record<string, unknown>;
230889
+ name?: string;
230890
+ parent?: number;
230891
+ slug?: string;
230892
+ taxonomy?: string;
230893
+ [key: string]: unknown;
230894
+ }
230895
+
230896
+ export interface ${itemTypeName} {
230897
+ count: number;
230898
+ description: string;
230899
+ id: number;
230900
+ link: string;
230901
+ name: string;
230902
+ parent: number;
230903
+ raw: ${coreDataRecordTypeName};
230904
+ slug: string;
230905
+ taxonomy: string;
230906
+ }
230907
+
230908
+ export interface ${dataSetTypeName} {
230909
+ items: ${itemTypeName}[];
230910
+ paginationInfo: {
230911
+ totalItems: number;
230912
+ totalPages: number;
230913
+ };
230914
+ }
230915
+ `;
230916
+ }
230917
+ return `export interface ${coreDataRecordTypeName} {
230918
+ id: number;
230919
+ date?: string;
230920
+ modified?: string;
230921
+ name?: string;
230922
+ slug?: string;
230923
+ status?: string;
230924
+ title?: string | {
230925
+ raw?: string;
230926
+ rendered?: string;
230927
+ };
230928
+ [key: string]: unknown;
230929
+ }
230930
+
230931
+ export interface ${itemTypeName} {
230932
+ id: number;
230933
+ raw: ${coreDataRecordTypeName};
230934
+ slug: string;
230935
+ status: string;
230936
+ title: string;
230937
+ updatedAt: string;
230938
+ }
230939
+
230653
230940
  export interface ${dataSetTypeName} {
230654
230941
  items: ${itemTypeName}[];
230655
230942
  paginationInfo: {
@@ -230678,22 +230965,74 @@ export interface ${dataSetTypeName} {
230678
230965
  }
230679
230966
  `;
230680
230967
  }
230681
- function buildAdminViewConfigSource(adminViewSlug, textDomain, restResource) {
230968
+ function buildAdminViewConfigSource(adminViewSlug, textDomain, source, restResource) {
230682
230969
  const pascalName = toPascalCase(adminViewSlug);
230683
230970
  const camelName = toCamelCase(adminViewSlug);
230684
230971
  const itemTypeName = `${pascalName}AdminViewItem`;
230685
230972
  const dataViewsName = `${camelName}AdminDataViews`;
230686
- const defaultViewFields = restResource ? "['id']" : "['title', 'status', 'updatedAt']";
230973
+ const isCoreDataSource = source?.kind === ADMIN_VIEW_CORE_DATA_SOURCE_KIND;
230974
+ const isTaxonomyCoreDataSource = source?.kind === ADMIN_VIEW_CORE_DATA_SOURCE_KIND && source.entityKind === "taxonomy";
230975
+ const defaultViewFields = restResource ? "['id']" : isTaxonomyCoreDataSource ? "['name', 'slug', 'count']" : isCoreDataSource ? "['title', 'slug', 'status', 'updatedAt']" : "['title', 'status', 'updatedAt']";
230687
230976
  const searchEnabled = restResource ? "false" : "true";
230688
- const titleFieldSource = restResource ? "" : ` titleField: 'title',
230977
+ const titleFieldSource = restResource ? "" : isTaxonomyCoreDataSource ? ` titleField: 'name',
230978
+ ` : ` titleField: 'title',
230689
230979
  `;
230690
- const defaultViewEnhancementsSource = restResource ? "" : ` sort: {
230980
+ const defaultViewEnhancementsSource = restResource ? "" : isTaxonomyCoreDataSource ? ` titleField: 'name',
230981
+ ` : isCoreDataSource ? ` titleField: 'title',
230982
+ ` : ` sort: {
230691
230983
  direction: 'desc',
230692
230984
  field: 'updatedAt',
230693
230985
  },
230694
230986
  titleField: 'title',
230695
230987
  `;
230696
- const additionalFieldsSource = restResource ? "\t\t// REST-backed screens start with the guaranteed ID column. Add project-owned fields here once they are declared on the REST record type." : ` owner: {
230988
+ const additionalFieldsSource = restResource ? "\t\t// REST-backed screens start with the guaranteed ID column. Add project-owned fields here once they are declared on the REST record type." : isTaxonomyCoreDataSource ? ` count: {
230989
+ label: __( 'Count', ${quoteTsString(textDomain)} ),
230990
+ schema: { type: 'integer' },
230991
+ },
230992
+ description: {
230993
+ label: __( 'Description', ${quoteTsString(textDomain)} ),
230994
+ schema: { type: 'string' },
230995
+ },
230996
+ link: {
230997
+ label: __( 'Link', ${quoteTsString(textDomain)} ),
230998
+ schema: { format: 'uri', type: 'string' },
230999
+ },
231000
+ name: {
231001
+ enableGlobalSearch: true,
231002
+ label: __( 'Name', ${quoteTsString(textDomain)} ),
231003
+ schema: { type: 'string' },
231004
+ },
231005
+ parent: {
231006
+ label: __( 'Parent', ${quoteTsString(textDomain)} ),
231007
+ schema: { type: 'integer' },
231008
+ },
231009
+ slug: {
231010
+ enableGlobalSearch: true,
231011
+ label: __( 'Slug', ${quoteTsString(textDomain)} ),
231012
+ schema: { type: 'string' },
231013
+ },
231014
+ taxonomy: {
231015
+ label: __( 'Taxonomy', ${quoteTsString(textDomain)} ),
231016
+ schema: { type: 'string' },
231017
+ },` : isCoreDataSource ? ` slug: {
231018
+ enableGlobalSearch: true,
231019
+ label: __( 'Slug', ${quoteTsString(textDomain)} ),
231020
+ schema: { type: 'string' },
231021
+ },
231022
+ status: {
231023
+ label: __( 'Status', ${quoteTsString(textDomain)} ),
231024
+ schema: { type: 'string' },
231025
+ },
231026
+ title: {
231027
+ enableGlobalSearch: true,
231028
+ label: __( 'Name', ${quoteTsString(textDomain)} ),
231029
+ schema: { type: 'string' },
231030
+ },
231031
+ updatedAt: {
231032
+ label: __( 'Updated', ${quoteTsString(textDomain)} ),
231033
+ schema: { format: 'date-time', type: 'string' },
231034
+ type: 'datetime',
231035
+ },` : ` owner: {
230697
231036
  label: __( 'Owner', ${quoteTsString(textDomain)} ),
230698
231037
  schema: { type: 'string' },
230699
231038
  },
@@ -230880,6 +231219,217 @@ export async function ${fetchName}(
230880
231219
  }
230881
231220
  `;
230882
231221
  }
231222
+ function buildCoreDataAdminViewDataSource(adminViewSlug, coreDataSource) {
231223
+ const pascalName = toPascalCase(adminViewSlug);
231224
+ const camelName = toCamelCase(adminViewSlug);
231225
+ const coreDataRecordTypeName = `${pascalName}CoreDataRecord`;
231226
+ const dataSetTypeName = `${pascalName}AdminViewDataSet`;
231227
+ const itemTypeName = `${pascalName}AdminViewItem`;
231228
+ const queryTypeName = `${pascalName}AdminViewQuery`;
231229
+ const dataViewsName = `${camelName}AdminDataViews`;
231230
+ const useEntityRecordName = `use${pascalName}EntityRecord`;
231231
+ const useEntityRecordsName = `use${pascalName}EntityRecords`;
231232
+ const useAdminViewDataName = `use${pascalName}AdminViewData`;
231233
+ if (coreDataSource.entityKind === "taxonomy") {
231234
+ return `import type { DataViewsView } from '@wp-typia/dataviews';
231235
+ import { useEntityRecord, useEntityRecords } from '@wordpress/core-data';
231236
+ import { useMemo } from '@wordpress/element';
231237
+
231238
+ import { ${dataViewsName} } from './config';
231239
+ import type {
231240
+ ${coreDataRecordTypeName},
231241
+ ${dataSetTypeName},
231242
+ ${itemTypeName},
231243
+ } from './types';
231244
+
231245
+ export interface ${queryTypeName} {
231246
+ page?: number;
231247
+ per_page?: number;
231248
+ search?: string;
231249
+ }
231250
+
231251
+ const CORE_DATA_ENTITY_KIND = ${quoteTsString(coreDataSource.entityKind)};
231252
+ const CORE_DATA_ENTITY_NAME = ${quoteTsString(coreDataSource.entityName)};
231253
+
231254
+ function normalizeCoreDataNumber(value: unknown): number {
231255
+ return typeof value === 'number' && Number.isFinite(value) ? value : 0;
231256
+ }
231257
+
231258
+ function normalizeCoreDataString(value: unknown): string {
231259
+ return typeof value === 'string' ? value : '';
231260
+ }
231261
+
231262
+ function normalizeTaxonomyRecord(record: ${coreDataRecordTypeName}): ${itemTypeName} {
231263
+ return {
231264
+ count: normalizeCoreDataNumber(record.count),
231265
+ description: normalizeCoreDataString(record.description),
231266
+ id: record.id,
231267
+ link: normalizeCoreDataString(record.link),
231268
+ name: normalizeCoreDataString(record.name) || normalizeCoreDataString(record.slug),
231269
+ parent: normalizeCoreDataNumber(record.parent),
231270
+ raw: record,
231271
+ slug: normalizeCoreDataString(record.slug),
231272
+ taxonomy: normalizeCoreDataString(record.taxonomy),
231273
+ };
231274
+ }
231275
+
231276
+ export function ${useEntityRecordName}(recordId: number | undefined) {
231277
+ return useEntityRecord<${coreDataRecordTypeName}>(
231278
+ CORE_DATA_ENTITY_KIND,
231279
+ CORE_DATA_ENTITY_NAME,
231280
+ recordId ?? 0,
231281
+ { enabled: typeof recordId === 'number' },
231282
+ );
231283
+ }
231284
+
231285
+ export function ${useEntityRecordsName}(view: DataViewsView<${itemTypeName}>) {
231286
+ const query = ${dataViewsName}.toQueryArgs<${queryTypeName}>(view, {
231287
+ perPageParam: 'per_page',
231288
+ });
231289
+
231290
+ return useEntityRecords<${coreDataRecordTypeName}>(
231291
+ CORE_DATA_ENTITY_KIND,
231292
+ CORE_DATA_ENTITY_NAME,
231293
+ query,
231294
+ );
231295
+ }
231296
+
231297
+ export function ${useAdminViewDataName}(view: DataViewsView<${itemTypeName}>) {
231298
+ const { hasResolved, isResolving, records, totalItems, totalPages } =
231299
+ ${useEntityRecordsName}(view);
231300
+ const items = useMemo(
231301
+ () => (records ?? []).map((record) => normalizeTaxonomyRecord(record)),
231302
+ [records],
231303
+ );
231304
+ const dataSet = useMemo<${dataSetTypeName}>(
231305
+ () => ({
231306
+ items,
231307
+ paginationInfo: {
231308
+ totalItems: totalItems ?? items.length,
231309
+ totalPages: Math.max(1, totalPages ?? 1),
231310
+ },
231311
+ }),
231312
+ [items, totalItems, totalPages],
231313
+ );
231314
+ const error =
231315
+ !isResolving && hasResolved && records === null
231316
+ ? 'Unable to load core-data entity records.'
231317
+ : null;
231318
+
231319
+ return {
231320
+ dataSet,
231321
+ error,
231322
+ isLoading: isResolving,
231323
+ };
231324
+ }
231325
+ `;
231326
+ }
231327
+ return `import type { DataViewsView } from '@wp-typia/dataviews';
231328
+ import { useEntityRecord, useEntityRecords } from '@wordpress/core-data';
231329
+ import { useMemo } from '@wordpress/element';
231330
+
231331
+ import { ${dataViewsName} } from './config';
231332
+ import type {
231333
+ ${coreDataRecordTypeName},
231334
+ ${dataSetTypeName},
231335
+ ${itemTypeName},
231336
+ } from './types';
231337
+
231338
+ export interface ${queryTypeName} {
231339
+ page?: number;
231340
+ per_page?: number;
231341
+ search?: string;
231342
+ }
231343
+
231344
+ const CORE_DATA_ENTITY_KIND = ${quoteTsString(coreDataSource.entityKind)};
231345
+ const CORE_DATA_ENTITY_NAME = ${quoteTsString(coreDataSource.entityName)};
231346
+
231347
+ function normalizeCoreDataString(value: unknown): string {
231348
+ return typeof value === 'string' ? value : '';
231349
+ }
231350
+
231351
+ function normalizeCoreDataTitle(record: ${coreDataRecordTypeName}): string {
231352
+ if (typeof record.title === 'string') {
231353
+ return record.title;
231354
+ }
231355
+ if (record.title && typeof record.title === 'object') {
231356
+ if (typeof record.title.rendered === 'string') {
231357
+ return record.title.rendered;
231358
+ }
231359
+ if (typeof record.title.raw === 'string') {
231360
+ return record.title.raw;
231361
+ }
231362
+ }
231363
+
231364
+ return normalizeCoreDataString(record.name) || normalizeCoreDataString(record.slug);
231365
+ }
231366
+
231367
+ function normalizeCoreDataUpdatedAt(record: ${coreDataRecordTypeName}): string {
231368
+ return normalizeCoreDataString(record.modified) || normalizeCoreDataString(record.date);
231369
+ }
231370
+
231371
+ function normalizeCoreDataRecord(record: ${coreDataRecordTypeName}): ${itemTypeName} {
231372
+ return {
231373
+ id: record.id,
231374
+ raw: record,
231375
+ slug: normalizeCoreDataString(record.slug),
231376
+ status: normalizeCoreDataString(record.status),
231377
+ title: normalizeCoreDataTitle(record),
231378
+ updatedAt: normalizeCoreDataUpdatedAt(record),
231379
+ };
231380
+ }
231381
+
231382
+ export function ${useEntityRecordName}(recordId: number | undefined) {
231383
+ return useEntityRecord<${coreDataRecordTypeName}>(
231384
+ CORE_DATA_ENTITY_KIND,
231385
+ CORE_DATA_ENTITY_NAME,
231386
+ recordId ?? 0,
231387
+ { enabled: typeof recordId === 'number' },
231388
+ );
231389
+ }
231390
+
231391
+ export function ${useEntityRecordsName}(view: DataViewsView<${itemTypeName}>) {
231392
+ const query = ${dataViewsName}.toQueryArgs<${queryTypeName}>(view, {
231393
+ perPageParam: 'per_page',
231394
+ });
231395
+
231396
+ return useEntityRecords<${coreDataRecordTypeName}>(
231397
+ CORE_DATA_ENTITY_KIND,
231398
+ CORE_DATA_ENTITY_NAME,
231399
+ query,
231400
+ );
231401
+ }
231402
+
231403
+ export function ${useAdminViewDataName}(view: DataViewsView<${itemTypeName}>) {
231404
+ const { hasResolved, isResolving, records, totalItems, totalPages } =
231405
+ ${useEntityRecordsName}(view);
231406
+ const items = useMemo(
231407
+ () => (records ?? []).map((record) => normalizeCoreDataRecord(record)),
231408
+ [records],
231409
+ );
231410
+ const dataSet = useMemo<${dataSetTypeName}>(
231411
+ () => ({
231412
+ items,
231413
+ paginationInfo: {
231414
+ totalItems: totalItems ?? items.length,
231415
+ totalPages: Math.max(1, totalPages ?? 1),
231416
+ },
231417
+ }),
231418
+ [items, totalItems, totalPages],
231419
+ );
231420
+ const error =
231421
+ !isResolving && hasResolved && records === null
231422
+ ? 'Unable to load core-data entity records.'
231423
+ : null;
231424
+
231425
+ return {
231426
+ dataSet,
231427
+ error,
231428
+ isLoading: isResolving,
231429
+ };
231430
+ }
231431
+ `;
231432
+ }
230883
231433
  function buildAdminViewScreenSource(adminViewSlug, textDomain) {
230884
231434
  const pascalName = toPascalCase(adminViewSlug);
230885
231435
  const camelName = toCamelCase(adminViewSlug);
@@ -230993,6 +231543,81 @@ export function ${componentName}() {
230993
231543
  }
230994
231544
  `;
230995
231545
  }
231546
+ function buildCoreDataAdminViewScreenSource(adminViewSlug, textDomain) {
231547
+ const pascalName = toPascalCase(adminViewSlug);
231548
+ const camelName = toCamelCase(adminViewSlug);
231549
+ const itemTypeName = `${pascalName}AdminViewItem`;
231550
+ const dataSetTypeName = `${pascalName}AdminViewDataSet`;
231551
+ const componentName = `${pascalName}AdminViewScreen`;
231552
+ const dataViewsName = `${camelName}AdminDataViews`;
231553
+ const useAdminViewDataName = `use${pascalName}AdminViewData`;
231554
+ const title = toTitleCase(adminViewSlug);
231555
+ return `import type { DataViewsConfig, DataViewsView } from '@wp-typia/dataviews';
231556
+ import { Notice, Spinner } from '@wordpress/components';
231557
+ import { useState } from '@wordpress/element';
231558
+ import { __ } from '@wordpress/i18n';
231559
+ import { DataViews } from '@wordpress/dataviews/wp';
231560
+
231561
+ import { ${dataViewsName} } from './config';
231562
+ import { ${useAdminViewDataName} } from './data';
231563
+ import type { ${dataSetTypeName}, ${itemTypeName} } from './types';
231564
+
231565
+ const TypedDataViews = DataViews as unknown as <TItem extends object>(
231566
+ props: DataViewsConfig<TItem>,
231567
+ ) => ReturnType<typeof DataViews>;
231568
+
231569
+ const EMPTY_DATA_SET: ${dataSetTypeName} = {
231570
+ items: [],
231571
+ paginationInfo: {
231572
+ totalItems: 0,
231573
+ totalPages: 1,
231574
+ },
231575
+ };
231576
+
231577
+ export function ${componentName}() {
231578
+ const [view, setView] = useState<DataViewsView<${itemTypeName}>>(
231579
+ ${dataViewsName}.defaultView,
231580
+ );
231581
+ const {
231582
+ dataSet = EMPTY_DATA_SET,
231583
+ error,
231584
+ isLoading,
231585
+ } = ${useAdminViewDataName}(view);
231586
+ const config = ${dataViewsName}.createConfig({
231587
+ data: dataSet.items,
231588
+ isLoading,
231589
+ onChangeView: setView,
231590
+ paginationInfo: dataSet.paginationInfo,
231591
+ view,
231592
+ });
231593
+
231594
+ return (
231595
+ <div className="wp-typia-admin-view-screen">
231596
+ <header className="wp-typia-admin-view-screen__header">
231597
+ <div>
231598
+ <p className="wp-typia-admin-view-screen__eyebrow">
231599
+ { __( 'DataViews admin screen', ${quoteTsString(textDomain)} ) }
231600
+ </p>
231601
+ <h1>{ __( ${quoteTsString(title)}, ${quoteTsString(textDomain)} ) }</h1>
231602
+ <p>
231603
+ { __( 'This screen reads from the WordPress core-data entity store. Extend data.ts when you need entity-specific field mapping or edit flows.', ${quoteTsString(textDomain)} ) }
231604
+ </p>
231605
+ </div>
231606
+ <div className="wp-typia-admin-view-screen__actions">
231607
+ { isLoading ? <Spinner /> : null }
231608
+ </div>
231609
+ </header>
231610
+ { error ? (
231611
+ <Notice isDismissible={ false } status="error">
231612
+ { error }
231613
+ </Notice>
231614
+ ) : null }
231615
+ <TypedDataViews<${itemTypeName}> { ...config } />
231616
+ </div>
231617
+ );
231618
+ }
231619
+ `;
231620
+ }
230996
231621
  function buildAdminViewEntrySource(adminViewSlug) {
230997
231622
  const pascalName = toPascalCase(adminViewSlug);
230998
231623
  const componentName = `${pascalName}AdminViewScreen`;
@@ -231162,15 +231787,22 @@ add_action( 'admin_menu', '${registerFunctionName}' );
231162
231787
  add_action( 'admin_enqueue_scripts', '${enqueueFunctionName}' );
231163
231788
  `;
231164
231789
  }
231165
- async function ensureAdminViewPackageDependencies(workspace) {
231790
+ async function ensureAdminViewPackageDependencies(workspace, adminViewSource) {
231166
231791
  const packageJsonPath = path51.join(workspace.projectDir, "package.json");
231167
231792
  const wpTypiaDataViewsVersion = resolvePackageVersionRange("@wp-typia/dataviews", DEFAULT_WP_TYPIA_DATAVIEWS_VERSION, "wp-typia-dataviews");
231168
231793
  const wordpressDataViewsVersion = resolvePackageVersionRange("@wordpress/dataviews", DEFAULT_WORDPRESS_DATAVIEWS_VERSION);
231794
+ const wordpressCoreDataVersion = resolvePackageVersionRange("@wordpress/core-data", DEFAULT_WORDPRESS_CORE_DATA_VERSION);
231795
+ const wordpressDataVersion = resolvePackageVersionRange("@wordpress/data", DEFAULT_WORDPRESS_DATA_VERSION);
231169
231796
  await patchFile(packageJsonPath, (source) => {
231170
231797
  const packageJson = JSON.parse(source);
231798
+ const coreDataDependencies = isAdminViewCoreDataSource(adminViewSource) ? {
231799
+ "@wordpress/core-data": packageJson.dependencies?.["@wordpress/core-data"] ?? wordpressCoreDataVersion,
231800
+ "@wordpress/data": packageJson.dependencies?.["@wordpress/data"] ?? wordpressDataVersion
231801
+ } : {};
231171
231802
  const nextDependencies = {
231172
231803
  ...packageJson.dependencies ?? {},
231173
- "@wordpress/dataviews": packageJson.dependencies?.["@wordpress/dataviews"] ?? wordpressDataViewsVersion
231804
+ "@wordpress/dataviews": packageJson.dependencies?.["@wordpress/dataviews"] ?? wordpressDataViewsVersion,
231805
+ ...coreDataDependencies
231174
231806
  };
231175
231807
  const nextDevDependencies = {
231176
231808
  ...packageJson.devDependencies ?? {},
@@ -231350,10 +231982,12 @@ async function runAddAdminViewCommand({
231350
231982
  source
231351
231983
  }) {
231352
231984
  const workspace = resolveWorkspaceProject(cwd);
231353
- const adminViewSlug = assertValidGeneratedSlug("Admin view name", normalizeBlockSlug(adminViewName), "wp-typia add admin-view <name> [--source rest-resource:<slug>]");
231985
+ assertAdminViewPackageAvailability();
231986
+ const adminViewSlug = assertValidGeneratedSlug("Admin view name", normalizeBlockSlug(adminViewName), "wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>]");
231354
231987
  const parsedSource = parseAdminViewSource(source);
231355
231988
  const inventory = readWorkspaceInventory(workspace.projectDir);
231356
231989
  const restResource = resolveRestResourceSource(inventory.restResources, parsedSource);
231990
+ const coreDataSource = isAdminViewCoreDataSource(parsedSource) ? parsedSource : undefined;
231357
231991
  assertAdminViewDoesNotExist(workspace.projectDir, adminViewSlug, inventory);
231358
231992
  const blockConfigPath = path51.join(workspace.projectDir, "scripts", "block-config.ts");
231359
231993
  const bootstrapPath = getWorkspaceBootstrapPath(workspace);
@@ -231378,14 +232012,14 @@ async function runAddAdminViewCommand({
231378
232012
  try {
231379
232013
  await fsp18.mkdir(adminViewDir, { recursive: true });
231380
232014
  await fsp18.mkdir(path51.dirname(adminViewPhpPath), { recursive: true });
231381
- await ensureAdminViewPackageDependencies(workspace);
232015
+ await ensureAdminViewPackageDependencies(workspace, parsedSource);
231382
232016
  await ensureAdminViewBootstrapAnchors(workspace);
231383
232017
  await ensureAdminViewBuildScriptAnchors(workspace);
231384
232018
  await ensureAdminViewWebpackAnchors(workspace);
231385
- await fsp18.writeFile(path51.join(adminViewDir, "types.ts"), buildAdminViewTypesSource(adminViewSlug, restResource), "utf8");
231386
- await fsp18.writeFile(path51.join(adminViewDir, "config.ts"), buildAdminViewConfigSource(adminViewSlug, workspace.workspace.textDomain, restResource), "utf8");
231387
- await fsp18.writeFile(path51.join(adminViewDir, "data.ts"), restResource ? buildRestAdminViewDataSource(adminViewSlug, restResource) : buildDefaultAdminViewDataSource(adminViewSlug), "utf8");
231388
- await fsp18.writeFile(path51.join(adminViewDir, "Screen.tsx"), buildAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain), "utf8");
232019
+ await fsp18.writeFile(path51.join(adminViewDir, "types.ts"), buildAdminViewTypesSource(adminViewSlug, restResource, coreDataSource), "utf8");
232020
+ await fsp18.writeFile(path51.join(adminViewDir, "config.ts"), buildAdminViewConfigSource(adminViewSlug, workspace.workspace.textDomain, parsedSource, restResource), "utf8");
232021
+ await fsp18.writeFile(path51.join(adminViewDir, "data.ts"), coreDataSource ? buildCoreDataAdminViewDataSource(adminViewSlug, coreDataSource) : restResource ? buildRestAdminViewDataSource(adminViewSlug, restResource) : buildDefaultAdminViewDataSource(adminViewSlug), "utf8");
232022
+ await fsp18.writeFile(path51.join(adminViewDir, "Screen.tsx"), coreDataSource ? buildCoreDataAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain) : buildAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain), "utf8");
231389
232023
  await fsp18.writeFile(path51.join(adminViewDir, "index.tsx"), buildAdminViewEntrySource(adminViewSlug), "utf8");
231390
232024
  await fsp18.writeFile(path51.join(adminViewDir, "style.scss"), buildAdminViewStyleSource(), "utf8");
231391
232025
  await fsp18.writeFile(adminViewPhpPath, buildAdminViewPhpSource(adminViewSlug, workspace), "utf8");
@@ -231396,19 +232030,24 @@ async function runAddAdminViewCommand({
231396
232030
  return {
231397
232031
  adminViewSlug,
231398
232032
  projectDir: workspace.projectDir,
231399
- source: parsedSource ? `${parsedSource.kind}:${parsedSource.slug}` : undefined
232033
+ source: parsedSource ? formatAdminViewSourceLocator(parsedSource) : undefined
231400
232034
  };
231401
232035
  } catch (error48) {
231402
232036
  await rollbackWorkspaceMutation(mutationSnapshot);
231403
232037
  throw error48;
231404
232038
  }
231405
232039
  }
231406
- var ADMIN_VIEW_SOURCE_KIND = "rest-resource", ADMIN_VIEWS_SCRIPT = "build/admin-views/index.js", ADMIN_VIEWS_ASSET = "build/admin-views/index.asset.php", ADMIN_VIEWS_STYLE = "build/admin-views/style-index.css", ADMIN_VIEWS_STYLE_RTL = "build/admin-views/style-index-rtl.css", ADMIN_VIEWS_PHP_GLOB = "/inc/admin-views/*.php", DEFAULT_WP_TYPIA_DATAVIEWS_VERSION = "^0.1.0", DEFAULT_WORDPRESS_DATAVIEWS_VERSION = "^14.1.0", require4;
232040
+ var ADMIN_VIEW_REST_SOURCE_KIND = "rest-resource", ADMIN_VIEW_CORE_DATA_SOURCE_KIND = "core-data", ADMIN_VIEW_CORE_DATA_ENTITY_KIND_IDS, ADMIN_VIEW_CORE_DATA_ENTITY_SEGMENT_PATTERN, ADMIN_VIEW_CORE_DATA_ENTITY_NAME_PATTERN, ADMIN_VIEW_SOURCE_USAGE = "wp-typia add admin-view <name> --source <rest-resource:slug|core-data:kind/name>", ADMIN_VIEWS_SCRIPT = "build/admin-views/index.js", ADMIN_VIEWS_ASSET = "build/admin-views/index.asset.php", ADMIN_VIEWS_STYLE = "build/admin-views/style-index.css", ADMIN_VIEWS_STYLE_RTL = "build/admin-views/style-index-rtl.css", ADMIN_VIEWS_PHP_GLOB = "/inc/admin-views/*.php", ADMIN_VIEW_ALLOW_UNPUBLISHED_DATAVIEWS_ENV = "WP_TYPIA_ALLOW_UNPUBLISHED_DATAVIEWS", ADMIN_VIEW_PUBLIC_INSTALLS_ENABLED = false, require4;
231407
232041
  var init_cli_add_workspace_admin_view = __esm(() => {
231408
232042
  init_workspace_project();
231409
232043
  init_workspace_inventory();
231410
232044
  init_template_registry();
231411
232045
  init_cli_add_shared();
232046
+ init_cli_diagnostics();
232047
+ init_package_versions();
232048
+ ADMIN_VIEW_CORE_DATA_ENTITY_KIND_IDS = ["postType", "taxonomy"];
232049
+ ADMIN_VIEW_CORE_DATA_ENTITY_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/u;
232050
+ ADMIN_VIEW_CORE_DATA_ENTITY_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/u;
231412
232051
  require4 = createRequire4(import.meta.url);
231413
232052
  });
231414
232053
 
@@ -234269,8 +234908,8 @@ async function ensureAbilityPackageScripts(workspace) {
234269
234908
  };
234270
234909
  const nextDependencies = {
234271
234910
  ...packageJson.dependencies ?? {},
234272
- [WP_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_ABILITIES_SCRIPT_MODULE_ID], WP_ABILITIES_PACKAGE_VERSION),
234273
- [WP_CORE_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_CORE_ABILITIES_SCRIPT_MODULE_ID], WP_CORE_ABILITIES_PACKAGE_VERSION)
234911
+ [WP_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_ABILITIES_SCRIPT_MODULE_ID], DEFAULT_WORDPRESS_ABILITIES_VERSION),
234912
+ [WP_CORE_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_CORE_ABILITIES_SCRIPT_MODULE_ID], DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION)
234274
234913
  };
234275
234914
  if (JSON.stringify(nextScripts) === JSON.stringify(packageJson.scripts ?? {}) && JSON.stringify(nextDependencies) === JSON.stringify(packageJson.dependencies ?? {})) {
234276
234915
  return;
@@ -234477,12 +235116,13 @@ async function runAddAbilityCommand({
234477
235116
  throw error48;
234478
235117
  }
234479
235118
  }
234480
- var import_semver2, ABILITY_SERVER_GLOB = "/inc/abilities/*.php", ABILITY_EDITOR_SCRIPT = "build/abilities/index.js", ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php", ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end", ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start", WP_ABILITIES_PACKAGE_VERSION = "^0.10.0", WP_CORE_ABILITIES_PACKAGE_VERSION = "^0.9.0", WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities", WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";
235119
+ var import_semver2, ABILITY_SERVER_GLOB = "/inc/abilities/*.php", ABILITY_EDITOR_SCRIPT = "build/abilities/index.js", ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php", ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end", ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start", WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities", WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";
234481
235120
  var init_cli_add_workspace_ability = __esm(() => {
234482
235121
  init_workspace_inventory();
234483
235122
  init_workspace_project();
234484
235123
  init_cli_add_shared();
234485
235124
  init_scaffold_compatibility();
235125
+ init_package_versions();
234486
235126
  import_semver2 = __toESM(require_semver2(), 1);
234487
235127
  });
234488
235128
 
@@ -237233,11 +237873,12 @@ function checkWorkspaceAdminViewConfig(adminView, inventory) {
237233
237873
  return createDoctorCheck2(`Admin view config ${adminView.slug}`, "pass", "Admin view uses a replaceable local fetcher");
237234
237874
  }
237235
237875
  const source = adminView.source.trim();
237236
- const sourceMatch = /^rest-resource:([a-z][a-z0-9-]*)$/u.exec(source);
237237
- const restResourceSlug = sourceMatch?.[1];
237876
+ const restSourceMatch = /^rest-resource:([a-z][a-z0-9-]*)$/u.exec(source);
237877
+ const coreDataSourceMatch = /^core-data:(postType|taxonomy)\/([a-z0-9][a-z0-9_-]*)$/u.exec(source);
237878
+ const restResourceSlug = restSourceMatch?.[1];
237238
237879
  const restResource = restResourceSlug ? inventory.restResources.find((entry) => entry.slug === restResourceSlug) : undefined;
237239
- const isValid2 = Boolean(restResource?.methods.includes("list"));
237240
- return createDoctorCheck2(`Admin view config ${adminView.slug}`, isValid2 ? "pass" : "fail", isValid2 ? `Admin view source ${source} is list-capable` : "Admin view source must use rest-resource:<slug> and reference a list-capable REST resource");
237880
+ const isValid2 = Boolean(restResource?.methods.includes("list")) || Boolean(coreDataSourceMatch);
237881
+ return createDoctorCheck2(`Admin view config ${adminView.slug}`, isValid2 ? "pass" : "fail", isValid2 ? `Admin view source ${source} is list-capable` : "Admin view source must use rest-resource:<slug> with a list-capable REST resource or core-data:<postType|taxonomy>/<name>");
237241
237882
  }
237242
237883
  function checkWorkspaceAdminViewBootstrap(projectDir, packageName, phpPrefix) {
237243
237884
  const packageBaseName = packageName.split("/").pop() ?? packageName;
@@ -291720,7 +292361,7 @@ var ADD_OPTION_METADATA = {
291720
292361
  type: "string"
291721
292362
  },
291722
292363
  source: {
291723
- description: "Optional data source locator for admin-view workflows, such as rest-resource:products.",
292364
+ description: "Optional data source locator for admin-view workflows, such as rest-resource:products or core-data:postType/post.",
291724
292365
  type: "string"
291725
292366
  },
291726
292367
  template: {
@@ -292024,7 +292665,7 @@ var ADD_KIND_REGISTRY = {
292024
292665
  description: "Add an opt-in DataViews-powered admin screen",
292025
292666
  nameLabel: "Admin view name",
292026
292667
  async prepareExecution(context) {
292027
- const name2 = requireAddKindName(context, "`wp-typia add admin-view` requires <name>. Usage: wp-typia add admin-view <name> [--source <rest-resource:slug>].");
292668
+ const name2 = requireAddKindName(context, "`wp-typia add admin-view` requires <name>. Usage: wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>].");
292028
292669
  const source = readOptionalStringFlag(context.flags, "source");
292029
292670
  return {
292030
292671
  execute: (cwd) => context.addRuntime.runAddAdminViewCommand({
@@ -292040,7 +292681,7 @@ var ADD_KIND_REGISTRY = {
292040
292681
  },
292041
292682
  sortOrder: 10,
292042
292683
  supportsDryRun: true,
292043
- usage: "wp-typia add admin-view <name> [--source <rest-resource:slug>] [--dry-run]",
292684
+ usage: "wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>] [--dry-run]",
292044
292685
  visibleFieldNames: () => ["kind", "name", "source"]
292045
292686
  }),
292046
292687
  "binding-source": defineAddKindRegistryEntry({
@@ -292659,7 +293300,7 @@ import path10 from "path";
292659
293300
  // package.json
292660
293301
  var package_default2 = {
292661
293302
  name: "wp-typia",
292662
- version: "0.21.0",
293303
+ version: "0.22.0",
292663
293304
  description: "Canonical CLI package for wp-typia scaffolding and project workflows",
292664
293305
  packageManager: "bun@1.3.11",
292665
293306
  type: "module",
@@ -292729,7 +293370,7 @@ var package_default2 = {
292729
293370
  "@bunli/tui": "0.6.0",
292730
293371
  "@bunli/utils": "0.6.0",
292731
293372
  "@wp-typia/api-client": "^0.4.5",
292732
- "@wp-typia/project-tools": "0.21.0",
293373
+ "@wp-typia/project-tools": "0.22.0",
292733
293374
  "better-result": "^2.7.0",
292734
293375
  react: "^19.2.5",
292735
293376
  "react-dom": "^19.2.5",
@@ -292912,6 +293553,31 @@ function buildStructuredCompletionSuccessPayload(command, completion, metadata2
292912
293553
  }
292913
293554
  };
292914
293555
  }
293556
+ function buildStructuredInitSuccessPayload(plan) {
293557
+ const completion = serializeCompletionPayload(buildInitCompletionPayload(plan));
293558
+ const files = Array.from(new Set([
293559
+ ...plan.plannedFiles.map((filePlan) => filePlan.path),
293560
+ ...plan.commandMode === "preview-only" ? plan.generatedArtifacts : []
293561
+ ]));
293562
+ return {
293563
+ ok: true,
293564
+ data: {
293565
+ command: "init",
293566
+ completion,
293567
+ detectedLayout: plan.detectedLayout,
293568
+ files: toNonEmptyArray(files),
293569
+ mode: plan.commandMode === "apply" ? "apply" : "preview",
293570
+ nextSteps: toNonEmptyArray(plan.nextSteps),
293571
+ packageManager: plan.packageManager,
293572
+ plan,
293573
+ projectDir: plan.projectDir,
293574
+ status: plan.status,
293575
+ summary: plan.summary,
293576
+ title: completion.title,
293577
+ warnings: toNonEmptyArray(plan.notes)
293578
+ }
293579
+ };
293580
+ }
292915
293581
  function formatCreateProgressLine(payload, markerOptions) {
292916
293582
  return formatOutputMarker("progress", `${payload.title}: ${payload.detail}`, markerOptions);
292917
293583
  }
@@ -294361,7 +295027,7 @@ var initCommand = defineCommand({
294361
295027
  projectDir: args.positional[0]
294362
295028
  }, { emitOutput: !prefersStructuredOutput });
294363
295029
  if (prefersStructuredOutput) {
294364
- args.output({ init: plan });
295030
+ args.output(buildStructuredInitSuccessPayload(plan));
294365
295031
  }
294366
295032
  } catch (error48) {
294367
295033
  emitCliDiagnosticFailure(args, {
@@ -295270,4 +295936,4 @@ export {
295270
295936
  cli
295271
295937
  };
295272
295938
 
295273
- //# debugId=BEEA7448AE2433F864756E2164756E21
295939
+ //# debugId=D9C2F8E8EFC1ECF864756E2164756E21