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.
@@ -20,13 +20,19 @@ import {
20
20
  scaffoldProject,
21
21
  syncPersistenceRestArtifacts,
22
22
  updatePluginHeaderCompatibility
23
- } from "./cli-pav309dt.js";
23
+ } from "./cli-1w5vkye4.js";
24
24
  import {
25
+ DEFAULT_WORDPRESS_ABILITIES_VERSION,
26
+ DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION,
27
+ DEFAULT_WORDPRESS_CORE_DATA_VERSION,
28
+ DEFAULT_WORDPRESS_DATAVIEWS_VERSION,
29
+ DEFAULT_WORDPRESS_DATA_VERSION,
30
+ DEFAULT_WP_TYPIA_DATAVIEWS_VERSION,
25
31
  getPackageVersions
26
- } from "./cli-syg9qpxw.js";
32
+ } from "./cli-39er8888.js";
27
33
  import {
28
34
  snapshotProjectVersion
29
- } from "./cli-jfj54qej.js";
35
+ } from "./cli-e623rs7g.js";
30
36
  import {
31
37
  ensureMigrationDirectories,
32
38
  parseMigrationConfig,
@@ -87,11 +93,14 @@ import {
87
93
  toPascalCase,
88
94
  toSnakeCase,
89
95
  toTitleCase
90
- } from "./cli-hx88xwr4.js";
96
+ } from "./cli-j180bk07.js";
91
97
  import {
92
98
  createManagedTempRoot
93
99
  } from "./cli-t73q5aqz.js";
94
- import"./cli-p95wr1q8.js";
100
+ import {
101
+ CLI_DIAGNOSTIC_CODES,
102
+ createCliDiagnosticCodeError
103
+ } from "./cli-p95wr1q8.js";
95
104
  import {
96
105
  resolveWorkspaceProject
97
106
  } from "./cli-pd5pqgre.js";
@@ -779,14 +788,19 @@ import fs3 from "fs";
779
788
  import { promises as fsp3 } from "fs";
780
789
  import { createRequire } from "module";
781
790
  import path4 from "path";
782
- var ADMIN_VIEW_SOURCE_KIND = "rest-resource";
791
+ var ADMIN_VIEW_REST_SOURCE_KIND = "rest-resource";
792
+ var ADMIN_VIEW_CORE_DATA_SOURCE_KIND = "core-data";
793
+ var ADMIN_VIEW_CORE_DATA_ENTITY_KIND_IDS = ["postType", "taxonomy"];
794
+ var ADMIN_VIEW_CORE_DATA_ENTITY_SEGMENT_PATTERN = /^[A-Za-z][A-Za-z0-9_-]*$/u;
795
+ var ADMIN_VIEW_CORE_DATA_ENTITY_NAME_PATTERN = /^[a-z0-9][a-z0-9_-]*$/u;
796
+ var ADMIN_VIEW_SOURCE_USAGE = "wp-typia add admin-view <name> --source <rest-resource:slug|core-data:kind/name>";
783
797
  var ADMIN_VIEWS_SCRIPT = "build/admin-views/index.js";
784
798
  var ADMIN_VIEWS_ASSET = "build/admin-views/index.asset.php";
785
799
  var ADMIN_VIEWS_STYLE = "build/admin-views/style-index.css";
786
800
  var ADMIN_VIEWS_STYLE_RTL = "build/admin-views/style-index-rtl.css";
787
801
  var ADMIN_VIEWS_PHP_GLOB = "/inc/admin-views/*.php";
788
- var DEFAULT_WP_TYPIA_DATAVIEWS_VERSION = "^0.1.0";
789
- var DEFAULT_WORDPRESS_DATAVIEWS_VERSION = "^14.1.0";
802
+ var ADMIN_VIEW_ALLOW_UNPUBLISHED_DATAVIEWS_ENV = "WP_TYPIA_ALLOW_UNPUBLISHED_DATAVIEWS";
803
+ var ADMIN_VIEW_PUBLIC_INSTALLS_ENABLED = false;
790
804
  var require2 = createRequire(import.meta.url);
791
805
  function toCamelCase(input) {
792
806
  const pascalCase = toPascalCase(input);
@@ -799,14 +813,25 @@ function normalizeVersionRange(value, fallback) {
799
813
  }
800
814
  return /^[~^<>=]/u.test(trimmed) ? trimmed : `^${trimmed}`;
801
815
  }
802
- function readPackageManifestVersion(packageJsonPath) {
816
+ function readPackageManifest(packageJsonPath) {
803
817
  try {
804
- const packageJson = JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
805
- return packageJson.version;
818
+ return JSON.parse(fs3.readFileSync(packageJsonPath, "utf8"));
806
819
  } catch {
807
820
  return;
808
821
  }
809
822
  }
823
+ function readPackageManifestVersion(packageJsonPath) {
824
+ return readPackageManifest(packageJsonPath)?.version;
825
+ }
826
+ function isAdminViewUnpublishedDataViewsOverrideEnabled() {
827
+ return process.env[ADMIN_VIEW_ALLOW_UNPUBLISHED_DATAVIEWS_ENV]?.trim() === "1";
828
+ }
829
+ function assertAdminViewPackageAvailability() {
830
+ if (isAdminViewUnpublishedDataViewsOverrideEnabled() || ADMIN_VIEW_PUBLIC_INSTALLS_ENABLED) {
831
+ return;
832
+ }
833
+ 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.");
834
+ }
810
835
  function detectJsonIndent(source) {
811
836
  const indentMatch = /\n([ \t]+)"/u.exec(source);
812
837
  return indentMatch?.[1] ?? 2;
@@ -831,22 +856,77 @@ function getAdminViewRelativeModuleSpecifier(adminViewSlug, workspaceFile) {
831
856
  const relativeModulePath = path4.posix.relative(adminViewDir, modulePath);
832
857
  return relativeModulePath.startsWith(".") ? relativeModulePath : `./${relativeModulePath}`;
833
858
  }
859
+ function isAdminViewCoreDataSource(source) {
860
+ return source?.kind === ADMIN_VIEW_CORE_DATA_SOURCE_KIND;
861
+ }
862
+ function isAdminViewRestResourceSource(source) {
863
+ return source?.kind === ADMIN_VIEW_REST_SOURCE_KIND;
864
+ }
865
+ function assertValidCoreDataEntitySegment(label, value) {
866
+ const trimmed = value.trim();
867
+ if (!trimmed) {
868
+ throw new Error(`${label} is required. Use \`${ADMIN_VIEW_SOURCE_USAGE}\`.`);
869
+ }
870
+ if (!ADMIN_VIEW_CORE_DATA_ENTITY_SEGMENT_PATTERN.test(trimmed)) {
871
+ throw new Error(`${label} must start with a letter and contain only letters, numbers, underscores, or hyphens.`);
872
+ }
873
+ return trimmed;
874
+ }
875
+ function assertValidCoreDataEntityName(value) {
876
+ const normalized = value.trim();
877
+ if (!normalized) {
878
+ throw new Error(`Admin view source entity name is required. Use \`${ADMIN_VIEW_SOURCE_USAGE}\`.`);
879
+ }
880
+ if (!ADMIN_VIEW_CORE_DATA_ENTITY_NAME_PATTERN.test(normalized)) {
881
+ 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.");
882
+ }
883
+ return normalized;
884
+ }
885
+ function assertValidCoreDataEntityKind(value) {
886
+ const normalized = assertValidCoreDataEntitySegment("Admin view source entity kind", value);
887
+ if (!ADMIN_VIEW_CORE_DATA_ENTITY_KIND_IDS.includes(normalized)) {
888
+ throw new Error(`Admin view core-data sources currently support only: ${ADMIN_VIEW_CORE_DATA_ENTITY_KIND_IDS.join(", ")}.`);
889
+ }
890
+ return normalized;
891
+ }
892
+ function formatAdminViewSourceLocator(source) {
893
+ if (isAdminViewCoreDataSource(source)) {
894
+ return `${source.kind}:${source.entityKind}/${source.entityName}`;
895
+ }
896
+ return `${source.kind}:${source.slug}`;
897
+ }
834
898
  function parseAdminViewSource(source) {
835
899
  const trimmed = source?.trim();
836
900
  if (!trimmed) {
837
901
  return;
838
902
  }
839
- const [kind, slug, extra] = trimmed.split(":");
840
- if (kind !== ADMIN_VIEW_SOURCE_KIND || !slug || extra !== undefined) {
841
- throw new Error("Admin view source must use `rest-resource:<slug>` for now.");
903
+ const separatorIndex = trimmed.indexOf(":");
904
+ const kind = separatorIndex === -1 ? trimmed : trimmed.slice(0, separatorIndex);
905
+ const locator = separatorIndex === -1 ? "" : trimmed.slice(separatorIndex + 1);
906
+ if (!locator) {
907
+ throw new Error("Admin view source must use `rest-resource:<slug>` or `core-data:<kind>/<name>`.");
842
908
  }
843
- return {
844
- kind,
845
- slug: assertValidGeneratedSlug("Admin view source slug", normalizeBlockSlug(slug), "wp-typia add admin-view <name> --source rest-resource:<slug>")
846
- };
909
+ if (kind === ADMIN_VIEW_REST_SOURCE_KIND) {
910
+ return {
911
+ kind,
912
+ slug: assertValidGeneratedSlug("Admin view source slug", locator, ADMIN_VIEW_SOURCE_USAGE)
913
+ };
914
+ }
915
+ if (kind === ADMIN_VIEW_CORE_DATA_SOURCE_KIND) {
916
+ const [entityKind, entityName, extra] = locator.split("/");
917
+ if (!entityKind || !entityName || extra !== undefined) {
918
+ throw new Error("Admin view core-data sources must use `core-data:<kind>/<name>`, for example `core-data:postType/post`.");
919
+ }
920
+ return {
921
+ entityKind: assertValidCoreDataEntityKind(entityKind),
922
+ entityName: assertValidCoreDataEntityName(entityName),
923
+ kind
924
+ };
925
+ }
926
+ throw new Error("Admin view source must use `rest-resource:<slug>` or `core-data:<kind>/<name>`.");
847
927
  }
848
928
  function resolveRestResourceSource(restResources, source) {
849
- if (!source) {
929
+ if (!isAdminViewRestResourceSource(source)) {
850
930
  return;
851
931
  }
852
932
  const restResource = restResources.find((entry) => entry.slug === source.slug);
@@ -864,7 +944,7 @@ function buildAdminViewConfigEntry(adminViewSlug, source) {
864
944
  ` file: ${quoteTsString(`src/admin-views/${adminViewSlug}/index.tsx`)},`,
865
945
  ` phpFile: ${quoteTsString(`inc/admin-views/${adminViewSlug}.php`)},`,
866
946
  ` slug: ${quoteTsString(adminViewSlug)},`,
867
- source ? ` source: ${quoteTsString(`${source.kind}:${source.slug}`)},` : null,
947
+ source ? ` source: ${quoteTsString(formatAdminViewSourceLocator(source))},` : null,
868
948
  "\t},"
869
949
  ].filter((line) => typeof line === "string").join(`
870
950
  `);
@@ -877,8 +957,9 @@ function buildAdminViewRegistrySource(adminViewSlugs) {
877
957
  ` : ""}// wp-typia add admin-view entries
878
958
  `;
879
959
  }
880
- function buildAdminViewTypesSource(adminViewSlug, restResource) {
960
+ function buildAdminViewTypesSource(adminViewSlug, restResource, coreDataSource) {
881
961
  const pascalName = toPascalCase(adminViewSlug);
962
+ const coreDataRecordTypeName = `${pascalName}CoreDataRecord`;
882
963
  const itemTypeName = `${pascalName}AdminViewItem`;
883
964
  const dataSetTypeName = `${pascalName}AdminViewDataSet`;
884
965
  if (restResource) {
@@ -888,6 +969,74 @@ function buildAdminViewTypesSource(adminViewSlug, restResource) {
888
969
 
889
970
  export type ${itemTypeName} = ${restPascalName}Record;
890
971
 
972
+ export interface ${dataSetTypeName} {
973
+ items: ${itemTypeName}[];
974
+ paginationInfo: {
975
+ totalItems: number;
976
+ totalPages: number;
977
+ };
978
+ }
979
+ `;
980
+ }
981
+ if (coreDataSource) {
982
+ if (coreDataSource.entityKind === "taxonomy") {
983
+ return `export interface ${coreDataRecordTypeName} {
984
+ count?: number;
985
+ description?: string;
986
+ id: number;
987
+ link?: string;
988
+ meta?: Record<string, unknown>;
989
+ name?: string;
990
+ parent?: number;
991
+ slug?: string;
992
+ taxonomy?: string;
993
+ [key: string]: unknown;
994
+ }
995
+
996
+ export interface ${itemTypeName} {
997
+ count: number;
998
+ description: string;
999
+ id: number;
1000
+ link: string;
1001
+ name: string;
1002
+ parent: number;
1003
+ raw: ${coreDataRecordTypeName};
1004
+ slug: string;
1005
+ taxonomy: string;
1006
+ }
1007
+
1008
+ export interface ${dataSetTypeName} {
1009
+ items: ${itemTypeName}[];
1010
+ paginationInfo: {
1011
+ totalItems: number;
1012
+ totalPages: number;
1013
+ };
1014
+ }
1015
+ `;
1016
+ }
1017
+ return `export interface ${coreDataRecordTypeName} {
1018
+ id: number;
1019
+ date?: string;
1020
+ modified?: string;
1021
+ name?: string;
1022
+ slug?: string;
1023
+ status?: string;
1024
+ title?: string | {
1025
+ raw?: string;
1026
+ rendered?: string;
1027
+ };
1028
+ [key: string]: unknown;
1029
+ }
1030
+
1031
+ export interface ${itemTypeName} {
1032
+ id: number;
1033
+ raw: ${coreDataRecordTypeName};
1034
+ slug: string;
1035
+ status: string;
1036
+ title: string;
1037
+ updatedAt: string;
1038
+ }
1039
+
891
1040
  export interface ${dataSetTypeName} {
892
1041
  items: ${itemTypeName}[];
893
1042
  paginationInfo: {
@@ -916,22 +1065,74 @@ export interface ${dataSetTypeName} {
916
1065
  }
917
1066
  `;
918
1067
  }
919
- function buildAdminViewConfigSource(adminViewSlug, textDomain, restResource) {
1068
+ function buildAdminViewConfigSource(adminViewSlug, textDomain, source, restResource) {
920
1069
  const pascalName = toPascalCase(adminViewSlug);
921
1070
  const camelName = toCamelCase(adminViewSlug);
922
1071
  const itemTypeName = `${pascalName}AdminViewItem`;
923
1072
  const dataViewsName = `${camelName}AdminDataViews`;
924
- const defaultViewFields = restResource ? "['id']" : "['title', 'status', 'updatedAt']";
1073
+ const isCoreDataSource = source?.kind === ADMIN_VIEW_CORE_DATA_SOURCE_KIND;
1074
+ const isTaxonomyCoreDataSource = source?.kind === ADMIN_VIEW_CORE_DATA_SOURCE_KIND && source.entityKind === "taxonomy";
1075
+ const defaultViewFields = restResource ? "['id']" : isTaxonomyCoreDataSource ? "['name', 'slug', 'count']" : isCoreDataSource ? "['title', 'slug', 'status', 'updatedAt']" : "['title', 'status', 'updatedAt']";
925
1076
  const searchEnabled = restResource ? "false" : "true";
926
- const titleFieldSource = restResource ? "" : ` titleField: 'title',
1077
+ const titleFieldSource = restResource ? "" : isTaxonomyCoreDataSource ? ` titleField: 'name',
1078
+ ` : ` titleField: 'title',
927
1079
  `;
928
- const defaultViewEnhancementsSource = restResource ? "" : ` sort: {
1080
+ const defaultViewEnhancementsSource = restResource ? "" : isTaxonomyCoreDataSource ? ` titleField: 'name',
1081
+ ` : isCoreDataSource ? ` titleField: 'title',
1082
+ ` : ` sort: {
929
1083
  direction: 'desc',
930
1084
  field: 'updatedAt',
931
1085
  },
932
1086
  titleField: 'title',
933
1087
  `;
934
- 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: {
1088
+ 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: {
1089
+ label: __( 'Count', ${quoteTsString(textDomain)} ),
1090
+ schema: { type: 'integer' },
1091
+ },
1092
+ description: {
1093
+ label: __( 'Description', ${quoteTsString(textDomain)} ),
1094
+ schema: { type: 'string' },
1095
+ },
1096
+ link: {
1097
+ label: __( 'Link', ${quoteTsString(textDomain)} ),
1098
+ schema: { format: 'uri', type: 'string' },
1099
+ },
1100
+ name: {
1101
+ enableGlobalSearch: true,
1102
+ label: __( 'Name', ${quoteTsString(textDomain)} ),
1103
+ schema: { type: 'string' },
1104
+ },
1105
+ parent: {
1106
+ label: __( 'Parent', ${quoteTsString(textDomain)} ),
1107
+ schema: { type: 'integer' },
1108
+ },
1109
+ slug: {
1110
+ enableGlobalSearch: true,
1111
+ label: __( 'Slug', ${quoteTsString(textDomain)} ),
1112
+ schema: { type: 'string' },
1113
+ },
1114
+ taxonomy: {
1115
+ label: __( 'Taxonomy', ${quoteTsString(textDomain)} ),
1116
+ schema: { type: 'string' },
1117
+ },` : isCoreDataSource ? ` slug: {
1118
+ enableGlobalSearch: true,
1119
+ label: __( 'Slug', ${quoteTsString(textDomain)} ),
1120
+ schema: { type: 'string' },
1121
+ },
1122
+ status: {
1123
+ label: __( 'Status', ${quoteTsString(textDomain)} ),
1124
+ schema: { type: 'string' },
1125
+ },
1126
+ title: {
1127
+ enableGlobalSearch: true,
1128
+ label: __( 'Name', ${quoteTsString(textDomain)} ),
1129
+ schema: { type: 'string' },
1130
+ },
1131
+ updatedAt: {
1132
+ label: __( 'Updated', ${quoteTsString(textDomain)} ),
1133
+ schema: { format: 'date-time', type: 'string' },
1134
+ type: 'datetime',
1135
+ },` : ` owner: {
935
1136
  label: __( 'Owner', ${quoteTsString(textDomain)} ),
936
1137
  schema: { type: 'string' },
937
1138
  },
@@ -1118,6 +1319,217 @@ export async function ${fetchName}(
1118
1319
  }
1119
1320
  `;
1120
1321
  }
1322
+ function buildCoreDataAdminViewDataSource(adminViewSlug, coreDataSource) {
1323
+ const pascalName = toPascalCase(adminViewSlug);
1324
+ const camelName = toCamelCase(adminViewSlug);
1325
+ const coreDataRecordTypeName = `${pascalName}CoreDataRecord`;
1326
+ const dataSetTypeName = `${pascalName}AdminViewDataSet`;
1327
+ const itemTypeName = `${pascalName}AdminViewItem`;
1328
+ const queryTypeName = `${pascalName}AdminViewQuery`;
1329
+ const dataViewsName = `${camelName}AdminDataViews`;
1330
+ const useEntityRecordName = `use${pascalName}EntityRecord`;
1331
+ const useEntityRecordsName = `use${pascalName}EntityRecords`;
1332
+ const useAdminViewDataName = `use${pascalName}AdminViewData`;
1333
+ if (coreDataSource.entityKind === "taxonomy") {
1334
+ return `import type { DataViewsView } from '@wp-typia/dataviews';
1335
+ import { useEntityRecord, useEntityRecords } from '@wordpress/core-data';
1336
+ import { useMemo } from '@wordpress/element';
1337
+
1338
+ import { ${dataViewsName} } from './config';
1339
+ import type {
1340
+ ${coreDataRecordTypeName},
1341
+ ${dataSetTypeName},
1342
+ ${itemTypeName},
1343
+ } from './types';
1344
+
1345
+ export interface ${queryTypeName} {
1346
+ page?: number;
1347
+ per_page?: number;
1348
+ search?: string;
1349
+ }
1350
+
1351
+ const CORE_DATA_ENTITY_KIND = ${quoteTsString(coreDataSource.entityKind)};
1352
+ const CORE_DATA_ENTITY_NAME = ${quoteTsString(coreDataSource.entityName)};
1353
+
1354
+ function normalizeCoreDataNumber(value: unknown): number {
1355
+ return typeof value === 'number' && Number.isFinite(value) ? value : 0;
1356
+ }
1357
+
1358
+ function normalizeCoreDataString(value: unknown): string {
1359
+ return typeof value === 'string' ? value : '';
1360
+ }
1361
+
1362
+ function normalizeTaxonomyRecord(record: ${coreDataRecordTypeName}): ${itemTypeName} {
1363
+ return {
1364
+ count: normalizeCoreDataNumber(record.count),
1365
+ description: normalizeCoreDataString(record.description),
1366
+ id: record.id,
1367
+ link: normalizeCoreDataString(record.link),
1368
+ name: normalizeCoreDataString(record.name) || normalizeCoreDataString(record.slug),
1369
+ parent: normalizeCoreDataNumber(record.parent),
1370
+ raw: record,
1371
+ slug: normalizeCoreDataString(record.slug),
1372
+ taxonomy: normalizeCoreDataString(record.taxonomy),
1373
+ };
1374
+ }
1375
+
1376
+ export function ${useEntityRecordName}(recordId: number | undefined) {
1377
+ return useEntityRecord<${coreDataRecordTypeName}>(
1378
+ CORE_DATA_ENTITY_KIND,
1379
+ CORE_DATA_ENTITY_NAME,
1380
+ recordId ?? 0,
1381
+ { enabled: typeof recordId === 'number' },
1382
+ );
1383
+ }
1384
+
1385
+ export function ${useEntityRecordsName}(view: DataViewsView<${itemTypeName}>) {
1386
+ const query = ${dataViewsName}.toQueryArgs<${queryTypeName}>(view, {
1387
+ perPageParam: 'per_page',
1388
+ });
1389
+
1390
+ return useEntityRecords<${coreDataRecordTypeName}>(
1391
+ CORE_DATA_ENTITY_KIND,
1392
+ CORE_DATA_ENTITY_NAME,
1393
+ query,
1394
+ );
1395
+ }
1396
+
1397
+ export function ${useAdminViewDataName}(view: DataViewsView<${itemTypeName}>) {
1398
+ const { hasResolved, isResolving, records, totalItems, totalPages } =
1399
+ ${useEntityRecordsName}(view);
1400
+ const items = useMemo(
1401
+ () => (records ?? []).map((record) => normalizeTaxonomyRecord(record)),
1402
+ [records],
1403
+ );
1404
+ const dataSet = useMemo<${dataSetTypeName}>(
1405
+ () => ({
1406
+ items,
1407
+ paginationInfo: {
1408
+ totalItems: totalItems ?? items.length,
1409
+ totalPages: Math.max(1, totalPages ?? 1),
1410
+ },
1411
+ }),
1412
+ [items, totalItems, totalPages],
1413
+ );
1414
+ const error =
1415
+ !isResolving && hasResolved && records === null
1416
+ ? 'Unable to load core-data entity records.'
1417
+ : null;
1418
+
1419
+ return {
1420
+ dataSet,
1421
+ error,
1422
+ isLoading: isResolving,
1423
+ };
1424
+ }
1425
+ `;
1426
+ }
1427
+ return `import type { DataViewsView } from '@wp-typia/dataviews';
1428
+ import { useEntityRecord, useEntityRecords } from '@wordpress/core-data';
1429
+ import { useMemo } from '@wordpress/element';
1430
+
1431
+ import { ${dataViewsName} } from './config';
1432
+ import type {
1433
+ ${coreDataRecordTypeName},
1434
+ ${dataSetTypeName},
1435
+ ${itemTypeName},
1436
+ } from './types';
1437
+
1438
+ export interface ${queryTypeName} {
1439
+ page?: number;
1440
+ per_page?: number;
1441
+ search?: string;
1442
+ }
1443
+
1444
+ const CORE_DATA_ENTITY_KIND = ${quoteTsString(coreDataSource.entityKind)};
1445
+ const CORE_DATA_ENTITY_NAME = ${quoteTsString(coreDataSource.entityName)};
1446
+
1447
+ function normalizeCoreDataString(value: unknown): string {
1448
+ return typeof value === 'string' ? value : '';
1449
+ }
1450
+
1451
+ function normalizeCoreDataTitle(record: ${coreDataRecordTypeName}): string {
1452
+ if (typeof record.title === 'string') {
1453
+ return record.title;
1454
+ }
1455
+ if (record.title && typeof record.title === 'object') {
1456
+ if (typeof record.title.rendered === 'string') {
1457
+ return record.title.rendered;
1458
+ }
1459
+ if (typeof record.title.raw === 'string') {
1460
+ return record.title.raw;
1461
+ }
1462
+ }
1463
+
1464
+ return normalizeCoreDataString(record.name) || normalizeCoreDataString(record.slug);
1465
+ }
1466
+
1467
+ function normalizeCoreDataUpdatedAt(record: ${coreDataRecordTypeName}): string {
1468
+ return normalizeCoreDataString(record.modified) || normalizeCoreDataString(record.date);
1469
+ }
1470
+
1471
+ function normalizeCoreDataRecord(record: ${coreDataRecordTypeName}): ${itemTypeName} {
1472
+ return {
1473
+ id: record.id,
1474
+ raw: record,
1475
+ slug: normalizeCoreDataString(record.slug),
1476
+ status: normalizeCoreDataString(record.status),
1477
+ title: normalizeCoreDataTitle(record),
1478
+ updatedAt: normalizeCoreDataUpdatedAt(record),
1479
+ };
1480
+ }
1481
+
1482
+ export function ${useEntityRecordName}(recordId: number | undefined) {
1483
+ return useEntityRecord<${coreDataRecordTypeName}>(
1484
+ CORE_DATA_ENTITY_KIND,
1485
+ CORE_DATA_ENTITY_NAME,
1486
+ recordId ?? 0,
1487
+ { enabled: typeof recordId === 'number' },
1488
+ );
1489
+ }
1490
+
1491
+ export function ${useEntityRecordsName}(view: DataViewsView<${itemTypeName}>) {
1492
+ const query = ${dataViewsName}.toQueryArgs<${queryTypeName}>(view, {
1493
+ perPageParam: 'per_page',
1494
+ });
1495
+
1496
+ return useEntityRecords<${coreDataRecordTypeName}>(
1497
+ CORE_DATA_ENTITY_KIND,
1498
+ CORE_DATA_ENTITY_NAME,
1499
+ query,
1500
+ );
1501
+ }
1502
+
1503
+ export function ${useAdminViewDataName}(view: DataViewsView<${itemTypeName}>) {
1504
+ const { hasResolved, isResolving, records, totalItems, totalPages } =
1505
+ ${useEntityRecordsName}(view);
1506
+ const items = useMemo(
1507
+ () => (records ?? []).map((record) => normalizeCoreDataRecord(record)),
1508
+ [records],
1509
+ );
1510
+ const dataSet = useMemo<${dataSetTypeName}>(
1511
+ () => ({
1512
+ items,
1513
+ paginationInfo: {
1514
+ totalItems: totalItems ?? items.length,
1515
+ totalPages: Math.max(1, totalPages ?? 1),
1516
+ },
1517
+ }),
1518
+ [items, totalItems, totalPages],
1519
+ );
1520
+ const error =
1521
+ !isResolving && hasResolved && records === null
1522
+ ? 'Unable to load core-data entity records.'
1523
+ : null;
1524
+
1525
+ return {
1526
+ dataSet,
1527
+ error,
1528
+ isLoading: isResolving,
1529
+ };
1530
+ }
1531
+ `;
1532
+ }
1121
1533
  function buildAdminViewScreenSource(adminViewSlug, textDomain) {
1122
1534
  const pascalName = toPascalCase(adminViewSlug);
1123
1535
  const camelName = toCamelCase(adminViewSlug);
@@ -1231,6 +1643,81 @@ export function ${componentName}() {
1231
1643
  }
1232
1644
  `;
1233
1645
  }
1646
+ function buildCoreDataAdminViewScreenSource(adminViewSlug, textDomain) {
1647
+ const pascalName = toPascalCase(adminViewSlug);
1648
+ const camelName = toCamelCase(adminViewSlug);
1649
+ const itemTypeName = `${pascalName}AdminViewItem`;
1650
+ const dataSetTypeName = `${pascalName}AdminViewDataSet`;
1651
+ const componentName = `${pascalName}AdminViewScreen`;
1652
+ const dataViewsName = `${camelName}AdminDataViews`;
1653
+ const useAdminViewDataName = `use${pascalName}AdminViewData`;
1654
+ const title = toTitleCase(adminViewSlug);
1655
+ return `import type { DataViewsConfig, DataViewsView } from '@wp-typia/dataviews';
1656
+ import { Notice, Spinner } from '@wordpress/components';
1657
+ import { useState } from '@wordpress/element';
1658
+ import { __ } from '@wordpress/i18n';
1659
+ import { DataViews } from '@wordpress/dataviews/wp';
1660
+
1661
+ import { ${dataViewsName} } from './config';
1662
+ import { ${useAdminViewDataName} } from './data';
1663
+ import type { ${dataSetTypeName}, ${itemTypeName} } from './types';
1664
+
1665
+ const TypedDataViews = DataViews as unknown as <TItem extends object>(
1666
+ props: DataViewsConfig<TItem>,
1667
+ ) => ReturnType<typeof DataViews>;
1668
+
1669
+ const EMPTY_DATA_SET: ${dataSetTypeName} = {
1670
+ items: [],
1671
+ paginationInfo: {
1672
+ totalItems: 0,
1673
+ totalPages: 1,
1674
+ },
1675
+ };
1676
+
1677
+ export function ${componentName}() {
1678
+ const [view, setView] = useState<DataViewsView<${itemTypeName}>>(
1679
+ ${dataViewsName}.defaultView,
1680
+ );
1681
+ const {
1682
+ dataSet = EMPTY_DATA_SET,
1683
+ error,
1684
+ isLoading,
1685
+ } = ${useAdminViewDataName}(view);
1686
+ const config = ${dataViewsName}.createConfig({
1687
+ data: dataSet.items,
1688
+ isLoading,
1689
+ onChangeView: setView,
1690
+ paginationInfo: dataSet.paginationInfo,
1691
+ view,
1692
+ });
1693
+
1694
+ return (
1695
+ <div className="wp-typia-admin-view-screen">
1696
+ <header className="wp-typia-admin-view-screen__header">
1697
+ <div>
1698
+ <p className="wp-typia-admin-view-screen__eyebrow">
1699
+ { __( 'DataViews admin screen', ${quoteTsString(textDomain)} ) }
1700
+ </p>
1701
+ <h1>{ __( ${quoteTsString(title)}, ${quoteTsString(textDomain)} ) }</h1>
1702
+ <p>
1703
+ { __( '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)} ) }
1704
+ </p>
1705
+ </div>
1706
+ <div className="wp-typia-admin-view-screen__actions">
1707
+ { isLoading ? <Spinner /> : null }
1708
+ </div>
1709
+ </header>
1710
+ { error ? (
1711
+ <Notice isDismissible={ false } status="error">
1712
+ { error }
1713
+ </Notice>
1714
+ ) : null }
1715
+ <TypedDataViews<${itemTypeName}> { ...config } />
1716
+ </div>
1717
+ );
1718
+ }
1719
+ `;
1720
+ }
1234
1721
  function buildAdminViewEntrySource(adminViewSlug) {
1235
1722
  const pascalName = toPascalCase(adminViewSlug);
1236
1723
  const componentName = `${pascalName}AdminViewScreen`;
@@ -1400,15 +1887,22 @@ add_action( 'admin_menu', '${registerFunctionName}' );
1400
1887
  add_action( 'admin_enqueue_scripts', '${enqueueFunctionName}' );
1401
1888
  `;
1402
1889
  }
1403
- async function ensureAdminViewPackageDependencies(workspace) {
1890
+ async function ensureAdminViewPackageDependencies(workspace, adminViewSource) {
1404
1891
  const packageJsonPath = path4.join(workspace.projectDir, "package.json");
1405
1892
  const wpTypiaDataViewsVersion = resolvePackageVersionRange("@wp-typia/dataviews", DEFAULT_WP_TYPIA_DATAVIEWS_VERSION, "wp-typia-dataviews");
1406
1893
  const wordpressDataViewsVersion = resolvePackageVersionRange("@wordpress/dataviews", DEFAULT_WORDPRESS_DATAVIEWS_VERSION);
1894
+ const wordpressCoreDataVersion = resolvePackageVersionRange("@wordpress/core-data", DEFAULT_WORDPRESS_CORE_DATA_VERSION);
1895
+ const wordpressDataVersion = resolvePackageVersionRange("@wordpress/data", DEFAULT_WORDPRESS_DATA_VERSION);
1407
1896
  await patchFile(packageJsonPath, (source) => {
1408
1897
  const packageJson = JSON.parse(source);
1898
+ const coreDataDependencies = isAdminViewCoreDataSource(adminViewSource) ? {
1899
+ "@wordpress/core-data": packageJson.dependencies?.["@wordpress/core-data"] ?? wordpressCoreDataVersion,
1900
+ "@wordpress/data": packageJson.dependencies?.["@wordpress/data"] ?? wordpressDataVersion
1901
+ } : {};
1409
1902
  const nextDependencies = {
1410
1903
  ...packageJson.dependencies ?? {},
1411
- "@wordpress/dataviews": packageJson.dependencies?.["@wordpress/dataviews"] ?? wordpressDataViewsVersion
1904
+ "@wordpress/dataviews": packageJson.dependencies?.["@wordpress/dataviews"] ?? wordpressDataViewsVersion,
1905
+ ...coreDataDependencies
1412
1906
  };
1413
1907
  const nextDevDependencies = {
1414
1908
  ...packageJson.devDependencies ?? {},
@@ -1588,10 +2082,12 @@ async function runAddAdminViewCommand({
1588
2082
  source
1589
2083
  }) {
1590
2084
  const workspace = resolveWorkspaceProject(cwd);
1591
- const adminViewSlug = assertValidGeneratedSlug("Admin view name", normalizeBlockSlug(adminViewName), "wp-typia add admin-view <name> [--source rest-resource:<slug>]");
2085
+ assertAdminViewPackageAvailability();
2086
+ const adminViewSlug = assertValidGeneratedSlug("Admin view name", normalizeBlockSlug(adminViewName), "wp-typia add admin-view <name> [--source <rest-resource:slug|core-data:kind/name>]");
1592
2087
  const parsedSource = parseAdminViewSource(source);
1593
2088
  const inventory = readWorkspaceInventory(workspace.projectDir);
1594
2089
  const restResource = resolveRestResourceSource(inventory.restResources, parsedSource);
2090
+ const coreDataSource = isAdminViewCoreDataSource(parsedSource) ? parsedSource : undefined;
1595
2091
  assertAdminViewDoesNotExist(workspace.projectDir, adminViewSlug, inventory);
1596
2092
  const blockConfigPath = path4.join(workspace.projectDir, "scripts", "block-config.ts");
1597
2093
  const bootstrapPath = getWorkspaceBootstrapPath(workspace);
@@ -1616,14 +2112,14 @@ async function runAddAdminViewCommand({
1616
2112
  try {
1617
2113
  await fsp3.mkdir(adminViewDir, { recursive: true });
1618
2114
  await fsp3.mkdir(path4.dirname(adminViewPhpPath), { recursive: true });
1619
- await ensureAdminViewPackageDependencies(workspace);
2115
+ await ensureAdminViewPackageDependencies(workspace, parsedSource);
1620
2116
  await ensureAdminViewBootstrapAnchors(workspace);
1621
2117
  await ensureAdminViewBuildScriptAnchors(workspace);
1622
2118
  await ensureAdminViewWebpackAnchors(workspace);
1623
- await fsp3.writeFile(path4.join(adminViewDir, "types.ts"), buildAdminViewTypesSource(adminViewSlug, restResource), "utf8");
1624
- await fsp3.writeFile(path4.join(adminViewDir, "config.ts"), buildAdminViewConfigSource(adminViewSlug, workspace.workspace.textDomain, restResource), "utf8");
1625
- await fsp3.writeFile(path4.join(adminViewDir, "data.ts"), restResource ? buildRestAdminViewDataSource(adminViewSlug, restResource) : buildDefaultAdminViewDataSource(adminViewSlug), "utf8");
1626
- await fsp3.writeFile(path4.join(adminViewDir, "Screen.tsx"), buildAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain), "utf8");
2119
+ await fsp3.writeFile(path4.join(adminViewDir, "types.ts"), buildAdminViewTypesSource(adminViewSlug, restResource, coreDataSource), "utf8");
2120
+ await fsp3.writeFile(path4.join(adminViewDir, "config.ts"), buildAdminViewConfigSource(adminViewSlug, workspace.workspace.textDomain, parsedSource, restResource), "utf8");
2121
+ await fsp3.writeFile(path4.join(adminViewDir, "data.ts"), coreDataSource ? buildCoreDataAdminViewDataSource(adminViewSlug, coreDataSource) : restResource ? buildRestAdminViewDataSource(adminViewSlug, restResource) : buildDefaultAdminViewDataSource(adminViewSlug), "utf8");
2122
+ await fsp3.writeFile(path4.join(adminViewDir, "Screen.tsx"), coreDataSource ? buildCoreDataAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain) : buildAdminViewScreenSource(adminViewSlug, workspace.workspace.textDomain), "utf8");
1627
2123
  await fsp3.writeFile(path4.join(adminViewDir, "index.tsx"), buildAdminViewEntrySource(adminViewSlug), "utf8");
1628
2124
  await fsp3.writeFile(path4.join(adminViewDir, "style.scss"), buildAdminViewStyleSource(), "utf8");
1629
2125
  await fsp3.writeFile(adminViewPhpPath, buildAdminViewPhpSource(adminViewSlug, workspace), "utf8");
@@ -1634,7 +2130,7 @@ async function runAddAdminViewCommand({
1634
2130
  return {
1635
2131
  adminViewSlug,
1636
2132
  projectDir: workspace.projectDir,
1637
- source: parsedSource ? `${parsedSource.kind}:${parsedSource.slug}` : undefined
2133
+ source: parsedSource ? formatAdminViewSourceLocator(parsedSource) : undefined
1638
2134
  };
1639
2135
  } catch (error) {
1640
2136
  await rollbackWorkspaceMutation(mutationSnapshot);
@@ -3862,8 +4358,6 @@ var ABILITY_EDITOR_SCRIPT = "build/abilities/index.js";
3862
4358
  var ABILITY_EDITOR_ASSET = "build/abilities/index.asset.php";
3863
4359
  var ABILITY_REGISTRY_END_MARKER = "// wp-typia add ability entries end";
3864
4360
  var ABILITY_REGISTRY_START_MARKER = "// wp-typia add ability entries start";
3865
- var WP_ABILITIES_PACKAGE_VERSION = "^0.10.0";
3866
- var WP_CORE_ABILITIES_PACKAGE_VERSION = "^0.9.0";
3867
4361
  var WP_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/abilities";
3868
4362
  var WP_CORE_ABILITIES_SCRIPT_MODULE_ID = "@wordpress/core-abilities";
3869
4363
  function resolveManagedDependencyVersion(existingVersion, requiredVersion) {
@@ -4493,8 +4987,8 @@ async function ensureAbilityPackageScripts(workspace) {
4493
4987
  };
4494
4988
  const nextDependencies = {
4495
4989
  ...packageJson.dependencies ?? {},
4496
- [WP_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_ABILITIES_SCRIPT_MODULE_ID], WP_ABILITIES_PACKAGE_VERSION),
4497
- [WP_CORE_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_CORE_ABILITIES_SCRIPT_MODULE_ID], WP_CORE_ABILITIES_PACKAGE_VERSION)
4990
+ [WP_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_ABILITIES_SCRIPT_MODULE_ID], DEFAULT_WORDPRESS_ABILITIES_VERSION),
4991
+ [WP_CORE_ABILITIES_SCRIPT_MODULE_ID]: resolveManagedDependencyVersion(packageJson.dependencies?.[WP_CORE_ABILITIES_SCRIPT_MODULE_ID], DEFAULT_WORDPRESS_CORE_ABILITIES_VERSION)
4498
4992
  };
4499
4993
  if (JSON.stringify(nextScripts) === JSON.stringify(packageJson.scripts ?? {}) && JSON.stringify(nextDependencies) === JSON.stringify(packageJson.dependencies ?? {})) {
4500
4994
  return;
@@ -6652,4 +7146,4 @@ export {
6652
7146
  ADD_BLOCK_TEMPLATE_IDS
6653
7147
  };
6654
7148
 
6655
- //# debugId=7C11AF8BB98BD78764756E2164756E21
7149
+ //# debugId=8932DC6C8A5BAD5564756E2164756E21