@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
|
@@ -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,102 @@ 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
|
+
if (template.id === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
|
|
25
|
+
lines.push(` Alias: ${WORKSPACE_TEMPLATE_ALIAS} (\`--template ${WORKSPACE_TEMPLATE_ALIAS}\`)`);
|
|
26
|
+
}
|
|
27
|
+
return lines.join("\n");
|
|
20
28
|
}
|
|
21
29
|
/**
|
|
22
30
|
* Format the detailed template description for `templates inspect`.
|
|
23
31
|
*
|
|
24
32
|
* This expands special layer combinations for the `persistence` and `compound`
|
|
25
|
-
* templates and returns a multi-line block
|
|
26
|
-
*
|
|
33
|
+
* templates and returns a multi-line block centered on human-facing identity,
|
|
34
|
+
* capabilities, and logical layer composition.
|
|
27
35
|
*
|
|
28
36
|
* @param template Template metadata including `id`, `defaultCategory`,
|
|
29
37
|
* `templateDir`, and `features`.
|
|
30
38
|
* @returns Multi-line template details text for CLI output.
|
|
31
39
|
*/
|
|
32
40
|
export function formatTemplateDetails(template) {
|
|
41
|
+
const detailLines = [
|
|
42
|
+
template.id,
|
|
43
|
+
`Summary: ${template.description}`,
|
|
44
|
+
...getTemplateIdentityLines(template),
|
|
45
|
+
`Category: ${template.defaultCategory}`,
|
|
46
|
+
];
|
|
47
|
+
const capabilityHints = getTemplateCapabilityHints(template);
|
|
48
|
+
if (capabilityHints.length > 0) {
|
|
49
|
+
detailLines.push("Capabilities:");
|
|
50
|
+
for (const capabilityHint of capabilityHints) {
|
|
51
|
+
detailLines.push(` - ${capabilityHint}`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
detailLines.push("Logical layers:");
|
|
55
|
+
for (const logicalLayer of getTemplateLogicalLayerSummaries(template)) {
|
|
56
|
+
detailLines.push(` - ${logicalLayer}`);
|
|
57
|
+
}
|
|
58
|
+
detailLines.push(`Features: ${template.features.join(", ")}`);
|
|
59
|
+
return detailLines.join("\n");
|
|
60
|
+
}
|
|
61
|
+
function getTemplateCapabilityHints(template) {
|
|
62
|
+
if (template.id === "persistence" || template.id === "compound") {
|
|
63
|
+
return ["--data-storage", "--persistence-policy", "external layers"];
|
|
64
|
+
}
|
|
65
|
+
if (template.id === "query-loop") {
|
|
66
|
+
return ["--query-post-type", "external layers"];
|
|
67
|
+
}
|
|
68
|
+
if (isBuiltInTemplateId(template.id)) {
|
|
69
|
+
return ["external layers"];
|
|
70
|
+
}
|
|
71
|
+
return [];
|
|
72
|
+
}
|
|
73
|
+
function getTemplateIdentityLines(template) {
|
|
74
|
+
if (template.id === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
|
|
75
|
+
return [
|
|
76
|
+
"Identity:",
|
|
77
|
+
` - Official package: ${OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE}`,
|
|
78
|
+
` - Alias: ${WORKSPACE_TEMPLATE_ALIAS} (\`--template ${WORKSPACE_TEMPLATE_ALIAS}\`)`,
|
|
79
|
+
"Type: official workspace scaffold",
|
|
80
|
+
];
|
|
81
|
+
}
|
|
82
|
+
return [
|
|
83
|
+
"Identity:",
|
|
84
|
+
` - Built-in template id: ${template.id}`,
|
|
85
|
+
"Type: built-in block scaffold",
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
function getTemplateLogicalLayerSummaries(template) {
|
|
33
89
|
if (!isBuiltInTemplateId(template.id)) {
|
|
90
|
+
return ["workspace package scaffold"];
|
|
91
|
+
}
|
|
92
|
+
if (template.id === "persistence") {
|
|
93
|
+
return [
|
|
94
|
+
"authenticated write policy: shared/base -> rest helpers (shared) -> persistence core -> authenticated write policy -> persistence overlay",
|
|
95
|
+
"public write policy: shared/base -> rest helpers (shared) -> persistence core -> public write policy -> persistence overlay",
|
|
96
|
+
];
|
|
97
|
+
}
|
|
98
|
+
if (template.id === "compound") {
|
|
34
99
|
return [
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
"Layers: workspace package scaffold",
|
|
40
|
-
`Features: ${template.features.join(", ")}`,
|
|
41
|
-
].join("\n");
|
|
100
|
+
"pure block family: shared/base -> compound core -> compound overlay",
|
|
101
|
+
"authenticated persistence: shared/base -> compound core -> rest helpers (shared) -> compound persistence core -> authenticated write policy -> compound overlay",
|
|
102
|
+
"public persistence: shared/base -> compound core -> rest helpers (shared) -> compound persistence core -> public write policy -> compound overlay",
|
|
103
|
+
];
|
|
42
104
|
}
|
|
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(" -> ")];
|
|
105
|
+
const overlayName = template.id === "query-loop" ? "query-loop overlay" : `${template.id} overlay`;
|
|
61
106
|
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");
|
|
107
|
+
`shared/base -> ${overlayName}`,
|
|
108
|
+
];
|
|
69
109
|
}
|
|
70
110
|
export { getTemplateById, getTemplateSelectOptions, listTemplates };
|
|
71
111
|
export { isBuiltInTemplateId };
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* Consumers should prefer these exports for scaffold, add, migrate, doctor,
|
|
7
7
|
* and workspace-aware helpers such as `getWorkspaceBlockSelectOptions`,
|
|
8
8
|
* `runAddBlockCommand`, `runAddVariationCommand`, `runAddPatternCommand`,
|
|
9
|
-
* `runAddBindingSourceCommand`, `
|
|
9
|
+
* `runAddBindingSourceCommand`, `runAddEditorPluginCommand`,
|
|
10
|
+
* `runAddHookedBlockCommand`,
|
|
10
11
|
* `HOOKED_BLOCK_POSITION_IDS`, and `runDoctor`.
|
|
11
12
|
*/
|
|
12
13
|
export { scaffoldProject, collectScaffoldAnswers, getDefaultAnswers, getTemplateVariables, resolvePackageManagerId, resolveTemplateId, } from "./scaffold.js";
|
|
@@ -21,5 +22,5 @@ export { buildCompoundChildStarterManifestDocument, getStarterManifestFiles, str
|
|
|
21
22
|
export type { EndpointAuthIntent, EndpointOpenApiAuthMode, EndpointOpenApiContractDocument, EndpointOpenApiDocumentOptions, EndpointOpenApiEndpointDefinition, EndpointOpenApiMethod, EndpointWordPressAuthDefinition, EndpointWordPressAuthMechanism, JsonSchemaDocument, JsonSchemaProjectionProfile, JsonSchemaObject, NormalizedEndpointAuthDefinition, OpenApiDocument, OpenApiInfo, OpenApiOperation, OpenApiParameter, OpenApiPathItem, OpenApiSecurityScheme, } from "./schema-core.js";
|
|
22
23
|
export { PACKAGE_MANAGER_IDS, PACKAGE_MANAGERS, formatPackageExecCommand, formatInstallCommand, formatRunScript, getPackageManager, getPackageManagerSelectOptions, transformPackageManagerText, } from "./package-managers.js";
|
|
23
24
|
export { TEMPLATE_IDS, TEMPLATE_REGISTRY, getTemplateById, getTemplateSelectOptions, listTemplates, } from "./template-registry.js";
|
|
24
|
-
export { createReadlinePrompt, createCliCommandError, CliDiagnosticError, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, isCliDiagnosticError, runAddBindingSourceCommand, runAddBlockCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
25
|
-
export type { CliDiagnosticMessage, DoctorCheck, HookedBlockPositionId, ReadlinePrompt, } from "./cli-core.js";
|
|
25
|
+
export { createReadlinePrompt, createCliCommandError, CliDiagnosticError, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, EDITOR_PLUGIN_SLOT_IDS, isCliDiagnosticError, runAddBindingSourceCommand, runAddBlockCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
26
|
+
export type { CliDiagnosticMessage, DoctorCheck, EditorPluginSlotId, HookedBlockPositionId, ReadlinePrompt, } from "./cli-core.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -6,7 +6,8 @@
|
|
|
6
6
|
* Consumers should prefer these exports for scaffold, add, migrate, doctor,
|
|
7
7
|
* and workspace-aware helpers such as `getWorkspaceBlockSelectOptions`,
|
|
8
8
|
* `runAddBlockCommand`, `runAddVariationCommand`, `runAddPatternCommand`,
|
|
9
|
-
* `runAddBindingSourceCommand`, `
|
|
9
|
+
* `runAddBindingSourceCommand`, `runAddEditorPluginCommand`,
|
|
10
|
+
* `runAddHookedBlockCommand`,
|
|
10
11
|
* `HOOKED_BLOCK_POSITION_IDS`, and `runDoctor`.
|
|
11
12
|
*/
|
|
12
13
|
export { scaffoldProject, collectScaffoldAnswers, getDefaultAnswers, getTemplateVariables, resolvePackageManagerId, resolveTemplateId, } from "./scaffold.js";
|
|
@@ -18,4 +19,4 @@ export { manifestAttributeToJsonSchema, projectJsonSchemaDocument, manifestToJso
|
|
|
18
19
|
export { buildCompoundChildStarterManifestDocument, getStarterManifestFiles, stringifyStarterManifest, } from "./starter-manifests.js";
|
|
19
20
|
export { PACKAGE_MANAGER_IDS, PACKAGE_MANAGERS, formatPackageExecCommand, formatInstallCommand, formatRunScript, getPackageManager, getPackageManagerSelectOptions, transformPackageManagerText, } from "./package-managers.js";
|
|
20
21
|
export { TEMPLATE_IDS, TEMPLATE_REGISTRY, getTemplateById, getTemplateSelectOptions, listTemplates, } from "./template-registry.js";
|
|
21
|
-
export { createReadlinePrompt, createCliCommandError, CliDiagnosticError, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, isCliDiagnosticError, runAddBindingSourceCommand, runAddBlockCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
22
|
+
export { createReadlinePrompt, createCliCommandError, CliDiagnosticError, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, EDITOR_PLUGIN_SLOT_IDS, isCliDiagnosticError, runAddBindingSourceCommand, runAddBlockCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
@@ -8,7 +8,7 @@ import fs from "node:fs";
|
|
|
8
8
|
import { promises as fsp } from "node:fs";
|
|
9
9
|
import path from "node:path";
|
|
10
10
|
import { formatRunScript, } from "./package-managers.js";
|
|
11
|
-
import { SHARED_TEST_PRESET_TEMPLATE_ROOT, SHARED_WP_ENV_PRESET_TEMPLATE_ROOT, } from "./template-registry.js";
|
|
11
|
+
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, SHARED_TEST_PRESET_TEMPLATE_ROOT, SHARED_WP_ENV_PRESET_TEMPLATE_ROOT, } from "./template-registry.js";
|
|
12
12
|
import { copyInterpolatedDirectory } from "./template-render.js";
|
|
13
13
|
function templateHasPersistenceSync(templateId, compoundPersistenceEnabled) {
|
|
14
14
|
return templateId === "persistence" || (templateId === "compound" && compoundPersistenceEnabled);
|
|
@@ -19,6 +19,11 @@ function templateSupportsGeneratedSyncWatchers(templateId) {
|
|
|
19
19
|
templateId === "persistence" ||
|
|
20
20
|
templateId === "compound");
|
|
21
21
|
}
|
|
22
|
+
function templateUsesDevAsPrimaryEntrypoint(templateId) {
|
|
23
|
+
return (templateSupportsGeneratedSyncWatchers(templateId) ||
|
|
24
|
+
templateId === "query-loop" ||
|
|
25
|
+
templateId === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE);
|
|
26
|
+
}
|
|
22
27
|
function getWatchSyncTypesScript(packageManager, templateId) {
|
|
23
28
|
if (templateId === "compound") {
|
|
24
29
|
return `chokidar "src/blocks/**/types.ts" "scripts/block-config.ts" --debounce 200 -c "${formatRunScript(packageManager, "sync-types")}"`;
|
|
@@ -138,5 +143,5 @@ export async function applyGeneratedProjectDxPackageJson({ compoundPersistenceEn
|
|
|
138
143
|
* scaffolded template.
|
|
139
144
|
*/
|
|
140
145
|
export function getPrimaryDevelopmentScript(templateId) {
|
|
141
|
-
return
|
|
146
|
+
return templateUsesDevAsPrimaryEntrypoint(templateId) ? "dev" : "start";
|
|
142
147
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import type { RestResourceMethodId } from "./cli-add-shared.js";
|
|
2
|
+
interface RestResourceTemplateVariablesLike {
|
|
3
|
+
namespace: string;
|
|
4
|
+
pascalCase: string;
|
|
5
|
+
slugKebabCase: string;
|
|
6
|
+
title: string;
|
|
7
|
+
}
|
|
8
|
+
interface SyncRestResourceArtifactsOptions {
|
|
9
|
+
clientFile: string;
|
|
10
|
+
methods: RestResourceMethodId[];
|
|
11
|
+
outputDir: string;
|
|
12
|
+
projectDir: string;
|
|
13
|
+
typesFile: string;
|
|
14
|
+
validatorsFile: string;
|
|
15
|
+
variables: RestResourceTemplateVariablesLike;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Build the endpoint manifest for a workspace-level REST resource scaffold.
|
|
19
|
+
*
|
|
20
|
+
* @param variables Template naming data used for contract names, routes, and OpenAPI info.
|
|
21
|
+
* @param methods Enabled REST methods for the generated resource.
|
|
22
|
+
* @returns Endpoint manifest consumed by schema, OpenAPI, and client generators.
|
|
23
|
+
*/
|
|
24
|
+
export declare function buildRestResourceEndpointManifest(variables: RestResourceTemplateVariablesLike, methods: RestResourceMethodId[]): import("@wp-typia/block-runtime/metadata-core").EndpointManifestDefinition<Record<string, {
|
|
25
|
+
sourceTypeName: string;
|
|
26
|
+
}>, import("@wp-typia/block-runtime/schema-core").EndpointOpenApiEndpointDefinition[]>;
|
|
27
|
+
/**
|
|
28
|
+
* Synchronize generated schemas, OpenAPI output, and endpoint client code for
|
|
29
|
+
* a workspace-level REST resource scaffold.
|
|
30
|
+
*
|
|
31
|
+
* @param options Resource file paths, enabled methods, and naming variables.
|
|
32
|
+
* @returns A promise that resolves after every generated REST artifact has been refreshed.
|
|
33
|
+
*/
|
|
34
|
+
export declare function syncRestResourceArtifacts({ clientFile, methods, outputDir, projectDir, typesFile, validatorsFile, variables, }: SyncRestResourceArtifactsOptions): Promise<void>;
|
|
35
|
+
export {};
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { defineEndpointManifest, syncEndpointClient, syncRestOpenApi, syncTypeSchemas, } from "@wp-typia/block-runtime/metadata-core";
|
|
3
|
+
/**
|
|
4
|
+
* Build the endpoint manifest for a workspace-level REST resource scaffold.
|
|
5
|
+
*
|
|
6
|
+
* @param variables Template naming data used for contract names, routes, and OpenAPI info.
|
|
7
|
+
* @param methods Enabled REST methods for the generated resource.
|
|
8
|
+
* @returns Endpoint manifest consumed by schema, OpenAPI, and client generators.
|
|
9
|
+
*/
|
|
10
|
+
export function buildRestResourceEndpointManifest(variables, methods) {
|
|
11
|
+
const basePath = `/${variables.namespace}/${variables.slugKebabCase}`;
|
|
12
|
+
const itemPath = `${basePath}/item`;
|
|
13
|
+
const contracts = {};
|
|
14
|
+
const endpoints = [];
|
|
15
|
+
if (methods.includes("list")) {
|
|
16
|
+
contracts["list-query"] = {
|
|
17
|
+
sourceTypeName: `${variables.pascalCase}ListQuery`,
|
|
18
|
+
};
|
|
19
|
+
contracts["list-response"] = {
|
|
20
|
+
sourceTypeName: `${variables.pascalCase}ListResponse`,
|
|
21
|
+
};
|
|
22
|
+
endpoints.push({
|
|
23
|
+
auth: "public",
|
|
24
|
+
method: "GET",
|
|
25
|
+
operationId: `list${variables.pascalCase}Resources`,
|
|
26
|
+
path: basePath,
|
|
27
|
+
queryContract: "list-query",
|
|
28
|
+
responseContract: "list-response",
|
|
29
|
+
summary: `List ${variables.title} resources.`,
|
|
30
|
+
tags: [variables.title],
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
if (methods.includes("read")) {
|
|
34
|
+
contracts["read-query"] = {
|
|
35
|
+
sourceTypeName: `${variables.pascalCase}ReadQuery`,
|
|
36
|
+
};
|
|
37
|
+
contracts["read-response"] = {
|
|
38
|
+
sourceTypeName: `${variables.pascalCase}ReadResponse`,
|
|
39
|
+
};
|
|
40
|
+
endpoints.push({
|
|
41
|
+
auth: "public",
|
|
42
|
+
method: "GET",
|
|
43
|
+
operationId: `read${variables.pascalCase}Resource`,
|
|
44
|
+
path: itemPath,
|
|
45
|
+
queryContract: "read-query",
|
|
46
|
+
responseContract: "read-response",
|
|
47
|
+
summary: `Read one ${variables.title} resource.`,
|
|
48
|
+
tags: [variables.title],
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
if (methods.includes("create")) {
|
|
52
|
+
contracts["create-request"] = {
|
|
53
|
+
sourceTypeName: `${variables.pascalCase}CreateRequest`,
|
|
54
|
+
};
|
|
55
|
+
contracts["create-response"] = {
|
|
56
|
+
sourceTypeName: `${variables.pascalCase}CreateResponse`,
|
|
57
|
+
};
|
|
58
|
+
endpoints.push({
|
|
59
|
+
auth: "authenticated",
|
|
60
|
+
bodyContract: "create-request",
|
|
61
|
+
method: "POST",
|
|
62
|
+
operationId: `create${variables.pascalCase}Resource`,
|
|
63
|
+
path: basePath,
|
|
64
|
+
responseContract: "create-response",
|
|
65
|
+
summary: `Create one ${variables.title} resource.`,
|
|
66
|
+
tags: [variables.title],
|
|
67
|
+
wordpressAuth: {
|
|
68
|
+
mechanism: "rest-nonce",
|
|
69
|
+
},
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
if (methods.includes("update")) {
|
|
73
|
+
contracts["update-query"] = {
|
|
74
|
+
sourceTypeName: `${variables.pascalCase}UpdateQuery`,
|
|
75
|
+
};
|
|
76
|
+
contracts["update-request"] = {
|
|
77
|
+
sourceTypeName: `${variables.pascalCase}UpdateRequest`,
|
|
78
|
+
};
|
|
79
|
+
contracts["update-response"] = {
|
|
80
|
+
sourceTypeName: `${variables.pascalCase}UpdateResponse`,
|
|
81
|
+
};
|
|
82
|
+
endpoints.push({
|
|
83
|
+
auth: "authenticated",
|
|
84
|
+
bodyContract: "update-request",
|
|
85
|
+
method: "POST",
|
|
86
|
+
operationId: `update${variables.pascalCase}Resource`,
|
|
87
|
+
path: itemPath,
|
|
88
|
+
queryContract: "update-query",
|
|
89
|
+
responseContract: "update-response",
|
|
90
|
+
summary: `Update one ${variables.title} resource.`,
|
|
91
|
+
tags: [variables.title],
|
|
92
|
+
wordpressAuth: {
|
|
93
|
+
mechanism: "rest-nonce",
|
|
94
|
+
},
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
if (methods.includes("delete")) {
|
|
98
|
+
contracts["delete-query"] = {
|
|
99
|
+
sourceTypeName: `${variables.pascalCase}DeleteQuery`,
|
|
100
|
+
};
|
|
101
|
+
contracts["delete-response"] = {
|
|
102
|
+
sourceTypeName: `${variables.pascalCase}DeleteResponse`,
|
|
103
|
+
};
|
|
104
|
+
endpoints.push({
|
|
105
|
+
auth: "authenticated",
|
|
106
|
+
method: "DELETE",
|
|
107
|
+
operationId: `delete${variables.pascalCase}Resource`,
|
|
108
|
+
path: itemPath,
|
|
109
|
+
queryContract: "delete-query",
|
|
110
|
+
responseContract: "delete-response",
|
|
111
|
+
summary: `Delete one ${variables.title} resource.`,
|
|
112
|
+
tags: [variables.title],
|
|
113
|
+
wordpressAuth: {
|
|
114
|
+
mechanism: "rest-nonce",
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
return defineEndpointManifest({
|
|
119
|
+
contracts,
|
|
120
|
+
endpoints,
|
|
121
|
+
info: {
|
|
122
|
+
title: `${variables.title} REST API`,
|
|
123
|
+
version: "1.0.0",
|
|
124
|
+
},
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Synchronize generated schemas, OpenAPI output, and endpoint client code for
|
|
129
|
+
* a workspace-level REST resource scaffold.
|
|
130
|
+
*
|
|
131
|
+
* @param options Resource file paths, enabled methods, and naming variables.
|
|
132
|
+
* @returns A promise that resolves after every generated REST artifact has been refreshed.
|
|
133
|
+
*/
|
|
134
|
+
export async function syncRestResourceArtifacts({ clientFile, methods, outputDir, projectDir, typesFile, validatorsFile, variables, }) {
|
|
135
|
+
const manifest = buildRestResourceEndpointManifest(variables, methods);
|
|
136
|
+
for (const [baseName, contract] of Object.entries(manifest.contracts)) {
|
|
137
|
+
await syncTypeSchemas({
|
|
138
|
+
jsonSchemaFile: path.join(outputDir, "api-schemas", `${baseName}.schema.json`),
|
|
139
|
+
openApiFile: path.join(outputDir, "api-schemas", `${baseName}.openapi.json`),
|
|
140
|
+
projectRoot: projectDir,
|
|
141
|
+
sourceTypeName: contract.sourceTypeName,
|
|
142
|
+
typesFile,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
await syncRestOpenApi({
|
|
146
|
+
manifest,
|
|
147
|
+
openApiFile: path.join(outputDir, "api.openapi.json"),
|
|
148
|
+
projectRoot: projectDir,
|
|
149
|
+
typesFile,
|
|
150
|
+
});
|
|
151
|
+
await syncEndpointClient({
|
|
152
|
+
clientFile,
|
|
153
|
+
manifest,
|
|
154
|
+
projectRoot: projectDir,
|
|
155
|
+
typesFile,
|
|
156
|
+
validatorsFile,
|
|
157
|
+
});
|
|
158
|
+
}
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
1
2
|
import { PACKAGE_MANAGER_IDS, getPackageManager, } from './package-managers.js';
|
|
2
3
|
import { normalizeBlockSlug, resolveScaffoldIdentifiers, validateBlockSlug, validateNamespace, } from './scaffold-identifiers.js';
|
|
3
4
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, TEMPLATE_IDS, getTemplateById, isBuiltInTemplateId, } from './template-registry.js';
|
|
4
5
|
import { getRemovedBuiltInTemplateMessage, isRemovedBuiltInTemplateId, } from './template-defaults.js';
|
|
5
6
|
import { toSnakeCase, toTitleCase, } from './string-case.js';
|
|
6
7
|
const WORKSPACE_TEMPLATE_ALIAS = 'workspace';
|
|
8
|
+
const TEMPLATE_SELECTION_HINT = `--template <${[
|
|
9
|
+
...TEMPLATE_IDS,
|
|
10
|
+
WORKSPACE_TEMPLATE_ALIAS,
|
|
11
|
+
].join('|')}|./path|github:owner/repo/path[#ref]|npm-package>`;
|
|
12
|
+
const TEMPLATE_SUGGESTION_IDS = [...TEMPLATE_IDS, WORKSPACE_TEMPLATE_ALIAS];
|
|
7
13
|
/**
|
|
8
14
|
* Detect the current author name from local Git config.
|
|
9
15
|
*
|
|
@@ -68,6 +74,60 @@ function normalizeTemplateSelection(templateId) {
|
|
|
68
74
|
? OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
|
|
69
75
|
: templateId;
|
|
70
76
|
}
|
|
77
|
+
function looksLikeExplicitExternalTemplateLocator(templateId) {
|
|
78
|
+
return (templateId.startsWith('./') ||
|
|
79
|
+
templateId.startsWith('../') ||
|
|
80
|
+
templateId.startsWith('/') ||
|
|
81
|
+
templateId.startsWith('@') ||
|
|
82
|
+
templateId.startsWith('github:') ||
|
|
83
|
+
templateId.includes('/'));
|
|
84
|
+
}
|
|
85
|
+
function getEditDistance(left, right) {
|
|
86
|
+
const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
87
|
+
const current = new Array(right.length + 1);
|
|
88
|
+
for (let leftIndex = 0; leftIndex < left.length; leftIndex += 1) {
|
|
89
|
+
current[0] = leftIndex + 1;
|
|
90
|
+
for (let rightIndex = 0; rightIndex < right.length; rightIndex += 1) {
|
|
91
|
+
const substitutionCost = left[leftIndex] === right[rightIndex] ? 0 : 1;
|
|
92
|
+
current[rightIndex + 1] = Math.min(current[rightIndex] + 1, previous[rightIndex + 1] + 1, previous[rightIndex] + substitutionCost);
|
|
93
|
+
}
|
|
94
|
+
for (let index = 0; index < current.length; index += 1) {
|
|
95
|
+
previous[index] = current[index];
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return previous[right.length];
|
|
99
|
+
}
|
|
100
|
+
function findMistypedBuiltInTemplateSuggestion(templateId) {
|
|
101
|
+
const normalizedTemplateId = templateId.trim().toLowerCase();
|
|
102
|
+
if (normalizedTemplateId.length === 0 ||
|
|
103
|
+
looksLikeExplicitExternalTemplateLocator(normalizedTemplateId)) {
|
|
104
|
+
return null;
|
|
105
|
+
}
|
|
106
|
+
let bestCandidate = null;
|
|
107
|
+
for (const candidateId of TEMPLATE_SUGGESTION_IDS) {
|
|
108
|
+
const distance = getEditDistance(normalizedTemplateId, candidateId);
|
|
109
|
+
if (bestCandidate === null ||
|
|
110
|
+
distance < bestCandidate.distance) {
|
|
111
|
+
bestCandidate = {
|
|
112
|
+
distance,
|
|
113
|
+
id: candidateId,
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return bestCandidate && bestCandidate.distance <= 2
|
|
118
|
+
? bestCandidate.id
|
|
119
|
+
: null;
|
|
120
|
+
}
|
|
121
|
+
function getMistypedBuiltInTemplateMessage(templateId) {
|
|
122
|
+
const suggestion = findMistypedBuiltInTemplateSuggestion(templateId);
|
|
123
|
+
if (!suggestion) {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
const suggestionDescription = suggestion === WORKSPACE_TEMPLATE_ALIAS
|
|
127
|
+
? 'official workspace scaffold'
|
|
128
|
+
: 'built-in scaffold';
|
|
129
|
+
return `Unknown template "${templateId}". Did you mean "${suggestion}"? Use \`--template ${suggestion}\` for the ${suggestionDescription}, or pass a local path, \`github:owner/repo/path[#ref]\`, or an npm package spec for an external template.`;
|
|
130
|
+
}
|
|
71
131
|
/**
|
|
72
132
|
* Resolve the scaffold template id from flags, defaults, and interactive selection.
|
|
73
133
|
*
|
|
@@ -80,16 +140,23 @@ export async function resolveTemplateId({ templateId, yes = false, isInteractive
|
|
|
80
140
|
if (isRemovedBuiltInTemplateId(templateId)) {
|
|
81
141
|
throw new Error(getRemovedBuiltInTemplateMessage(templateId));
|
|
82
142
|
}
|
|
143
|
+
if (normalizedTemplateId === OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE) {
|
|
144
|
+
return normalizedTemplateId;
|
|
145
|
+
}
|
|
83
146
|
if (isBuiltInTemplateId(normalizedTemplateId)) {
|
|
84
147
|
return getTemplateById(normalizedTemplateId).id;
|
|
85
148
|
}
|
|
149
|
+
const mistypedBuiltInTemplateMessage = getMistypedBuiltInTemplateMessage(templateId);
|
|
150
|
+
if (mistypedBuiltInTemplateMessage) {
|
|
151
|
+
throw new Error(mistypedBuiltInTemplateMessage);
|
|
152
|
+
}
|
|
86
153
|
return normalizedTemplateId;
|
|
87
154
|
}
|
|
88
155
|
if (yes) {
|
|
89
156
|
return 'basic';
|
|
90
157
|
}
|
|
91
158
|
if (!isInteractive || !selectTemplate) {
|
|
92
|
-
throw new Error(`Template is required in non-interactive mode. Use
|
|
159
|
+
throw new Error(`Template is required in non-interactive mode. Use ${TEMPLATE_SELECTION_HINT}.`);
|
|
93
160
|
}
|
|
94
161
|
return normalizeTemplateSelection(await selectTemplate());
|
|
95
162
|
}
|
|
@@ -160,4 +227,3 @@ export async function collectScaffoldAnswers({ projectName, templateId, yes = fa
|
|
|
160
227
|
title: await promptText('Block title', toTitleCase(identifiers.slug)),
|
|
161
228
|
};
|
|
162
229
|
}
|
|
163
|
-
import { execSync } from 'node:child_process';
|
|
@@ -2,7 +2,7 @@ import { type BuiltInBlockArtifact } from "./built-in-block-artifacts.js";
|
|
|
2
2
|
import type { BuiltInCodeArtifact } from "./built-in-block-code-artifacts.js";
|
|
3
3
|
import { type BuiltInTemplateId } from "./template-registry.js";
|
|
4
4
|
import type { PackageManagerId } from "./package-managers.js";
|
|
5
|
-
import type { ScaffoldTemplateVariables } from "./scaffold.js";
|
|
5
|
+
import type { ScaffoldProgressEvent, ScaffoldTemplateVariables } from "./scaffold.js";
|
|
6
6
|
export { buildGitignore, buildReadme, mergeTextLines, } from "./scaffold-documents.js";
|
|
7
7
|
export interface InstallDependenciesOptions {
|
|
8
8
|
packageManager: PackageManagerId;
|
|
@@ -16,7 +16,7 @@ export declare function writeStarterManifestFiles(targetDir: string, templateId:
|
|
|
16
16
|
*/
|
|
17
17
|
export declare function seedBuiltInPersistenceArtifacts(targetDir: string, templateId: BuiltInTemplateId, variables: ScaffoldTemplateVariables): Promise<void>;
|
|
18
18
|
export declare function normalizePackageManagerFiles(targetDir: string, packageManagerId: PackageManagerId): Promise<void>;
|
|
19
|
-
export declare function
|
|
19
|
+
export declare function removeQueryLoopPlaceholderFiles(projectDir: string, templateId: string): Promise<void>;
|
|
20
20
|
export declare function removeUnexpectedLockfiles(targetDir: string, packageManagerId: PackageManagerId): Promise<void>;
|
|
21
21
|
/**
|
|
22
22
|
* Recursively normalizes generated text files for the selected package manager
|
|
@@ -33,7 +33,7 @@ export declare function applyWorkspaceMigrationCapability(projectDir: string, pa
|
|
|
33
33
|
* Applies a built-in scaffold into the target directory, including generated
|
|
34
34
|
* code artifacts, starter manifests, preset files, and placeholder rewrites.
|
|
35
35
|
*/
|
|
36
|
-
export declare function applyBuiltInScaffoldProjectFiles({ projectDir, templateDir, templateId, variables, artifacts, codeArtifacts, readmeContent, gitignoreContent, allowExistingDir, packageManager, withMigrationUi, withTestPreset, withWpEnv, noInstall, installDependencies, repositoryReference, }: {
|
|
36
|
+
export declare function applyBuiltInScaffoldProjectFiles({ projectDir, templateDir, templateId, variables, artifacts, codeArtifacts, readmeContent, gitignoreContent, allowExistingDir, packageManager, withMigrationUi, withTestPreset, withWpEnv, noInstall, installDependencies, repositoryReference, onProgress, }: {
|
|
37
37
|
projectDir: string;
|
|
38
38
|
templateDir: string;
|
|
39
39
|
templateId: BuiltInTemplateId;
|
|
@@ -50,4 +50,5 @@ export declare function applyBuiltInScaffoldProjectFiles({ projectDir, templateD
|
|
|
50
50
|
noInstall?: boolean;
|
|
51
51
|
installDependencies?: ((options: InstallDependenciesOptions) => Promise<void>) | undefined;
|
|
52
52
|
repositoryReference?: string;
|
|
53
|
+
onProgress?: ((event: ScaffoldProgressEvent) => void | Promise<void>) | undefined;
|
|
53
54
|
}): Promise<void>;
|