@wp-typia/project-tools 0.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (187) hide show
  1. package/README.md +32 -0
  2. package/dist/runtime/cli-add.d.ts +38 -0
  3. package/dist/runtime/cli-add.js +561 -0
  4. package/dist/runtime/cli-core.d.ts +25 -0
  5. package/dist/runtime/cli-core.js +25 -0
  6. package/dist/runtime/cli-doctor.d.ts +34 -0
  7. package/dist/runtime/cli-doctor.js +131 -0
  8. package/dist/runtime/cli-help.d.ts +9 -0
  9. package/dist/runtime/cli-help.js +37 -0
  10. package/dist/runtime/cli-prompt.d.ts +21 -0
  11. package/dist/runtime/cli-prompt.js +53 -0
  12. package/dist/runtime/cli-scaffold.d.ts +79 -0
  13. package/dist/runtime/cli-scaffold.js +206 -0
  14. package/dist/runtime/cli-templates.d.ts +30 -0
  15. package/dist/runtime/cli-templates.js +61 -0
  16. package/dist/runtime/index.d.ts +9 -0
  17. package/dist/runtime/index.js +7 -0
  18. package/dist/runtime/json-utils.d.ts +10 -0
  19. package/dist/runtime/json-utils.js +12 -0
  20. package/dist/runtime/local-dev-presets.d.ts +26 -0
  21. package/dist/runtime/local-dev-presets.js +132 -0
  22. package/dist/runtime/metadata-analysis.d.ts +11 -0
  23. package/dist/runtime/metadata-analysis.js +285 -0
  24. package/dist/runtime/metadata-model.d.ts +84 -0
  25. package/dist/runtime/metadata-model.js +59 -0
  26. package/dist/runtime/metadata-parser.d.ts +53 -0
  27. package/dist/runtime/metadata-parser.js +794 -0
  28. package/dist/runtime/metadata-php-render.d.ts +29 -0
  29. package/dist/runtime/metadata-php-render.js +549 -0
  30. package/dist/runtime/metadata-projection.d.ts +7 -0
  31. package/dist/runtime/metadata-projection.js +233 -0
  32. package/dist/runtime/migration-constants.d.ts +15 -0
  33. package/dist/runtime/migration-constants.js +16 -0
  34. package/dist/runtime/migration-diff.d.ts +2 -0
  35. package/dist/runtime/migration-diff.js +537 -0
  36. package/dist/runtime/migration-fixtures.d.ts +8 -0
  37. package/dist/runtime/migration-fixtures.js +94 -0
  38. package/dist/runtime/migration-fuzz-plan.d.ts +2 -0
  39. package/dist/runtime/migration-fuzz-plan.js +50 -0
  40. package/dist/runtime/migration-manifest.d.ts +19 -0
  41. package/dist/runtime/migration-manifest.js +129 -0
  42. package/dist/runtime/migration-project.d.ts +94 -0
  43. package/dist/runtime/migration-project.js +1101 -0
  44. package/dist/runtime/migration-render.d.ts +11 -0
  45. package/dist/runtime/migration-render.js +741 -0
  46. package/dist/runtime/migration-risk.d.ts +4 -0
  47. package/dist/runtime/migration-risk.js +52 -0
  48. package/dist/runtime/migration-types.d.ts +249 -0
  49. package/dist/runtime/migration-types.js +1 -0
  50. package/dist/runtime/migration-ui-capability.d.ts +17 -0
  51. package/dist/runtime/migration-ui-capability.js +190 -0
  52. package/dist/runtime/migration-utils.d.ts +69 -0
  53. package/dist/runtime/migration-utils.js +246 -0
  54. package/dist/runtime/migrations.d.ts +249 -0
  55. package/dist/runtime/migrations.js +1061 -0
  56. package/dist/runtime/object-utils.d.ts +12 -0
  57. package/dist/runtime/object-utils.js +14 -0
  58. package/dist/runtime/package-managers.d.ts +28 -0
  59. package/dist/runtime/package-managers.js +156 -0
  60. package/dist/runtime/package-versions.d.ts +10 -0
  61. package/dist/runtime/package-versions.js +68 -0
  62. package/dist/runtime/scaffold-onboarding.d.ts +32 -0
  63. package/dist/runtime/scaffold-onboarding.js +99 -0
  64. package/dist/runtime/scaffold.d.ts +146 -0
  65. package/dist/runtime/scaffold.js +612 -0
  66. package/dist/runtime/schema-core.d.ts +267 -0
  67. package/dist/runtime/schema-core.js +597 -0
  68. package/dist/runtime/starter-manifests.d.ts +25 -0
  69. package/dist/runtime/starter-manifests.js +383 -0
  70. package/dist/runtime/string-case.d.ts +36 -0
  71. package/dist/runtime/string-case.js +69 -0
  72. package/dist/runtime/template-builtins.d.ts +38 -0
  73. package/dist/runtime/template-builtins.js +72 -0
  74. package/dist/runtime/template-defaults.d.ts +75 -0
  75. package/dist/runtime/template-defaults.js +65 -0
  76. package/dist/runtime/template-registry.d.ts +36 -0
  77. package/dist/runtime/template-registry.js +94 -0
  78. package/dist/runtime/template-render.d.ts +24 -0
  79. package/dist/runtime/template-render.js +113 -0
  80. package/dist/runtime/template-source.d.ts +71 -0
  81. package/dist/runtime/template-source.js +821 -0
  82. package/dist/runtime/typia-tags.d.ts +1 -0
  83. package/dist/runtime/typia-tags.js +1 -0
  84. package/package.json +79 -0
  85. package/templates/_shared/base/languages/.gitkeep +1 -0
  86. package/templates/_shared/base/package.json.mustache +41 -0
  87. package/templates/_shared/base/scripts/sync-types-to-block-json.ts.mustache +118 -0
  88. package/templates/_shared/base/src/hooks.ts.mustache +19 -0
  89. package/templates/_shared/base/src/validator-toolkit.ts.mustache +31 -0
  90. package/templates/_shared/base/tsconfig.json.mustache +21 -0
  91. package/templates/_shared/base/webpack.config.js.mustache +99 -0
  92. package/templates/_shared/base/{{slugKebabCase}}.php.mustache +53 -0
  93. package/templates/_shared/compound/core/package.json.mustache +45 -0
  94. package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +559 -0
  95. package/templates/_shared/compound/core/scripts/block-config.ts.mustache +13 -0
  96. package/templates/_shared/compound/core/scripts/sync-types-to-block-json.ts.mustache +53 -0
  97. package/templates/_shared/compound/core/webpack.config.js.mustache +141 -0
  98. package/templates/_shared/compound/core/{{slugKebabCase}}.php.mustache +51 -0
  99. package/templates/_shared/compound/persistence/package.json.mustache +50 -0
  100. package/templates/_shared/compound/persistence/scripts/block-config.ts.mustache +59 -0
  101. package/templates/_shared/compound/persistence/scripts/sync-rest-contracts.ts.mustache +101 -0
  102. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/api-types.ts.mustache +21 -0
  103. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/api-validators.ts.mustache +32 -0
  104. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/api.ts.mustache +68 -0
  105. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/block.json.mustache +52 -0
  106. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/data.ts.mustache +192 -0
  107. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/edit.tsx.mustache +123 -0
  108. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/hooks.ts.mustache +11 -0
  109. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/interactivity.ts.mustache +132 -0
  110. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/render.php.mustache +158 -0
  111. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/save.tsx.mustache +3 -0
  112. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/types.ts.mustache +56 -0
  113. package/templates/_shared/compound/persistence/src/blocks/{{slugKebabCase}}/validators.ts.mustache +32 -0
  114. package/templates/_shared/compound/persistence-auth/{{slugKebabCase}}.php.mustache +294 -0
  115. package/templates/_shared/compound/persistence-public/{{slugKebabCase}}.php.mustache +312 -0
  116. package/templates/_shared/migration-ui/common/src/admin/migration-dashboard.tsx +394 -0
  117. package/templates/_shared/migration-ui/common/src/migration-detector.ts +9 -0
  118. package/templates/_shared/migration-ui/common/src/migrations/helpers.ts +490 -0
  119. package/templates/_shared/migration-ui/common/src/migrations/index.ts +886 -0
  120. package/templates/_shared/persistence/auth/{{slugKebabCase}}.php.mustache +290 -0
  121. package/templates/_shared/persistence/core/package.json.mustache +46 -0
  122. package/templates/_shared/persistence/core/scripts/sync-rest-contracts.ts.mustache +113 -0
  123. package/templates/_shared/persistence/core/scripts/sync-types-to-block-json.ts.mustache +125 -0
  124. package/templates/_shared/persistence/core/src/api-types.ts.mustache +21 -0
  125. package/templates/_shared/persistence/core/src/api-validators.ts.mustache +32 -0
  126. package/templates/_shared/persistence/core/src/api.ts.mustache +68 -0
  127. package/templates/_shared/persistence/core/src/data.ts.mustache +192 -0
  128. package/templates/_shared/persistence/core/src/index.tsx.mustache +25 -0
  129. package/templates/_shared/persistence/core/src/interactivity.ts.mustache +134 -0
  130. package/templates/_shared/persistence/core/src/save.tsx.mustache +5 -0
  131. package/templates/_shared/persistence/core/src/validators.ts.mustache +32 -0
  132. package/templates/_shared/persistence/core/{{slugKebabCase}}.php.mustache +336 -0
  133. package/templates/_shared/persistence/public/{{slugKebabCase}}.php.mustache +308 -0
  134. package/templates/_shared/presets/test-preset/.wp-env.test.json.mustache +16 -0
  135. package/templates/_shared/presets/test-preset/playwright.config.ts.mustache +22 -0
  136. package/templates/_shared/presets/test-preset/scripts/wait-for-wp-env.mjs.mustache +102 -0
  137. package/templates/_shared/presets/test-preset/scripts/wp-env-utils.cjs.mustache +32 -0
  138. package/templates/_shared/presets/test-preset/tests/e2e/smoke.spec.ts.mustache +34 -0
  139. package/templates/_shared/presets/wp-env/.wp-env.json.mustache +16 -0
  140. package/templates/_shared/rest-helpers/auth/inc/rest-auth.php.mustache +37 -0
  141. package/templates/_shared/rest-helpers/public/inc/rest-public.php.mustache +314 -0
  142. package/templates/_shared/rest-helpers/shared/inc/rest-shared.php.mustache +58 -0
  143. package/templates/_shared/workspace/persistence-auth/inc/rest-auth.php.mustache +36 -0
  144. package/templates/_shared/workspace/persistence-auth/inc/rest-shared.php.mustache +55 -0
  145. package/templates/_shared/workspace/persistence-auth/server.php.mustache +237 -0
  146. package/templates/_shared/workspace/persistence-public/inc/rest-public.php.mustache +273 -0
  147. package/templates/_shared/workspace/persistence-public/inc/rest-shared.php.mustache +55 -0
  148. package/templates/_shared/workspace/persistence-public/server.php.mustache +252 -0
  149. package/templates/basic/src/block.json.mustache +51 -0
  150. package/templates/basic/src/edit.tsx.mustache +128 -0
  151. package/templates/basic/src/editor.scss.mustache +8 -0
  152. package/templates/basic/src/hooks.ts.mustache +18 -0
  153. package/templates/basic/src/index.tsx.mustache +45 -0
  154. package/templates/basic/src/save.tsx.mustache +30 -0
  155. package/templates/basic/src/style.scss.mustache +40 -0
  156. package/templates/basic/src/types.ts.mustache +56 -0
  157. package/templates/basic/src/validators.ts.mustache +26 -0
  158. package/templates/compound/src/blocks/{{slugKebabCase}}/block.json.mustache +37 -0
  159. package/templates/compound/src/blocks/{{slugKebabCase}}/children.ts.mustache +25 -0
  160. package/templates/compound/src/blocks/{{slugKebabCase}}/edit.tsx.mustache +93 -0
  161. package/templates/compound/src/blocks/{{slugKebabCase}}/hooks.ts.mustache +11 -0
  162. package/templates/compound/src/blocks/{{slugKebabCase}}/index.tsx.mustache +25 -0
  163. package/templates/compound/src/blocks/{{slugKebabCase}}/save.tsx.mustache +32 -0
  164. package/templates/compound/src/blocks/{{slugKebabCase}}/style.scss.mustache +31 -0
  165. package/templates/compound/src/blocks/{{slugKebabCase}}/types.ts.mustache +13 -0
  166. package/templates/compound/src/blocks/{{slugKebabCase}}/validators.ts.mustache +17 -0
  167. package/templates/compound/src/blocks/{{slugKebabCase}}-item/block.json.mustache +35 -0
  168. package/templates/compound/src/blocks/{{slugKebabCase}}-item/edit.tsx.mustache +50 -0
  169. package/templates/compound/src/blocks/{{slugKebabCase}}-item/hooks.ts.mustache +11 -0
  170. package/templates/compound/src/blocks/{{slugKebabCase}}-item/index.tsx.mustache +25 -0
  171. package/templates/compound/src/blocks/{{slugKebabCase}}-item/save.tsx.mustache +24 -0
  172. package/templates/compound/src/blocks/{{slugKebabCase}}-item/types.ts.mustache +12 -0
  173. package/templates/compound/src/blocks/{{slugKebabCase}}-item/validators.ts.mustache +17 -0
  174. package/templates/interactivity/package.json.mustache +42 -0
  175. package/templates/interactivity/src/block.json.mustache +73 -0
  176. package/templates/interactivity/src/edit.tsx.mustache +270 -0
  177. package/templates/interactivity/src/index.tsx.mustache +32 -0
  178. package/templates/interactivity/src/interactivity.ts.mustache +152 -0
  179. package/templates/interactivity/src/save.tsx.mustache +101 -0
  180. package/templates/interactivity/src/style.scss.mustache +60 -0
  181. package/templates/interactivity/src/types.ts.mustache +32 -0
  182. package/templates/interactivity/src/validators.ts.mustache +36 -0
  183. package/templates/persistence/src/block.json.mustache +52 -0
  184. package/templates/persistence/src/edit.tsx.mustache +165 -0
  185. package/templates/persistence/src/render.php.mustache +126 -0
  186. package/templates/persistence/src/style.scss.mustache +46 -0
  187. package/templates/persistence/src/types.ts.mustache +55 -0
@@ -0,0 +1,141 @@
1
+ const fs = require( 'fs' );
2
+ const path = require( 'path' );
3
+ const defaultConfig = require( '@wordpress/scripts/config/webpack.config' );
4
+
5
+ const STATIC_METADATA_FILENAMES = new Set( [
6
+ 'block.json',
7
+ 'render.php',
8
+ 'typia.openapi.json',
9
+ 'typia.manifest.json',
10
+ 'typia-migration-registry.php',
11
+ 'typia.schema.json',
12
+ 'typia-validator.php',
13
+ ] );
14
+
15
+ function isMetadataAsset( filename ) {
16
+ return (
17
+ STATIC_METADATA_FILENAMES.has( filename ) ||
18
+ filename.endsWith( '.schema.json' ) ||
19
+ filename.endsWith( '.openapi.json' )
20
+ );
21
+ }
22
+
23
+ function getBlockDirs() {
24
+ const blocksRoot = path.resolve( process.cwd(), 'src/blocks' );
25
+
26
+ if ( ! fs.existsSync( blocksRoot ) ) {
27
+ return [];
28
+ }
29
+
30
+ return fs
31
+ .readdirSync( blocksRoot, { withFileTypes: true } )
32
+ .filter( ( entry ) => entry.isDirectory() )
33
+ .map( ( entry ) => ( {
34
+ dir: path.join( blocksRoot, entry.name ),
35
+ slug: entry.name,
36
+ } ) );
37
+ }
38
+
39
+ function getMetadataEntries() {
40
+ const entries = [];
41
+ const rootMigrationRegistryPath = path.resolve(
42
+ process.cwd(),
43
+ 'typia-migration-registry.php'
44
+ );
45
+
46
+ if ( fs.existsSync( rootMigrationRegistryPath ) ) {
47
+ entries.push( {
48
+ inputPath: rootMigrationRegistryPath,
49
+ outputPath: 'typia-migration-registry.php',
50
+ } );
51
+ }
52
+
53
+ for ( const blockDir of getBlockDirs() ) {
54
+ for ( const inputPath of findMetadataFiles( blockDir.dir ) ) {
55
+ entries.push( {
56
+ inputPath,
57
+ outputPath: path.join(
58
+ 'blocks',
59
+ blockDir.slug,
60
+ path.relative( blockDir.dir, inputPath )
61
+ ),
62
+ } );
63
+ }
64
+ }
65
+
66
+ return entries;
67
+ }
68
+
69
+ function findMetadataFiles( directory ) {
70
+ const metadataFiles = [];
71
+
72
+ for ( const entry of fs.readdirSync( directory, {
73
+ withFileTypes: true,
74
+ } ) ) {
75
+ const entryPath = path.join( directory, entry.name );
76
+
77
+ if ( entry.isDirectory() ) {
78
+ metadataFiles.push( ...findMetadataFiles( entryPath ) );
79
+ continue;
80
+ }
81
+
82
+ if ( entry.isFile() && isMetadataAsset( entry.name ) ) {
83
+ metadataFiles.push( entryPath );
84
+ }
85
+ }
86
+
87
+ return metadataFiles;
88
+ }
89
+
90
+ function getEditorEntries() {
91
+ return Object.fromEntries(
92
+ getBlockDirs().map( ( blockDir ) => [
93
+ `blocks/${ blockDir.slug }/index`,
94
+ path.join( blockDir.dir, 'index.tsx' ),
95
+ ] )
96
+ );
97
+ }
98
+
99
+ function getOptionalModuleEntries() {
100
+ const entries = [];
101
+
102
+ for ( const blockDir of getBlockDirs() ) {
103
+ for ( const filename of [
104
+ 'interactivity.ts',
105
+ 'interactivity.js',
106
+ 'view.ts',
107
+ 'view.js',
108
+ ] ) {
109
+ const entryPath = path.join( blockDir.dir, filename );
110
+ if ( ! fs.existsSync( entryPath ) ) {
111
+ continue;
112
+ }
113
+
114
+ entries.push( [
115
+ `blocks/${ blockDir.slug }/${ filename.replace(
116
+ /\.[^.]+$/,
117
+ ''
118
+ ) }`,
119
+ entryPath,
120
+ ] );
121
+ }
122
+ }
123
+
124
+ return Object.fromEntries( entries );
125
+ }
126
+
127
+ module.exports = async () => {
128
+ const { createTypiaWebpackConfig } = await import( '@wp-typia/block-runtime/blocks' );
129
+
130
+ return createTypiaWebpackConfig( {
131
+ defaultConfig,
132
+ fs,
133
+ path,
134
+ getArtifactEntries: getMetadataEntries,
135
+ getEditorEntries,
136
+ getOptionalModuleEntries,
137
+ importTypiaWebpackPlugin: () => import( '@typia/unplugin/webpack' ),
138
+ moduleEntriesMode: 'replace',
139
+ nonModuleEntriesMode: 'replace',
140
+ } );
141
+ };
@@ -0,0 +1,51 @@
1
+ <?php
2
+ /**
3
+ * Plugin Name: {{title}}
4
+ * Description: {{description}}
5
+ * Version: 0.1.0
6
+ * Requires at least: 6.7
7
+ * Tested up to: 6.9
8
+ * Requires PHP: 8.0
9
+ * Author: {{author}}
10
+ * License: GPL-2.0-or-later
11
+ * License URI: https://www.gnu.org/licenses/gpl-2.0.html
12
+ * Text Domain: {{textDomain}}
13
+ * Domain Path: /languages
14
+ */
15
+
16
+ if ( ! defined( 'ABSPATH' ) ) {
17
+ exit;
18
+ }
19
+
20
+ function {{phpPrefix}}_load_textdomain() {
21
+ load_plugin_textdomain(
22
+ '{{textDomain}}',
23
+ false,
24
+ dirname( plugin_basename( __FILE__ ) ) . '/languages'
25
+ );
26
+ }
27
+
28
+ function {{phpPrefix}}_get_build_root() {
29
+ return __DIR__ . '/build/blocks';
30
+ }
31
+
32
+ function {{phpPrefix}}_register_blocks() {
33
+ $build_root = {{phpPrefix}}_get_build_root();
34
+ if ( ! is_dir( $build_root ) ) {
35
+ return;
36
+ }
37
+
38
+ $block_dirs = glob( $build_root . '/*', GLOB_ONLYDIR );
39
+ if ( ! is_array( $block_dirs ) ) {
40
+ return;
41
+ }
42
+
43
+ foreach ( $block_dirs as $block_dir ) {
44
+ if ( file_exists( $block_dir . '/block.json' ) ) {
45
+ register_block_type( $block_dir );
46
+ }
47
+ }
48
+ }
49
+
50
+ add_action( 'init', '{{phpPrefix}}_load_textdomain' );
51
+ add_action( 'init', '{{phpPrefix}}_register_blocks' );
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "{{slug}}",
3
+ "version": "0.1.0",
4
+ "packageManager": "bun@1.3.10",
5
+ "description": "{{description}}",
6
+ "author": "{{author}}",
7
+ "license": "GPL-2.0-or-later",
8
+ "main": "build/index.js",
9
+ "scripts": {
10
+ "add-child": "tsx scripts/add-compound-child.ts",
11
+ "sync-types": "tsx scripts/sync-types-to-block-json.ts",
12
+ "sync-rest": "tsx scripts/sync-rest-contracts.ts",
13
+ "build": "bun run sync-types --check && bun run sync-rest --check && wp-scripts build --experimental-modules",
14
+ "start": "bun run sync-types && bun run sync-rest && wp-scripts start --experimental-modules",
15
+ "dev": "bun run start",
16
+ "typecheck": "bun run sync-types --check && bun run sync-rest --check && tsc --noEmit",
17
+ "lint:js": "wp-scripts lint-js",
18
+ "lint:css": "wp-scripts lint-style",
19
+ "lint": "bun run lint:js && bun run lint:css",
20
+ "format": "wp-scripts format"
21
+ },
22
+ "devDependencies": {
23
+ "@wp-typia/block-runtime": "{{blockRuntimePackageVersion}}",
24
+ "@wp-typia/api-client": "{{apiClientPackageVersion}}",
25
+ "@wp-typia/block-types": "{{blockTypesPackageVersion}}",
26
+ "@wp-typia/rest": "{{restPackageVersion}}",
27
+ "@typia/unplugin": "^12.0.1",
28
+ "@wordpress/browserslist-config": "^6.42.0",
29
+ "@wordpress/scripts": "^30.22.0",
30
+ "@types/react": "^19.2.2",
31
+ "@types/react-dom": "^19.2.2",
32
+ "@types/wordpress__block-editor": "^11.5.17",
33
+ "@types/wordpress__blocks": "^12.5.18",
34
+ "ajv": "^8.18.0",
35
+ "eslint-plugin-jsx-a11y": "^6.10.2",
36
+ "prettier": "2.8.8",
37
+ "tsx": "^4.20.5",
38
+ "typescript": "^5.9.2",
39
+ "typia": "^12.0.1"
40
+ },
41
+ "dependencies": {
42
+ "@wordpress/api-fetch": "^7.42.0",
43
+ "@wordpress/block-editor": "^15.2.0",
44
+ "@wordpress/blocks": "^15.2.0",
45
+ "@wordpress/components": "^30.2.0",
46
+ "@wordpress/element": "^6.29.0",
47
+ "@wordpress/i18n": "^6.2.0",
48
+ "@wordpress/interactivity": "^6.29.0"
49
+ }
50
+ }
@@ -0,0 +1,59 @@
1
+ import { defineEndpointManifest } from '@wp-typia/block-runtime/metadata-core';
2
+
3
+ export const BLOCKS = [
4
+ {
5
+ apiTypesFile: 'src/blocks/{{slugKebabCase}}/api-types.ts',
6
+ attributeTypeName: '{{pascalCase}}Attributes',
7
+ restManifest: defineEndpointManifest( {
8
+ contracts: {
9
+ 'state-query': {
10
+ sourceTypeName: '{{pascalCase}}StateQuery',
11
+ },
12
+ 'write-state-request': {
13
+ sourceTypeName: '{{pascalCase}}WriteStateRequest',
14
+ },
15
+ 'state-response': {
16
+ sourceTypeName: '{{pascalCase}}StateResponse',
17
+ },
18
+ },
19
+ endpoints: [
20
+ {
21
+ auth: 'public',
22
+ method: 'GET',
23
+ operationId: 'get{{pascalCase}}State',
24
+ path: '/{{namespace}}/v1/{{slugKebabCase}}/state',
25
+ queryContract: 'state-query',
26
+ responseContract: 'state-response',
27
+ summary: 'Read the current persisted state.',
28
+ tags: [ '{{title}}' ],
29
+ },
30
+ {
31
+ auth: '{{restWriteAuthIntent}}',
32
+ bodyContract: 'write-state-request',
33
+ method: 'POST',
34
+ operationId: 'write{{pascalCase}}State',
35
+ path: '/{{namespace}}/v1/{{slugKebabCase}}/state',
36
+ responseContract: 'state-response',
37
+ summary: 'Write the current persisted state.',
38
+ tags: [ '{{title}}' ],
39
+ wordpressAuth: {
40
+ mechanism: '{{restWriteAuthMechanism}}',
41
+ },
42
+ },
43
+ ],
44
+ info: {
45
+ title: '{{title}} REST API',
46
+ version: '1.0.0',
47
+ },
48
+ } ),
49
+ openApiFile: 'src/blocks/{{slugKebabCase}}/api.openapi.json',
50
+ slug: '{{slugKebabCase}}',
51
+ typesFile: 'src/blocks/{{slugKebabCase}}/types.ts',
52
+ },
53
+ {
54
+ slug: '{{slugKebabCase}}-item',
55
+ attributeTypeName: '{{pascalCase}}ItemAttributes',
56
+ typesFile: 'src/blocks/{{slugKebabCase}}-item/types.ts',
57
+ },
58
+ // add-child: insert new block config entries here
59
+ ] as const;
@@ -0,0 +1,101 @@
1
+ /* eslint-disable no-console */
2
+ import path from 'node:path';
3
+
4
+ import {
5
+ syncEndpointClient,
6
+ syncRestOpenApi,
7
+ syncTypeSchemas,
8
+ } from '@wp-typia/block-runtime/metadata-core';
9
+
10
+ import { BLOCKS } from './block-config';
11
+
12
+ function parseCliOptions( argv: string[] ) {
13
+ const options = {
14
+ check: false,
15
+ };
16
+
17
+ for ( const argument of argv ) {
18
+ if ( argument === '--check' ) {
19
+ options.check = true;
20
+ continue;
21
+ }
22
+
23
+ throw new Error( `Unknown sync-rest flag: ${ argument }` );
24
+ }
25
+
26
+ return options;
27
+ }
28
+
29
+ async function main() {
30
+ const options = parseCliOptions( process.argv.slice( 2 ) );
31
+
32
+ for ( const block of BLOCKS ) {
33
+ if (
34
+ ! ( 'apiTypesFile' in block ) ||
35
+ ! block.apiTypesFile ||
36
+ ! ( 'restManifest' in block ) ||
37
+ ! block.restManifest
38
+ ) {
39
+ continue;
40
+ }
41
+
42
+ for ( const [ baseName, contract ] of Object.entries( block.restManifest.contracts ) ) {
43
+ await syncTypeSchemas( {
44
+ jsonSchemaFile: path.join(
45
+ 'src',
46
+ 'blocks',
47
+ block.slug,
48
+ 'api-schemas',
49
+ `${ baseName }.schema.json`
50
+ ),
51
+ openApiFile: path.join(
52
+ 'src',
53
+ 'blocks',
54
+ block.slug,
55
+ 'api-schemas',
56
+ `${ baseName }.openapi.json`
57
+ ),
58
+ sourceTypeName: contract.sourceTypeName,
59
+ typesFile: block.apiTypesFile,
60
+ }, {
61
+ check: options.check,
62
+ } );
63
+ }
64
+
65
+ if ( block.restManifest.endpoints.length > 0 ) {
66
+ await syncEndpointClient( {
67
+ clientFile: path.join(
68
+ 'src',
69
+ 'blocks',
70
+ block.slug,
71
+ 'api-client.ts'
72
+ ),
73
+ manifest: block.restManifest,
74
+ typesFile: block.apiTypesFile,
75
+ }, {
76
+ check: options.check,
77
+ } );
78
+
79
+ if ( block.openApiFile ) {
80
+ await syncRestOpenApi( {
81
+ manifest: block.restManifest,
82
+ openApiFile: block.openApiFile,
83
+ typesFile: block.apiTypesFile,
84
+ }, {
85
+ check: options.check,
86
+ } );
87
+ }
88
+ }
89
+ }
90
+
91
+ console.log(
92
+ options.check
93
+ ? '✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents are already up to date with the TypeScript types!'
94
+ : '✅ REST contract schemas, portable API clients, and endpoint-aware OpenAPI documents generated from TypeScript types!'
95
+ );
96
+ }
97
+
98
+ main().catch( ( error ) => {
99
+ console.error( '❌ REST contract sync failed:', error );
100
+ process.exit( 1 );
101
+ } );
@@ -0,0 +1,21 @@
1
+ import { tags } from 'typia';
2
+
3
+ export interface {{pascalCase}}StateQuery {
4
+ postId: number & tags.Type< 'uint32' >;
5
+ resourceKey: string & tags.MinLength< 1 > & tags.MaxLength< 100 >;
6
+ }
7
+
8
+ export interface {{pascalCase}}WriteStateRequest {
9
+ postId: number & tags.Type< 'uint32' >;
10
+ {{publicWriteRequestIdDeclaration}}
11
+ publicWriteToken?: string & tags.MinLength< 1 > & tags.MaxLength< 512 >;
12
+ resourceKey: string & tags.MinLength< 1 > & tags.MaxLength< 100 >;
13
+ delta?: number & tags.Minimum< 1 > & tags.Type< 'uint32' > & tags.Default< 1 >;
14
+ }
15
+
16
+ export interface {{pascalCase}}StateResponse {
17
+ postId: number & tags.Type< 'uint32' >;
18
+ resourceKey: string & tags.MinLength< 1 > & tags.MaxLength< 100 >;
19
+ count: number & tags.Minimum< 0 > & tags.Type< 'uint32' >;
20
+ storage: ( 'post-meta' | 'custom-table' );
21
+ }
@@ -0,0 +1,32 @@
1
+ import typia from 'typia';
2
+
3
+ import {
4
+ toValidationResult,
5
+ type ValidationResult,
6
+ } from '@wp-typia/api-client';
7
+ import type {
8
+ {{pascalCase}}StateQuery,
9
+ {{pascalCase}}StateResponse,
10
+ {{pascalCase}}WriteStateRequest,
11
+ } from './api-types';
12
+
13
+ const validateStateQuery = typia.createValidate< {{pascalCase}}StateQuery >();
14
+ const validateWriteStateRequest =
15
+ typia.createValidate< {{pascalCase}}WriteStateRequest >();
16
+ const validateStateResponse =
17
+ typia.createValidate< {{pascalCase}}StateResponse >();
18
+
19
+ export const apiValidators = {
20
+ stateQuery: (
21
+ input: unknown
22
+ ): ValidationResult< {{pascalCase}}StateQuery > =>
23
+ toValidationResult( validateStateQuery( input ) ),
24
+ stateResponse: (
25
+ input: unknown
26
+ ): ValidationResult< {{pascalCase}}StateResponse > =>
27
+ toValidationResult( validateStateResponse( input ) ),
28
+ writeStateRequest: (
29
+ input: unknown
30
+ ): ValidationResult< {{pascalCase}}WriteStateRequest > =>
31
+ toValidationResult( validateWriteStateRequest( input ) ),
32
+ };
@@ -0,0 +1,68 @@
1
+ import {
2
+ callEndpoint,
3
+ resolveRestRouteUrl,
4
+ } from '@wp-typia/rest';
5
+
6
+ import {
7
+ type {{pascalCase}}StateQuery,
8
+ type {{pascalCase}}WriteStateRequest,
9
+ } from './api-types';
10
+ import {
11
+ get{{pascalCase}}StateEndpoint,
12
+ write{{pascalCase}}StateEndpoint,
13
+ } from './api-client';
14
+
15
+ export function resolveRestNonce( fallback?: string ): string | undefined {
16
+ if ( typeof fallback === 'string' && fallback.length > 0 ) {
17
+ return fallback;
18
+ }
19
+
20
+ if ( typeof window === 'undefined' ) {
21
+ return undefined;
22
+ }
23
+
24
+ const wpApiSettings = ( window as typeof window & {
25
+ wpApiSettings?: { nonce?: string };
26
+ } ).wpApiSettings;
27
+
28
+ return typeof wpApiSettings?.nonce === 'string' && wpApiSettings.nonce.length > 0
29
+ ? wpApiSettings.nonce
30
+ : undefined;
31
+ }
32
+
33
+ export const stateEndpoint = {
34
+ ...get{{pascalCase}}StateEndpoint,
35
+ buildRequestOptions: () => ( {
36
+ url: resolveRestRouteUrl( get{{pascalCase}}StateEndpoint.path ),
37
+ } ),
38
+ };
39
+
40
+ export const writeStateEndpoint = {
41
+ ...write{{pascalCase}}StateEndpoint,
42
+ buildRequestOptions: () => ( {
43
+ url: resolveRestRouteUrl( write{{pascalCase}}StateEndpoint.path ),
44
+ } ),
45
+ };
46
+
47
+ export function fetchState(
48
+ request: {{pascalCase}}StateQuery
49
+ ) {
50
+ return callEndpoint( stateEndpoint, request );
51
+ }
52
+
53
+ export function writeState(
54
+ request: {{pascalCase}}WriteStateRequest,
55
+ restNonce?: string
56
+ ) {
57
+ const nonce = resolveRestNonce( restNonce );
58
+
59
+ return callEndpoint( writeStateEndpoint, request, {
60
+ requestOptions: nonce
61
+ ? {
62
+ headers: {
63
+ 'X-WP-Nonce': nonce,
64
+ },
65
+ }
66
+ : undefined,
67
+ } );
68
+ }
@@ -0,0 +1,52 @@
1
+ {
2
+ "$schema": "https://schemas.wp.org/trunk/block.json",
3
+ "apiVersion": 3,
4
+ "name": "{{namespace}}/{{slugKebabCase}}",
5
+ "version": "{{blockMetadataVersion}}",
6
+ "title": {{titleJson}},
7
+ "category": "{{category}}",
8
+ "icon": "{{icon}}",
9
+ "description": "{{description}}",
10
+ "example": {},
11
+ "supports": {
12
+ "html": false,
13
+ "anchor": true,
14
+ "className": true,
15
+ "interactivity": true
16
+ },
17
+ "attributes": {
18
+ "heading": {
19
+ "type": "string",
20
+ "source": "html",
21
+ "selector": ".{{cssClassName}}__heading",
22
+ "default": {{titleJson}}
23
+ },
24
+ "intro": {
25
+ "type": "string",
26
+ "source": "html",
27
+ "selector": ".{{cssClassName}}__intro",
28
+ "default": "Add and reorder internal items inside this compound block."
29
+ },
30
+ "showDividers": {
31
+ "type": "boolean",
32
+ "default": true
33
+ },
34
+ "showCount": {
35
+ "type": "boolean",
36
+ "default": true
37
+ },
38
+ "buttonLabel": {
39
+ "type": "string",
40
+ "default": "Persist Count"
41
+ },
42
+ "resourceKey": {
43
+ "type": "string",
44
+ "default": ""
45
+ }
46
+ },
47
+ "textdomain": "{{textDomain}}",
48
+ "editorScript": "file:./index.js",
49
+ "style": "file:./style-index.css",
50
+ "viewScriptModule": "file:./interactivity.js",
51
+ "render": "file:./render.php"
52
+ }