@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
|
@@ -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
|
: '';
|
|
@@ -37,6 +38,13 @@ export function buildReadme(templateId, variables, packageManager, { withMigrati
|
|
|
37
38
|
const migrationSection = withMigrationUi
|
|
38
39
|
? `## Migration UI\n\nThis scaffold already includes an initialized migration workspace at \`v1\`, generated deprecated/runtime artifacts, and an editor-embedded migration dashboard. Migration versions are schema lineage labels and are separate from your package or plugin release version. Use the existing CLI commands to snapshot, diff, scaffold, verify, and fuzz future schema changes.\n\n\`\`\`bash\n${formatRunScript(packageManager, 'migration:doctor')}\n${formatRunScript(packageManager, 'migration:verify')}\n${formatRunScript(packageManager, 'migration:fuzz')}\n\`\`\`\n\nRun \`migration:init\` only when retrofitting migration support into an older project that was not scaffolded with \`--with-migration-ui\`.`
|
|
39
40
|
: '';
|
|
41
|
+
const advancedSyncSection = optionalOnboardingSteps.length > 0
|
|
42
|
+
? `## Advanced Sync\n\n\`\`\`bash\n${optionalOnboardingSteps.join('\n')}\n\`\`\`\n\n${getOptionalOnboardingNote(packageManager, templateId, {
|
|
43
|
+
compoundPersistenceEnabled,
|
|
44
|
+
})}`
|
|
45
|
+
: `## ${noStepsHeading}\n\n${getOptionalOnboardingNote(packageManager, templateId, {
|
|
46
|
+
compoundPersistenceEnabled,
|
|
47
|
+
})}`;
|
|
40
48
|
return `# ${variables.title}
|
|
41
49
|
|
|
42
50
|
${variables.description}
|
|
@@ -63,15 +71,7 @@ ${formatRunScript(packageManager, 'build')}
|
|
|
63
71
|
${formatRunScript(packageManager, 'typecheck')}
|
|
64
72
|
\`\`\`
|
|
65
73
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
\`\`\`bash
|
|
69
|
-
${optionalOnboardingSteps.join('\n')}
|
|
70
|
-
\`\`\`
|
|
71
|
-
|
|
72
|
-
${getOptionalOnboardingNote(packageManager, templateId, {
|
|
73
|
-
compoundPersistenceEnabled,
|
|
74
|
-
})}
|
|
74
|
+
${advancedSyncSection}
|
|
75
75
|
|
|
76
76
|
## Before First Commit
|
|
77
77
|
|
|
@@ -13,6 +13,9 @@ function templateHasPersistenceSync(templateId, { compoundPersistenceEnabled = f
|
|
|
13
13
|
* Returns the optional sync script names to suggest for a template.
|
|
14
14
|
*/
|
|
15
15
|
export function getOptionalSyncScriptNames(templateId, options = {}) {
|
|
16
|
+
if (templateId === "query-loop") {
|
|
17
|
+
return [];
|
|
18
|
+
}
|
|
16
19
|
const availableScripts = new Set(options.availableScripts ?? []);
|
|
17
20
|
if (availableScripts.has("sync")) {
|
|
18
21
|
return ["sync"];
|
|
@@ -37,6 +40,9 @@ export function getOptionalOnboardingSteps(packageManager, templateId, options =
|
|
|
37
40
|
* Returns the quick-start note explaining the scaffold's primary local loop.
|
|
38
41
|
*/
|
|
39
42
|
export function getQuickStartWorkflowNote(packageManager, templateId = "basic", options = {}) {
|
|
43
|
+
if (templateId === "query-loop") {
|
|
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
|
+
}
|
|
40
46
|
const developmentScript = getPrimaryDevelopmentScript(templateId);
|
|
41
47
|
const devCommand = formatRunScript(packageManager, developmentScript);
|
|
42
48
|
const startCommand = formatRunScript(packageManager, "start");
|
|
@@ -55,6 +61,9 @@ export function getQuickStartWorkflowNote(packageManager, templateId = "basic",
|
|
|
55
61
|
* Returns the onboarding note explaining when manual sync is optional.
|
|
56
62
|
*/
|
|
57
63
|
export function getOptionalOnboardingNote(packageManager, templateId = "basic", options = {}) {
|
|
64
|
+
if (templateId === "query-loop") {
|
|
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
|
+
}
|
|
58
67
|
const optionalSyncScripts = getOptionalSyncScriptNames(templateId, options);
|
|
59
68
|
const hasUnifiedSync = optionalSyncScripts.includes("sync");
|
|
60
69
|
const syncSteps = optionalSyncScripts.map((scriptName) => formatRunScript(packageManager, scriptName));
|
|
@@ -100,6 +109,9 @@ export function getInitialCommitNote() {
|
|
|
100
109
|
* Returns source-of-truth guidance for generated artifacts by template mode.
|
|
101
110
|
*/
|
|
102
111
|
export function getTemplateSourceOfTruthNote(templateId, { compoundPersistenceEnabled = false } = {}) {
|
|
112
|
+
if (templateId === "query-loop") {
|
|
113
|
+
return "`src/index.ts` remains the source of truth for the Query Loop variation name, default query attributes, `allowedControls`, and the minimal inline starter `innerBlocks`. Use `src/patterns/*.php` for richer connected layout presets that stay tied to the same variation namespace, use `src/query-extension.ts` for custom query seed values or optional editor-only hook registration, and use `inc/query-runtime.php` to keep frontend and editor preview query mapping aligned for those custom keys. The generated plugin bootstrap should stay focused on script registration, pattern loading, and explicit runtime glue for the variation.";
|
|
114
|
+
}
|
|
103
115
|
if (templateId === "compound") {
|
|
104
116
|
const compoundBase = "`src/blocks/*/types.ts` files remain the source of truth for each block's `block.json`, `typia.manifest.json`, and `typia-validator.php`. Fresh scaffolds include starter `typia.manifest.json` files so editor imports resolve before the first sync.";
|
|
105
117
|
if (compoundPersistenceEnabled) {
|
|
@@ -123,9 +135,13 @@ export function getCompoundExtensionWorkflowSection(packageManager, templateId)
|
|
|
123
135
|
|
|
124
136
|
\`\`\`bash
|
|
125
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')}
|
|
126
142
|
\`\`\`
|
|
127
143
|
|
|
128
|
-
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.`;
|
|
129
145
|
}
|
|
130
146
|
function formatPhpRestExtensionPointsSection({ apiTypesPath, extraNote, mainPhpPath, mainPhpScope, transportPath, }) {
|
|
131
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") {
|
|
@@ -73,7 +73,13 @@ export function getTemplateVariables(templateId, answers) {
|
|
|
73
73
|
dataStorageMode,
|
|
74
74
|
dashCase: slug,
|
|
75
75
|
description,
|
|
76
|
+
descriptionJson: JSON.stringify(description),
|
|
76
77
|
frontendCssClassName: buildFrontendCssClassName(cssClassName),
|
|
78
|
+
queryAllowedControlsJson: JSON.stringify([], null, 2),
|
|
79
|
+
queryPostType: answers.queryPostType?.trim() || 'post',
|
|
80
|
+
queryPostTypeJson: JSON.stringify(answers.queryPostType?.trim() || 'post'),
|
|
81
|
+
queryVariationNamespace: `${namespace}/${slug}`,
|
|
82
|
+
queryVariationNamespaceJson: JSON.stringify(`${namespace}/${slug}`),
|
|
77
83
|
isAuthenticatedPersistencePolicy: persistencePolicy === 'authenticated' ? 'true' : 'false',
|
|
78
84
|
isPublicPersistencePolicy: persistencePolicy === 'public' ? 'true' : 'false',
|
|
79
85
|
bootstrapCredentialDeclarations: persistencePolicy === 'public'
|
|
@@ -15,6 +15,7 @@ export interface ScaffoldAnswers {
|
|
|
15
15
|
persistencePolicy?: PersistencePolicy;
|
|
16
16
|
/** Snake_case PHP symbol prefix used for generated functions, constants, and keys. */
|
|
17
17
|
phpPrefix?: string;
|
|
18
|
+
queryPostType?: string;
|
|
18
19
|
slug: string;
|
|
19
20
|
/** Kebab-case WordPress text domain used in block metadata and i18n strings. */
|
|
20
21
|
textDomain?: string;
|
|
@@ -46,6 +47,7 @@ export interface ScaffoldTemplateVariables extends Record<string, string> {
|
|
|
46
47
|
dashCase: string;
|
|
47
48
|
dataStorageMode: DataStorageMode;
|
|
48
49
|
description: string;
|
|
50
|
+
descriptionJson: string;
|
|
49
51
|
frontendCssClassName: string;
|
|
50
52
|
keyword: string;
|
|
51
53
|
namespace: string;
|
|
@@ -53,6 +55,11 @@ export interface ScaffoldTemplateVariables extends Record<string, string> {
|
|
|
53
55
|
pascalCase: string;
|
|
54
56
|
phpPrefix: string;
|
|
55
57
|
phpPrefixUpper: string;
|
|
58
|
+
queryAllowedControlsJson: string;
|
|
59
|
+
queryPostTypeJson: string;
|
|
60
|
+
queryPostType: string;
|
|
61
|
+
queryVariationNamespace: string;
|
|
62
|
+
queryVariationNamespaceJson: string;
|
|
56
63
|
isAuthenticatedPersistencePolicy: "false" | "true";
|
|
57
64
|
isPublicPersistencePolicy: "false" | "true";
|
|
58
65
|
bootstrapCredentialDeclarations: string;
|
|
@@ -106,6 +113,7 @@ export interface CollectScaffoldAnswersOptions {
|
|
|
106
113
|
projectName: string;
|
|
107
114
|
promptText?: (message: string, defaultValue: string, validate?: (value: string) => true | string) => Promise<string>;
|
|
108
115
|
persistencePolicy?: PersistencePolicy;
|
|
116
|
+
queryPostType?: string;
|
|
109
117
|
textDomain?: string;
|
|
110
118
|
templateId: string;
|
|
111
119
|
withTestPreset?: boolean;
|
|
@@ -116,6 +124,11 @@ interface InstallDependenciesOptions {
|
|
|
116
124
|
packageManager: PackageManagerId;
|
|
117
125
|
projectDir: string;
|
|
118
126
|
}
|
|
127
|
+
export interface ScaffoldProgressEvent {
|
|
128
|
+
detail: string;
|
|
129
|
+
phase: "finalize-project" | "generate-files" | "install-dependencies" | "resolve-template" | "seed-artifacts";
|
|
130
|
+
title: string;
|
|
131
|
+
}
|
|
119
132
|
interface ScaffoldProjectOptions {
|
|
120
133
|
allowExistingDir?: boolean;
|
|
121
134
|
answers: ScaffoldAnswers;
|
|
@@ -126,6 +139,7 @@ interface ScaffoldProjectOptions {
|
|
|
126
139
|
externalLayerSourceLabel?: string;
|
|
127
140
|
installDependencies?: ((options: InstallDependenciesOptions) => Promise<void>) | undefined;
|
|
128
141
|
noInstall?: boolean;
|
|
142
|
+
onProgress?: ((event: ScaffoldProgressEvent) => void | Promise<void>) | undefined;
|
|
129
143
|
packageManager: PackageManagerId;
|
|
130
144
|
persistencePolicy?: PersistencePolicy;
|
|
131
145
|
projectDir: string;
|
|
@@ -149,4 +163,4 @@ export { collectScaffoldAnswers, detectAuthor, getDefaultAnswers, resolvePackage
|
|
|
149
163
|
export { getTemplateVariables } from "./scaffold-template-variables.js";
|
|
150
164
|
export declare function isDataStorageMode(value: string): value is DataStorageMode;
|
|
151
165
|
export declare function isPersistencePolicy(value: string): value is PersistencePolicy;
|
|
152
|
-
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,
|
|
@@ -22,6 +22,10 @@ export declare const BUILTIN_TEMPLATE_METADATA_DEFAULTS: Readonly<{
|
|
|
22
22
|
category: "widgets";
|
|
23
23
|
icon: "screenoptions";
|
|
24
24
|
}>;
|
|
25
|
+
"query-loop": Readonly<{
|
|
26
|
+
category: "widgets";
|
|
27
|
+
icon: "query-pagination";
|
|
28
|
+
}>;
|
|
25
29
|
}>;
|
|
26
30
|
/**
|
|
27
31
|
* Shared hidden child block metadata defaults for compound scaffolds.
|
|
@@ -56,6 +60,9 @@ export declare function getBuiltInTemplateMetadataDefaults(templateId: keyof typ
|
|
|
56
60
|
}> | Readonly<{
|
|
57
61
|
category: "widgets";
|
|
58
62
|
icon: "screenoptions";
|
|
63
|
+
}> | Readonly<{
|
|
64
|
+
category: "widgets";
|
|
65
|
+
icon: "query-pagination";
|
|
59
66
|
}>;
|
|
60
67
|
/**
|
|
61
68
|
* Checks whether a template id points at a removed built-in scaffold.
|
|
@@ -22,6 +22,10 @@ export const BUILTIN_TEMPLATE_METADATA_DEFAULTS = Object.freeze({
|
|
|
22
22
|
category: "widgets",
|
|
23
23
|
icon: "screenoptions",
|
|
24
24
|
}),
|
|
25
|
+
"query-loop": Object.freeze({
|
|
26
|
+
category: "widgets",
|
|
27
|
+
icon: "query-pagination",
|
|
28
|
+
}),
|
|
25
29
|
});
|
|
26
30
|
/**
|
|
27
31
|
* Shared hidden child block metadata defaults for compound scaffolds.
|
|
@@ -14,7 +14,7 @@ export declare const SHARED_MIGRATION_UI_TEMPLATE_ROOT: string;
|
|
|
14
14
|
export declare const SHARED_WORKSPACE_TEMPLATE_ROOT: string;
|
|
15
15
|
export declare const SHARED_TEST_PRESET_TEMPLATE_ROOT: string;
|
|
16
16
|
export declare const SHARED_WP_ENV_PRESET_TEMPLATE_ROOT: string;
|
|
17
|
-
export declare const BUILTIN_TEMPLATE_IDS: readonly ["basic", "interactivity", "persistence", "compound"];
|
|
17
|
+
export declare const BUILTIN_TEMPLATE_IDS: readonly ["basic", "interactivity", "persistence", "compound", "query-loop"];
|
|
18
18
|
export declare const OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE = "@wp-typia/create-workspace-template";
|
|
19
19
|
export type BuiltInTemplateId = (typeof BUILTIN_TEMPLATE_IDS)[number];
|
|
20
20
|
export type PersistencePolicy = "authenticated" | "public";
|
|
@@ -40,7 +40,13 @@ export const SHARED_MIGRATION_UI_TEMPLATE_ROOT = path.join(SHARED_TEMPLATE_ROOT,
|
|
|
40
40
|
export const SHARED_WORKSPACE_TEMPLATE_ROOT = path.join(SHARED_TEMPLATE_ROOT, "workspace");
|
|
41
41
|
export const SHARED_TEST_PRESET_TEMPLATE_ROOT = path.join(SHARED_PRESET_TEMPLATE_ROOT, "test-preset");
|
|
42
42
|
export const SHARED_WP_ENV_PRESET_TEMPLATE_ROOT = path.join(SHARED_PRESET_TEMPLATE_ROOT, "wp-env");
|
|
43
|
-
export const BUILTIN_TEMPLATE_IDS = [
|
|
43
|
+
export const BUILTIN_TEMPLATE_IDS = [
|
|
44
|
+
"basic",
|
|
45
|
+
"interactivity",
|
|
46
|
+
"persistence",
|
|
47
|
+
"compound",
|
|
48
|
+
"query-loop",
|
|
49
|
+
];
|
|
44
50
|
export const OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE = "@wp-typia/create-workspace-template";
|
|
45
51
|
export const TEMPLATE_REGISTRY = Object.freeze([
|
|
46
52
|
{
|
|
@@ -71,6 +77,13 @@ export const TEMPLATE_REGISTRY = Object.freeze([
|
|
|
71
77
|
features: ["InnerBlocks", "Hidden child blocks", "Optional persistence layer"],
|
|
72
78
|
templateDir: path.join(TEMPLATE_ROOT, "compound"),
|
|
73
79
|
},
|
|
80
|
+
{
|
|
81
|
+
id: "query-loop",
|
|
82
|
+
description: "A Query Loop block variation scaffold with stable namespace-based identity, inline starter layout, connected pattern presets, custom query seams, and runtime parity hooks",
|
|
83
|
+
defaultCategory: getBuiltInTemplateMetadataDefaults("query-loop").category,
|
|
84
|
+
features: ["core/query variation", "Default innerBlocks", "Connected patterns", "Custom query hooks", "Runtime parity hooks", "Allowed controls"],
|
|
85
|
+
templateDir: path.join(TEMPLATE_ROOT, "query-loop"),
|
|
86
|
+
},
|
|
74
87
|
{
|
|
75
88
|
id: OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE,
|
|
76
89
|
description: "The official empty workspace template that powers `wp-typia add ...` workflows",
|
|
@@ -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
|
*
|