@wp-typia/project-tools 0.16.14 → 0.18.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.
- package/dist/runtime/block-generator-service-core.d.ts +1 -1
- package/dist/runtime/block-generator-service-core.js +2 -1
- package/dist/runtime/block-generator-service-spec.d.ts +8 -1
- package/dist/runtime/block-generator-service-spec.js +27 -0
- package/dist/runtime/built-in-block-artifacts.js +1 -0
- package/dist/runtime/built-in-block-code-artifacts.js +14 -1
- package/dist/runtime/built-in-block-code-templates/compound-child.d.ts +2 -2
- package/dist/runtime/built-in-block-code-templates/compound-child.js +30 -2
- package/dist/runtime/built-in-block-code-templates/compound-parent.d.ts +1 -1
- package/dist/runtime/built-in-block-code-templates/compound-parent.js +139 -19
- package/dist/runtime/built-in-block-code-templates/query-loop.d.ts +1 -0
- package/dist/runtime/built-in-block-code-templates/query-loop.js +70 -0
- package/dist/runtime/built-in-block-code-templates.d.ts +1 -0
- package/dist/runtime/built-in-block-code-templates.js +1 -0
- package/dist/runtime/built-in-block-non-ts-artifacts.js +2 -0
- package/dist/runtime/cli-add-block.d.ts +2 -1
- package/dist/runtime/cli-add-block.js +19 -1
- package/dist/runtime/cli-add-shared.d.ts +55 -1
- package/dist/runtime/cli-add-shared.js +101 -2
- package/dist/runtime/cli-add-workspace-assets.d.ts +21 -1
- package/dist/runtime/cli-add-workspace-assets.js +417 -1
- package/dist/runtime/cli-add-workspace-rest.d.ts +14 -0
- package/dist/runtime/cli-add-workspace-rest.js +1060 -0
- package/dist/runtime/cli-add-workspace.d.ts +10 -1
- package/dist/runtime/cli-add-workspace.js +10 -1
- package/dist/runtime/cli-add.d.ts +3 -3
- package/dist/runtime/cli-add.js +2 -2
- package/dist/runtime/cli-core.d.ts +3 -1
- package/dist/runtime/cli-core.js +2 -1
- package/dist/runtime/cli-doctor-workspace.js +135 -1
- package/dist/runtime/cli-help.js +10 -5
- package/dist/runtime/cli-scaffold.d.ts +11 -2
- package/dist/runtime/cli-scaffold.js +137 -36
- package/dist/runtime/cli-templates.d.ts +4 -4
- package/dist/runtime/cli-templates.js +79 -39
- package/dist/runtime/index.d.ts +4 -3
- package/dist/runtime/index.js +3 -2
- package/dist/runtime/local-dev-presets.js +27 -12
- package/dist/runtime/rest-resource-artifacts.d.ts +35 -0
- package/dist/runtime/rest-resource-artifacts.js +158 -0
- package/dist/runtime/scaffold-answer-resolution.d.ts +1 -1
- package/dist/runtime/scaffold-answer-resolution.js +94 -3
- package/dist/runtime/scaffold-apply-utils.d.ts +4 -3
- package/dist/runtime/scaffold-apply-utils.js +34 -17
- package/dist/runtime/scaffold-bootstrap.d.ts +15 -0
- package/dist/runtime/scaffold-bootstrap.js +29 -7
- package/dist/runtime/scaffold-documents.js +9 -9
- package/dist/runtime/scaffold-onboarding.js +17 -1
- package/dist/runtime/scaffold-package-manager-files.js +6 -1
- package/dist/runtime/scaffold-template-variables.js +6 -0
- package/dist/runtime/scaffold.d.ts +15 -1
- package/dist/runtime/scaffold.js +50 -8
- package/dist/runtime/template-defaults.d.ts +7 -0
- package/dist/runtime/template-defaults.js +4 -0
- package/dist/runtime/template-registry.d.ts +1 -1
- package/dist/runtime/template-registry.js +14 -1
- package/dist/runtime/template-render.d.ts +5 -2
- package/dist/runtime/template-render.js +9 -3
- package/dist/runtime/template-source-contracts.d.ts +11 -0
- package/dist/runtime/template-source-external.d.ts +1 -1
- package/dist/runtime/template-source-external.js +45 -13
- package/dist/runtime/template-source-normalization.d.ts +1 -1
- package/dist/runtime/template-source-normalization.js +5 -1
- package/dist/runtime/template-source-remote.d.ts +5 -0
- package/dist/runtime/template-source-remote.js +33 -0
- package/dist/runtime/template-source.js +30 -1
- package/dist/runtime/workspace-inventory.d.ts +43 -1
- package/dist/runtime/workspace-inventory.js +132 -1
- package/dist/runtime/workspace-project.d.ts +1 -1
- package/dist/runtime/workspace-project.js +2 -2
- package/package.json +3 -3
- package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +428 -49
- package/templates/query-loop/inc/query-runtime.php.mustache +85 -0
- package/templates/query-loop/package.json.mustache +32 -0
- package/templates/query-loop/src/patterns/grid.php.mustache +49 -0
- package/templates/query-loop/src/patterns/list.php.mustache +48 -0
- package/templates/query-loop/src/query-extension.ts.mustache +41 -0
- package/templates/query-loop/webpack.config.js.mustache +16 -0
- package/templates/query-loop/{{slugKebabCase}}.php.mustache +84 -0
|
@@ -4,5 +4,5 @@ export declare class BlockGeneratorService {
|
|
|
4
4
|
plan({ allowExistingDir, answers, cwd, dataStorageMode, externalLayerId, externalLayerSource, externalLayerSourceLabel, noInstall, packageManager, persistencePolicy, projectDir, repositoryReference, templateId, variant, withMigrationUi, withTestPreset, withWpEnv, }: PlanBlockInput): Promise<PlanBlockResult>;
|
|
5
5
|
validate({ plan }: ValidateBlockInput): Promise<ValidateBlockResult>;
|
|
6
6
|
render({ validated }: RenderBlockInput): Promise<RenderBlockResult>;
|
|
7
|
-
apply({ rendered, installDependencies, }: ApplyBlockInput): Promise<ScaffoldProjectResult>;
|
|
7
|
+
apply({ rendered, installDependencies, onProgress, }: ApplyBlockInput): Promise<ScaffoldProjectResult>;
|
|
8
8
|
}
|
|
@@ -222,7 +222,7 @@ export class BlockGeneratorService {
|
|
|
222
222
|
});
|
|
223
223
|
return rendered;
|
|
224
224
|
}
|
|
225
|
-
async apply({ rendered, installDependencies, }) {
|
|
225
|
+
async apply({ rendered, installDependencies, onProgress, }) {
|
|
226
226
|
const cachedArtifacts = renderedArtifactCache.get(rendered);
|
|
227
227
|
const currentVariablesFingerprint = createVariablesFingerprint(rendered.variables);
|
|
228
228
|
const artifacts = cachedArtifacts &&
|
|
@@ -246,6 +246,7 @@ export class BlockGeneratorService {
|
|
|
246
246
|
codeArtifacts,
|
|
247
247
|
installDependencies,
|
|
248
248
|
noInstall: rendered.target.noInstall,
|
|
249
|
+
onProgress,
|
|
249
250
|
packageManager: rendered.target.packageManager,
|
|
250
251
|
projectDir: rendered.target.projectDir,
|
|
251
252
|
repositoryReference: rendered.target.repositoryReference,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PackageManagerId } from "./package-managers.js";
|
|
2
2
|
import { type BuiltInTemplateId } from "./template-registry.js";
|
|
3
3
|
import type { InstallDependenciesOptions } from "./scaffold-apply-utils.js";
|
|
4
|
-
import type { DataStorageMode, PersistencePolicy, ScaffoldAnswers, ScaffoldTemplateVariables } from "./scaffold.js";
|
|
4
|
+
import type { DataStorageMode, PersistencePolicy, ScaffoldAnswers, ScaffoldProgressEvent, ScaffoldTemplateVariables } from "./scaffold.js";
|
|
5
5
|
export interface BlockSpec {
|
|
6
6
|
block: {
|
|
7
7
|
namespace: string;
|
|
@@ -27,6 +27,11 @@ export interface BlockSpec {
|
|
|
27
27
|
project: {
|
|
28
28
|
author: string;
|
|
29
29
|
};
|
|
30
|
+
queryLoop: {
|
|
31
|
+
allowedControls: readonly string[];
|
|
32
|
+
enabled: boolean;
|
|
33
|
+
postType: string;
|
|
34
|
+
};
|
|
30
35
|
runtime: {
|
|
31
36
|
withMigrationUi: boolean;
|
|
32
37
|
withTestPreset: boolean;
|
|
@@ -66,6 +71,7 @@ export interface PlanBlockInput {
|
|
|
66
71
|
templateId: BuiltInTemplateId;
|
|
67
72
|
variant?: string;
|
|
68
73
|
withMigrationUi?: boolean;
|
|
74
|
+
queryPostType?: string;
|
|
69
75
|
withTestPreset?: boolean;
|
|
70
76
|
withWpEnv?: boolean;
|
|
71
77
|
}
|
|
@@ -99,6 +105,7 @@ export interface RenderBlockResult extends ValidateBlockResult {
|
|
|
99
105
|
export interface ApplyBlockInput {
|
|
100
106
|
rendered: RenderBlockResult;
|
|
101
107
|
installDependencies?: ((options: InstallDependenciesOptions) => Promise<void>) | undefined;
|
|
108
|
+
onProgress?: ((event: ScaffoldProgressEvent) => void | Promise<void>) | undefined;
|
|
102
109
|
}
|
|
103
110
|
export declare function createBuiltInBlockSpec({ answers, dataStorageMode, persistencePolicy, templateId, withMigrationUi, withTestPreset, withWpEnv, }: Omit<PlanBlockInput, "allowExistingDir" | "cwd" | "noInstall" | "packageManager" | "projectDir" | "variant">): BlockSpec;
|
|
104
111
|
export declare function buildTemplateVariablesFromBlockSpec(spec: BlockSpec): ScaffoldTemplateVariables;
|
|
@@ -24,6 +24,15 @@ function getBuiltInPersistenceSpec({ templateId, dataStorageMode, persistencePol
|
|
|
24
24
|
enabled: false,
|
|
25
25
|
};
|
|
26
26
|
}
|
|
27
|
+
const DEFAULT_QUERY_LOOP_ALLOWED_CONTROLS = [
|
|
28
|
+
"inherit",
|
|
29
|
+
"postType",
|
|
30
|
+
"order",
|
|
31
|
+
"sticky",
|
|
32
|
+
"taxQuery",
|
|
33
|
+
"author",
|
|
34
|
+
"search",
|
|
35
|
+
];
|
|
27
36
|
export function createBuiltInBlockSpec({ answers, dataStorageMode, persistencePolicy, templateId, withMigrationUi = false, withTestPreset = false, withWpEnv = false, }) {
|
|
28
37
|
const template = getTemplateById(templateId);
|
|
29
38
|
const metadataDefaults = getBuiltInTemplateMetadataDefaults(templateId);
|
|
@@ -52,6 +61,17 @@ export function createBuiltInBlockSpec({ answers, dataStorageMode, persistencePo
|
|
|
52
61
|
project: {
|
|
53
62
|
author: answers.author.trim(),
|
|
54
63
|
},
|
|
64
|
+
queryLoop: templateId === "query-loop"
|
|
65
|
+
? {
|
|
66
|
+
allowedControls: DEFAULT_QUERY_LOOP_ALLOWED_CONTROLS,
|
|
67
|
+
enabled: true,
|
|
68
|
+
postType: (answers.queryPostType ?? "post").trim() || "post",
|
|
69
|
+
}
|
|
70
|
+
: {
|
|
71
|
+
allowedControls: [],
|
|
72
|
+
enabled: false,
|
|
73
|
+
postType: "post",
|
|
74
|
+
},
|
|
55
75
|
runtime: {
|
|
56
76
|
withMigrationUi,
|
|
57
77
|
withTestPreset,
|
|
@@ -82,6 +102,7 @@ export function buildTemplateVariablesFromBlockSpec(spec) {
|
|
|
82
102
|
const persistencePolicy = persistenceEnabled
|
|
83
103
|
? spec.persistence.persistencePolicy
|
|
84
104
|
: "authenticated";
|
|
105
|
+
const queryVariationNamespace = `${namespace}/${slug}`;
|
|
85
106
|
return {
|
|
86
107
|
apiClientPackageVersion,
|
|
87
108
|
author: spec.project.author,
|
|
@@ -101,7 +122,13 @@ export function buildTemplateVariablesFromBlockSpec(spec) {
|
|
|
101
122
|
dashCase: slug,
|
|
102
123
|
dataStorageMode,
|
|
103
124
|
description: spec.metadata.description,
|
|
125
|
+
descriptionJson: JSON.stringify(spec.metadata.description),
|
|
104
126
|
frontendCssClassName: buildFrontendCssClassName(cssClassName),
|
|
127
|
+
queryAllowedControlsJson: JSON.stringify(spec.queryLoop.enabled ? spec.queryLoop.allowedControls : [], null, 2),
|
|
128
|
+
queryPostType: spec.queryLoop.enabled ? spec.queryLoop.postType : "post",
|
|
129
|
+
queryPostTypeJson: JSON.stringify(spec.queryLoop.enabled ? spec.queryLoop.postType : "post"),
|
|
130
|
+
queryVariationNamespace,
|
|
131
|
+
queryVariationNamespaceJson: JSON.stringify(queryVariationNamespace),
|
|
105
132
|
isAuthenticatedPersistencePolicy: persistencePolicy === "authenticated" ? "true" : "false",
|
|
106
133
|
isPublicPersistencePolicy: persistencePolicy === "public" ? "true" : "false",
|
|
107
134
|
bootstrapCredentialDeclarations: persistencePolicy === "public"
|
|
@@ -115,6 +115,7 @@ function buildCompoundParentArtifact(variables) {
|
|
|
115
115
|
icon: variables.icon,
|
|
116
116
|
description: variables.description,
|
|
117
117
|
example: {},
|
|
118
|
+
allowedBlocks: [`${variables.namespace}/${variables.slugKebabCase}-item`],
|
|
118
119
|
supports: persistenceEnabled
|
|
119
120
|
? {
|
|
120
121
|
html: false,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { buildBuiltInNonTsArtifacts } from "./built-in-block-non-ts-artifacts.js";
|
|
2
|
-
import { BASIC_EDIT_TEMPLATE, BASIC_INDEX_TEMPLATE, BASIC_SAVE_TEMPLATE, BASIC_VALIDATORS_TEMPLATE, BLOCK_METADATA_WRAPPER_TEMPLATE, COMPOUND_CHILD_EDIT_TEMPLATE, COMPOUND_CHILD_INDEX_TEMPLATE, COMPOUND_CHILD_SAVE_TEMPLATE, COMPOUND_CHILD_VALIDATORS_TEMPLATE, COMPOUND_CHILDREN_TEMPLATE, COMPOUND_LOCAL_HOOKS_TEMPLATE, COMPOUND_PARENT_EDIT_TEMPLATE, COMPOUND_PARENT_INDEX_TEMPLATE, COMPOUND_PARENT_SAVE_TEMPLATE, COMPOUND_PARENT_VALIDATORS_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_EDIT_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_INTERACTIVITY_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_SAVE_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_VALIDATORS_TEMPLATE, INTERACTIVITY_EDIT_TEMPLATE, INTERACTIVITY_INDEX_TEMPLATE, INTERACTIVITY_SAVE_TEMPLATE, INTERACTIVITY_SCRIPT_TEMPLATE, INTERACTIVITY_VALIDATORS_TEMPLATE, MANIFEST_DEFAULTS_DOCUMENT_WRAPPER_TEMPLATE, MANIFEST_DOCUMENT_WRAPPER_TEMPLATE, PERSISTENCE_EDIT_TEMPLATE, PERSISTENCE_INDEX_TEMPLATE, PERSISTENCE_INTERACTIVITY_TEMPLATE, PERSISTENCE_SAVE_TEMPLATE, PERSISTENCE_VALIDATORS_TEMPLATE, SHARED_HOOKS_TEMPLATE, } from "./built-in-block-code-templates.js";
|
|
2
|
+
import { BASIC_EDIT_TEMPLATE, BASIC_INDEX_TEMPLATE, BASIC_SAVE_TEMPLATE, BASIC_VALIDATORS_TEMPLATE, BLOCK_METADATA_WRAPPER_TEMPLATE, COMPOUND_CHILD_EDIT_TEMPLATE, COMPOUND_CHILD_INDEX_TEMPLATE, COMPOUND_CHILD_SAVE_TEMPLATE, COMPOUND_CHILD_VALIDATORS_TEMPLATE, COMPOUND_CHILDREN_TEMPLATE, COMPOUND_LOCAL_HOOKS_TEMPLATE, COMPOUND_PARENT_EDIT_TEMPLATE, COMPOUND_PARENT_INDEX_TEMPLATE, COMPOUND_PARENT_SAVE_TEMPLATE, COMPOUND_PARENT_VALIDATORS_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_EDIT_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_INTERACTIVITY_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_SAVE_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_VALIDATORS_TEMPLATE, INTERACTIVITY_EDIT_TEMPLATE, INTERACTIVITY_INDEX_TEMPLATE, INTERACTIVITY_SAVE_TEMPLATE, INTERACTIVITY_SCRIPT_TEMPLATE, INTERACTIVITY_VALIDATORS_TEMPLATE, MANIFEST_DEFAULTS_DOCUMENT_WRAPPER_TEMPLATE, MANIFEST_DOCUMENT_WRAPPER_TEMPLATE, PERSISTENCE_EDIT_TEMPLATE, PERSISTENCE_INDEX_TEMPLATE, PERSISTENCE_INTERACTIVITY_TEMPLATE, PERSISTENCE_SAVE_TEMPLATE, PERSISTENCE_VALIDATORS_TEMPLATE, QUERY_LOOP_INDEX_TEMPLATE, SHARED_HOOKS_TEMPLATE, } from "./built-in-block-code-templates.js";
|
|
3
3
|
import { renderMustacheTemplateString } from "./template-render.js";
|
|
4
4
|
function renderCodeTemplate(template, variables) {
|
|
5
5
|
const rendered = renderMustacheTemplateString(template, variables);
|
|
@@ -162,6 +162,17 @@ function buildPersistenceCodeArtifacts(variables) {
|
|
|
162
162
|
...buildBuiltInNonTsArtifacts({ templateId: "persistence", variables }),
|
|
163
163
|
]);
|
|
164
164
|
}
|
|
165
|
+
function buildQueryLoopCodeArtifacts(variables) {
|
|
166
|
+
return ensureUniqueArtifactPaths([
|
|
167
|
+
...createCodeArtifacts([
|
|
168
|
+
{
|
|
169
|
+
relativePath: "src/index.ts",
|
|
170
|
+
template: QUERY_LOOP_INDEX_TEMPLATE,
|
|
171
|
+
},
|
|
172
|
+
], variables),
|
|
173
|
+
...buildBuiltInNonTsArtifacts({ templateId: "query-loop", variables }),
|
|
174
|
+
]);
|
|
175
|
+
}
|
|
165
176
|
/**
|
|
166
177
|
* Build the emitter-owned scaffold files for a built-in template family.
|
|
167
178
|
*
|
|
@@ -179,6 +190,8 @@ export function buildBuiltInCodeArtifacts({ templateId, variables, }) {
|
|
|
179
190
|
return buildPersistenceCodeArtifacts(variables);
|
|
180
191
|
case "compound":
|
|
181
192
|
return buildCompoundCodeArtifacts(variables);
|
|
193
|
+
case "query-loop":
|
|
194
|
+
return buildQueryLoopCodeArtifacts(variables);
|
|
182
195
|
default: {
|
|
183
196
|
const unhandledTemplateId = templateId;
|
|
184
197
|
throw new Error(`Unhandled built-in template id: ${unhandledTemplateId}`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const COMPOUND_CHILD_EDIT_TEMPLATE = "import type { BlockEditProps } from '@wp-typia/block-types/blocks/registration';\nimport { RichText, useBlockProps } from '@wordpress/block-editor';\nimport { Notice } from '@wordpress/components';\nimport { __ } from '@wordpress/i18n';\n\nimport { useTypiaValidation } from './hooks';\nimport type { {{pascalCase}}ItemAttributes } from './types';\nimport {\n\tcreateAttributeUpdater,\n\tvalidate{{pascalCase}}ItemAttributes,\n} from './validators';\n\ntype EditProps = BlockEditProps< {{pascalCase}}ItemAttributes >;\n\nexport default function Edit( {\n\tattributes,\n\tsetAttributes,\n}: EditProps ) {\n\tconst updateAttribute = createAttributeUpdater( attributes, setAttributes );\n\tconst { errorMessages, isValid } = useTypiaValidation(\n\t\tattributes,\n\t\tvalidate{{pascalCase}}ItemAttributes\n\t);\n\n\treturn (\n\t\t<div { ...useBlockProps( { className: '{{compoundChildCssClassName}}' } ) }>\n\t\t\t<RichText\n\t\t\t\ttagName=\"h4\"\n\t\t\t\tclassName=\"{{compoundChildCssClassName}}__title\"\n\t\t\t\tvalue={ attributes.title ?? '' }\n\t\t\t\tonChange={ ( title ) => updateAttribute( 'title', title ) }\n\t\t\t\tplaceholder={ __( {{compoundChildTitleJson}}, '{{textDomain}}' ) }\n\t\t\t/>\n\t\t\t<RichText\n\t\t\t\ttagName=\"p\"\n\t\t\t\tclassName=\"{{compoundChildCssClassName}}__body\"\n\t\t\t\tvalue={ attributes.body ?? '' }\n\t\t\t\tonChange={ ( body ) => updateAttribute( 'body', body ) }\n\t\t\t\tplaceholder={ __( 'Add supporting details for this internal item.', '{{textDomain}}' ) }\n\t\t\t/>\n\t\t\t{ ! isValid && (\n\t\t\t\t<Notice status=\"error\" isDismissible={ false }>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t{ errorMessages.map( ( error, index ) => <li key={ index }>{ error }</li> ) }\n\t\t\t\t\t</ul>\n\t\t\t\t</Notice>\n\t\t\t) }\n\t\t</div>\n\t);\n}\n";
|
|
2
|
-
export declare const COMPOUND_CHILD_SAVE_TEMPLATE = "import { RichText, useBlockProps } from '@wordpress/block-editor';\n\nimport type { {{pascalCase}}ItemAttributes } from './types';\n\nexport default function Save( {\n\tattributes,\n}: {\n\tattributes: {{pascalCase}}ItemAttributes;\n} ) {\n\treturn (\n\t\t<div { ...useBlockProps.save( { className: '{{compoundChildCssClassName}}' } ) }>\n\t\t\t<RichText.Content\n\t\t\t\ttagName=\"h4\"\n\t\t\t\tclassName=\"{{compoundChildCssClassName}}__title\"\n\t\t\t\tvalue={ attributes.title }\n\t\t\t/>\n\t\t\t<RichText.Content\n\t\t\t\ttagName=\"p\"\n\t\t\t\tclassName=\"{{compoundChildCssClassName}}__body\"\n\t\t\t\tvalue={ attributes.body }\n\t\t\t/>\n\t\t</div>\n\t);\n}\n";
|
|
1
|
+
export declare const COMPOUND_CHILD_EDIT_TEMPLATE = "import type { BlockEditProps } from '@wp-typia/block-types/blocks/registration';\nimport { InnerBlocks, RichText, useBlockProps } from '@wordpress/block-editor';\nimport { Notice } from '@wordpress/components';\nimport { __ } from '@wordpress/i18n';\n\nimport metadata from './block-metadata';\nimport {\n\tgetChildAllowedBlocks,\n\tgetChildTemplate,\n\thasNestedChildBlocks,\n} from '../{{slugKebabCase}}/children';\nimport { useTypiaValidation } from './hooks';\nimport type { {{pascalCase}}ItemAttributes } from './types';\nimport {\n\tcreateAttributeUpdater,\n\tvalidate{{pascalCase}}ItemAttributes,\n} from './validators';\n\ntype EditProps = BlockEditProps< {{pascalCase}}ItemAttributes >;\n\nexport default function Edit( {\n\tattributes,\n\tsetAttributes,\n}: EditProps ) {\n\tconst updateAttribute = createAttributeUpdater( attributes, setAttributes );\n\tconst { errorMessages, isValid } = useTypiaValidation(\n\t\tattributes,\n\t\tvalidate{{pascalCase}}ItemAttributes\n\t);\n\tconst nestedAllowedBlocks = getChildAllowedBlocks( metadata.name );\n\tconst nestedTemplate = getChildTemplate( metadata.name );\n\tconst showsNestedChildren = hasNestedChildBlocks( metadata.name );\n\n\treturn (\n\t\t<div { ...useBlockProps( { className: '{{compoundChildCssClassName}}' } ) }>\n\t\t\t<RichText\n\t\t\t\ttagName=\"h4\"\n\t\t\t\tclassName=\"{{compoundChildCssClassName}}__title\"\n\t\t\t\tvalue={ attributes.title ?? '' }\n\t\t\t\tonChange={ ( title ) => updateAttribute( 'title', title ) }\n\t\t\t\tplaceholder={ __( {{compoundChildTitleJson}}, '{{textDomain}}' ) }\n\t\t\t/>\n\t\t\t<RichText\n\t\t\t\ttagName=\"p\"\n\t\t\t\tclassName=\"{{compoundChildCssClassName}}__body\"\n\t\t\t\tvalue={ attributes.body ?? '' }\n\t\t\t\tonChange={ ( body ) => updateAttribute( 'body', body ) }\n\t\t\t\tplaceholder={ __( 'Add supporting details for this internal item.', '{{textDomain}}' ) }\n\t\t\t/>\n\t\t\t{ ! isValid && (\n\t\t\t\t<Notice status=\"error\" isDismissible={ false }>\n\t\t\t\t\t<ul>\n\t\t\t\t\t\t{ errorMessages.map( ( error, index ) => <li key={ index }>{ error }</li> ) }\n\t\t\t\t\t</ul>\n\t\t\t\t</Notice>\n\t\t\t) }\n\t\t\t{ showsNestedChildren && (\n\t\t\t\t<div className=\"{{compoundChildCssClassName}}__children\">\n\t\t\t\t\t<InnerBlocks\n\t\t\t\t\t\tallowedBlocks={ nestedAllowedBlocks }\n\t\t\t\t\t\trenderAppender={ InnerBlocks.ButtonBlockAppender }\n\t\t\t\t\t\ttemplate={ nestedTemplate }\n\t\t\t\t\t\ttemplateLock={ false }\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t) }\n\t\t</div>\n\t);\n}\n";
|
|
2
|
+
export declare const COMPOUND_CHILD_SAVE_TEMPLATE = "import { InnerBlocks, RichText, useBlockProps } from '@wordpress/block-editor';\n\nimport metadata from './block-metadata';\nimport { hasNestedChildBlocks } from '../{{slugKebabCase}}/children';\nimport type { {{pascalCase}}ItemAttributes } from './types';\n\nexport default function Save( {\n\tattributes,\n}: {\n\tattributes: {{pascalCase}}ItemAttributes;\n} ) {\n\tconst showsNestedChildren = hasNestedChildBlocks( metadata.name );\n\n\treturn (\n\t\t<div { ...useBlockProps.save( { className: '{{compoundChildCssClassName}}' } ) }>\n\t\t\t<RichText.Content\n\t\t\t\ttagName=\"h4\"\n\t\t\t\tclassName=\"{{compoundChildCssClassName}}__title\"\n\t\t\t\tvalue={ attributes.title }\n\t\t\t/>\n\t\t\t<RichText.Content\n\t\t\t\ttagName=\"p\"\n\t\t\t\tclassName=\"{{compoundChildCssClassName}}__body\"\n\t\t\t\tvalue={ attributes.body }\n\t\t\t/>\n\t\t\t{ showsNestedChildren && (\n\t\t\t\t<div className=\"{{compoundChildCssClassName}}__children\">\n\t\t\t\t\t<InnerBlocks.Content />\n\t\t\t\t</div>\n\t\t\t) }\n\t\t</div>\n\t);\n}\n";
|
|
3
3
|
export declare const COMPOUND_CHILD_INDEX_TEMPLATE = "import {\n\tregisterScaffoldBlockType,\n\ttype BlockConfiguration,\n} from '@wp-typia/block-types/blocks/registration';\nimport {\n\tbuildScaffoldBlockRegistration,\n\tparseScaffoldBlockMetadata,\n} from '@wp-typia/block-runtime/blocks';\n\nimport Edit from './edit';\nimport Save from './save';\nimport metadata from './block-metadata';\nimport '../{{slugKebabCase}}/style.scss';\n\nimport type { {{pascalCase}}ItemAttributes } from './types';\n\nconst registration = buildScaffoldBlockRegistration(\n\tparseScaffoldBlockMetadata<BlockConfiguration< {{pascalCase}}ItemAttributes >>( metadata ),\n\t{\n\t\tedit: Edit,\n\t\tsave: Save,\n\t}\n);\n\nregisterScaffoldBlockType(registration.name, registration.settings);\n";
|
|
4
4
|
export declare const COMPOUND_CHILD_VALIDATORS_TEMPLATE = "import typia from 'typia';\nimport currentManifest from './manifest-defaults-document';\nimport type {\n\t{{pascalCase}}ItemAttributes,\n\t{{pascalCase}}ItemValidationResult,\n} from './types';\nimport { createTemplateValidatorToolkit } from '../../validator-toolkit';\n\nconst scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}ItemAttributes >( {\n\tassert: typia.createAssert< {{pascalCase}}ItemAttributes >(),\n\tclone: typia.misc.createClone< {{pascalCase}}ItemAttributes >() as (\n\t\tvalue: {{pascalCase}}ItemAttributes,\n\t) => {{pascalCase}}ItemAttributes,\n\tis: typia.createIs< {{pascalCase}}ItemAttributes >(),\n\tmanifest: currentManifest,\n\tprune: typia.misc.createPrune< {{pascalCase}}ItemAttributes >(),\n\trandom: typia.createRandom< {{pascalCase}}ItemAttributes >() as (\n\t\t...args: unknown[]\n\t) => {{pascalCase}}ItemAttributes,\n\tvalidate: typia.createValidate< {{pascalCase}}ItemAttributes >(),\n} );\n\nexport const validate{{pascalCase}}ItemAttributes =\n\tscaffoldValidators.validateAttributes as (\n\t\tattributes: unknown\n\t) => {{pascalCase}}ItemValidationResult;\n\nexport const validators = scaffoldValidators.validators;\n\nexport const sanitize{{pascalCase}}ItemAttributes =\n\tscaffoldValidators.sanitizeAttributes as (\n\t\tattributes: Partial< {{pascalCase}}ItemAttributes >\n\t) => {{pascalCase}}ItemAttributes;\n\nexport const createAttributeUpdater = scaffoldValidators.createAttributeUpdater;\n";
|
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
export const COMPOUND_CHILD_EDIT_TEMPLATE = `import type { BlockEditProps } from '@wp-typia/block-types/blocks/registration';
|
|
2
|
-
import { RichText, useBlockProps } from '@wordpress/block-editor';
|
|
2
|
+
import { InnerBlocks, RichText, useBlockProps } from '@wordpress/block-editor';
|
|
3
3
|
import { Notice } from '@wordpress/components';
|
|
4
4
|
import { __ } from '@wordpress/i18n';
|
|
5
5
|
|
|
6
|
+
import metadata from './block-metadata';
|
|
7
|
+
import {
|
|
8
|
+
\tgetChildAllowedBlocks,
|
|
9
|
+
\tgetChildTemplate,
|
|
10
|
+
\thasNestedChildBlocks,
|
|
11
|
+
} from '../{{slugKebabCase}}/children';
|
|
6
12
|
import { useTypiaValidation } from './hooks';
|
|
7
13
|
import type { {{pascalCase}}ItemAttributes } from './types';
|
|
8
14
|
import {
|
|
@@ -21,6 +27,9 @@ export default function Edit( {
|
|
|
21
27
|
\t\tattributes,
|
|
22
28
|
\t\tvalidate{{pascalCase}}ItemAttributes
|
|
23
29
|
\t);
|
|
30
|
+
\tconst nestedAllowedBlocks = getChildAllowedBlocks( metadata.name );
|
|
31
|
+
\tconst nestedTemplate = getChildTemplate( metadata.name );
|
|
32
|
+
\tconst showsNestedChildren = hasNestedChildBlocks( metadata.name );
|
|
24
33
|
|
|
25
34
|
\treturn (
|
|
26
35
|
\t\t<div { ...useBlockProps( { className: '{{compoundChildCssClassName}}' } ) }>
|
|
@@ -45,12 +54,24 @@ export default function Edit( {
|
|
|
45
54
|
\t\t\t\t\t</ul>
|
|
46
55
|
\t\t\t\t</Notice>
|
|
47
56
|
\t\t\t) }
|
|
57
|
+
\t\t\t{ showsNestedChildren && (
|
|
58
|
+
\t\t\t\t<div className="{{compoundChildCssClassName}}__children">
|
|
59
|
+
\t\t\t\t\t<InnerBlocks
|
|
60
|
+
\t\t\t\t\t\tallowedBlocks={ nestedAllowedBlocks }
|
|
61
|
+
\t\t\t\t\t\trenderAppender={ InnerBlocks.ButtonBlockAppender }
|
|
62
|
+
\t\t\t\t\t\ttemplate={ nestedTemplate }
|
|
63
|
+
\t\t\t\t\t\ttemplateLock={ false }
|
|
64
|
+
\t\t\t\t\t/>
|
|
65
|
+
\t\t\t\t</div>
|
|
66
|
+
\t\t\t) }
|
|
48
67
|
\t\t</div>
|
|
49
68
|
\t);
|
|
50
69
|
}
|
|
51
70
|
`;
|
|
52
|
-
export const COMPOUND_CHILD_SAVE_TEMPLATE = `import { RichText, useBlockProps } from '@wordpress/block-editor';
|
|
71
|
+
export const COMPOUND_CHILD_SAVE_TEMPLATE = `import { InnerBlocks, RichText, useBlockProps } from '@wordpress/block-editor';
|
|
53
72
|
|
|
73
|
+
import metadata from './block-metadata';
|
|
74
|
+
import { hasNestedChildBlocks } from '../{{slugKebabCase}}/children';
|
|
54
75
|
import type { {{pascalCase}}ItemAttributes } from './types';
|
|
55
76
|
|
|
56
77
|
export default function Save( {
|
|
@@ -58,6 +79,8 @@ export default function Save( {
|
|
|
58
79
|
}: {
|
|
59
80
|
\tattributes: {{pascalCase}}ItemAttributes;
|
|
60
81
|
} ) {
|
|
82
|
+
\tconst showsNestedChildren = hasNestedChildBlocks( metadata.name );
|
|
83
|
+
|
|
61
84
|
\treturn (
|
|
62
85
|
\t\t<div { ...useBlockProps.save( { className: '{{compoundChildCssClassName}}' } ) }>
|
|
63
86
|
\t\t\t<RichText.Content
|
|
@@ -70,6 +93,11 @@ export default function Save( {
|
|
|
70
93
|
\t\t\t\tclassName="{{compoundChildCssClassName}}__body"
|
|
71
94
|
\t\t\t\tvalue={ attributes.body }
|
|
72
95
|
\t\t\t/>
|
|
96
|
+
\t\t\t{ showsNestedChildren && (
|
|
97
|
+
\t\t\t\t<div className="{{compoundChildCssClassName}}__children">
|
|
98
|
+
\t\t\t\t\t<InnerBlocks.Content />
|
|
99
|
+
\t\t\t\t</div>
|
|
100
|
+
\t\t\t) }
|
|
73
101
|
\t\t</div>
|
|
74
102
|
\t);
|
|
75
103
|
}
|
|
@@ -3,4 +3,4 @@ export declare const COMPOUND_PARENT_SAVE_TEMPLATE = "import { InnerBlocks, Rich
|
|
|
3
3
|
export declare const COMPOUND_PARENT_INDEX_TEMPLATE = "import {\n\tregisterScaffoldBlockType,\n\ttype BlockConfiguration,\n} from '@wp-typia/block-types/blocks/registration';\nimport {\n\tbuildScaffoldBlockRegistration,\n\tparseScaffoldBlockMetadata,\n} from '@wp-typia/block-runtime/blocks';\n\nimport Edit from './edit';\nimport Save from './save';\nimport metadata from './block-metadata';\nimport './style.scss';\n\nimport type { {{pascalCase}}Attributes } from './types';\n\nconst registration = buildScaffoldBlockRegistration(\n\tparseScaffoldBlockMetadata<BlockConfiguration< {{pascalCase}}Attributes >>( metadata ),\n\t{\n\t\tedit: Edit,\n\t\tsave: Save,\n\t}\n);\n\nregisterScaffoldBlockType(registration.name, registration.settings);\n";
|
|
4
4
|
export declare const COMPOUND_LOCAL_HOOKS_TEMPLATE = "export {\n\tformatValidationError,\n\tformatValidationErrors,\n\tuseTypiaValidation,\n} from '../../hooks';\n\nexport type {\n\tTypiaValidationError,\n\tValidationResult,\n\tValidationState,\n} from '../../hooks';\n";
|
|
5
5
|
export declare const COMPOUND_PARENT_VALIDATORS_TEMPLATE = "import typia from 'typia';\nimport currentManifest from './manifest-defaults-document';\nimport type {\n\t{{pascalCase}}Attributes,\n\t{{pascalCase}}ValidationResult,\n} from './types';\nimport { createTemplateValidatorToolkit } from '../../validator-toolkit';\n\nconst scaffoldValidators = createTemplateValidatorToolkit< {{pascalCase}}Attributes >( {\n\tassert: typia.createAssert< {{pascalCase}}Attributes >(),\n\tclone: typia.misc.createClone< {{pascalCase}}Attributes >() as (\n\t\tvalue: {{pascalCase}}Attributes,\n\t) => {{pascalCase}}Attributes,\n\tis: typia.createIs< {{pascalCase}}Attributes >(),\n\tmanifest: currentManifest,\n\tprune: typia.misc.createPrune< {{pascalCase}}Attributes >(),\n\trandom: typia.createRandom< {{pascalCase}}Attributes >() as (\n\t\t...args: unknown[]\n\t) => {{pascalCase}}Attributes,\n\tvalidate: typia.createValidate< {{pascalCase}}Attributes >(),\n} );\n\nexport const validate{{pascalCase}}Attributes =\n\tscaffoldValidators.validateAttributes as (\n\t\tattributes: unknown\n\t) => {{pascalCase}}ValidationResult;\n\nexport const validators = scaffoldValidators.validators;\n\nexport const sanitize{{pascalCase}}Attributes =\n\tscaffoldValidators.sanitizeAttributes as (\n\t\tattributes: Partial< {{pascalCase}}Attributes >\n\t) => {{pascalCase}}Attributes;\n\nexport const createAttributeUpdater = scaffoldValidators.createAttributeUpdater;\n";
|
|
6
|
-
export declare const COMPOUND_CHILDREN_TEMPLATE = "import type { BlockTemplate } from '@wp-typia/block-types/blocks/registration';\n\nexport const DEFAULT_CHILD_BLOCK_NAME = '{{namespace}}/{{slugKebabCase}}-item';\n\nexport
|
|
6
|
+
export declare const COMPOUND_CHILDREN_TEMPLATE = "import type { BlockTemplate } from '@wp-typia/block-types/blocks/registration';\n\nexport const DEFAULT_CHILD_BLOCK_NAME = '{{namespace}}/{{slugKebabCase}}-item';\n\nexport interface CompoundChildSpec {\n\tancestorKeys: string[];\n\tblockName: string;\n\tbodyPlaceholder: string;\n\tcontainer: boolean;\n\tfolderSlug: string;\n\tkey: string;\n\tplacement: 'nested' | 'root';\n\tsupportsInserter: boolean;\n\ttemplateInstances: Array< Record< string, unknown > >;\n\ttitle: string;\n}\n\nconst ROOT_BLOCK_NAME = '{{namespace}}/{{slugKebabCase}}';\n\nexport const COMPOUND_CHILD_SPECS: CompoundChildSpec[] = [\n\t{\n\t\tancestorKeys: [],\n\t\tblockName: DEFAULT_CHILD_BLOCK_NAME,\n\t\tbodyPlaceholder: 'Add supporting details for this internal item.',\n\t\tcontainer: false,\n\t\tfolderSlug: '{{slugKebabCase}}-item',\n\t\tkey: 'item',\n\t\tplacement: 'root',\n\t\tsupportsInserter: false,\n\t\ttemplateInstances: [\n\t\t\t{\n\t\t\t\tbody: 'Add supporting details for the first internal item.',\n\t\t\t\ttitle: 'First Item',\n\t\t\t},\n\t\t\t{\n\t\t\t\tbody: 'Add supporting details for the second internal item.',\n\t\t\t\ttitle: 'Second Item',\n\t\t\t},\n\t\t],\n\t\ttitle: '{{compoundChildTitle}}',\n\t},\n\t// add-child: insert new child specs here\n];\n\nfunction getChildSpecByKey( key: string ): CompoundChildSpec | undefined {\n\treturn COMPOUND_CHILD_SPECS.find( ( spec ) => spec.key === key );\n}\n\nfunction buildTemplateEntriesForSpec( spec: CompoundChildSpec ): BlockTemplate {\n\tconst nestedTemplate = buildNestedTemplateForKey( spec.key );\n\n\treturn spec.templateInstances.map( ( attributes ) =>\n\t\tnestedTemplate.length > 0\n\t\t\t? [ spec.blockName, attributes, nestedTemplate ]\n\t\t\t: [ spec.blockName, attributes ]\n\t);\n}\n\nfunction buildNestedTemplateForKey( key: string ): BlockTemplate {\n\treturn COMPOUND_CHILD_SPECS.filter(\n\t\t( spec ) =>\n\t\t\tspec.placement === 'nested' &&\n\t\t\tspec.ancestorKeys[ spec.ancestorKeys.length - 1 ] === key\n\t).flatMap( ( spec ) => buildTemplateEntriesForSpec( spec ) );\n}\n\nexport const ALLOWED_CHILD_BLOCKS = COMPOUND_CHILD_SPECS.filter(\n\t( spec ) => spec.placement === 'root'\n).map( ( spec ) => spec.blockName );\n\nexport const DEFAULT_CHILD_TEMPLATE: BlockTemplate =\n\tCOMPOUND_CHILD_SPECS.filter( ( spec ) => spec.placement === 'root' ).flatMap(\n\t\t( spec ) => buildTemplateEntriesForSpec( spec )\n\t);\n\nexport function getChildSpec( blockName: string ): CompoundChildSpec | undefined {\n\treturn COMPOUND_CHILD_SPECS.find( ( spec ) => spec.blockName === blockName );\n}\n\nexport function getChildAllowedBlocks(\n\tblockName: string\n): string[] | undefined {\n\tconst childSpec = getChildSpec( blockName );\n\tif ( ! childSpec ) {\n\t\treturn undefined;\n\t}\n\n\tconst directDescendants = COMPOUND_CHILD_SPECS.filter(\n\t\t( spec ) =>\n\t\t\tspec.placement === 'nested' &&\n\t\t\tspec.ancestorKeys[ spec.ancestorKeys.length - 1 ] === childSpec.key\n\t).map( ( spec ) => spec.blockName );\n\n\tif ( directDescendants.length > 0 ) {\n\t\treturn directDescendants;\n\t}\n\n\treturn childSpec.container ? [] : undefined;\n}\n\nexport function getChildAncestorBlockNames(\n\tblockName: string\n): string[] | undefined {\n\tconst childSpec = getChildSpec( blockName );\n\tif ( ! childSpec || childSpec.ancestorKeys.length === 0 ) {\n\t\treturn undefined;\n\t}\n\n\treturn childSpec.ancestorKeys.flatMap( ( key ) => {\n\t\tconst ancestorSpec = getChildSpecByKey( key );\n\t\treturn ancestorSpec ? [ ancestorSpec.blockName ] : [];\n\t} );\n}\n\nexport function getChildTemplate(\n\tblockName: string\n): BlockTemplate | undefined {\n\tconst childSpec = getChildSpec( blockName );\n\tif ( ! childSpec ) {\n\t\treturn undefined;\n\t}\n\n\tconst nestedTemplate = buildNestedTemplateForKey( childSpec.key );\n\tif ( nestedTemplate.length > 0 ) {\n\t\treturn nestedTemplate;\n\t}\n\n\treturn childSpec.container ? [] : undefined;\n}\n\nexport function hasNestedChildBlocks( blockName: string ): boolean {\n\tconst childSpec = getChildSpec( blockName );\n\tif ( ! childSpec ) {\n\t\treturn false;\n\t}\n\n\treturn childSpec.container || buildNestedTemplateForKey( childSpec.key ).length > 0;\n}\n\nexport function isRootCompoundChildBlock( blockName: string ): boolean {\n\tconst childSpec = getChildSpec( blockName );\n\treturn childSpec?.placement === 'root';\n}\n\nexport { ROOT_BLOCK_NAME };\n";
|
|
@@ -203,25 +203,145 @@ export const COMPOUND_CHILDREN_TEMPLATE = `import type { BlockTemplate } from '@
|
|
|
203
203
|
|
|
204
204
|
export const DEFAULT_CHILD_BLOCK_NAME = '{{namespace}}/{{slugKebabCase}}-item';
|
|
205
205
|
|
|
206
|
-
export
|
|
207
|
-
\
|
|
208
|
-
\
|
|
209
|
-
|
|
206
|
+
export interface CompoundChildSpec {
|
|
207
|
+
\tancestorKeys: string[];
|
|
208
|
+
\tblockName: string;
|
|
209
|
+
\tbodyPlaceholder: string;
|
|
210
|
+
\tcontainer: boolean;
|
|
211
|
+
\tfolderSlug: string;
|
|
212
|
+
\tkey: string;
|
|
213
|
+
\tplacement: 'nested' | 'root';
|
|
214
|
+
\tsupportsInserter: boolean;
|
|
215
|
+
\ttemplateInstances: Array< Record< string, unknown > >;
|
|
216
|
+
\ttitle: string;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
const ROOT_BLOCK_NAME = '{{namespace}}/{{slugKebabCase}}';
|
|
210
220
|
|
|
211
|
-
export const
|
|
212
|
-
\t
|
|
213
|
-
\t\
|
|
214
|
-
\t\
|
|
215
|
-
\t\
|
|
216
|
-
\t\
|
|
217
|
-
\t\
|
|
218
|
-
\t
|
|
219
|
-
\t
|
|
220
|
-
\t\
|
|
221
|
-
\t\
|
|
222
|
-
\t\t\
|
|
223
|
-
\t\t\
|
|
224
|
-
\t\t
|
|
225
|
-
\t
|
|
221
|
+
export const COMPOUND_CHILD_SPECS: CompoundChildSpec[] = [
|
|
222
|
+
\t{
|
|
223
|
+
\t\tancestorKeys: [],
|
|
224
|
+
\t\tblockName: DEFAULT_CHILD_BLOCK_NAME,
|
|
225
|
+
\t\tbodyPlaceholder: 'Add supporting details for this internal item.',
|
|
226
|
+
\t\tcontainer: false,
|
|
227
|
+
\t\tfolderSlug: '{{slugKebabCase}}-item',
|
|
228
|
+
\t\tkey: 'item',
|
|
229
|
+
\t\tplacement: 'root',
|
|
230
|
+
\t\tsupportsInserter: false,
|
|
231
|
+
\t\ttemplateInstances: [
|
|
232
|
+
\t\t\t{
|
|
233
|
+
\t\t\t\tbody: 'Add supporting details for the first internal item.',
|
|
234
|
+
\t\t\t\ttitle: 'First Item',
|
|
235
|
+
\t\t\t},
|
|
236
|
+
\t\t\t{
|
|
237
|
+
\t\t\t\tbody: 'Add supporting details for the second internal item.',
|
|
238
|
+
\t\t\t\ttitle: 'Second Item',
|
|
239
|
+
\t\t\t},
|
|
240
|
+
\t\t],
|
|
241
|
+
\t\ttitle: '{{compoundChildTitle}}',
|
|
242
|
+
\t},
|
|
243
|
+
\t// add-child: insert new child specs here
|
|
226
244
|
];
|
|
245
|
+
|
|
246
|
+
function getChildSpecByKey( key: string ): CompoundChildSpec | undefined {
|
|
247
|
+
\treturn COMPOUND_CHILD_SPECS.find( ( spec ) => spec.key === key );
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function buildTemplateEntriesForSpec( spec: CompoundChildSpec ): BlockTemplate {
|
|
251
|
+
\tconst nestedTemplate = buildNestedTemplateForKey( spec.key );
|
|
252
|
+
|
|
253
|
+
\treturn spec.templateInstances.map( ( attributes ) =>
|
|
254
|
+
\t\tnestedTemplate.length > 0
|
|
255
|
+
\t\t\t? [ spec.blockName, attributes, nestedTemplate ]
|
|
256
|
+
\t\t\t: [ spec.blockName, attributes ]
|
|
257
|
+
\t);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function buildNestedTemplateForKey( key: string ): BlockTemplate {
|
|
261
|
+
\treturn COMPOUND_CHILD_SPECS.filter(
|
|
262
|
+
\t\t( spec ) =>
|
|
263
|
+
\t\t\tspec.placement === 'nested' &&
|
|
264
|
+
\t\t\tspec.ancestorKeys[ spec.ancestorKeys.length - 1 ] === key
|
|
265
|
+
\t).flatMap( ( spec ) => buildTemplateEntriesForSpec( spec ) );
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export const ALLOWED_CHILD_BLOCKS = COMPOUND_CHILD_SPECS.filter(
|
|
269
|
+
\t( spec ) => spec.placement === 'root'
|
|
270
|
+
).map( ( spec ) => spec.blockName );
|
|
271
|
+
|
|
272
|
+
export const DEFAULT_CHILD_TEMPLATE: BlockTemplate =
|
|
273
|
+
\tCOMPOUND_CHILD_SPECS.filter( ( spec ) => spec.placement === 'root' ).flatMap(
|
|
274
|
+
\t\t( spec ) => buildTemplateEntriesForSpec( spec )
|
|
275
|
+
\t);
|
|
276
|
+
|
|
277
|
+
export function getChildSpec( blockName: string ): CompoundChildSpec | undefined {
|
|
278
|
+
\treturn COMPOUND_CHILD_SPECS.find( ( spec ) => spec.blockName === blockName );
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
export function getChildAllowedBlocks(
|
|
282
|
+
\tblockName: string
|
|
283
|
+
): string[] | undefined {
|
|
284
|
+
\tconst childSpec = getChildSpec( blockName );
|
|
285
|
+
\tif ( ! childSpec ) {
|
|
286
|
+
\t\treturn undefined;
|
|
287
|
+
\t}
|
|
288
|
+
|
|
289
|
+
\tconst directDescendants = COMPOUND_CHILD_SPECS.filter(
|
|
290
|
+
\t\t( spec ) =>
|
|
291
|
+
\t\t\tspec.placement === 'nested' &&
|
|
292
|
+
\t\t\tspec.ancestorKeys[ spec.ancestorKeys.length - 1 ] === childSpec.key
|
|
293
|
+
\t).map( ( spec ) => spec.blockName );
|
|
294
|
+
|
|
295
|
+
\tif ( directDescendants.length > 0 ) {
|
|
296
|
+
\t\treturn directDescendants;
|
|
297
|
+
\t}
|
|
298
|
+
|
|
299
|
+
\treturn childSpec.container ? [] : undefined;
|
|
300
|
+
}
|
|
301
|
+
|
|
302
|
+
export function getChildAncestorBlockNames(
|
|
303
|
+
\tblockName: string
|
|
304
|
+
): string[] | undefined {
|
|
305
|
+
\tconst childSpec = getChildSpec( blockName );
|
|
306
|
+
\tif ( ! childSpec || childSpec.ancestorKeys.length === 0 ) {
|
|
307
|
+
\t\treturn undefined;
|
|
308
|
+
\t}
|
|
309
|
+
|
|
310
|
+
\treturn childSpec.ancestorKeys.flatMap( ( key ) => {
|
|
311
|
+
\t\tconst ancestorSpec = getChildSpecByKey( key );
|
|
312
|
+
\t\treturn ancestorSpec ? [ ancestorSpec.blockName ] : [];
|
|
313
|
+
\t} );
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export function getChildTemplate(
|
|
317
|
+
\tblockName: string
|
|
318
|
+
): BlockTemplate | undefined {
|
|
319
|
+
\tconst childSpec = getChildSpec( blockName );
|
|
320
|
+
\tif ( ! childSpec ) {
|
|
321
|
+
\t\treturn undefined;
|
|
322
|
+
\t}
|
|
323
|
+
|
|
324
|
+
\tconst nestedTemplate = buildNestedTemplateForKey( childSpec.key );
|
|
325
|
+
\tif ( nestedTemplate.length > 0 ) {
|
|
326
|
+
\t\treturn nestedTemplate;
|
|
327
|
+
\t}
|
|
328
|
+
|
|
329
|
+
\treturn childSpec.container ? [] : undefined;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
export function hasNestedChildBlocks( blockName: string ): boolean {
|
|
333
|
+
\tconst childSpec = getChildSpec( blockName );
|
|
334
|
+
\tif ( ! childSpec ) {
|
|
335
|
+
\t\treturn false;
|
|
336
|
+
\t}
|
|
337
|
+
|
|
338
|
+
\treturn childSpec.container || buildNestedTemplateForKey( childSpec.key ).length > 0;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export function isRootCompoundChildBlock( blockName: string ): boolean {
|
|
342
|
+
\tconst childSpec = getChildSpec( blockName );
|
|
343
|
+
\treturn childSpec?.placement === 'root';
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
export { ROOT_BLOCK_NAME };
|
|
227
347
|
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const QUERY_LOOP_INDEX_TEMPLATE = "import { registerBlockVariation } from '@wordpress/blocks';\nimport type { BlockVariation } from '@wp-typia/block-types/blocks/registration';\nimport { __ } from '@wordpress/i18n';\nimport {\n getQueryLoopCustomAllowedControls,\n getQueryLoopCustomQuerySeed,\n registerQueryLoopEditorExtensions,\n} from './query-extension';\n\ntype QueryLoopVariationAttributes = {\n namespace?: string;\n query?: {\n inherit?: boolean;\n order?: 'asc' | 'desc';\n orderBy?: string;\n perPage?: number;\n postType?: string;\n wpTypiaVariation?: string;\n [key: string]: unknown;\n };\n};\n\ntype QueryLoopVariation = BlockVariation<QueryLoopVariationAttributes> & {\n allowedControls: string[];\n};\n\nconst VARIATION_NAME = {{queryVariationNamespaceJson}};\nconst DEFAULT_ALLOWED_CONTROLS = {{queryAllowedControlsJson}};\nconst customQuerySeed = getQueryLoopCustomQuerySeed();\nconst allowedControls = Array.from(\n new Set([...DEFAULT_ALLOWED_CONTROLS, ...getQueryLoopCustomAllowedControls()]),\n);\n\nconst queryLoopVariation = {\n name: VARIATION_NAME,\n title: __({{titleJson}}, '{{textDomain}}'),\n description: __({{descriptionJson}}, '{{textDomain}}'),\n scope: ['inserter'],\n isActive: ['namespace'],\n attributes: {\n namespace: VARIATION_NAME,\n query: {\n inherit: false,\n order: 'desc',\n orderBy: 'date',\n perPage: 6,\n postType: {{queryPostTypeJson}},\n ...customQuerySeed,\n wpTypiaVariation: VARIATION_NAME,\n },\n },\n allowedControls,\n innerBlocks: [\n [\n 'core/post-template',\n {},\n [\n ['core/post-featured-image'],\n ['core/post-title', { isLink: true }],\n ['core/post-excerpt'],\n ],\n ],\n ['core/query-pagination'],\n ['core/query-no-results'],\n ],\n} satisfies QueryLoopVariation;\n\nregisterBlockVariation('core/query', queryLoopVariation);\nregisterQueryLoopEditorExtensions({ variationName: VARIATION_NAME });\n";
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export const QUERY_LOOP_INDEX_TEMPLATE = `import { registerBlockVariation } from '@wordpress/blocks';
|
|
2
|
+
import type { BlockVariation } from '@wp-typia/block-types/blocks/registration';
|
|
3
|
+
import { __ } from '@wordpress/i18n';
|
|
4
|
+
import {
|
|
5
|
+
getQueryLoopCustomAllowedControls,
|
|
6
|
+
getQueryLoopCustomQuerySeed,
|
|
7
|
+
registerQueryLoopEditorExtensions,
|
|
8
|
+
} from './query-extension';
|
|
9
|
+
|
|
10
|
+
type QueryLoopVariationAttributes = {
|
|
11
|
+
namespace?: string;
|
|
12
|
+
query?: {
|
|
13
|
+
inherit?: boolean;
|
|
14
|
+
order?: 'asc' | 'desc';
|
|
15
|
+
orderBy?: string;
|
|
16
|
+
perPage?: number;
|
|
17
|
+
postType?: string;
|
|
18
|
+
wpTypiaVariation?: string;
|
|
19
|
+
[key: string]: unknown;
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
type QueryLoopVariation = BlockVariation<QueryLoopVariationAttributes> & {
|
|
24
|
+
allowedControls: string[];
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
const VARIATION_NAME = {{queryVariationNamespaceJson}};
|
|
28
|
+
const DEFAULT_ALLOWED_CONTROLS = {{queryAllowedControlsJson}};
|
|
29
|
+
const customQuerySeed = getQueryLoopCustomQuerySeed();
|
|
30
|
+
const allowedControls = Array.from(
|
|
31
|
+
new Set([...DEFAULT_ALLOWED_CONTROLS, ...getQueryLoopCustomAllowedControls()]),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const queryLoopVariation = {
|
|
35
|
+
name: VARIATION_NAME,
|
|
36
|
+
title: __({{titleJson}}, '{{textDomain}}'),
|
|
37
|
+
description: __({{descriptionJson}}, '{{textDomain}}'),
|
|
38
|
+
scope: ['inserter'],
|
|
39
|
+
isActive: ['namespace'],
|
|
40
|
+
attributes: {
|
|
41
|
+
namespace: VARIATION_NAME,
|
|
42
|
+
query: {
|
|
43
|
+
inherit: false,
|
|
44
|
+
order: 'desc',
|
|
45
|
+
orderBy: 'date',
|
|
46
|
+
perPage: 6,
|
|
47
|
+
postType: {{queryPostTypeJson}},
|
|
48
|
+
...customQuerySeed,
|
|
49
|
+
wpTypiaVariation: VARIATION_NAME,
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
allowedControls,
|
|
53
|
+
innerBlocks: [
|
|
54
|
+
[
|
|
55
|
+
'core/post-template',
|
|
56
|
+
{},
|
|
57
|
+
[
|
|
58
|
+
['core/post-featured-image'],
|
|
59
|
+
['core/post-title', { isLink: true }],
|
|
60
|
+
['core/post-excerpt'],
|
|
61
|
+
],
|
|
62
|
+
],
|
|
63
|
+
['core/query-pagination'],
|
|
64
|
+
['core/query-no-results'],
|
|
65
|
+
],
|
|
66
|
+
} satisfies QueryLoopVariation;
|
|
67
|
+
|
|
68
|
+
registerBlockVariation('core/query', queryLoopVariation);
|
|
69
|
+
registerQueryLoopEditorExtensions({ variationName: VARIATION_NAME });
|
|
70
|
+
`;
|
|
@@ -6,4 +6,5 @@ export { BLOCK_METADATA_WRAPPER_TEMPLATE, MANIFEST_DEFAULTS_DOCUMENT_WRAPPER_TEM
|
|
|
6
6
|
export { BASIC_EDIT_TEMPLATE, BASIC_INDEX_TEMPLATE, BASIC_SAVE_TEMPLATE, BASIC_VALIDATORS_TEMPLATE, } from "./built-in-block-code-templates/basic.js";
|
|
7
7
|
export { INTERACTIVITY_EDIT_TEMPLATE, INTERACTIVITY_INDEX_TEMPLATE, INTERACTIVITY_SAVE_TEMPLATE, INTERACTIVITY_SCRIPT_TEMPLATE, INTERACTIVITY_VALIDATORS_TEMPLATE, } from "./built-in-block-code-templates/interactivity.js";
|
|
8
8
|
export { PERSISTENCE_EDIT_TEMPLATE, PERSISTENCE_INDEX_TEMPLATE, PERSISTENCE_INTERACTIVITY_TEMPLATE, PERSISTENCE_SAVE_TEMPLATE, PERSISTENCE_VALIDATORS_TEMPLATE, } from "./built-in-block-code-templates/persistence.js";
|
|
9
|
+
export { QUERY_LOOP_INDEX_TEMPLATE, } from "./built-in-block-code-templates/query-loop.js";
|
|
9
10
|
export { COMPOUND_CHILD_EDIT_TEMPLATE, COMPOUND_CHILD_INDEX_TEMPLATE, COMPOUND_CHILDREN_TEMPLATE, COMPOUND_CHILD_SAVE_TEMPLATE, COMPOUND_CHILD_VALIDATORS_TEMPLATE, COMPOUND_LOCAL_HOOKS_TEMPLATE, COMPOUND_PARENT_EDIT_TEMPLATE, COMPOUND_PARENT_INDEX_TEMPLATE, COMPOUND_PARENT_SAVE_TEMPLATE, COMPOUND_PARENT_VALIDATORS_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_EDIT_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_INTERACTIVITY_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_SAVE_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_VALIDATORS_TEMPLATE, } from "./built-in-block-code-templates/compound.js";
|
|
@@ -6,4 +6,5 @@ export { BLOCK_METADATA_WRAPPER_TEMPLATE, MANIFEST_DEFAULTS_DOCUMENT_WRAPPER_TEM
|
|
|
6
6
|
export { BASIC_EDIT_TEMPLATE, BASIC_INDEX_TEMPLATE, BASIC_SAVE_TEMPLATE, BASIC_VALIDATORS_TEMPLATE, } from "./built-in-block-code-templates/basic.js";
|
|
7
7
|
export { INTERACTIVITY_EDIT_TEMPLATE, INTERACTIVITY_INDEX_TEMPLATE, INTERACTIVITY_SAVE_TEMPLATE, INTERACTIVITY_SCRIPT_TEMPLATE, INTERACTIVITY_VALIDATORS_TEMPLATE, } from "./built-in-block-code-templates/interactivity.js";
|
|
8
8
|
export { PERSISTENCE_EDIT_TEMPLATE, PERSISTENCE_INDEX_TEMPLATE, PERSISTENCE_INTERACTIVITY_TEMPLATE, PERSISTENCE_SAVE_TEMPLATE, PERSISTENCE_VALIDATORS_TEMPLATE, } from "./built-in-block-code-templates/persistence.js";
|
|
9
|
+
export { QUERY_LOOP_INDEX_TEMPLATE, } from "./built-in-block-code-templates/query-loop.js";
|
|
9
10
|
export { COMPOUND_CHILD_EDIT_TEMPLATE, COMPOUND_CHILD_INDEX_TEMPLATE, COMPOUND_CHILDREN_TEMPLATE, COMPOUND_CHILD_SAVE_TEMPLATE, COMPOUND_CHILD_VALIDATORS_TEMPLATE, COMPOUND_LOCAL_HOOKS_TEMPLATE, COMPOUND_PARENT_EDIT_TEMPLATE, COMPOUND_PARENT_INDEX_TEMPLATE, COMPOUND_PARENT_SAVE_TEMPLATE, COMPOUND_PARENT_VALIDATORS_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_EDIT_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_INTERACTIVITY_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_SAVE_TEMPLATE, COMPOUND_PERSISTENCE_PARENT_VALIDATORS_TEMPLATE, } from "./built-in-block-code-templates/compound.js";
|
|
@@ -555,6 +555,8 @@ export function buildBuiltInNonTsArtifacts({ templateId, variables, }) {
|
|
|
555
555
|
return buildPersistenceArtifacts(variables);
|
|
556
556
|
case "compound":
|
|
557
557
|
return buildCompoundArtifacts(variables);
|
|
558
|
+
case "query-loop":
|
|
559
|
+
return [];
|
|
558
560
|
default: {
|
|
559
561
|
const unhandledTemplateId = templateId;
|
|
560
562
|
throw new Error(`Unhandled built-in template id: ${unhandledTemplateId}`);
|
|
@@ -27,7 +27,8 @@ export declare function seedWorkspaceMigrationProject(projectDir: string, curren
|
|
|
27
27
|
* succeeds.
|
|
28
28
|
* @throws {Error} When the template id is unknown, persistence flags are used
|
|
29
29
|
* with unsupported templates, the command runs outside an official workspace,
|
|
30
|
-
* or target block paths
|
|
30
|
+
* workspace dependencies have not been installed yet, or target block paths
|
|
31
|
+
* already exist.
|
|
31
32
|
*/
|
|
32
33
|
export declare function runAddBlockCommand({ blockName, cwd, dataStorageMode, externalLayerId, externalLayerSource, persistencePolicy, selectExternalLayerId, templateId, }: RunAddBlockCommandOptions): Promise<{
|
|
33
34
|
blockSlugs: string[];
|
|
@@ -15,8 +15,15 @@ import { buildConfigEntries, buildMigrationBlocks, buildServerTemplateRoot, } fr
|
|
|
15
15
|
import { COMPOUND_SHARED_SUPPORT_FILES, collectLegacyCompoundValidatorPaths, ensureBlockConfigCanAddRestManifests, ensureCompoundWorkspaceSupportFiles, } from "./cli-add-block-legacy-validator.js";
|
|
16
16
|
import { parseTemplateLocator, resolveTemplateSeed, } from "./template-source.js";
|
|
17
17
|
import { resolveExternalTemplateLayers, } from "./template-layers.js";
|
|
18
|
+
import { formatInstallCommand, } from "./package-managers.js";
|
|
18
19
|
import { resolveOptionalInteractiveExternalLayerId, } from "./external-layer-selection.js";
|
|
19
20
|
const COLLECTION_IMPORT_LINE = "import '../../collection';";
|
|
21
|
+
// This is a lightweight preflight heuristic for the common install layouts:
|
|
22
|
+
// node_modules for npm/pnpm/bun/yarn-classic and Yarn PnP marker files.
|
|
23
|
+
// It intentionally favors fast user guidance over exhaustive detection, so
|
|
24
|
+
// stale node_modules or hoisted installs outside the workspace root can still
|
|
25
|
+
// fall through to deeper resolver errors.
|
|
26
|
+
const WORKSPACE_INSTALL_MARKERS = ["node_modules", ".pnp.cjs", ".pnp.loader.mjs"];
|
|
20
27
|
async function ensureCollectionImport(filePath) {
|
|
21
28
|
await patchFile(filePath, (source) => {
|
|
22
29
|
if (source.includes(COLLECTION_IMPORT_LINE)) {
|
|
@@ -69,6 +76,15 @@ function resolveExternalLayerSourceFromCaller(source, callerCwd) {
|
|
|
69
76
|
}
|
|
70
77
|
return path.resolve(callerCwd, source);
|
|
71
78
|
}
|
|
79
|
+
function hasInstalledWorkspaceDependencies(projectDir) {
|
|
80
|
+
return WORKSPACE_INSTALL_MARKERS.some((marker) => fs.existsSync(path.join(projectDir, marker)));
|
|
81
|
+
}
|
|
82
|
+
function assertWorkspaceDependenciesInstalled(workspace) {
|
|
83
|
+
if (hasInstalledWorkspaceDependencies(workspace.projectDir)) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
throw new Error(`Workspace dependencies have not been installed yet. Run \`${formatInstallCommand(workspace.packageManager)}\` from the workspace root before using \`wp-typia add block ...\`.`);
|
|
87
|
+
}
|
|
72
88
|
async function copyScaffoldedBlockSlice(projectDir, templateId, tempProjectDir, variables, legacyValidatorPaths = []) {
|
|
73
89
|
if (templateId === "compound") {
|
|
74
90
|
await ensureCompoundWorkspaceSupportFiles(projectDir, tempProjectDir, legacyValidatorPaths);
|
|
@@ -248,7 +264,8 @@ export async function seedWorkspaceMigrationProject(projectDir, currentMigration
|
|
|
248
264
|
* succeeds.
|
|
249
265
|
* @throws {Error} When the template id is unknown, persistence flags are used
|
|
250
266
|
* with unsupported templates, the command runs outside an official workspace,
|
|
251
|
-
* or target block paths
|
|
267
|
+
* workspace dependencies have not been installed yet, or target block paths
|
|
268
|
+
* already exist.
|
|
252
269
|
*/
|
|
253
270
|
export async function runAddBlockCommand({ blockName, cwd = process.cwd(), dataStorageMode, externalLayerId, externalLayerSource, persistencePolicy, selectExternalLayerId, templateId = "basic", }) {
|
|
254
271
|
if (!isAddBlockTemplateId(templateId)) {
|
|
@@ -257,6 +274,7 @@ export async function runAddBlockCommand({ blockName, cwd = process.cwd(), dataS
|
|
|
257
274
|
const resolvedTemplateId = templateId;
|
|
258
275
|
assertPersistenceFlagsAllowed(resolvedTemplateId, { dataStorageMode, persistencePolicy });
|
|
259
276
|
const workspace = resolveWorkspaceProject(cwd);
|
|
277
|
+
assertWorkspaceDependenciesInstalled(workspace);
|
|
260
278
|
const normalizedExternalLayerId = normalizeExternalLayerOption(externalLayerId);
|
|
261
279
|
const normalizedExternalLayerSource = resolveExternalLayerSourceFromCaller(normalizeExternalLayerOption(externalLayerSource), cwd);
|
|
262
280
|
const resolvedExternalLayerSelection = await resolveOptionalInteractiveExternalLayerId({
|