@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
|
@@ -1,11 +1,83 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
|
+
import { promises as fsp } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
2
4
|
import path from "node:path";
|
|
3
5
|
import { collectScaffoldAnswers, DATA_STORAGE_MODES, PERSISTENCE_POLICIES, isDataStorageMode, isPersistencePolicy, resolvePackageManagerId, resolveTemplateId, scaffoldProject, } from "./scaffold.js";
|
|
6
|
+
import { parseAlternateRenderTargets } from "./alternate-render-targets.js";
|
|
7
|
+
import { parseCompoundInnerBlocksPreset } from "./compound-inner-blocks.js";
|
|
4
8
|
import { formatInstallCommand, formatRunScript, } from "./package-managers.js";
|
|
5
9
|
import { getPrimaryDevelopmentScript } from "./local-dev-presets.js";
|
|
6
10
|
import { getOptionalOnboardingNote, getOptionalOnboardingSteps, } from "./scaffold-onboarding.js";
|
|
11
|
+
import { formatNonEmptyTargetDirectoryError } from "./scaffold-bootstrap.js";
|
|
7
12
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, isBuiltInTemplateId, } from "./template-registry.js";
|
|
8
13
|
import { resolveOptionalInteractiveExternalLayerId, } from "./external-layer-selection.js";
|
|
14
|
+
import { assertBuiltInTemplateVariantAllowed, resolveLocalCliPathOption, normalizeOptionalCliString, } from "./cli-validation.js";
|
|
15
|
+
async function listRelativeProjectFiles(rootDir) {
|
|
16
|
+
const relativeFiles = [];
|
|
17
|
+
async function visit(currentDir) {
|
|
18
|
+
const entries = await fsp.readdir(currentDir, { withFileTypes: true });
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
21
|
+
if (entry.isDirectory()) {
|
|
22
|
+
await visit(absolutePath);
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
relativeFiles.push(path
|
|
26
|
+
.relative(rootDir, absolutePath)
|
|
27
|
+
.replace(path.sep === "\\" ? /\\/gu : /\//gu, "/"));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
await visit(rootDir);
|
|
31
|
+
return relativeFiles.sort((left, right) => left.localeCompare(right));
|
|
32
|
+
}
|
|
33
|
+
async function assertDryRunTargetDirectoryReady(projectDir, allowExistingDir) {
|
|
34
|
+
if (!fs.existsSync(projectDir) || allowExistingDir) {
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
const entries = await fsp.readdir(projectDir);
|
|
38
|
+
if (entries.length > 0) {
|
|
39
|
+
throw new Error(formatNonEmptyTargetDirectoryError(projectDir));
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async function buildScaffoldDryRunPlan({ allowExistingDir, alternateRenderTargets, answers, cwd, dataStorageMode, externalLayerId, externalLayerSource, externalLayerSourceLabel, installDependencies, noInstall, onProgress, packageManager, persistencePolicy, projectDir, templateId, variant, withMigrationUi, withTestPreset, withWpEnv, }) {
|
|
43
|
+
await assertDryRunTargetDirectoryReady(projectDir, allowExistingDir);
|
|
44
|
+
const tempRoot = await fsp.mkdtemp(path.join(os.tmpdir(), "wp-typia-scaffold-plan-"));
|
|
45
|
+
const previewProjectDir = path.join(tempRoot, "preview-project");
|
|
46
|
+
try {
|
|
47
|
+
const result = await scaffoldProject({
|
|
48
|
+
allowExistingDir: false,
|
|
49
|
+
alternateRenderTargets,
|
|
50
|
+
answers,
|
|
51
|
+
cwd,
|
|
52
|
+
dataStorageMode,
|
|
53
|
+
externalLayerId,
|
|
54
|
+
externalLayerSource,
|
|
55
|
+
externalLayerSourceLabel,
|
|
56
|
+
installDependencies,
|
|
57
|
+
noInstall: true,
|
|
58
|
+
onProgress,
|
|
59
|
+
packageManager,
|
|
60
|
+
persistencePolicy,
|
|
61
|
+
projectDir: previewProjectDir,
|
|
62
|
+
templateId,
|
|
63
|
+
variant,
|
|
64
|
+
withMigrationUi,
|
|
65
|
+
withTestPreset,
|
|
66
|
+
withWpEnv,
|
|
67
|
+
});
|
|
68
|
+
const files = await listRelativeProjectFiles(previewProjectDir);
|
|
69
|
+
return {
|
|
70
|
+
plan: {
|
|
71
|
+
dependencyInstall: noInstall ? "skipped-by-flag" : "would-install",
|
|
72
|
+
files,
|
|
73
|
+
},
|
|
74
|
+
result,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
await fsp.rm(tempRoot, { force: true, recursive: true });
|
|
79
|
+
}
|
|
80
|
+
}
|
|
9
81
|
function validateCreateProjectInput(projectInput) {
|
|
10
82
|
const normalizedProjectInput = projectInput.trim();
|
|
11
83
|
if (normalizedProjectInput.length === 0) {
|
|
@@ -41,14 +113,74 @@ function templateUsesPersistenceSettings(templateId, options) {
|
|
|
41
113
|
function templateSupportsPersistenceFlags(templateId) {
|
|
42
114
|
return templateId === "persistence" || templateId === "compound";
|
|
43
115
|
}
|
|
116
|
+
function templateSupportsCompoundInnerBlocksPreset(templateId) {
|
|
117
|
+
return templateId === "compound";
|
|
118
|
+
}
|
|
119
|
+
function createTemplateLabel(templateId) {
|
|
120
|
+
return templateId === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
|
|
121
|
+
? "`--template workspace`"
|
|
122
|
+
: `"${templateId}"`;
|
|
123
|
+
}
|
|
124
|
+
function collectTemplateCapabilityWarnings(options) {
|
|
125
|
+
const warnings = [];
|
|
126
|
+
const trimmedQueryPostType = options.queryPostType?.trim();
|
|
127
|
+
if (trimmedQueryPostType &&
|
|
128
|
+
options.templateId !== "query-loop" &&
|
|
129
|
+
(isBuiltInTemplateId(options.templateId) ||
|
|
130
|
+
options.templateId === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE)) {
|
|
131
|
+
warnings.push(`\`--query-post-type\` only applies to \`wp-typia create --template query-loop\`, which scaffolds a create-time \`core/query\` variation instead of a standalone block. ${createTemplateLabel(options.templateId)} will ignore "${trimmedQueryPostType}".`);
|
|
132
|
+
}
|
|
133
|
+
if (options.withMigrationUi === true &&
|
|
134
|
+
!isBuiltInTemplateId(options.templateId) &&
|
|
135
|
+
options.templateId !== OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
|
|
136
|
+
warnings.push(`\`--with-migration-ui\` was ignored for ${createTemplateLabel(options.templateId)}. Migration UI currently scaffolds built-in templates and the official \`--template workspace\` flow; external templates still need to opt into that surface explicitly.`);
|
|
137
|
+
}
|
|
138
|
+
return warnings;
|
|
139
|
+
}
|
|
140
|
+
function templateSupportsAlternateRenderTargets(options) {
|
|
141
|
+
if (!options.alternateRenderTargets) {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
if (options.templateId === "persistence") {
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
if (options.templateId !== "compound") {
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
150
|
+
return templateUsesPersistenceSettings(options.templateId, {
|
|
151
|
+
dataStorageMode: options.dataStorageMode,
|
|
152
|
+
persistencePolicy: options.persistencePolicy,
|
|
153
|
+
});
|
|
154
|
+
}
|
|
44
155
|
function validateCreateFlagContract(options) {
|
|
45
|
-
const { dataStorageMode, persistencePolicy, templateId, variant } = options;
|
|
156
|
+
const { alternateRenderTargets, dataStorageMode, innerBlocksPreset, persistencePolicy, templateId, variant, } = options;
|
|
46
157
|
if ((dataStorageMode || persistencePolicy) &&
|
|
47
158
|
!templateSupportsPersistenceFlags(templateId)) {
|
|
48
159
|
throw new Error("`--data-storage` and `--persistence-policy` are supported only for `wp-typia create --template persistence` or `--template compound`.");
|
|
49
160
|
}
|
|
50
|
-
if (
|
|
51
|
-
|
|
161
|
+
if (alternateRenderTargets &&
|
|
162
|
+
!templateSupportsAlternateRenderTargets({
|
|
163
|
+
alternateRenderTargets,
|
|
164
|
+
dataStorageMode,
|
|
165
|
+
persistencePolicy,
|
|
166
|
+
templateId,
|
|
167
|
+
})) {
|
|
168
|
+
if (templateId === "compound") {
|
|
169
|
+
throw new Error("`--alternate-render-targets` on `wp-typia create --template compound` requires the persistence-enabled server render path. Add `--data-storage <post-meta|custom-table>` or `--persistence-policy <authenticated|public>` first.");
|
|
170
|
+
}
|
|
171
|
+
throw new Error("`--alternate-render-targets` is supported only for `wp-typia create --template persistence` or persistence-enabled `--template compound` scaffolds.");
|
|
172
|
+
}
|
|
173
|
+
parseAlternateRenderTargets(alternateRenderTargets);
|
|
174
|
+
if (innerBlocksPreset &&
|
|
175
|
+
!templateSupportsCompoundInnerBlocksPreset(templateId)) {
|
|
176
|
+
throw new Error("`--inner-blocks-preset` is supported only for `wp-typia create --template compound`.");
|
|
177
|
+
}
|
|
178
|
+
parseCompoundInnerBlocksPreset(innerBlocksPreset);
|
|
179
|
+
if (isBuiltInTemplateId(templateId)) {
|
|
180
|
+
assertBuiltInTemplateVariantAllowed({
|
|
181
|
+
templateId,
|
|
182
|
+
variant,
|
|
183
|
+
});
|
|
52
184
|
}
|
|
53
185
|
}
|
|
54
186
|
function parseSelectableValue(label, value, isValue, allowedValues) {
|
|
@@ -135,14 +267,13 @@ export function getOptionalOnboarding({ availableScripts, packageManager, templa
|
|
|
135
267
|
* project.
|
|
136
268
|
* @returns The scaffold result together with next-step guidance.
|
|
137
269
|
*/
|
|
138
|
-
export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templateId, dataStorageMode, externalLayerId, externalLayerSource, persistencePolicy, packageManager, namespace, textDomain, phpPrefix, queryPostType, yes = false, noInstall = false, isInteractive = false, allowExistingDir = false, selectTemplate, selectDataStorage, selectExternalLayerId, selectPersistencePolicy, selectPackageManager, promptText, installDependencies = undefined, variant, selectWithTestPreset, selectWithWpEnv, selectWithMigrationUi, withMigrationUi, withTestPreset, withWpEnv, }) {
|
|
139
|
-
const normalizedExternalLayerId =
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
externalLayerSource
|
|
144
|
-
|
|
145
|
-
: undefined;
|
|
270
|
+
export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templateId, alternateRenderTargets, dataStorageMode, dryRun = false, externalLayerId, externalLayerSource, innerBlocksPreset, persistencePolicy, packageManager, namespace, textDomain, phpPrefix, queryPostType, yes = false, noInstall = false, onProgress, isInteractive = false, allowExistingDir = false, selectTemplate, selectDataStorage, selectExternalLayerId, selectPersistencePolicy, selectPackageManager, promptText, installDependencies = undefined, variant, selectWithTestPreset, selectWithWpEnv, selectWithMigrationUi, withMigrationUi, withTestPreset, withWpEnv, }) {
|
|
271
|
+
const normalizedExternalLayerId = normalizeOptionalCliString(externalLayerId);
|
|
272
|
+
const normalizedExternalLayerSource = resolveLocalCliPathOption({
|
|
273
|
+
cwd,
|
|
274
|
+
label: "--external-layer-source",
|
|
275
|
+
value: externalLayerSource,
|
|
276
|
+
});
|
|
146
277
|
validateCreateProjectInput(projectInput);
|
|
147
278
|
const resolvedTemplateId = await resolveTemplateId({
|
|
148
279
|
templateId,
|
|
@@ -151,11 +282,14 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
|
|
|
151
282
|
selectTemplate,
|
|
152
283
|
});
|
|
153
284
|
validateCreateFlagContract({
|
|
285
|
+
alternateRenderTargets,
|
|
154
286
|
dataStorageMode,
|
|
287
|
+
innerBlocksPreset,
|
|
155
288
|
persistencePolicy,
|
|
156
289
|
templateId: resolvedTemplateId,
|
|
157
290
|
variant,
|
|
158
291
|
});
|
|
292
|
+
const resolvedInnerBlocksPreset = parseCompoundInnerBlocksPreset(innerBlocksPreset);
|
|
159
293
|
const resolvedExternalLayerSelection = isBuiltInTemplateId(resolvedTemplateId) && isInteractive
|
|
160
294
|
? await resolveOptionalInteractiveExternalLayerId({
|
|
161
295
|
callerCwd: cwd,
|
|
@@ -234,47 +368,81 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
|
|
|
234
368
|
yes,
|
|
235
369
|
promptText,
|
|
236
370
|
});
|
|
237
|
-
|
|
238
|
-
answers
|
|
239
|
-
allowExistingDir,
|
|
240
|
-
cwd,
|
|
241
|
-
dataStorageMode: resolvedDataStorage,
|
|
242
|
-
externalLayerId: resolvedExternalLayerSelection.externalLayerId,
|
|
243
|
-
externalLayerSource: resolvedExternalLayerSelection.externalLayerSource,
|
|
244
|
-
externalLayerSourceLabel: normalizedExternalLayerSource,
|
|
245
|
-
installDependencies,
|
|
246
|
-
noInstall,
|
|
247
|
-
packageManager: resolvedPackageManager,
|
|
248
|
-
persistencePolicy: resolvedPersistencePolicy,
|
|
249
|
-
projectDir,
|
|
250
|
-
templateId: resolvedTemplateId,
|
|
251
|
-
variant,
|
|
252
|
-
withMigrationUi: resolvedWithMigrationUi,
|
|
253
|
-
withTestPreset: resolvedWithTestPreset,
|
|
254
|
-
withWpEnv: resolvedWithWpEnv,
|
|
255
|
-
});
|
|
256
|
-
let availableScripts;
|
|
257
|
-
try {
|
|
258
|
-
const parsedPackageJson = JSON.parse(fs.readFileSync(path.join(projectDir, "package.json"), "utf8"));
|
|
259
|
-
const scripts = parsedPackageJson.scripts &&
|
|
260
|
-
typeof parsedPackageJson.scripts === "object" &&
|
|
261
|
-
!Array.isArray(parsedPackageJson.scripts)
|
|
262
|
-
? parsedPackageJson.scripts
|
|
263
|
-
: {};
|
|
264
|
-
availableScripts = Object.entries(scripts)
|
|
265
|
-
.filter(([, value]) => typeof value === "string")
|
|
266
|
-
.map(([scriptName]) => scriptName);
|
|
371
|
+
if (resolvedTemplateId === "compound" && resolvedInnerBlocksPreset) {
|
|
372
|
+
answers.compoundInnerBlocksPreset = resolvedInnerBlocksPreset;
|
|
267
373
|
}
|
|
268
|
-
|
|
269
|
-
|
|
374
|
+
const resolvedResult = dryRun
|
|
375
|
+
? await buildScaffoldDryRunPlan({
|
|
376
|
+
allowExistingDir,
|
|
377
|
+
alternateRenderTargets,
|
|
378
|
+
answers,
|
|
379
|
+
cwd,
|
|
380
|
+
dataStorageMode: resolvedDataStorage,
|
|
381
|
+
externalLayerId: resolvedExternalLayerSelection.externalLayerId,
|
|
382
|
+
externalLayerSource: resolvedExternalLayerSelection.externalLayerSource,
|
|
383
|
+
externalLayerSourceLabel: normalizedExternalLayerSource,
|
|
384
|
+
installDependencies,
|
|
385
|
+
noInstall,
|
|
386
|
+
onProgress,
|
|
387
|
+
packageManager: resolvedPackageManager,
|
|
388
|
+
persistencePolicy: resolvedPersistencePolicy,
|
|
389
|
+
projectDir,
|
|
390
|
+
templateId: resolvedTemplateId,
|
|
391
|
+
variant,
|
|
392
|
+
withMigrationUi: resolvedWithMigrationUi,
|
|
393
|
+
withTestPreset: resolvedWithTestPreset,
|
|
394
|
+
withWpEnv: resolvedWithWpEnv,
|
|
395
|
+
})
|
|
396
|
+
: {
|
|
397
|
+
plan: undefined,
|
|
398
|
+
result: await scaffoldProject({
|
|
399
|
+
alternateRenderTargets,
|
|
400
|
+
answers,
|
|
401
|
+
allowExistingDir,
|
|
402
|
+
cwd,
|
|
403
|
+
dataStorageMode: resolvedDataStorage,
|
|
404
|
+
externalLayerId: resolvedExternalLayerSelection.externalLayerId,
|
|
405
|
+
externalLayerSource: resolvedExternalLayerSelection.externalLayerSource,
|
|
406
|
+
externalLayerSourceLabel: normalizedExternalLayerSource,
|
|
407
|
+
installDependencies,
|
|
408
|
+
noInstall,
|
|
409
|
+
onProgress,
|
|
410
|
+
packageManager: resolvedPackageManager,
|
|
411
|
+
persistencePolicy: resolvedPersistencePolicy,
|
|
412
|
+
projectDir,
|
|
413
|
+
templateId: resolvedTemplateId,
|
|
414
|
+
variant,
|
|
415
|
+
withMigrationUi: resolvedWithMigrationUi,
|
|
416
|
+
withTestPreset: resolvedWithTestPreset,
|
|
417
|
+
withWpEnv: resolvedWithWpEnv,
|
|
418
|
+
}),
|
|
419
|
+
};
|
|
420
|
+
let availableScripts;
|
|
421
|
+
if (!dryRun) {
|
|
422
|
+
try {
|
|
423
|
+
const parsedPackageJson = JSON.parse(fs.readFileSync(path.join(projectDir, "package.json"), "utf8"));
|
|
424
|
+
const scripts = parsedPackageJson.scripts &&
|
|
425
|
+
typeof parsedPackageJson.scripts === "object" &&
|
|
426
|
+
!Array.isArray(parsedPackageJson.scripts)
|
|
427
|
+
? parsedPackageJson.scripts
|
|
428
|
+
: {};
|
|
429
|
+
availableScripts = Object.entries(scripts)
|
|
430
|
+
.filter(([, value]) => typeof value === "string")
|
|
431
|
+
.map(([scriptName]) => scriptName);
|
|
432
|
+
}
|
|
433
|
+
catch {
|
|
434
|
+
availableScripts = undefined;
|
|
435
|
+
}
|
|
270
436
|
}
|
|
271
437
|
return {
|
|
438
|
+
dryRun,
|
|
272
439
|
optionalOnboarding: getOptionalOnboarding({
|
|
273
440
|
availableScripts,
|
|
274
441
|
packageManager: resolvedPackageManager,
|
|
275
442
|
templateId: resolvedTemplateId,
|
|
276
|
-
compoundPersistenceEnabled: result.variables.compoundPersistenceEnabled === "true",
|
|
443
|
+
compoundPersistenceEnabled: resolvedResult.result.variables.compoundPersistenceEnabled === "true",
|
|
277
444
|
}),
|
|
445
|
+
plan: resolvedResult.plan,
|
|
278
446
|
projectDir,
|
|
279
447
|
projectInput,
|
|
280
448
|
packageManager: resolvedPackageManager,
|
|
@@ -286,8 +454,16 @@ export async function runScaffoldFlow({ projectInput, cwd = process.cwd(), templ
|
|
|
286
454
|
templateId: resolvedTemplateId,
|
|
287
455
|
}),
|
|
288
456
|
result: {
|
|
289
|
-
...result,
|
|
290
|
-
warnings: [
|
|
457
|
+
...resolvedResult.result,
|
|
458
|
+
warnings: [
|
|
459
|
+
...resolvedResult.result.warnings,
|
|
460
|
+
...collectTemplateCapabilityWarnings({
|
|
461
|
+
queryPostType,
|
|
462
|
+
templateId: resolvedTemplateId,
|
|
463
|
+
withMigrationUi,
|
|
464
|
+
}),
|
|
465
|
+
...collectProjectDirectoryWarnings(projectDir),
|
|
466
|
+
],
|
|
291
467
|
},
|
|
292
468
|
};
|
|
293
469
|
}
|
|
@@ -8,18 +8,18 @@ import type { TemplateDefinition } from "./template-registry.js";
|
|
|
8
8
|
*/
|
|
9
9
|
export declare function formatTemplateSummary(template: TemplateDefinition): string;
|
|
10
10
|
/**
|
|
11
|
-
* Format the feature hint
|
|
11
|
+
* Format the feature and capability hint lines shown under a template summary.
|
|
12
12
|
*
|
|
13
13
|
* @param template Template metadata including the `features` list.
|
|
14
|
-
* @returns Indented feature text for CLI list output.
|
|
14
|
+
* @returns Indented feature and capability text for CLI list output.
|
|
15
15
|
*/
|
|
16
16
|
export declare function formatTemplateFeatures(template: TemplateDefinition): string;
|
|
17
17
|
/**
|
|
18
18
|
* Format the detailed template description for `templates inspect`.
|
|
19
19
|
*
|
|
20
20
|
* This expands special layer combinations for the `persistence` and `compound`
|
|
21
|
-
* templates and returns a multi-line block
|
|
22
|
-
*
|
|
21
|
+
* templates and returns a multi-line block centered on human-facing identity,
|
|
22
|
+
* capabilities, and logical layer composition.
|
|
23
23
|
*
|
|
24
24
|
* @param template Template metadata including `id`, `defaultCategory`,
|
|
25
25
|
* `templateDir`, and `features`.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
1
|
+
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, getTemplateById, getTemplateSelectOptions, isBuiltInTemplateId, listTemplates, } from "./template-registry.js";
|
|
2
|
+
const WORKSPACE_TEMPLATE_ALIAS = "workspace";
|
|
3
3
|
/**
|
|
4
4
|
* Format one line of template list output for a built-in template.
|
|
5
5
|
*
|
|
@@ -10,62 +10,127 @@ export function formatTemplateSummary(template) {
|
|
|
10
10
|
return `${template.id.padEnd(14)} ${template.description}`;
|
|
11
11
|
}
|
|
12
12
|
/**
|
|
13
|
-
* Format the feature hint
|
|
13
|
+
* Format the feature and capability hint lines shown under a template summary.
|
|
14
14
|
*
|
|
15
15
|
* @param template Template metadata including the `features` list.
|
|
16
|
-
* @returns Indented feature text for CLI list output.
|
|
16
|
+
* @returns Indented feature and capability text for CLI list output.
|
|
17
17
|
*/
|
|
18
18
|
export function formatTemplateFeatures(template) {
|
|
19
|
-
|
|
19
|
+
const lines = [` Features: ${template.features.join(" • ")}`];
|
|
20
|
+
const capabilityHints = getTemplateCapabilityHints(template);
|
|
21
|
+
if (capabilityHints.length > 0) {
|
|
22
|
+
lines.push(` Supports: ${capabilityHints.join(" • ")}`);
|
|
23
|
+
}
|
|
24
|
+
const specialNotes = getTemplateSpecialNotes(template);
|
|
25
|
+
if (specialNotes.length > 0) {
|
|
26
|
+
lines.push(` Notes: ${specialNotes.join(" • ")}`);
|
|
27
|
+
}
|
|
28
|
+
if (template.id === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
|
|
29
|
+
lines.push(` Alias: ${WORKSPACE_TEMPLATE_ALIAS} (\`--template ${WORKSPACE_TEMPLATE_ALIAS}\`)`);
|
|
30
|
+
}
|
|
31
|
+
return lines.join("\n");
|
|
20
32
|
}
|
|
21
33
|
/**
|
|
22
34
|
* Format the detailed template description for `templates inspect`.
|
|
23
35
|
*
|
|
24
36
|
* This expands special layer combinations for the `persistence` and `compound`
|
|
25
|
-
* templates and returns a multi-line block
|
|
26
|
-
*
|
|
37
|
+
* templates and returns a multi-line block centered on human-facing identity,
|
|
38
|
+
* capabilities, and logical layer composition.
|
|
27
39
|
*
|
|
28
40
|
* @param template Template metadata including `id`, `defaultCategory`,
|
|
29
41
|
* `templateDir`, and `features`.
|
|
30
42
|
* @returns Multi-line template details text for CLI output.
|
|
31
43
|
*/
|
|
32
44
|
export function formatTemplateDetails(template) {
|
|
45
|
+
const detailLines = [
|
|
46
|
+
template.id,
|
|
47
|
+
`Summary: ${template.description}`,
|
|
48
|
+
...getTemplateIdentityLines(template),
|
|
49
|
+
`Category: ${template.defaultCategory}`,
|
|
50
|
+
];
|
|
51
|
+
const capabilityHints = getTemplateCapabilityHints(template);
|
|
52
|
+
if (capabilityHints.length > 0) {
|
|
53
|
+
detailLines.push("Capabilities:");
|
|
54
|
+
for (const capabilityHint of capabilityHints) {
|
|
55
|
+
detailLines.push(` - ${capabilityHint}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
const specialNotes = getTemplateSpecialNotes(template);
|
|
59
|
+
if (specialNotes.length > 0) {
|
|
60
|
+
detailLines.push("Notes:");
|
|
61
|
+
for (const specialNote of specialNotes) {
|
|
62
|
+
detailLines.push(` - ${specialNote}`);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
detailLines.push("Logical layers:");
|
|
66
|
+
for (const logicalLayer of getTemplateLogicalLayerSummaries(template)) {
|
|
67
|
+
detailLines.push(` - ${logicalLayer}`);
|
|
68
|
+
}
|
|
69
|
+
detailLines.push(`Features: ${template.features.join(", ")}`);
|
|
70
|
+
return detailLines.join("\n");
|
|
71
|
+
}
|
|
72
|
+
function getTemplateCapabilityHints(template) {
|
|
73
|
+
if (template.id === "persistence" || template.id === "compound") {
|
|
74
|
+
return [
|
|
75
|
+
"--alternate-render-targets",
|
|
76
|
+
"--data-storage",
|
|
77
|
+
"--persistence-policy",
|
|
78
|
+
"external layers",
|
|
79
|
+
];
|
|
80
|
+
}
|
|
81
|
+
if (template.id === "query-loop") {
|
|
82
|
+
return ["--query-post-type", "external layers"];
|
|
83
|
+
}
|
|
84
|
+
if (isBuiltInTemplateId(template.id)) {
|
|
85
|
+
return ["external layers"];
|
|
86
|
+
}
|
|
87
|
+
return [];
|
|
88
|
+
}
|
|
89
|
+
function getTemplateSpecialNotes(template) {
|
|
90
|
+
if (template.id === "query-loop") {
|
|
91
|
+
return [
|
|
92
|
+
"Create-time variation scaffold only; use `wp-typia create <project-dir> --template query-loop` instead of `wp-typia add block`.",
|
|
93
|
+
"Owns a `core/query` variation, so it does not generate `src/types.ts`, `block.json`, or Typia manifests.",
|
|
94
|
+
];
|
|
95
|
+
}
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
function getTemplateIdentityLines(template) {
|
|
99
|
+
if (template.id === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
|
|
100
|
+
return [
|
|
101
|
+
"Identity:",
|
|
102
|
+
` - Official package: ${OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE}`,
|
|
103
|
+
` - Alias: ${WORKSPACE_TEMPLATE_ALIAS} (\`--template ${WORKSPACE_TEMPLATE_ALIAS}\`)`,
|
|
104
|
+
"Type: official workspace scaffold",
|
|
105
|
+
];
|
|
106
|
+
}
|
|
107
|
+
return [
|
|
108
|
+
"Identity:",
|
|
109
|
+
` - Built-in template id: ${template.id}`,
|
|
110
|
+
"Type: built-in block scaffold",
|
|
111
|
+
];
|
|
112
|
+
}
|
|
113
|
+
function getTemplateLogicalLayerSummaries(template) {
|
|
33
114
|
if (!isBuiltInTemplateId(template.id)) {
|
|
115
|
+
return ["workspace package scaffold"];
|
|
116
|
+
}
|
|
117
|
+
if (template.id === "persistence") {
|
|
118
|
+
return [
|
|
119
|
+
"authenticated write policy: shared/base -> rest helpers (shared) -> persistence core -> authenticated write policy -> persistence overlay",
|
|
120
|
+
"public write policy: shared/base -> rest helpers (shared) -> persistence core -> public write policy -> persistence overlay",
|
|
121
|
+
];
|
|
122
|
+
}
|
|
123
|
+
if (template.id === "compound") {
|
|
34
124
|
return [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"Layers: workspace package scaffold",
|
|
40
|
-
`Features: ${template.features.join(", ")}`,
|
|
41
|
-
].join("\n");
|
|
125
|
+
"pure block family: shared/base -> compound core -> compound overlay",
|
|
126
|
+
"authenticated persistence: shared/base -> compound core -> rest helpers (shared) -> compound persistence core -> authenticated write policy -> compound overlay",
|
|
127
|
+
"public persistence: shared/base -> compound core -> rest helpers (shared) -> compound persistence core -> public write policy -> compound overlay",
|
|
128
|
+
];
|
|
42
129
|
}
|
|
43
|
-
const
|
|
44
|
-
? [
|
|
45
|
-
`authenticated: ${getBuiltInTemplateLayerDirs(template.id, { persistencePolicy: "authenticated" }).join(" -> ")}`,
|
|
46
|
-
`public: ${getBuiltInTemplateLayerDirs(template.id, { persistencePolicy: "public" }).join(" -> ")}`,
|
|
47
|
-
]
|
|
48
|
-
: template.id === "compound"
|
|
49
|
-
? [
|
|
50
|
-
`pure: ${getBuiltInTemplateLayerDirs(template.id).join(" -> ")}`,
|
|
51
|
-
`authenticated+persistence: ${getBuiltInTemplateLayerDirs(template.id, {
|
|
52
|
-
persistenceEnabled: true,
|
|
53
|
-
persistencePolicy: "authenticated",
|
|
54
|
-
}).join(" -> ")}`,
|
|
55
|
-
`public+persistence: ${getBuiltInTemplateLayerDirs(template.id, {
|
|
56
|
-
persistenceEnabled: true,
|
|
57
|
-
persistencePolicy: "public",
|
|
58
|
-
}).join(" -> ")}`,
|
|
59
|
-
]
|
|
60
|
-
: [getBuiltInTemplateLayerDirs(template.id).join(" -> ")];
|
|
130
|
+
const overlayName = template.id === "query-loop" ? "query-loop overlay" : `${template.id} overlay`;
|
|
61
131
|
return [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
`Category: ${template.defaultCategory}`,
|
|
65
|
-
`Overlay path: ${template.templateDir}`,
|
|
66
|
-
`Layers: ${layers.join("\n")}`,
|
|
67
|
-
`Features: ${template.features.join(", ")}`,
|
|
68
|
-
].join("\n");
|
|
132
|
+
`shared/base -> ${overlayName}`,
|
|
133
|
+
];
|
|
69
134
|
}
|
|
70
135
|
export { getTemplateById, getTemplateSelectOptions, listTemplates };
|
|
71
136
|
export { isBuiltInTemplateId };
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Normalize one optional CLI string flag by trimming whitespace and collapsing
|
|
3
|
+
* empty strings to `undefined`.
|
|
4
|
+
*
|
|
5
|
+
* @param value Raw CLI value before normalization.
|
|
6
|
+
* @returns The trimmed string when present, otherwise `undefined`.
|
|
7
|
+
*/
|
|
8
|
+
export declare function normalizeOptionalCliString(value?: string): string | undefined;
|
|
9
|
+
/**
|
|
10
|
+
* Resolve one CLI path flag relative to the caller when it is expressed as a
|
|
11
|
+
* local filesystem path.
|
|
12
|
+
*
|
|
13
|
+
* Non-local values such as npm package specs or `github:` locators pass
|
|
14
|
+
* through unchanged. Local relative and absolute paths are resolved against the
|
|
15
|
+
* provided `cwd` and must exist on disk.
|
|
16
|
+
*
|
|
17
|
+
* @param options Path resolution inputs for one CLI flag.
|
|
18
|
+
* @param options.cwd Caller working directory used for relative path
|
|
19
|
+
* resolution.
|
|
20
|
+
* @param options.label Human-readable option label used in thrown errors.
|
|
21
|
+
* @param options.value Raw CLI value before trimming and path resolution.
|
|
22
|
+
* @returns The normalized string, or `undefined` when the option was omitted.
|
|
23
|
+
* @throws When a local-looking path resolves to a missing filesystem entry.
|
|
24
|
+
*/
|
|
25
|
+
export declare function resolveLocalCliPathOption(options: {
|
|
26
|
+
cwd: string;
|
|
27
|
+
label: string;
|
|
28
|
+
value?: string;
|
|
29
|
+
}): string | undefined;
|
|
30
|
+
/**
|
|
31
|
+
* Validate the built-in template composition rule for external layers.
|
|
32
|
+
*
|
|
33
|
+
* @param options External layer CLI options after normalization.
|
|
34
|
+
* @param options.externalLayerId Optional selected layer id.
|
|
35
|
+
* @param options.externalLayerSource Optional layer source locator or path.
|
|
36
|
+
* @throws When `externalLayerId` is provided without `externalLayerSource`.
|
|
37
|
+
*/
|
|
38
|
+
export declare function assertExternalLayerCompositionOptions(options: {
|
|
39
|
+
externalLayerId?: string;
|
|
40
|
+
externalLayerSource?: string;
|
|
41
|
+
}): void;
|
|
42
|
+
/**
|
|
43
|
+
* Build the shared error message used when a built-in template receives a
|
|
44
|
+
* `--variant` override.
|
|
45
|
+
*
|
|
46
|
+
* @param options Built-in template context.
|
|
47
|
+
* @param options.templateId Built-in template id that rejected the variant.
|
|
48
|
+
* @param options.variant User-supplied variant override.
|
|
49
|
+
* @returns The canonical user-facing error message.
|
|
50
|
+
*/
|
|
51
|
+
export declare function createBuiltInVariantErrorMessage(options: {
|
|
52
|
+
templateId: string;
|
|
53
|
+
variant: string;
|
|
54
|
+
}): string;
|
|
55
|
+
/**
|
|
56
|
+
* Reject unsupported `--variant` usage for built-in templates.
|
|
57
|
+
*
|
|
58
|
+
* @param options Built-in template validation context.
|
|
59
|
+
* @param options.templateId Built-in template id being scaffolded.
|
|
60
|
+
* @param options.variant Optional variant override from CLI flags.
|
|
61
|
+
* @throws When a built-in template receives any explicit `--variant` value.
|
|
62
|
+
*/
|
|
63
|
+
export declare function assertBuiltInTemplateVariantAllowed(options: {
|
|
64
|
+
templateId: string;
|
|
65
|
+
variant?: string;
|
|
66
|
+
}): void;
|