@wp-typia/project-tools 0.17.0 → 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 +2 -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 +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/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 -6
- package/dist/runtime/cli-scaffold.d.ts +10 -2
- package/dist/runtime/cli-scaffold.js +136 -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 +7 -2
- 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 +68 -2
- 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 +2 -1
- package/dist/runtime/scaffold-onboarding.js +7 -3
- package/dist/runtime/scaffold-package-manager-files.js +6 -1
- package/dist/runtime/scaffold.d.ts +7 -1
- package/dist/runtime/scaffold.js +50 -8
- 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/src/validator-toolkit.ts.mustache +0 -1
|
@@ -10,12 +10,17 @@ import { ensureMigrationDirectories, writeInitialMigrationScaffold, writeMigrati
|
|
|
10
10
|
import { syncPersistenceRestArtifacts, } from "./persistence-rest-artifacts.js";
|
|
11
11
|
import { buildGitignore, buildReadme, mergeTextLines, } from "./scaffold-documents.js";
|
|
12
12
|
import { getStarterManifestFiles, stringifyStarterManifest, } from "./starter-manifests.js";
|
|
13
|
+
import { formatNonEmptyTargetDirectoryError, } from "./scaffold-bootstrap.js";
|
|
13
14
|
import { stringifyBuiltInBlockJsonDocument, } from "./built-in-block-artifacts.js";
|
|
14
15
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, } from "./template-registry.js";
|
|
15
16
|
import { copyInterpolatedDirectory } from "./template-render.js";
|
|
16
|
-
import { formatInstallCommand, formatPackageExecCommand,
|
|
17
|
+
import { formatInstallCommand, formatPackageExecCommand, transformPackageManagerText, } from "./package-managers.js";
|
|
18
|
+
import { normalizePackageJson } from "./scaffold-package-manager-files.js";
|
|
17
19
|
import { replaceRepositoryReferencePlaceholders, resolveScaffoldRepositoryReference, } from "./scaffold-repository-reference.js";
|
|
18
20
|
export { buildGitignore, buildReadme, mergeTextLines, } from "./scaffold-documents.js";
|
|
21
|
+
async function reportScaffoldProgress(onProgress, event) {
|
|
22
|
+
await onProgress?.(event);
|
|
23
|
+
}
|
|
19
24
|
const EPHEMERAL_NODE_MODULES_LINK_TYPE = process.platform === "win32" ? "junction" : "dir";
|
|
20
25
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
21
26
|
const LOCKFILES = {
|
|
@@ -34,7 +39,7 @@ export async function ensureDirectory(targetDir, allowExisting = false) {
|
|
|
34
39
|
}
|
|
35
40
|
const entries = await fsp.readdir(targetDir);
|
|
36
41
|
if (entries.length > 0) {
|
|
37
|
-
throw new Error(
|
|
42
|
+
throw new Error(formatNonEmptyTargetDirectoryError(targetDir));
|
|
38
43
|
}
|
|
39
44
|
}
|
|
40
45
|
export async function writeStarterManifestFiles(targetDir, templateId, variables, artifacts) {
|
|
@@ -135,22 +140,13 @@ export async function normalizePackageManagerFiles(targetDir, packageManagerId)
|
|
|
135
140
|
await fsp.rm(yarnRcPath, { force: true });
|
|
136
141
|
}
|
|
137
142
|
}
|
|
138
|
-
export async function
|
|
139
|
-
|
|
140
|
-
if (!fs.existsSync(packageJsonPath)) {
|
|
143
|
+
export async function removeQueryLoopPlaceholderFiles(projectDir, templateId) {
|
|
144
|
+
if (templateId !== "query-loop") {
|
|
141
145
|
return;
|
|
142
146
|
}
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (packageJson.scripts) {
|
|
147
|
-
for (const [key, value] of Object.entries(packageJson.scripts)) {
|
|
148
|
-
if (typeof value === "string") {
|
|
149
|
-
packageJson.scripts[key] = transformPackageManagerText(value, packageManagerId);
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
}
|
|
153
|
-
await fsp.writeFile(packageJsonPath, `${JSON.stringify(packageJson, null, "\t")}\n`, "utf8");
|
|
147
|
+
await fsp.rm(path.join(projectDir, "src", "validator-toolkit.ts"), {
|
|
148
|
+
force: true,
|
|
149
|
+
});
|
|
154
150
|
}
|
|
155
151
|
export async function removeUnexpectedLockfiles(targetDir, packageManagerId) {
|
|
156
152
|
const keep = new Set(LOCKFILES[packageManagerId] ?? []);
|
|
@@ -254,8 +250,13 @@ export async function applyWorkspaceMigrationCapability(projectDir, packageManag
|
|
|
254
250
|
* Applies a built-in scaffold into the target directory, including generated
|
|
255
251
|
* code artifacts, starter manifests, preset files, and placeholder rewrites.
|
|
256
252
|
*/
|
|
257
|
-
export async function applyBuiltInScaffoldProjectFiles({ projectDir, templateDir, templateId, variables, artifacts, codeArtifacts, readmeContent, gitignoreContent, allowExistingDir = false, packageManager, withMigrationUi = false, withTestPreset = false, withWpEnv = false, noInstall = false, installDependencies, repositoryReference, }) {
|
|
253
|
+
export async function applyBuiltInScaffoldProjectFiles({ projectDir, templateDir, templateId, variables, artifacts, codeArtifacts, readmeContent, gitignoreContent, allowExistingDir = false, packageManager, withMigrationUi = false, withTestPreset = false, withWpEnv = false, noInstall = false, installDependencies, repositoryReference, onProgress, }) {
|
|
258
254
|
await ensureDirectory(projectDir, allowExistingDir);
|
|
255
|
+
await reportScaffoldProgress(onProgress, {
|
|
256
|
+
detail: "Copying built-in template files and writing generated source modules.",
|
|
257
|
+
phase: "generate-files",
|
|
258
|
+
title: "Generating project files",
|
|
259
|
+
});
|
|
259
260
|
await copyInterpolatedDirectory(templateDir, projectDir, variables);
|
|
260
261
|
if (codeArtifacts && codeArtifacts.length > 0) {
|
|
261
262
|
await writeBuiltInCodeArtifacts(projectDir, codeArtifacts);
|
|
@@ -263,6 +264,11 @@ export async function applyBuiltInScaffoldProjectFiles({ projectDir, templateDir
|
|
|
263
264
|
if (artifacts && artifacts.length > 0) {
|
|
264
265
|
await writeBuiltInStructuralArtifacts(projectDir, artifacts);
|
|
265
266
|
}
|
|
267
|
+
await reportScaffoldProgress(onProgress, {
|
|
268
|
+
detail: "Writing starter manifests, local presets, and seeded template artifacts.",
|
|
269
|
+
phase: "seed-artifacts",
|
|
270
|
+
title: "Seeding scaffold artifacts",
|
|
271
|
+
});
|
|
266
272
|
await writeStarterManifestFiles(projectDir, templateId, variables, artifacts);
|
|
267
273
|
await seedBuiltInPersistenceArtifacts(projectDir, templateId, variables);
|
|
268
274
|
await applyLocalDevPresetFiles({
|
|
@@ -279,6 +285,11 @@ export async function applyBuiltInScaffoldProjectFiles({ projectDir, templateDir
|
|
|
279
285
|
variables,
|
|
280
286
|
});
|
|
281
287
|
}
|
|
288
|
+
await reportScaffoldProgress(onProgress, {
|
|
289
|
+
detail: "Writing README, normalizing package metadata, and aligning package-manager files.",
|
|
290
|
+
phase: "finalize-project",
|
|
291
|
+
title: "Finalizing scaffold output",
|
|
292
|
+
});
|
|
282
293
|
const readmePath = path.join(projectDir, "README.md");
|
|
283
294
|
if (!fs.existsSync(readmePath)) {
|
|
284
295
|
await fsp.writeFile(readmePath, readmeContent ??
|
|
@@ -302,12 +313,18 @@ export async function applyBuiltInScaffoldProjectFiles({ projectDir, templateDir
|
|
|
302
313
|
withTestPreset,
|
|
303
314
|
withWpEnv,
|
|
304
315
|
});
|
|
316
|
+
await removeQueryLoopPlaceholderFiles(projectDir, templateId);
|
|
305
317
|
await normalizePackageManagerFiles(projectDir, packageManager);
|
|
306
318
|
await removeUnexpectedLockfiles(projectDir, packageManager);
|
|
307
319
|
await replaceTextRecursively(projectDir, packageManager, {
|
|
308
320
|
repositoryReference,
|
|
309
321
|
});
|
|
310
322
|
if (!noInstall) {
|
|
323
|
+
await reportScaffoldProgress(onProgress, {
|
|
324
|
+
detail: "Installing project dependencies with the selected package manager.",
|
|
325
|
+
phase: "install-dependencies",
|
|
326
|
+
title: "Installing dependencies",
|
|
327
|
+
});
|
|
311
328
|
const installer = installDependencies ?? defaultInstallDependencies;
|
|
312
329
|
await installer({
|
|
313
330
|
projectDir,
|
|
@@ -9,6 +9,14 @@ import type { BuiltInTemplateId } from "./template-registry.js";
|
|
|
9
9
|
* @returns A promise that resolves once the directory precondition is satisfied.
|
|
10
10
|
*/
|
|
11
11
|
export declare function ensureScaffoldDirectory(targetDir: string, allowExisting?: boolean): Promise<void>;
|
|
12
|
+
/**
|
|
13
|
+
* Format the actionable error message used when a scaffold target directory
|
|
14
|
+
* already exists and is not empty.
|
|
15
|
+
*
|
|
16
|
+
* @param targetDir Absolute path to the target directory being evaluated.
|
|
17
|
+
* @returns A human-readable error string with next-step guidance.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatNonEmptyTargetDirectoryError(targetDir: string): string;
|
|
12
20
|
/**
|
|
13
21
|
* Writes built-in starter manifest files into a scaffolded project.
|
|
14
22
|
*
|
|
@@ -28,6 +36,13 @@ export declare function writeStarterManifestFiles(targetDir: string, templateId:
|
|
|
28
36
|
* @returns A promise that resolves after any required persistence artifacts are generated.
|
|
29
37
|
*/
|
|
30
38
|
export declare function seedBuiltInPersistenceArtifacts(targetDir: string, templateId: BuiltInTemplateId, variables: ScaffoldTemplateVariables): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Detects whether a scaffolded project declares the workspace project model.
|
|
41
|
+
*
|
|
42
|
+
* @param projectDir Absolute scaffold target directory.
|
|
43
|
+
* @returns `true` when the project metadata identifies a workspace scaffold.
|
|
44
|
+
*/
|
|
45
|
+
export declare function isWorkspaceProject(projectDir: string): boolean;
|
|
31
46
|
/**
|
|
32
47
|
* Detects whether a scaffolded project is the official workspace template.
|
|
33
48
|
*
|
|
@@ -25,9 +25,26 @@ export async function ensureScaffoldDirectory(targetDir, allowExisting = false)
|
|
|
25
25
|
}
|
|
26
26
|
const entries = await fsp.readdir(targetDir);
|
|
27
27
|
if (entries.length > 0) {
|
|
28
|
-
throw new Error(
|
|
28
|
+
throw new Error(formatNonEmptyTargetDirectoryError(targetDir));
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
|
+
function readGeneratedPackageJson(projectDir) {
|
|
32
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
33
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Format the actionable error message used when a scaffold target directory
|
|
40
|
+
* already exists and is not empty.
|
|
41
|
+
*
|
|
42
|
+
* @param targetDir Absolute path to the target directory being evaluated.
|
|
43
|
+
* @returns A human-readable error string with next-step guidance.
|
|
44
|
+
*/
|
|
45
|
+
export function formatNonEmptyTargetDirectoryError(targetDir) {
|
|
46
|
+
return `Target directory is not empty: ${targetDir}. Choose a new project directory, or empty this directory before rerunning the scaffold.`;
|
|
47
|
+
}
|
|
31
48
|
/**
|
|
32
49
|
* Writes built-in starter manifest files into a scaffolded project.
|
|
33
50
|
*
|
|
@@ -77,6 +94,15 @@ export async function seedBuiltInPersistenceArtifacts(targetDir, templateId, var
|
|
|
77
94
|
});
|
|
78
95
|
});
|
|
79
96
|
}
|
|
97
|
+
/**
|
|
98
|
+
* Detects whether a scaffolded project declares the workspace project model.
|
|
99
|
+
*
|
|
100
|
+
* @param projectDir Absolute scaffold target directory.
|
|
101
|
+
* @returns `true` when the project metadata identifies a workspace scaffold.
|
|
102
|
+
*/
|
|
103
|
+
export function isWorkspaceProject(projectDir) {
|
|
104
|
+
return readGeneratedPackageJson(projectDir)?.wpTypia?.projectType === "workspace";
|
|
105
|
+
}
|
|
80
106
|
/**
|
|
81
107
|
* Detects whether a scaffolded project is the official workspace template.
|
|
82
108
|
*
|
|
@@ -84,12 +110,8 @@ export async function seedBuiltInPersistenceArtifacts(targetDir, templateId, var
|
|
|
84
110
|
* @returns `true` when the project metadata identifies the official workspace template.
|
|
85
111
|
*/
|
|
86
112
|
export function isOfficialWorkspaceProject(projectDir) {
|
|
87
|
-
const
|
|
88
|
-
|
|
89
|
-
return false;
|
|
90
|
-
}
|
|
91
|
-
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
92
|
-
return (packageJson.wpTypia?.projectType === "workspace" &&
|
|
113
|
+
const packageJson = readGeneratedPackageJson(projectDir);
|
|
114
|
+
return (packageJson?.wpTypia?.projectType === "workspace" &&
|
|
93
115
|
packageJson.wpTypia?.templatePackage === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE);
|
|
94
116
|
}
|
|
95
117
|
/**
|
|
@@ -28,6 +28,7 @@ export function buildReadme(templateId, variables, packageManager, { withMigrati
|
|
|
28
28
|
slug: variables.slug,
|
|
29
29
|
});
|
|
30
30
|
const developmentScript = getPrimaryDevelopmentScript(templateId);
|
|
31
|
+
const noStepsHeading = templateId === 'query-loop' ? 'Variation Workflow' : 'Artifact Refresh';
|
|
31
32
|
const wpEnvSection = withWpEnv
|
|
32
33
|
? `## Local WordPress\n\n\`\`\`bash\n${formatRunScript(packageManager, 'wp-env:start')}\n${formatRunScript(packageManager, 'wp-env:stop')}\n${formatRunScript(packageManager, 'wp-env:reset')}\n\`\`\``
|
|
33
34
|
: '';
|
|
@@ -41,7 +42,7 @@ export function buildReadme(templateId, variables, packageManager, { withMigrati
|
|
|
41
42
|
? `## Advanced Sync\n\n\`\`\`bash\n${optionalOnboardingSteps.join('\n')}\n\`\`\`\n\n${getOptionalOnboardingNote(packageManager, templateId, {
|
|
42
43
|
compoundPersistenceEnabled,
|
|
43
44
|
})}`
|
|
44
|
-
: `##
|
|
45
|
+
: `## ${noStepsHeading}\n\n${getOptionalOnboardingNote(packageManager, templateId, {
|
|
45
46
|
compoundPersistenceEnabled,
|
|
46
47
|
})}`;
|
|
47
48
|
return `# ${variables.title}
|
|
@@ -41,7 +41,7 @@ export function getOptionalOnboardingSteps(packageManager, templateId, options =
|
|
|
41
41
|
*/
|
|
42
42
|
export function getQuickStartWorkflowNote(packageManager, templateId = "basic", options = {}) {
|
|
43
43
|
if (templateId === "query-loop") {
|
|
44
|
-
return `${formatRunScript(packageManager, "
|
|
44
|
+
return `${formatRunScript(packageManager, "dev")} runs the editor build/watch loop that registers your Query Loop variation in the block editor. This scaffold is editor-facing by design: update \`src/index.ts\` when you want to change the variation namespace, default query, allowed controls, or the minimal inline starter layout, update \`src/patterns/*.php\` when you want richer connected layout presets in the inserter, use \`src/query-extension.ts\` when the variation needs custom query params or optional editor-side hooks, and mirror frontend/editor preview query mapping in \`inc/query-runtime.php\`.`;
|
|
45
45
|
}
|
|
46
46
|
const developmentScript = getPrimaryDevelopmentScript(templateId);
|
|
47
47
|
const devCommand = formatRunScript(packageManager, developmentScript);
|
|
@@ -62,7 +62,7 @@ export function getQuickStartWorkflowNote(packageManager, templateId = "basic",
|
|
|
62
62
|
*/
|
|
63
63
|
export function getOptionalOnboardingNote(packageManager, templateId = "basic", options = {}) {
|
|
64
64
|
if (templateId === "query-loop") {
|
|
65
|
-
return `This scaffold does not generate \`block.json
|
|
65
|
+
return `This scaffold does not generate a \`sync\` script, \`block.json\`, or Typia manifests. Edit \`src/index.ts\` to change the variation contract, edit \`src/patterns/*.php\` when you want richer connected layouts beyond the inline fallback, edit \`src/query-extension.ts\` when you need variation-specific query params or custom editor hooks, and edit \`inc/query-runtime.php\` when those params need frontend or editor preview parity. Then rerun ${formatRunScript(packageManager, "build")}, ${formatRunScript(packageManager, "dev")}, or ${formatRunScript(packageManager, "typecheck")} as needed.`;
|
|
66
66
|
}
|
|
67
67
|
const optionalSyncScripts = getOptionalSyncScriptNames(templateId, options);
|
|
68
68
|
const hasUnifiedSync = optionalSyncScripts.includes("sync");
|
|
@@ -135,9 +135,13 @@ export function getCompoundExtensionWorkflowSection(packageManager, templateId)
|
|
|
135
135
|
|
|
136
136
|
\`\`\`bash
|
|
137
137
|
${formatRunScript(packageManager, "add-child", '--slug faq-item --title "FAQ Item"')}
|
|
138
|
+
|
|
139
|
+
${formatRunScript(packageManager, "add-child", '--slug section --title "Section" --container --inserter visible')}
|
|
140
|
+
|
|
141
|
+
${formatRunScript(packageManager, "add-child", '--slug clause --title "Clause" --ancestor section')}
|
|
138
142
|
\`\`\`
|
|
139
143
|
|
|
140
|
-
This scaffolds
|
|
144
|
+
This scaffolds additional compound child block types, updates \`scripts/block-config.ts\` and \`src/blocks/*/children.ts\`, and now supports root-level hidden children, visible container children, and nested ancestor chains for richer document-style block hierarchies.`;
|
|
141
145
|
}
|
|
142
146
|
function formatPhpRestExtensionPointsSection({ apiTypesPath, extraNote, mainPhpPath, mainPhpScope, transportPath, }) {
|
|
143
147
|
const schemaJsonGlob = apiTypesPath.replace(/api-types\.ts$/u, "api-schemas/*.schema.json");
|
|
@@ -38,7 +38,12 @@ export async function normalizePackageJson(targetDir, packageManagerId) {
|
|
|
38
38
|
}
|
|
39
39
|
const packageManager = getPackageManager(packageManagerId);
|
|
40
40
|
const packageJson = JSON.parse(await fsp.readFile(packageJsonPath, "utf8"));
|
|
41
|
-
|
|
41
|
+
if (packageManagerId === "npm") {
|
|
42
|
+
delete packageJson.packageManager;
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
packageJson.packageManager = packageManager.packageManagerField;
|
|
46
|
+
}
|
|
42
47
|
if (packageJson.scripts) {
|
|
43
48
|
for (const [key, value] of Object.entries(packageJson.scripts)) {
|
|
44
49
|
if (typeof value === "string") {
|
|
@@ -124,6 +124,11 @@ interface InstallDependenciesOptions {
|
|
|
124
124
|
packageManager: PackageManagerId;
|
|
125
125
|
projectDir: string;
|
|
126
126
|
}
|
|
127
|
+
export interface ScaffoldProgressEvent {
|
|
128
|
+
detail: string;
|
|
129
|
+
phase: "finalize-project" | "generate-files" | "install-dependencies" | "resolve-template" | "seed-artifacts";
|
|
130
|
+
title: string;
|
|
131
|
+
}
|
|
127
132
|
interface ScaffoldProjectOptions {
|
|
128
133
|
allowExistingDir?: boolean;
|
|
129
134
|
answers: ScaffoldAnswers;
|
|
@@ -134,6 +139,7 @@ interface ScaffoldProjectOptions {
|
|
|
134
139
|
externalLayerSourceLabel?: string;
|
|
135
140
|
installDependencies?: ((options: InstallDependenciesOptions) => Promise<void>) | undefined;
|
|
136
141
|
noInstall?: boolean;
|
|
142
|
+
onProgress?: ((event: ScaffoldProgressEvent) => void | Promise<void>) | undefined;
|
|
137
143
|
packageManager: PackageManagerId;
|
|
138
144
|
persistencePolicy?: PersistencePolicy;
|
|
139
145
|
projectDir: string;
|
|
@@ -157,4 +163,4 @@ export { collectScaffoldAnswers, detectAuthor, getDefaultAnswers, resolvePackage
|
|
|
157
163
|
export { getTemplateVariables } from "./scaffold-template-variables.js";
|
|
158
164
|
export declare function isDataStorageMode(value: string): value is DataStorageMode;
|
|
159
165
|
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>;
|
|
166
|
+
export declare function scaffoldProject({ projectDir, templateId, answers, 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,10 +2,10 @@ 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";
|
|
@@ -29,7 +29,10 @@ function normalizeTemplateSelection(templateId) {
|
|
|
29
29
|
? OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
|
|
30
30
|
: templateId;
|
|
31
31
|
}
|
|
32
|
-
|
|
32
|
+
async function reportScaffoldProgress(onProgress, event) {
|
|
33
|
+
await onProgress?.(event);
|
|
34
|
+
}
|
|
35
|
+
export async function scaffoldProject({ projectDir, templateId, answers, 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
36
|
const resolvedTemplateId = normalizeTemplateSelection(templateId);
|
|
34
37
|
const resolvedPackageManager = getPackageManager(packageManager).id;
|
|
35
38
|
const isBuiltInTemplate = isBuiltInTemplateId(resolvedTemplateId);
|
|
@@ -38,6 +41,11 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
38
41
|
}
|
|
39
42
|
if (isBuiltInTemplate) {
|
|
40
43
|
const blockGeneratorService = new BlockGeneratorService();
|
|
44
|
+
await reportScaffoldProgress(onProgress, {
|
|
45
|
+
detail: "Preparing template layers, variants, and generated artifact plans.",
|
|
46
|
+
phase: "resolve-template",
|
|
47
|
+
title: "Resolving scaffold template",
|
|
48
|
+
});
|
|
41
49
|
const plan = await blockGeneratorService.plan({
|
|
42
50
|
allowExistingDir,
|
|
43
51
|
answers,
|
|
@@ -61,6 +69,7 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
61
69
|
const rendered = await blockGeneratorService.render({ validated });
|
|
62
70
|
return blockGeneratorService.apply({
|
|
63
71
|
installDependencies,
|
|
72
|
+
onProgress,
|
|
64
73
|
rendered,
|
|
65
74
|
});
|
|
66
75
|
}
|
|
@@ -72,13 +81,25 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
72
81
|
dataStorageMode: dataStorageMode ?? answers.dataStorageMode,
|
|
73
82
|
persistencePolicy: persistencePolicy ?? answers.persistencePolicy,
|
|
74
83
|
});
|
|
84
|
+
await reportScaffoldProgress(onProgress, {
|
|
85
|
+
detail: "Loading template files, variants, and external package metadata when needed.",
|
|
86
|
+
phase: "resolve-template",
|
|
87
|
+
title: "Resolving scaffold template",
|
|
88
|
+
});
|
|
75
89
|
const templateSource = await resolveTemplateSource(resolvedTemplateId, cwd, variables, variant);
|
|
76
|
-
const supportsMigrationUi = isBuiltInTemplate ||
|
|
90
|
+
const supportsMigrationUi = isBuiltInTemplate ||
|
|
91
|
+
templateSource.isOfficialWorkspaceTemplate === true ||
|
|
92
|
+
templateSource.supportsMigrationUi === true;
|
|
77
93
|
if (withMigrationUi && !supportsMigrationUi) {
|
|
78
94
|
await templateSource.cleanup?.();
|
|
79
|
-
throw new Error("`--with-migration-ui` is currently supported only for built-in templates and
|
|
95
|
+
throw new Error("`--with-migration-ui` is currently supported only for built-in templates and workspace-capable wp-typia templates.");
|
|
80
96
|
}
|
|
81
97
|
try {
|
|
98
|
+
await reportScaffoldProgress(onProgress, {
|
|
99
|
+
detail: "Copying scaffold files into the target project directory.",
|
|
100
|
+
phase: "generate-files",
|
|
101
|
+
title: "Generating project files",
|
|
102
|
+
});
|
|
82
103
|
await ensureScaffoldDirectory(projectDir, allowExistingDir);
|
|
83
104
|
await copyInterpolatedDirectory(templateSource.templateDir, projectDir, variables);
|
|
84
105
|
}
|
|
@@ -87,8 +108,13 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
87
108
|
await templateSource.cleanup();
|
|
88
109
|
}
|
|
89
110
|
}
|
|
90
|
-
const
|
|
111
|
+
const isWorkspace = isWorkspaceProject(projectDir);
|
|
91
112
|
if (isBuiltInTemplate) {
|
|
113
|
+
await reportScaffoldProgress(onProgress, {
|
|
114
|
+
detail: "Writing starter manifests, local presets, and template-specific generated artifacts.",
|
|
115
|
+
phase: "seed-artifacts",
|
|
116
|
+
title: "Seeding scaffold artifacts",
|
|
117
|
+
});
|
|
92
118
|
await writeStarterManifestFiles(projectDir, resolvedTemplateId, variables);
|
|
93
119
|
await seedBuiltInPersistenceArtifacts(projectDir, resolvedTemplateId, variables);
|
|
94
120
|
await applyLocalDevPresetFiles({
|
|
@@ -105,14 +131,25 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
105
131
|
variables,
|
|
106
132
|
});
|
|
107
133
|
}
|
|
134
|
+
await removeQueryLoopPlaceholderFiles(projectDir, resolvedTemplateId);
|
|
108
135
|
}
|
|
109
|
-
else if (withMigrationUi &&
|
|
136
|
+
else if (withMigrationUi && isWorkspace) {
|
|
137
|
+
await reportScaffoldProgress(onProgress, {
|
|
138
|
+
detail: "Initializing workspace migration scripts and starter migration files.",
|
|
139
|
+
phase: "seed-artifacts",
|
|
140
|
+
title: "Seeding scaffold artifacts",
|
|
141
|
+
});
|
|
110
142
|
await applyWorkspaceMigrationCapability(projectDir, resolvedPackageManager);
|
|
111
143
|
}
|
|
144
|
+
await reportScaffoldProgress(onProgress, {
|
|
145
|
+
detail: "Writing README, normalizing package metadata, and aligning package-manager files.",
|
|
146
|
+
phase: "finalize-project",
|
|
147
|
+
title: "Finalizing scaffold output",
|
|
148
|
+
});
|
|
112
149
|
const readmePath = path.join(projectDir, "README.md");
|
|
113
150
|
if (!fs.existsSync(readmePath)) {
|
|
114
151
|
await fsp.writeFile(readmePath, buildReadme(resolvedTemplateId, variables, resolvedPackageManager, {
|
|
115
|
-
withMigrationUi: isBuiltInTemplate ||
|
|
152
|
+
withMigrationUi: isBuiltInTemplate || isWorkspace ? withMigrationUi : false,
|
|
116
153
|
withTestPreset: isBuiltInTemplate ? withTestPreset : false,
|
|
117
154
|
withWpEnv: isBuiltInTemplate ? withWpEnv : false,
|
|
118
155
|
}), "utf8");
|
|
@@ -139,6 +176,11 @@ export async function scaffoldProject({ projectDir, templateId, answers, dataSto
|
|
|
139
176
|
repositoryReference,
|
|
140
177
|
});
|
|
141
178
|
if (!noInstall) {
|
|
179
|
+
await reportScaffoldProgress(onProgress, {
|
|
180
|
+
detail: "Installing project dependencies with the selected package manager.",
|
|
181
|
+
phase: "install-dependencies",
|
|
182
|
+
title: "Installing dependencies",
|
|
183
|
+
});
|
|
142
184
|
const installer = installDependencies ?? defaultInstallDependencies;
|
|
143
185
|
await installer({
|
|
144
186
|
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;
|