@wp-typia/project-tools 0.17.0 → 0.19.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/alternate-render-targets.d.ts +5 -0
- package/dist/runtime/alternate-render-targets.js +29 -0
- package/dist/runtime/block-generator-service-core.d.ts +2 -2
- package/dist/runtime/block-generator-service-core.js +13 -8
- package/dist/runtime/block-generator-service-spec.d.ts +10 -2
- package/dist/runtime/block-generator-service-spec.js +43 -1
- package/dist/runtime/built-in-block-artifacts.js +1 -0
- 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 +35 -2
- package/dist/runtime/built-in-block-code-templates/compound-parent.d.ts +2 -2
- package/dist/runtime/built-in-block-code-templates/compound-parent.js +204 -27
- package/dist/runtime/built-in-block-code-templates/compound-persistence.d.ts +1 -1
- package/dist/runtime/built-in-block-code-templates/compound-persistence.js +11 -8
- package/dist/runtime/built-in-block-non-ts-artifacts.js +505 -2
- package/dist/runtime/cli-add-block.d.ts +6 -2
- package/dist/runtime/cli-add-block.js +71 -24
- package/dist/runtime/cli-add-shared.d.ts +58 -2
- package/dist/runtime/cli-add-shared.js +111 -12
- 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 +5 -1
- package/dist/runtime/cli-core.js +3 -1
- package/dist/runtime/cli-doctor-workspace.js +135 -1
- package/dist/runtime/cli-help.js +12 -7
- package/dist/runtime/cli-scaffold.d.ts +12 -2
- package/dist/runtime/cli-scaffold.js +222 -46
- package/dist/runtime/cli-templates.d.ts +4 -4
- package/dist/runtime/cli-templates.js +104 -39
- package/dist/runtime/cli-validation.d.ts +66 -0
- package/dist/runtime/cli-validation.js +92 -0
- package/dist/runtime/compound-inner-blocks.d.ts +78 -0
- package/dist/runtime/compound-inner-blocks.js +88 -0
- package/dist/runtime/index.d.ts +6 -3
- package/dist/runtime/index.js +4 -2
- package/dist/runtime/local-dev-presets.js +7 -2
- package/dist/runtime/migration-command-surface.js +2 -0
- package/dist/runtime/package-versions.d.ts +1 -0
- package/dist/runtime/package-versions.js +12 -0
- 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.js +78 -8
- 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 +24 -3
- package/dist/runtime/scaffold-identifiers.d.ts +17 -0
- package/dist/runtime/scaffold-identifiers.js +22 -0
- package/dist/runtime/scaffold-onboarding.js +25 -13
- package/dist/runtime/scaffold-package-manager-files.js +6 -1
- package/dist/runtime/scaffold-template-variables.js +22 -0
- package/dist/runtime/scaffold.d.ts +22 -1
- package/dist/runtime/scaffold.js +56 -11
- 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 +35 -4
- 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 +3 -3
- package/package.json +9 -4
- package/templates/_shared/compound/core/scripts/add-compound-child.ts.mustache +728 -49
- package/templates/query-loop/src/validator-toolkit.ts.mustache +0 -1
|
@@ -2,6 +2,7 @@ import { buildTemplateVariablesFromBlockSpec, createBuiltInBlockSpec, } from './
|
|
|
2
2
|
import { getPackageVersions } from './package-versions.js';
|
|
3
3
|
import { buildBlockCssClassName, buildFrontendCssClassName, resolveScaffoldIdentifiers, } from './scaffold-identifiers.js';
|
|
4
4
|
import { BUILTIN_BLOCK_METADATA_VERSION, COMPOUND_CHILD_BLOCK_METADATA_DEFAULTS, getBuiltInTemplateMetadataDefaults, } from './template-defaults.js';
|
|
5
|
+
import { DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID, getCompoundInnerBlocksPresetDefinition, } from './compound-inner-blocks.js';
|
|
5
6
|
import { getTemplateById, isBuiltInTemplateId, } from './template-registry.js';
|
|
6
7
|
import { toPascalCase, toSnakeCase, } from './string-case.js';
|
|
7
8
|
/**
|
|
@@ -43,6 +44,8 @@ export function getTemplateVariables(templateId, answers) {
|
|
|
43
44
|
const compoundChildTitle = `${title} Item`;
|
|
44
45
|
const cssClassName = buildBlockCssClassName(namespace, slug);
|
|
45
46
|
const compoundChildCssClassName = buildBlockCssClassName(namespace, `${slug}-item`);
|
|
47
|
+
const compoundInnerBlocksPreset = answers.compoundInnerBlocksPreset ?? DEFAULT_COMPOUND_INNER_BLOCKS_PRESET_ID;
|
|
48
|
+
const compoundInnerBlocksPresetDefinition = getCompoundInnerBlocksPresetDefinition(compoundInnerBlocksPreset);
|
|
46
49
|
const compoundPersistenceEnabled = templateId === 'persistence'
|
|
47
50
|
? true
|
|
48
51
|
: templateId === 'compound'
|
|
@@ -55,6 +58,8 @@ export function getTemplateVariables(templateId, answers) {
|
|
|
55
58
|
? answers.persistencePolicy ?? 'authenticated'
|
|
56
59
|
: 'authenticated';
|
|
57
60
|
return {
|
|
61
|
+
alternateRenderTargetsCsv: '',
|
|
62
|
+
alternateRenderTargetsJson: '[]',
|
|
58
63
|
apiClientPackageVersion,
|
|
59
64
|
author: answers.author.trim(),
|
|
60
65
|
blockRuntimePackageVersion,
|
|
@@ -68,6 +73,23 @@ export function getTemplateVariables(templateId, answers) {
|
|
|
68
73
|
compoundChildIcon: COMPOUND_CHILD_BLOCK_METADATA_DEFAULTS.icon,
|
|
69
74
|
compoundChildTitleJson: JSON.stringify(compoundChildTitle),
|
|
70
75
|
compoundPersistenceEnabled: compoundPersistenceEnabled ? 'true' : 'false',
|
|
76
|
+
compoundInnerBlocksDirectInsert: compoundInnerBlocksPresetDefinition.directInsert
|
|
77
|
+
? 'true'
|
|
78
|
+
: 'false',
|
|
79
|
+
compoundInnerBlocksOrientation: compoundInnerBlocksPresetDefinition.orientation ?? '',
|
|
80
|
+
compoundInnerBlocksOrientationExpression: compoundInnerBlocksPresetDefinition.orientation
|
|
81
|
+
? `'${compoundInnerBlocksPresetDefinition.orientation}'`
|
|
82
|
+
: 'undefined',
|
|
83
|
+
compoundInnerBlocksPreset,
|
|
84
|
+
compoundInnerBlocksPresetDescription: compoundInnerBlocksPresetDefinition.description,
|
|
85
|
+
compoundInnerBlocksPresetLabel: compoundInnerBlocksPresetDefinition.label,
|
|
86
|
+
compoundInnerBlocksTemplateLockExpression: compoundInnerBlocksPresetDefinition.templateLock === false
|
|
87
|
+
? 'false'
|
|
88
|
+
: `'${compoundInnerBlocksPresetDefinition.templateLock}'`,
|
|
89
|
+
hasAlternateEmailRenderTarget: 'false',
|
|
90
|
+
hasAlternateMjmlRenderTarget: 'false',
|
|
91
|
+
hasAlternatePlainTextRenderTarget: 'false',
|
|
92
|
+
hasAlternateRenderTargets: 'false',
|
|
71
93
|
projectToolsPackageVersion,
|
|
72
94
|
cssClassName,
|
|
73
95
|
dataStorageMode,
|
|
@@ -8,6 +8,7 @@ import type { PackageManagerId } from "./package-managers.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export interface ScaffoldAnswers {
|
|
10
10
|
author: string;
|
|
11
|
+
compoundInnerBlocksPreset?: import("./compound-inner-blocks.js").CompoundInnerBlocksPresetId;
|
|
11
12
|
dataStorageMode?: DataStorageMode;
|
|
12
13
|
description: string;
|
|
13
14
|
/** Block namespace used in generated block names such as `namespace/slug`. */
|
|
@@ -29,6 +30,8 @@ export type PersistencePolicy = (typeof PERSISTENCE_POLICIES)[number];
|
|
|
29
30
|
* Normalized template variables shared by built-in and remote scaffold flows.
|
|
30
31
|
*/
|
|
31
32
|
export interface ScaffoldTemplateVariables extends Record<string, string> {
|
|
33
|
+
alternateRenderTargetsCsv: string;
|
|
34
|
+
alternateRenderTargetsJson: string;
|
|
32
35
|
apiClientPackageVersion: string;
|
|
33
36
|
author: string;
|
|
34
37
|
blockRuntimePackageVersion: string;
|
|
@@ -42,6 +45,17 @@ export interface ScaffoldTemplateVariables extends Record<string, string> {
|
|
|
42
45
|
compoundChildIcon: string;
|
|
43
46
|
compoundChildTitleJson: string;
|
|
44
47
|
compoundPersistenceEnabled: "false" | "true";
|
|
48
|
+
compoundInnerBlocksDirectInsert: "false" | "true";
|
|
49
|
+
compoundInnerBlocksOrientation: "" | "horizontal" | "vertical";
|
|
50
|
+
compoundInnerBlocksOrientationExpression: string;
|
|
51
|
+
compoundInnerBlocksPreset: string;
|
|
52
|
+
compoundInnerBlocksPresetDescription: string;
|
|
53
|
+
compoundInnerBlocksPresetLabel: string;
|
|
54
|
+
compoundInnerBlocksTemplateLockExpression: string;
|
|
55
|
+
hasAlternateEmailRenderTarget: "false" | "true";
|
|
56
|
+
hasAlternateMjmlRenderTarget: "false" | "true";
|
|
57
|
+
hasAlternatePlainTextRenderTarget: "false" | "true";
|
|
58
|
+
hasAlternateRenderTargets: "false" | "true";
|
|
45
59
|
projectToolsPackageVersion: string;
|
|
46
60
|
cssClassName: string;
|
|
47
61
|
dashCase: string;
|
|
@@ -124,8 +138,14 @@ interface InstallDependenciesOptions {
|
|
|
124
138
|
packageManager: PackageManagerId;
|
|
125
139
|
projectDir: string;
|
|
126
140
|
}
|
|
141
|
+
export interface ScaffoldProgressEvent {
|
|
142
|
+
detail: string;
|
|
143
|
+
phase: "finalize-project" | "generate-files" | "install-dependencies" | "resolve-template" | "seed-artifacts";
|
|
144
|
+
title: string;
|
|
145
|
+
}
|
|
127
146
|
interface ScaffoldProjectOptions {
|
|
128
147
|
allowExistingDir?: boolean;
|
|
148
|
+
alternateRenderTargets?: string;
|
|
129
149
|
answers: ScaffoldAnswers;
|
|
130
150
|
cwd?: string;
|
|
131
151
|
dataStorageMode?: DataStorageMode;
|
|
@@ -134,6 +154,7 @@ interface ScaffoldProjectOptions {
|
|
|
134
154
|
externalLayerSourceLabel?: string;
|
|
135
155
|
installDependencies?: ((options: InstallDependenciesOptions) => Promise<void>) | undefined;
|
|
136
156
|
noInstall?: boolean;
|
|
157
|
+
onProgress?: ((event: ScaffoldProgressEvent) => void | Promise<void>) | undefined;
|
|
137
158
|
packageManager: PackageManagerId;
|
|
138
159
|
persistencePolicy?: PersistencePolicy;
|
|
139
160
|
projectDir: string;
|
|
@@ -157,4 +178,4 @@ export { collectScaffoldAnswers, detectAuthor, getDefaultAnswers, resolvePackage
|
|
|
157
178
|
export { getTemplateVariables } from "./scaffold-template-variables.js";
|
|
158
179
|
export declare function isDataStorageMode(value: string): value is DataStorageMode;
|
|
159
180
|
export declare function isPersistencePolicy(value: string): value is PersistencePolicy;
|
|
160
|
-
export declare function scaffoldProject({ projectDir, templateId, answers, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, repositoryReference, cwd, allowExistingDir, noInstall, installDependencies, variant, withMigrationUi, withTestPreset, withWpEnv, }: ScaffoldProjectOptions): Promise<ScaffoldProjectResult>;
|
|
181
|
+
export declare function scaffoldProject({ projectDir, templateId, answers, alternateRenderTargets, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, repositoryReference, cwd, allowExistingDir, noInstall, installDependencies, onProgress, variant, withMigrationUi, withTestPreset, withWpEnv, }: ScaffoldProjectOptions): Promise<ScaffoldProjectResult>;
|
package/dist/runtime/scaffold.js
CHANGED
|
@@ -2,16 +2,17 @@ import fs from "node:fs";
|
|
|
2
2
|
import { promises as fsp } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { getPackageManager } from "./package-managers.js";
|
|
5
|
-
import { buildGitignore, buildReadme, mergeTextLines, replaceTextRecursively, } from "./scaffold-apply-utils.js";
|
|
5
|
+
import { buildGitignore, buildReadme, mergeTextLines, removeQueryLoopPlaceholderFiles, replaceTextRecursively, } from "./scaffold-apply-utils.js";
|
|
6
6
|
import { applyGeneratedProjectDxPackageJson, applyLocalDevPresetFiles, } from "./local-dev-presets.js";
|
|
7
7
|
import { applyMigrationUiCapability } from "./migration-ui-capability.js";
|
|
8
|
-
import { applyWorkspaceMigrationCapability, ensureScaffoldDirectory,
|
|
8
|
+
import { applyWorkspaceMigrationCapability, ensureScaffoldDirectory, isWorkspaceProject, seedBuiltInPersistenceArtifacts, writeStarterManifestFiles, } from "./scaffold-bootstrap.js";
|
|
9
9
|
import { defaultInstallDependencies, normalizePackageJson, normalizePackageManagerFiles, removeUnexpectedLockfiles, } from "./scaffold-package-manager-files.js";
|
|
10
10
|
import { copyInterpolatedDirectory } from "./template-render.js";
|
|
11
11
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, isBuiltInTemplateId, } from "./template-registry.js";
|
|
12
12
|
import { resolveTemplateSource } from "./template-source.js";
|
|
13
13
|
import { BlockGeneratorService, } from "./block-generator-service.js";
|
|
14
14
|
import { getTemplateVariables } from "./scaffold-template-variables.js";
|
|
15
|
+
import { assertExternalLayerCompositionOptions, } from "./cli-validation.js";
|
|
15
16
|
const WORKSPACE_TEMPLATE_ALIAS = "workspace";
|
|
16
17
|
export const DATA_STORAGE_MODES = ["post-meta", "custom-table"];
|
|
17
18
|
export const PERSISTENCE_POLICIES = ["authenticated", "public"];
|
|
@@ -29,17 +30,27 @@ function normalizeTemplateSelection(templateId) {
|
|
|
29
30
|
? OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
|
|
30
31
|
: templateId;
|
|
31
32
|
}
|
|
32
|
-
|
|
33
|
+
async function reportScaffoldProgress(onProgress, event) {
|
|
34
|
+
await onProgress?.(event);
|
|
35
|
+
}
|
|
36
|
+
export async function scaffoldProject({ projectDir, templateId, answers, alternateRenderTargets, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, repositoryReference, cwd = process.cwd(), allowExistingDir = false, noInstall = false, installDependencies = undefined, onProgress = undefined, variant, withMigrationUi = false, withTestPreset = false, withWpEnv = false, }) {
|
|
33
37
|
const resolvedTemplateId = normalizeTemplateSelection(templateId);
|
|
34
38
|
const resolvedPackageManager = getPackageManager(packageManager).id;
|
|
35
39
|
const isBuiltInTemplate = isBuiltInTemplateId(resolvedTemplateId);
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
40
|
+
assertExternalLayerCompositionOptions({
|
|
41
|
+
externalLayerId,
|
|
42
|
+
externalLayerSource,
|
|
43
|
+
});
|
|
39
44
|
if (isBuiltInTemplate) {
|
|
40
45
|
const blockGeneratorService = new BlockGeneratorService();
|
|
46
|
+
await reportScaffoldProgress(onProgress, {
|
|
47
|
+
detail: "Preparing template layers, variants, and generated artifact plans.",
|
|
48
|
+
phase: "resolve-template",
|
|
49
|
+
title: "Resolving scaffold template",
|
|
50
|
+
});
|
|
41
51
|
const plan = await blockGeneratorService.plan({
|
|
42
52
|
allowExistingDir,
|
|
53
|
+
alternateRenderTargets,
|
|
43
54
|
answers,
|
|
44
55
|
cwd,
|
|
45
56
|
dataStorageMode: dataStorageMode ?? answers.dataStorageMode,
|
|
@@ -61,6 +72,7 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
61
72
|
const rendered = await blockGeneratorService.render({ validated });
|
|
62
73
|
return blockGeneratorService.apply({
|
|
63
74
|
installDependencies,
|
|
75
|
+
onProgress,
|
|
64
76
|
rendered,
|
|
65
77
|
});
|
|
66
78
|
}
|
|
@@ -72,13 +84,25 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
72
84
|
dataStorageMode: dataStorageMode ?? answers.dataStorageMode,
|
|
73
85
|
persistencePolicy: persistencePolicy ?? answers.persistencePolicy,
|
|
74
86
|
});
|
|
87
|
+
await reportScaffoldProgress(onProgress, {
|
|
88
|
+
detail: "Loading template files, variants, and external package metadata when needed.",
|
|
89
|
+
phase: "resolve-template",
|
|
90
|
+
title: "Resolving scaffold template",
|
|
91
|
+
});
|
|
75
92
|
const templateSource = await resolveTemplateSource(resolvedTemplateId, cwd, variables, variant);
|
|
76
|
-
const supportsMigrationUi = isBuiltInTemplate ||
|
|
93
|
+
const supportsMigrationUi = isBuiltInTemplate ||
|
|
94
|
+
templateSource.isOfficialWorkspaceTemplate === true ||
|
|
95
|
+
templateSource.supportsMigrationUi === true;
|
|
77
96
|
if (withMigrationUi && !supportsMigrationUi) {
|
|
78
97
|
await templateSource.cleanup?.();
|
|
79
|
-
throw new Error("`--with-migration-ui` is currently supported only for built-in templates and
|
|
98
|
+
throw new Error("`--with-migration-ui` is currently supported only for built-in templates and workspace-capable wp-typia templates.");
|
|
80
99
|
}
|
|
81
100
|
try {
|
|
101
|
+
await reportScaffoldProgress(onProgress, {
|
|
102
|
+
detail: "Copying scaffold files into the target project directory.",
|
|
103
|
+
phase: "generate-files",
|
|
104
|
+
title: "Generating project files",
|
|
105
|
+
});
|
|
82
106
|
await ensureScaffoldDirectory(projectDir, allowExistingDir);
|
|
83
107
|
await copyInterpolatedDirectory(templateSource.templateDir, projectDir, variables);
|
|
84
108
|
}
|
|
@@ -87,8 +111,13 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
87
111
|
await templateSource.cleanup();
|
|
88
112
|
}
|
|
89
113
|
}
|
|
90
|
-
const
|
|
114
|
+
const isWorkspace = isWorkspaceProject(projectDir);
|
|
91
115
|
if (isBuiltInTemplate) {
|
|
116
|
+
await reportScaffoldProgress(onProgress, {
|
|
117
|
+
detail: "Writing starter manifests, local presets, and template-specific generated artifacts.",
|
|
118
|
+
phase: "seed-artifacts",
|
|
119
|
+
title: "Seeding scaffold artifacts",
|
|
120
|
+
});
|
|
92
121
|
await writeStarterManifestFiles(projectDir, resolvedTemplateId, variables);
|
|
93
122
|
await seedBuiltInPersistenceArtifacts(projectDir, resolvedTemplateId, variables);
|
|
94
123
|
await applyLocalDevPresetFiles({
|
|
@@ -105,14 +134,25 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
105
134
|
variables,
|
|
106
135
|
});
|
|
107
136
|
}
|
|
137
|
+
await removeQueryLoopPlaceholderFiles(projectDir, resolvedTemplateId);
|
|
108
138
|
}
|
|
109
|
-
else if (withMigrationUi &&
|
|
139
|
+
else if (withMigrationUi && isWorkspace) {
|
|
140
|
+
await reportScaffoldProgress(onProgress, {
|
|
141
|
+
detail: "Initializing workspace migration scripts and starter migration files.",
|
|
142
|
+
phase: "seed-artifacts",
|
|
143
|
+
title: "Seeding scaffold artifacts",
|
|
144
|
+
});
|
|
110
145
|
await applyWorkspaceMigrationCapability(projectDir, resolvedPackageManager);
|
|
111
146
|
}
|
|
147
|
+
await reportScaffoldProgress(onProgress, {
|
|
148
|
+
detail: "Writing README, normalizing package metadata, and aligning package-manager files.",
|
|
149
|
+
phase: "finalize-project",
|
|
150
|
+
title: "Finalizing scaffold output",
|
|
151
|
+
});
|
|
112
152
|
const readmePath = path.join(projectDir, "README.md");
|
|
113
153
|
if (!fs.existsSync(readmePath)) {
|
|
114
154
|
await fsp.writeFile(readmePath, buildReadme(resolvedTemplateId, variables, resolvedPackageManager, {
|
|
115
|
-
withMigrationUi: isBuiltInTemplate ||
|
|
155
|
+
withMigrationUi: isBuiltInTemplate || isWorkspace ? withMigrationUi : false,
|
|
116
156
|
withTestPreset: isBuiltInTemplate ? withTestPreset : false,
|
|
117
157
|
withWpEnv: isBuiltInTemplate ? withWpEnv : false,
|
|
118
158
|
}), "utf8");
|
|
@@ -139,6 +179,11 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
139
179
|
repositoryReference,
|
|
140
180
|
});
|
|
141
181
|
if (!noInstall) {
|
|
182
|
+
await reportScaffoldProgress(onProgress, {
|
|
183
|
+
detail: "Installing project dependencies with the selected package manager.",
|
|
184
|
+
phase: "install-dependencies",
|
|
185
|
+
title: "Installing dependencies",
|
|
186
|
+
});
|
|
142
187
|
const installer = installDependencies ?? defaultInstallDependencies;
|
|
143
188
|
await installer({
|
|
144
189
|
projectDir,
|
|
@@ -13,8 +13,9 @@ export interface CopyRawDirectoryOptions {
|
|
|
13
13
|
*
|
|
14
14
|
* Throwing or rejecting aborts the copy and bubbles to the caller.
|
|
15
15
|
*/
|
|
16
|
-
filter?:
|
|
16
|
+
filter?: CopyDirectoryFilter;
|
|
17
17
|
}
|
|
18
|
+
export type CopyDirectoryFilter = (sourcePath: string, destinationPath: string, entry: fs.Dirent) => boolean | Promise<boolean>;
|
|
18
19
|
/**
|
|
19
20
|
* Render a Mustache template with full Mustache semantics while leaving values
|
|
20
21
|
* unescaped for scaffold source generation.
|
|
@@ -28,7 +29,9 @@ export declare function copyRawDirectory(sourceDir: string, targetDir: string, o
|
|
|
28
29
|
* Copy a template directory using full Mustache semantics for filenames and
|
|
29
30
|
* text-file contents while leaving rendered values unescaped.
|
|
30
31
|
*/
|
|
31
|
-
export declare function copyRenderedDirectory(sourceDir: string, targetDir: string, view: TemplateRenderView
|
|
32
|
+
export declare function copyRenderedDirectory(sourceDir: string, targetDir: string, view: TemplateRenderView, options?: {
|
|
33
|
+
filter?: CopyDirectoryFilter;
|
|
34
|
+
}): Promise<void>;
|
|
32
35
|
/**
|
|
33
36
|
* Copy a template directory using direct `{{key}}` replacement only.
|
|
34
37
|
*
|
|
@@ -66,15 +66,19 @@ function stripTemplateExtension(entryName) {
|
|
|
66
66
|
function renderTemplateDestinationName(entryName, view, renderString) {
|
|
67
67
|
return renderString(stripTemplateExtension(entryName), view);
|
|
68
68
|
}
|
|
69
|
-
async function traverseTemplateDirectory({ prepareDirectory, renderString, sourceDir, targetDir, view, visitFile, }) {
|
|
69
|
+
async function traverseTemplateDirectory({ filter, prepareDirectory, renderString, sourceDir, targetDir, view, visitFile, }) {
|
|
70
70
|
const entries = await fsp.readdir(sourceDir, { withFileTypes: true });
|
|
71
71
|
for (const entry of entries) {
|
|
72
72
|
const sourcePath = path.join(sourceDir, entry.name);
|
|
73
73
|
const destinationName = renderTemplateDestinationName(entry.name, view, renderString);
|
|
74
74
|
const destinationPath = resolveRenderedPath(targetDir, destinationName);
|
|
75
|
+
if (filter && !(await filter(sourcePath, destinationPath, entry))) {
|
|
76
|
+
continue;
|
|
77
|
+
}
|
|
75
78
|
if (entry.isDirectory()) {
|
|
76
79
|
await prepareDirectory?.(destinationPath);
|
|
77
80
|
await traverseTemplateDirectory({
|
|
81
|
+
filter,
|
|
78
82
|
prepareDirectory,
|
|
79
83
|
renderString,
|
|
80
84
|
sourceDir: sourcePath,
|
|
@@ -90,9 +94,10 @@ async function traverseTemplateDirectory({ prepareDirectory, renderString, sourc
|
|
|
90
94
|
});
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
|
-
async function copyTemplateDirectory({ renderString, sourceDir, targetDir, view, }) {
|
|
97
|
+
async function copyTemplateDirectory({ filter, renderString, sourceDir, targetDir, view, }) {
|
|
94
98
|
await fsp.mkdir(targetDir, { recursive: true });
|
|
95
99
|
await traverseTemplateDirectory({
|
|
100
|
+
filter,
|
|
96
101
|
prepareDirectory: async (directoryPath) => {
|
|
97
102
|
await fsp.mkdir(directoryPath, { recursive: true });
|
|
98
103
|
},
|
|
@@ -134,8 +139,9 @@ export async function copyRawDirectory(sourceDir, targetDir, options = {}) {
|
|
|
134
139
|
* Copy a template directory using full Mustache semantics for filenames and
|
|
135
140
|
* text-file contents while leaving rendered values unescaped.
|
|
136
141
|
*/
|
|
137
|
-
export async function copyRenderedDirectory(sourceDir, targetDir, view) {
|
|
142
|
+
export async function copyRenderedDirectory(sourceDir, targetDir, view, options = {}) {
|
|
138
143
|
await copyTemplateDirectory({
|
|
144
|
+
filter: options.filter,
|
|
139
145
|
renderString: renderMustacheTemplateString,
|
|
140
146
|
sourceDir,
|
|
141
147
|
targetDir,
|
|
@@ -35,6 +35,11 @@ export interface ResolvedTemplateSource {
|
|
|
35
35
|
features: string[];
|
|
36
36
|
format: TemplateSourceFormat;
|
|
37
37
|
isOfficialWorkspaceTemplate?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* True when the resolved template can participate in scaffold migration UI
|
|
40
|
+
* seeding, such as rendered wp-typia workspace templates.
|
|
41
|
+
*/
|
|
42
|
+
supportsMigrationUi?: boolean;
|
|
38
43
|
templateDir: string;
|
|
39
44
|
cleanup?: () => Promise<void>;
|
|
40
45
|
selectedVariant?: string | null;
|
|
@@ -58,6 +63,11 @@ export interface ExternalTemplateConfig<TView extends UnknownRecord = TemplateVa
|
|
|
58
63
|
blockTemplatesPath?: string;
|
|
59
64
|
defaultValues?: Partial<TView>;
|
|
60
65
|
folderName?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Relative template root that renders a fuller wp-typia plugin/workspace
|
|
68
|
+
* scaffold instead of a create-block subset.
|
|
69
|
+
*/
|
|
70
|
+
pluginTemplatesPath?: string;
|
|
61
71
|
transformer?: (view: TView) => UnknownRecord | Promise<UnknownRecord>;
|
|
62
72
|
variants?: Record<string, Partial<TView>>;
|
|
63
73
|
}
|
|
@@ -65,6 +75,7 @@ export interface SeedSource {
|
|
|
65
75
|
assetsDir?: string;
|
|
66
76
|
blockDir: string;
|
|
67
77
|
cleanup?: () => Promise<void>;
|
|
78
|
+
formatHint?: 'create-block-subset' | 'wp-typia';
|
|
68
79
|
rootDir: string;
|
|
69
80
|
selectedVariant?: string | null;
|
|
70
81
|
warnings?: string[];
|
|
@@ -11,7 +11,7 @@ export declare const EXTERNAL_TEMPLATE_ENTRY_CANDIDATES: readonly ["index.js", "
|
|
|
11
11
|
*/
|
|
12
12
|
export declare function getExternalTemplateEntry(sourceDir: string): string | null;
|
|
13
13
|
/**
|
|
14
|
-
* Load an official external
|
|
14
|
+
* Load an official external template config and render its seed.
|
|
15
15
|
*
|
|
16
16
|
* @param sourceDir Source directory that contains the external template config.
|
|
17
17
|
* @param context Template render context used for the selected variant.
|
|
@@ -55,7 +55,6 @@ async function loadExternalTemplateConfig(sourceDir) {
|
|
|
55
55
|
}
|
|
56
56
|
const warnings = [];
|
|
57
57
|
for (const ignoredKey of [
|
|
58
|
-
'pluginTemplatesPath',
|
|
59
58
|
'wpScripts',
|
|
60
59
|
'wpEnv',
|
|
61
60
|
'customScripts',
|
|
@@ -105,9 +104,42 @@ function extractVariantRenderValues(variantConfig) {
|
|
|
105
104
|
delete values.assetsPath;
|
|
106
105
|
delete values.blockTemplatesPath;
|
|
107
106
|
delete values.folderName;
|
|
107
|
+
delete values.pluginTemplatesPath;
|
|
108
108
|
delete values.transformer;
|
|
109
109
|
return values;
|
|
110
110
|
}
|
|
111
|
+
function resolveConfiguredTemplatePath(config, variantConfig) {
|
|
112
|
+
const variantPluginTemplatesPath = typeof variantConfig.pluginTemplatesPath === 'string'
|
|
113
|
+
? variantConfig.pluginTemplatesPath
|
|
114
|
+
: null;
|
|
115
|
+
const variantBlockTemplatesPath = typeof variantConfig.blockTemplatesPath === 'string'
|
|
116
|
+
? variantConfig.blockTemplatesPath
|
|
117
|
+
: null;
|
|
118
|
+
const configBlockTemplatesPath = typeof config.blockTemplatesPath === 'string'
|
|
119
|
+
? config.blockTemplatesPath
|
|
120
|
+
: null;
|
|
121
|
+
const configPluginTemplatesPath = typeof config.pluginTemplatesPath === 'string'
|
|
122
|
+
? config.pluginTemplatesPath
|
|
123
|
+
: null;
|
|
124
|
+
const templatePath = variantPluginTemplatesPath ??
|
|
125
|
+
variantBlockTemplatesPath ??
|
|
126
|
+
configBlockTemplatesPath ??
|
|
127
|
+
configPluginTemplatesPath;
|
|
128
|
+
if (!templatePath) {
|
|
129
|
+
throw new Error('External template config must define blockTemplatesPath or pluginTemplatesPath.');
|
|
130
|
+
}
|
|
131
|
+
const configuredFolderName = (typeof variantConfig.folderName === 'string'
|
|
132
|
+
? variantConfig.folderName
|
|
133
|
+
: config.folderName) ?? null;
|
|
134
|
+
return {
|
|
135
|
+
folderName: configuredFolderName || '.',
|
|
136
|
+
formatHint: templatePath === variantPluginTemplatesPath ||
|
|
137
|
+
templatePath === configPluginTemplatesPath
|
|
138
|
+
? 'wp-typia'
|
|
139
|
+
: 'create-block-subset',
|
|
140
|
+
templatePath,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
111
143
|
async function buildExternalTemplateView(context, config, selectedVariant, variantConfig) {
|
|
112
144
|
const mergedView = {
|
|
113
145
|
...(config.defaultValues ?? {}),
|
|
@@ -131,7 +163,7 @@ async function buildExternalTemplateView(context, config, selectedVariant, varia
|
|
|
131
163
|
};
|
|
132
164
|
}
|
|
133
165
|
/**
|
|
134
|
-
* Load an official external
|
|
166
|
+
* Load an official external template config and render its seed.
|
|
135
167
|
*
|
|
136
168
|
* @param sourceDir Source directory that contains the external template config.
|
|
137
169
|
* @param context Template render context used for the selected variant.
|
|
@@ -141,25 +173,24 @@ async function buildExternalTemplateView(context, config, selectedVariant, varia
|
|
|
141
173
|
export async function renderCreateBlockExternalTemplate(sourceDir, context, requestedVariant) {
|
|
142
174
|
const { config, warnings } = await loadExternalTemplateConfig(sourceDir);
|
|
143
175
|
const { selectedVariant, variantConfig } = getVariantConfig(config, requestedVariant);
|
|
144
|
-
const
|
|
145
|
-
? variantConfig.blockTemplatesPath
|
|
146
|
-
: config.blockTemplatesPath) ?? null;
|
|
147
|
-
if (!blockTemplatesPath) {
|
|
148
|
-
throw new Error('External template config must define blockTemplatesPath.');
|
|
149
|
-
}
|
|
176
|
+
const { folderName, formatHint, templatePath } = resolveConfiguredTemplatePath(config, variantConfig);
|
|
150
177
|
const tempRoot = await fsp.mkdtemp(path.join(os.tmpdir(), 'wp-typia-create-block-external-'));
|
|
151
178
|
const cleanup = async () => {
|
|
152
179
|
await fsp.rm(tempRoot, { force: true, recursive: true });
|
|
153
180
|
};
|
|
154
181
|
try {
|
|
155
182
|
const renderedRoot = path.join(tempRoot, 'rendered');
|
|
156
|
-
const folderName = (typeof variantConfig.folderName === 'string'
|
|
157
|
-
? variantConfig.folderName
|
|
158
|
-
: config.folderName) || '.';
|
|
159
183
|
const blockDir = resolveSourceSubpath(renderedRoot, folderName);
|
|
160
184
|
const view = await buildExternalTemplateView(context, config, selectedVariant, variantConfig);
|
|
161
|
-
const blockTemplateDir = resolveSourceSubpath(sourceDir,
|
|
162
|
-
await copyRenderedDirectory(blockTemplateDir, blockDir, view
|
|
185
|
+
const blockTemplateDir = resolveSourceSubpath(sourceDir, templatePath);
|
|
186
|
+
await copyRenderedDirectory(blockTemplateDir, blockDir, view, {
|
|
187
|
+
filter: (sourcePath, _destinationPath, entry) => {
|
|
188
|
+
const mustacheVariantPath = path.join(path.dirname(sourcePath), `${entry.name}.mustache`);
|
|
189
|
+
return !(entry.isFile() &&
|
|
190
|
+
(entry.name === 'package.json' || entry.name === 'README.md') &&
|
|
191
|
+
fs.existsSync(mustacheVariantPath));
|
|
192
|
+
},
|
|
193
|
+
});
|
|
163
194
|
const assetsPath = typeof variantConfig.assetsPath === 'string'
|
|
164
195
|
? variantConfig.assetsPath
|
|
165
196
|
: config.assetsPath;
|
|
@@ -172,6 +203,7 @@ export async function renderCreateBlockExternalTemplate(sourceDir, context, requ
|
|
|
172
203
|
: undefined,
|
|
173
204
|
blockDir,
|
|
174
205
|
cleanup,
|
|
206
|
+
formatHint,
|
|
175
207
|
rootDir: tempRoot,
|
|
176
208
|
selectedVariant,
|
|
177
209
|
warnings,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { renderCreateBlockExternalTemplate } from './template-source-external.js';
|
|
2
|
-
export { getDefaultCategory, normalizeCreateBlockSubset, normalizeWpTypiaTemplateSeed, } from './template-source-remote.js';
|
|
2
|
+
export { getTemplateProjectType, getDefaultCategory, normalizeCreateBlockSubset, normalizeWpTypiaTemplateSeed, } from './template-source-remote.js';
|
|
3
3
|
import type { TemplateSourceFormat, TemplateVariableContext } from './template-source-contracts.js';
|
|
4
4
|
export declare function getTemplateVariableContext(variables: {
|
|
5
5
|
[key: string]: string;
|
|
@@ -4,8 +4,9 @@ import path from 'node:path';
|
|
|
4
4
|
import { loadExternalTemplateLayerManifest } from './template-layers.js';
|
|
5
5
|
import { getPackageVersions } from './package-versions.js';
|
|
6
6
|
import { getExternalTemplateEntry } from './template-source-external.js';
|
|
7
|
+
import { getTemplateProjectType } from './template-source-remote.js';
|
|
7
8
|
export { renderCreateBlockExternalTemplate } from './template-source-external.js';
|
|
8
|
-
export { getDefaultCategory, normalizeCreateBlockSubset, normalizeWpTypiaTemplateSeed, } from './template-source-remote.js';
|
|
9
|
+
export { getTemplateProjectType, getDefaultCategory, normalizeCreateBlockSubset, normalizeWpTypiaTemplateSeed, } from './template-source-remote.js';
|
|
9
10
|
export function getTemplateVariableContext(variables) {
|
|
10
11
|
const { apiClientPackageVersion, blockRuntimePackageVersion, blockTypesPackageVersion, projectToolsPackageVersion, restPackageVersion, } = getPackageVersions();
|
|
11
12
|
return {
|
|
@@ -35,6 +36,9 @@ export async function detectTemplateSourceFormat(sourceDir) {
|
|
|
35
36
|
if (getExternalTemplateEntry(sourceDir)) {
|
|
36
37
|
return 'create-block-external';
|
|
37
38
|
}
|
|
39
|
+
if (getTemplateProjectType(sourceDir) !== null) {
|
|
40
|
+
return 'wp-typia';
|
|
41
|
+
}
|
|
38
42
|
const sourceRoot = fs.existsSync(path.join(sourceDir, 'src'))
|
|
39
43
|
? path.join(sourceDir, 'src')
|
|
40
44
|
: sourceDir;
|
|
@@ -6,6 +6,11 @@ import type { ResolvedTemplateSource, SeedSource, TemplateVariableContext } from
|
|
|
6
6
|
* @returns The declared block category, or "widgets" when detection fails.
|
|
7
7
|
*/
|
|
8
8
|
export declare function getDefaultCategory(sourceDir: string): string;
|
|
9
|
+
/**
|
|
10
|
+
* Read `wpTypia.projectType` from a rendered or source template package
|
|
11
|
+
* manifest and return it when present.
|
|
12
|
+
*/
|
|
13
|
+
export declare function getTemplateProjectType(sourceDir: string): string | null;
|
|
9
14
|
/**
|
|
10
15
|
* Copy a wp-typia seed into a normalized temporary template directory.
|
|
11
16
|
*
|
|
@@ -39,6 +39,33 @@ export function getDefaultCategory(sourceDir) {
|
|
|
39
39
|
return 'widgets';
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
|
+
function readTemplatePackageJson(sourceDir) {
|
|
43
|
+
for (const candidate of [
|
|
44
|
+
path.join(sourceDir, 'package.json.mustache'),
|
|
45
|
+
path.join(sourceDir, 'package.json'),
|
|
46
|
+
]) {
|
|
47
|
+
if (!fs.existsSync(candidate)) {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(fs.readFileSync(candidate, 'utf8'));
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
continue;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Read `wpTypia.projectType` from a rendered or source template package
|
|
61
|
+
* manifest and return it when present.
|
|
62
|
+
*/
|
|
63
|
+
export function getTemplateProjectType(sourceDir) {
|
|
64
|
+
const packageJson = readTemplatePackageJson(sourceDir);
|
|
65
|
+
return typeof packageJson?.wpTypia?.projectType === 'string'
|
|
66
|
+
? packageJson.wpTypia.projectType
|
|
67
|
+
: null;
|
|
68
|
+
}
|
|
42
69
|
/**
|
|
43
70
|
* Copy a wp-typia seed into a normalized temporary template directory.
|
|
44
71
|
*
|
|
@@ -57,6 +84,12 @@ export async function normalizeWpTypiaTemplateSeed(seed) {
|
|
|
57
84
|
fs.existsSync(mustacheVariantPath));
|
|
58
85
|
},
|
|
59
86
|
});
|
|
87
|
+
if (seed.assetsDir && fs.existsSync(seed.assetsDir)) {
|
|
88
|
+
await fsp.cp(seed.assetsDir, path.join(normalizedDir, 'assets'), {
|
|
89
|
+
recursive: true,
|
|
90
|
+
force: true,
|
|
91
|
+
});
|
|
92
|
+
}
|
|
60
93
|
}
|
|
61
94
|
catch (error) {
|
|
62
95
|
await fsp.rm(tempRoot, { force: true, recursive: true });
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, isBuiltInTemplateId, } from './template-registry.js';
|
|
2
2
|
import { resolveBuiltInTemplateSource } from './template-builtins.js';
|
|
3
3
|
import { parseTemplateLocator, } from './template-source-locators.js';
|
|
4
|
-
import { detectTemplateSourceFormat, getDefaultCategory, getTemplateVariableContext, normalizeCreateBlockSubset, normalizeWpTypiaTemplateSeed, renderCreateBlockExternalTemplate, } from './template-source-normalization.js';
|
|
4
|
+
import { detectTemplateSourceFormat, getTemplateProjectType, getDefaultCategory, getTemplateVariableContext, normalizeCreateBlockSubset, normalizeWpTypiaTemplateSeed, renderCreateBlockExternalTemplate, } from './template-source-normalization.js';
|
|
5
5
|
import { isOfficialWorkspaceTemplateSeed, resolveTemplateSeed, } from './template-source-seeds.js';
|
|
6
|
+
import { assertBuiltInTemplateVariantAllowed, } from './cli-validation.js';
|
|
6
7
|
export { parseGitHubTemplateLocator, parseNpmTemplateLocator, parseTemplateLocator, } from './template-source-locators.js';
|
|
7
8
|
export { resolveTemplateSeed } from './template-source-seeds.js';
|
|
8
9
|
export async function resolveTemplateSource(templateId, cwd, variables, variant) {
|
|
9
10
|
if (isBuiltInTemplateId(templateId)) {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
11
|
+
assertBuiltInTemplateVariantAllowed({
|
|
12
|
+
templateId,
|
|
13
|
+
variant,
|
|
14
|
+
});
|
|
13
15
|
return resolveBuiltInTemplateSource(templateId, {
|
|
14
16
|
persistenceEnabled: variables.compoundPersistenceEnabled === 'true',
|
|
15
17
|
persistencePolicy: variables.persistencePolicy === 'public' ? 'public' : 'authenticated',
|
|
@@ -28,6 +30,7 @@ export async function resolveTemplateSource(templateId, cwd, variables, variant)
|
|
|
28
30
|
throw new Error(`--variant is only supported for official external template configs. Received variant "${variant}" for "${templateId}".`);
|
|
29
31
|
}
|
|
30
32
|
normalizedSeed = await normalizeWpTypiaTemplateSeed(seed);
|
|
33
|
+
const supportsMigrationUi = getTemplateProjectType(seed.blockDir) === 'workspace';
|
|
31
34
|
return {
|
|
32
35
|
id: templateId,
|
|
33
36
|
defaultCategory: getDefaultCategory(seed.blockDir),
|
|
@@ -35,6 +38,7 @@ export async function resolveTemplateSource(templateId, cwd, variables, variant)
|
|
|
35
38
|
features: ['Remote source', 'wp-typia format'],
|
|
36
39
|
format,
|
|
37
40
|
isOfficialWorkspaceTemplate,
|
|
41
|
+
supportsMigrationUi,
|
|
38
42
|
templateDir: normalizedSeed.blockDir,
|
|
39
43
|
cleanup: normalizedSeed.cleanup,
|
|
40
44
|
};
|
|
@@ -48,6 +52,33 @@ export async function resolveTemplateSource(templateId, cwd, variables, variant)
|
|
|
48
52
|
})()
|
|
49
53
|
: seed;
|
|
50
54
|
if (format === 'create-block-external') {
|
|
55
|
+
const renderedFormat = normalizedSeed.formatHint ??
|
|
56
|
+
(await detectTemplateSourceFormat(normalizedSeed.blockDir));
|
|
57
|
+
if (renderedFormat === 'wp-typia') {
|
|
58
|
+
const normalized = await normalizeWpTypiaTemplateSeed(normalizedSeed);
|
|
59
|
+
const supportsMigrationUi = getTemplateProjectType(normalizedSeed.blockDir) === 'workspace';
|
|
60
|
+
return {
|
|
61
|
+
cleanup: async () => {
|
|
62
|
+
await normalized.cleanup?.();
|
|
63
|
+
await seed.cleanup?.();
|
|
64
|
+
},
|
|
65
|
+
defaultCategory: getDefaultCategory(normalizedSeed.blockDir),
|
|
66
|
+
description: 'A wp-typia scaffold normalized from an official external template config',
|
|
67
|
+
features: [
|
|
68
|
+
'Remote source',
|
|
69
|
+
'official external template',
|
|
70
|
+
'wp-typia format',
|
|
71
|
+
...(supportsMigrationUi ? ['workspace-capable scaffold'] : []),
|
|
72
|
+
],
|
|
73
|
+
format,
|
|
74
|
+
id: 'remote:create-block-external',
|
|
75
|
+
isOfficialWorkspaceTemplate,
|
|
76
|
+
selectedVariant: normalizedSeed.selectedVariant ?? null,
|
|
77
|
+
supportsMigrationUi,
|
|
78
|
+
templateDir: normalized.blockDir,
|
|
79
|
+
warnings: normalizedSeed.warnings ?? [],
|
|
80
|
+
};
|
|
81
|
+
}
|
|
51
82
|
const normalized = await normalizeCreateBlockSubset(normalizedSeed, context);
|
|
52
83
|
return {
|
|
53
84
|
...normalized,
|