@wp-typia/create-workspace-template 0.17.1 → 0.18.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.
- package/README.md +23 -0
- package/README.md.mustache +22 -0
- package/package.json +1 -1
- package/package.json.mustache +4 -4
- package/scripts/block-config.ts.mustache +22 -1
- package/scripts/sync-types-to-block-json.ts.mustache +138 -2
- package/src/inner-blocks-templates.ts.mustache +13 -0
- package/{{slugKebabCase}}.php.mustache +5 -1
package/README.md
CHANGED
|
@@ -16,16 +16,39 @@ npm run wp-typia:add -- block my-block --template basic
|
|
|
16
16
|
npm run wp-typia:add -- integration-env local-smoke --wp-env --release-zip --service docker-compose
|
|
17
17
|
npm run wp-typia:add -- style callout-emphasis --block my-block
|
|
18
18
|
npm run wp-typia:add -- transform quote-to-block --from core/quote --to my-block
|
|
19
|
+
npm run wp-typia:add -- pattern hero-layout
|
|
20
|
+
npm run wp-typia:add -- pattern hero-photo-section --scope section --section-role hero --tags hero,image
|
|
19
21
|
npm run wp-typia:add -- binding-source hero-data
|
|
20
22
|
npm run wp-typia:add -- binding-source hero-data --block my-block --attribute headline
|
|
21
23
|
npm run wp-typia:add -- contract external-retrieve-response --type ExternalRetrieveResponse
|
|
22
24
|
npm run wp-typia:add -- rest-resource external-record --manual --namespace legacy/v1 --route-pattern '/records/(?P<post_id>[\d]+)' --permission-callback legacy_can_read_records --controller-class Legacy\\Records\\Controller
|
|
23
25
|
npm run wp-typia:add -- post-meta integration-state --post-type post --type IntegrationStateMeta
|
|
26
|
+
npm run wp-typia:add -- binding-source integration-state-source --from-post-meta integration-state --meta-path status --block my-block --attribute headline
|
|
24
27
|
npm run wp-typia:add -- editor-plugin review-workflow --slot sidebar
|
|
25
28
|
npm run wp-typia:add -- editor-plugin seo-notes --slot document-setting-panel
|
|
26
29
|
npm run wp-typia:add -- hooked-block my-block --anchor core/post-content --position after
|
|
27
30
|
```
|
|
28
31
|
|
|
32
|
+
Typed block nesting rules live in `BLOCK_NESTING` inside
|
|
33
|
+
`scripts/block-config.ts`. Declare `parent`, `ancestor`, or `allowedBlocks`
|
|
34
|
+
relationships there and `wp-typia sync --check` will validate referenced block
|
|
35
|
+
names in the workspace namespace while allowing external targets like
|
|
36
|
+
`core/group`, then keep the matching `block.json` metadata current.
|
|
37
|
+
Declare default editor `InnerBlocks` templates in `BLOCK_TEMPLATES` and
|
|
38
|
+
`wp-typia sync` will generate `src/inner-blocks-templates.ts` with constants you
|
|
39
|
+
can import from edit components.
|
|
40
|
+
Pattern files listed in `PATTERNS` are parsed during the same sync flow so
|
|
41
|
+
`wp-typia sync --check` can first validate typed catalog metadata such as
|
|
42
|
+
duplicate slugs, `scope`, `sectionRole`, `tags`, `thumbnailUrl`, and
|
|
43
|
+
`contentFile`, then catch serialized block content that violates the declared
|
|
44
|
+
`allowedBlocks`, `parent`, or `ancestor` rules. Unknown or unparseable pattern
|
|
45
|
+
blocks are reported as warnings so the first implementation stays non-mutating.
|
|
46
|
+
The validator reads serialized `<!-- wp:* -->` block comment boundaries
|
|
47
|
+
conservatively and does not execute dynamic PHP content.
|
|
48
|
+
For a complete generic family with a container, section, title, body, and media
|
|
49
|
+
block, see the Nesting Contracts Guide in the hosted docs and the checked
|
|
50
|
+
fixture at `tests/fixtures/nested-block-family.ts`.
|
|
51
|
+
|
|
29
52
|
## CLI binary policy
|
|
30
53
|
|
|
31
54
|
Official workspace projects install `wp-typia` as a local devDependency and
|
package/README.md.mustache
CHANGED
|
@@ -38,11 +38,33 @@ bun run wp-typia:add variation hero-card --block counter-card
|
|
|
38
38
|
bun run wp-typia:add style callout-emphasis --block counter-card
|
|
39
39
|
bun run wp-typia:add transform quote-to-counter --from core/quote --to counter-card
|
|
40
40
|
bun run wp-typia:add pattern hero-layout
|
|
41
|
+
bun run wp-typia:add pattern hero-photo-section --scope section --section-role hero --tags hero,image
|
|
41
42
|
bun run wp-typia:add rest-resource snapshots --namespace {{namespace}}/v1 --methods list,read,create
|
|
42
43
|
bun run wp-typia:add rest-resource external-record --manual --namespace legacy/v1 --route-pattern '/records/(?P<post_id>[\d]+)' --permission-callback legacy_can_read_records --controller-class Legacy\\Records\\Controller
|
|
43
44
|
bun run wp-typia:add post-meta integration-state --post-type post
|
|
45
|
+
bun run wp-typia:add binding-source integration-state-source --from-post-meta integration-state --meta-path status --block counter-card --attribute headline
|
|
44
46
|
```
|
|
45
47
|
|
|
48
|
+
Typed block nesting rules live in `BLOCK_NESTING` inside
|
|
49
|
+
`scripts/block-config.ts`. Declare `parent`, `ancestor`, or `allowedBlocks`
|
|
50
|
+
relationships there and `wp-typia sync --check` will validate referenced block
|
|
51
|
+
names in the workspace namespace while allowing external targets like
|
|
52
|
+
`core/group`, then keep the matching `block.json` metadata current.
|
|
53
|
+
Declare default editor `InnerBlocks` templates in `BLOCK_TEMPLATES` and
|
|
54
|
+
`wp-typia sync` will generate `src/inner-blocks-templates.ts` with constants you
|
|
55
|
+
can import from edit components.
|
|
56
|
+
Pattern files listed in `PATTERNS` are parsed during the same sync flow so
|
|
57
|
+
`wp-typia sync --check` can first validate typed catalog metadata such as
|
|
58
|
+
duplicate slugs, `scope`, `sectionRole`, `tags`, `thumbnailUrl`, and
|
|
59
|
+
`contentFile`, then catch serialized block content that violates the declared
|
|
60
|
+
`allowedBlocks`, `parent`, or `ancestor` rules. Unknown or unparseable pattern
|
|
61
|
+
blocks are reported as warnings so the first implementation stays non-mutating.
|
|
62
|
+
The validator reads serialized `<!-- wp:* -->` block comment boundaries
|
|
63
|
+
conservatively and does not execute dynamic PHP content.
|
|
64
|
+
For a complete generic family with a container, section, title, body, and media
|
|
65
|
+
block, see the Nesting Contracts Guide in the hosted docs and the checked
|
|
66
|
+
fixture at `tests/fixtures/nested-block-family.ts`.
|
|
67
|
+
|
|
46
68
|
## CLI Commands
|
|
47
69
|
|
|
48
70
|
This workspace installs the executable `wp-typia` CLI as a local devDependency
|
package/package.json
CHANGED
package/package.json.mustache
CHANGED
|
@@ -51,13 +51,13 @@
|
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@wordpress/api-fetch": "^7.42.0",
|
|
54
|
-
"@wordpress/block-editor": "
|
|
55
|
-
"@wordpress/blocks": "
|
|
54
|
+
"@wordpress/block-editor": "~15.19.0",
|
|
55
|
+
"@wordpress/blocks": "~15.19.0",
|
|
56
56
|
"@wordpress/components": "^30.2.0",
|
|
57
|
-
"@wordpress/editor": "
|
|
57
|
+
"@wordpress/editor": "~14.46.0",
|
|
58
58
|
"@wordpress/element": "^6.29.0",
|
|
59
59
|
"@wordpress/i18n": "^6.2.0",
|
|
60
60
|
"@wordpress/interactivity": "^6.29.0",
|
|
61
|
-
"@wordpress/plugins": "
|
|
61
|
+
"@wordpress/plugins": "~7.46.0"
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import {
|
|
2
|
+
defineBlockNesting,
|
|
3
|
+
defineInnerBlocksTemplates,
|
|
4
|
+
} from '@wp-typia/block-runtime/metadata-core';
|
|
5
|
+
|
|
1
6
|
export interface WorkspaceBlockConfig {
|
|
2
7
|
slug: string;
|
|
3
8
|
attributeTypeName: string;
|
|
@@ -9,6 +14,14 @@ export interface WorkspaceBlockConfig {
|
|
|
9
14
|
>;
|
|
10
15
|
}
|
|
11
16
|
|
|
17
|
+
export const BLOCK_NESTING = defineBlockNesting( {
|
|
18
|
+
// Add parent, ancestor, and allowedBlocks relationships here.
|
|
19
|
+
} );
|
|
20
|
+
|
|
21
|
+
export const BLOCK_TEMPLATES = defineInnerBlocksTemplates( {
|
|
22
|
+
// Add default InnerBlocks templates here.
|
|
23
|
+
} );
|
|
24
|
+
|
|
12
25
|
export interface WorkspaceVariationConfig {
|
|
13
26
|
block: string;
|
|
14
27
|
file: string;
|
|
@@ -30,14 +43,22 @@ export interface WorkspaceBlockTransformConfig {
|
|
|
30
43
|
}
|
|
31
44
|
|
|
32
45
|
export interface WorkspacePatternConfig {
|
|
33
|
-
|
|
46
|
+
contentFile?: string;
|
|
47
|
+
file?: string;
|
|
48
|
+
scope?: 'full' | 'section';
|
|
49
|
+
sectionRole?: string;
|
|
34
50
|
slug: string;
|
|
51
|
+
tags?: string[];
|
|
52
|
+
thumbnailUrl?: string;
|
|
53
|
+
title?: string;
|
|
35
54
|
}
|
|
36
55
|
|
|
37
56
|
export interface WorkspaceBindingSourceConfig {
|
|
38
57
|
attribute?: string;
|
|
39
58
|
block?: string;
|
|
40
59
|
editorFile: string;
|
|
60
|
+
metaPath?: string;
|
|
61
|
+
postMeta?: string;
|
|
41
62
|
serverFile: string;
|
|
42
63
|
slug: string;
|
|
43
64
|
}
|
|
@@ -1,9 +1,22 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
|
+
import fs from 'node:fs';
|
|
2
3
|
import path from 'node:path';
|
|
3
4
|
|
|
4
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
formatBlockPatternContentNestingDiagnostics,
|
|
7
|
+
validateBlockPatternContentNesting,
|
|
8
|
+
syncInnerBlocksTemplateModule,
|
|
9
|
+
syncBlockMetadata,
|
|
10
|
+
validateBlockNestingContract,
|
|
11
|
+
validateInnerBlocksTemplates,
|
|
12
|
+
} from '@wp-typia/block-runtime/metadata-core';
|
|
13
|
+
import {
|
|
14
|
+
formatPatternCatalogDiagnostics,
|
|
15
|
+
resolvePatternCatalogContentFile,
|
|
16
|
+
validatePatternCatalog,
|
|
17
|
+
} from '@wp-typia/project-tools/pattern-catalog';
|
|
5
18
|
|
|
6
|
-
import { BLOCKS } from './block-config';
|
|
19
|
+
import { BLOCK_NESTING, BLOCK_TEMPLATES, BLOCKS, PATTERNS } from './block-config';
|
|
7
20
|
|
|
8
21
|
function parseCliOptions( argv: string[] ) {
|
|
9
22
|
const options = {
|
|
@@ -22,9 +35,129 @@ function parseCliOptions( argv: string[] ) {
|
|
|
22
35
|
return options;
|
|
23
36
|
}
|
|
24
37
|
|
|
38
|
+
function readWorkspaceBlockName( block: ( typeof BLOCKS )[ number ] ): string {
|
|
39
|
+
const blockJsonFile = path.join( 'src', 'blocks', block.slug, 'block.json' );
|
|
40
|
+
let blockJson: { name?: unknown };
|
|
41
|
+
try {
|
|
42
|
+
blockJson = JSON.parse( fs.readFileSync( blockJsonFile, 'utf8' ) ) as {
|
|
43
|
+
name?: unknown;
|
|
44
|
+
};
|
|
45
|
+
} catch ( error ) {
|
|
46
|
+
throw new Error(
|
|
47
|
+
`Failed to read block.json for block "${ block.slug }" at ${ blockJsonFile }: ${
|
|
48
|
+
error instanceof Error ? error.message : String( error )
|
|
49
|
+
}`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if ( typeof blockJson.name !== 'string' || blockJson.name.trim() === '' ) {
|
|
53
|
+
throw new Error( `${ blockJsonFile } must define a string "name".` );
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return blockJson.name;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function readPatternFileContent( pattern: ( typeof PATTERNS )[ number ] ): string {
|
|
60
|
+
const patternFile = resolvePatternCatalogContentFile( pattern );
|
|
61
|
+
if ( ! patternFile ) {
|
|
62
|
+
throw new Error(
|
|
63
|
+
`Pattern "${ pattern.slug }" must declare contentFile or file in scripts/block-config.ts.`
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
try {
|
|
67
|
+
return fs.readFileSync( patternFile, 'utf8' );
|
|
68
|
+
} catch ( error ) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`Failed to read pattern "${ pattern.slug }" at ${ patternFile }: ${
|
|
71
|
+
error instanceof Error ? error.message : String( error )
|
|
72
|
+
}`
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function validatePatternCatalogMetadata() {
|
|
78
|
+
const result = validatePatternCatalog( PATTERNS, {
|
|
79
|
+
projectDir: process.cwd(),
|
|
80
|
+
} );
|
|
81
|
+
|
|
82
|
+
if ( result.warnings.length > 0 ) {
|
|
83
|
+
console.warn(
|
|
84
|
+
`⚠️ Pattern catalog validation warnings:\n${ formatPatternCatalogDiagnostics(
|
|
85
|
+
result.warnings
|
|
86
|
+
) }`
|
|
87
|
+
);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if ( result.errors.length > 0 ) {
|
|
91
|
+
throw new Error(
|
|
92
|
+
`Pattern catalog metadata is invalid:\n${ formatPatternCatalogDiagnostics(
|
|
93
|
+
result.errors
|
|
94
|
+
) }`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function validatePatternContentNesting( knownBlockNames: readonly string[] ) {
|
|
100
|
+
const diagnostics = PATTERNS.flatMap( ( pattern ) => {
|
|
101
|
+
const content = readPatternFileContent( pattern );
|
|
102
|
+
return validateBlockPatternContentNesting( content, {
|
|
103
|
+
allowExternalBlockNames: true,
|
|
104
|
+
knownBlockNames,
|
|
105
|
+
nesting: BLOCK_NESTING,
|
|
106
|
+
patternFile: resolvePatternCatalogContentFile( pattern ),
|
|
107
|
+
} ).diagnostics;
|
|
108
|
+
} );
|
|
109
|
+
const warnings = diagnostics.filter(
|
|
110
|
+
( diagnostic ) => diagnostic.severity === 'warning'
|
|
111
|
+
);
|
|
112
|
+
const errors = diagnostics.filter(
|
|
113
|
+
( diagnostic ) => diagnostic.severity === 'error'
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
if ( warnings.length > 0 ) {
|
|
117
|
+
console.warn(
|
|
118
|
+
`⚠️ Pattern nesting validation warnings:\n${ formatBlockPatternContentNestingDiagnostics(
|
|
119
|
+
warnings
|
|
120
|
+
) }`
|
|
121
|
+
);
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
if ( errors.length > 0 ) {
|
|
125
|
+
throw new Error(
|
|
126
|
+
`Pattern content violates block nesting contract:\n${ formatBlockPatternContentNestingDiagnostics(
|
|
127
|
+
errors
|
|
128
|
+
) }`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
25
133
|
async function main() {
|
|
26
134
|
const options = parseCliOptions( process.argv.slice( 2 ) );
|
|
27
135
|
|
|
136
|
+
const knownBlockNames = BLOCKS.map( readWorkspaceBlockName );
|
|
137
|
+
validateBlockNestingContract( BLOCK_NESTING, {
|
|
138
|
+
allowExternalBlockNames: true,
|
|
139
|
+
knownBlockNames,
|
|
140
|
+
} );
|
|
141
|
+
validateInnerBlocksTemplates( BLOCK_TEMPLATES, {
|
|
142
|
+
allowExternalBlockNames: true,
|
|
143
|
+
knownBlockNames,
|
|
144
|
+
nesting: BLOCK_NESTING,
|
|
145
|
+
} );
|
|
146
|
+
validatePatternCatalogMetadata();
|
|
147
|
+
validatePatternContentNesting( knownBlockNames );
|
|
148
|
+
await syncInnerBlocksTemplateModule(
|
|
149
|
+
{
|
|
150
|
+
allowExternalBlockNames: true,
|
|
151
|
+
knownBlockNames,
|
|
152
|
+
nesting: BLOCK_NESTING,
|
|
153
|
+
outputFile: path.join( 'src', 'inner-blocks-templates.ts' ),
|
|
154
|
+
templates: BLOCK_TEMPLATES,
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
check: options.check,
|
|
158
|
+
}
|
|
159
|
+
);
|
|
160
|
+
|
|
28
161
|
if ( BLOCKS.length === 0 ) {
|
|
29
162
|
console.log(
|
|
30
163
|
options.check
|
|
@@ -38,9 +171,12 @@ async function main() {
|
|
|
38
171
|
const baseDir = path.join( 'src', 'blocks', block.slug );
|
|
39
172
|
const result = await syncBlockMetadata(
|
|
40
173
|
{
|
|
174
|
+
allowExternalBlockNames: true,
|
|
41
175
|
blockJsonFile: path.join( baseDir, 'block.json' ),
|
|
42
176
|
jsonSchemaFile: path.join( baseDir, 'typia.schema.json' ),
|
|
177
|
+
knownBlockNames,
|
|
43
178
|
manifestFile: path.join( baseDir, 'typia.manifest.json' ),
|
|
179
|
+
nesting: BLOCK_NESTING,
|
|
44
180
|
openApiFile: path.join( baseDir, 'typia.openapi.json' ),
|
|
45
181
|
sourceTypeName: block.attributeTypeName,
|
|
46
182
|
typesFile: block.typesFile,
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* This file is generated by wp-typia. Do not edit manually. */
|
|
2
|
+
|
|
3
|
+
export type WpTypiaInnerBlocksTemplateAttributes = Record<string, unknown>;
|
|
4
|
+
export type WpTypiaInnerBlocksTemplateItem = [
|
|
5
|
+
blockName: string,
|
|
6
|
+
attributes?: WpTypiaInnerBlocksTemplateAttributes,
|
|
7
|
+
innerBlocks?: WpTypiaInnerBlocksTemplate,
|
|
8
|
+
];
|
|
9
|
+
export type WpTypiaInnerBlocksTemplate = WpTypiaInnerBlocksTemplateItem[];
|
|
10
|
+
|
|
11
|
+
export const INNER_BLOCKS_TEMPLATES = {} satisfies Record<string, WpTypiaInnerBlocksTemplate>;
|
|
12
|
+
|
|
13
|
+
export type WpTypiaInnerBlocksTemplateName = keyof typeof INNER_BLOCKS_TEMPLATES;
|
|
@@ -177,7 +177,11 @@ function {{phpPrefix}}_register_pattern_category() {
|
|
|
177
177
|
}
|
|
178
178
|
|
|
179
179
|
function {{phpPrefix}}_register_patterns() {
|
|
180
|
-
|
|
180
|
+
$pattern_modules = array_merge(
|
|
181
|
+
glob( __DIR__ . '/src/patterns/*.php' ) ?: array(),
|
|
182
|
+
glob( __DIR__ . '/src/patterns/*/*.php' ) ?: array()
|
|
183
|
+
);
|
|
184
|
+
foreach ( $pattern_modules as $pattern_module ) {
|
|
181
185
|
require $pattern_module;
|
|
182
186
|
}
|
|
183
187
|
}
|