@wp-typia/project-tools 0.24.1 → 0.24.3
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/cli-add-help.js +2 -2
- package/dist/runtime/cli-add-types.d.ts +2 -2
- package/dist/runtime/cli-add-types.js +2 -2
- package/dist/runtime/cli-add-workspace-pattern-options.js +20 -8
- package/dist/runtime/cli-add.d.ts +1 -1
- package/dist/runtime/cli-add.js +1 -1
- package/dist/runtime/cli-help.js +2 -2
- package/dist/runtime/cli-scaffold-emission.d.ts +124 -0
- package/dist/runtime/cli-scaffold-emission.js +45 -0
- package/dist/runtime/cli-scaffold-files.d.ts +22 -0
- package/dist/runtime/cli-scaffold-files.js +69 -0
- package/dist/runtime/cli-scaffold-output.d.ts +79 -0
- package/dist/runtime/cli-scaffold-output.js +49 -0
- package/dist/runtime/cli-scaffold-validation.d.ts +82 -0
- package/dist/runtime/cli-scaffold-validation.js +190 -0
- package/dist/runtime/cli-scaffold.d.ts +10 -44
- package/dist/runtime/cli-scaffold.js +34 -327
- package/dist/runtime/index.d.ts +1 -1
- package/dist/runtime/index.js +1 -1
- package/dist/runtime/pattern-catalog.d.ts +2 -1
- package/dist/runtime/pattern-catalog.js +2 -2
- package/package.json +2 -2
|
@@ -14,7 +14,7 @@ export function formatAddHelpText() {
|
|
|
14
14
|
wp-typia add variation <name> --block <block-slug> [--dry-run]
|
|
15
15
|
wp-typia add style <name> --block <block-slug> [--dry-run]
|
|
16
16
|
wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug> [--dry-run]
|
|
17
|
-
wp-typia add pattern <name> [--scope <full|section>] [--section-role <role>] [--catalog-title <title>] [--tags <tag
|
|
17
|
+
wp-typia add pattern <name> [--scope <full|section>] [--section-role <role>] [--catalog-title <title>] [--tags <tag,...>] [--tag <tag>...] [--thumbnail-url <url>] [--dry-run]
|
|
18
18
|
wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>] [--from-post-meta|--post-meta <post-meta> [--meta-path <field>]] [--dry-run]
|
|
19
19
|
wp-typia add contract <name> [--type <ExportedTypeName>] [--dry-run]
|
|
20
20
|
wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <${REST_RESOURCE_METHOD_IDS.join(",")}>] [--route-pattern <route-pattern>] [--permission-callback <callback>] [--controller-class <ClassName>] [--controller-extends <BaseClass>] [--dry-run]
|
|
@@ -42,7 +42,7 @@ Notes:
|
|
|
42
42
|
\`add variation\` targets an existing block slug from \`scripts/block-config.ts\`.
|
|
43
43
|
\`add style\` registers a Block Styles option for an existing generated block.
|
|
44
44
|
\`add transform\` adds a block-to-block transform into an existing generated block.
|
|
45
|
-
\`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/full/\` or \`src/patterns/sections/\` and records typed catalog metadata in \`PATTERNS\`; pass \`--catalog-title "Hero Photo"\` to override the generated catalog title,
|
|
45
|
+
\`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/full/\` or \`src/patterns/sections/\` and records typed catalog metadata in \`PATTERNS\`; pass \`--catalog-title "Hero Photo"\` to override the generated catalog title, pass \`--tags hero,landing\` for a comma-separated tag list, and repeat \`--tag hero --tag landing\` for single tag values.
|
|
46
46
|
\`add binding-source\` scaffolds shared PHP and editor registration under \`src/bindings/\`; pass \`--block\` and \`--attribute\` together to declare an end-to-end bindable attribute on an existing generated block. Pass \`--from-post-meta\` or \`--post-meta\` to generate a source backed by a typed post-meta contract; \`--meta-path\` selects one top-level field as the default binding arg.
|
|
47
47
|
\`add contract\` registers a standalone TypeScript wire contract under \`src/contracts/\` and generates a stable JSON Schema artifact without creating PHP route glue.
|
|
48
48
|
\`add rest-resource\` scaffolds plugin-level TypeScript REST contracts under \`src/rest/\` and PHP route glue under \`inc/rest/\`. Use \`--route-pattern\`, \`--permission-callback\`, \`--controller-class\`, and \`--controller-extends\` when an existing WordPress controller or permission model needs to own part of the generated route surface.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { PATTERN_CATALOG_SCOPE_IDS, type PatternCatalogScope } from "./pattern-catalog.js";
|
|
1
|
+
import { PATTERN_CATALOG_SCOPE_IDS, PATTERN_SECTION_ROLE_PATTERN, PATTERN_TAG_PATTERN, type PatternCatalogScope } from "./pattern-catalog.js";
|
|
2
2
|
export { ADD_KIND_IDS } from "./cli-add-kind-ids.js";
|
|
3
3
|
export type { AddKindId } from "./cli-add-kind-ids.js";
|
|
4
|
-
export { PATTERN_CATALOG_SCOPE_IDS };
|
|
4
|
+
export { PATTERN_CATALOG_SCOPE_IDS, PATTERN_SECTION_ROLE_PATTERN, PATTERN_TAG_PATTERN, };
|
|
5
5
|
export type { PatternCatalogScope };
|
|
6
6
|
/**
|
|
7
7
|
* Supported plugin-level REST resource methods accepted by
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { suggestCloseId } from "./id-suggestions.js";
|
|
2
|
-
import { PATTERN_CATALOG_SCOPE_IDS, } from "./pattern-catalog.js";
|
|
2
|
+
import { PATTERN_CATALOG_SCOPE_IDS, PATTERN_SECTION_ROLE_PATTERN, PATTERN_TAG_PATTERN, } from "./pattern-catalog.js";
|
|
3
3
|
export { ADD_KIND_IDS } from "./cli-add-kind-ids.js";
|
|
4
|
-
export { PATTERN_CATALOG_SCOPE_IDS };
|
|
4
|
+
export { PATTERN_CATALOG_SCOPE_IDS, PATTERN_SECTION_ROLE_PATTERN, PATTERN_TAG_PATTERN, };
|
|
5
5
|
/**
|
|
6
6
|
* Supported plugin-level REST resource methods accepted by
|
|
7
7
|
* `wp-typia add rest-resource --methods`.
|
|
@@ -1,9 +1,8 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
3
|
-
import { isValidPatternThumbnailUrl, PATTERN_CATALOG_SCOPE_IDS, } from "./pattern-catalog.js";
|
|
2
|
+
import { normalizeBlockSlug, } from "./cli-add-shared.js";
|
|
3
|
+
import { isValidPatternThumbnailUrl, PATTERN_CATALOG_SCOPE_IDS, PATTERN_SECTION_ROLE_PATTERN, PATTERN_TAG_PATTERN, } from "./pattern-catalog.js";
|
|
4
4
|
import { toTitleCase } from "./string-case.js";
|
|
5
5
|
const PATTERN_CONTENT_FILE_ROOT = "src/patterns/";
|
|
6
|
-
const PATTERN_TAG_PATTERN = /^[a-z0-9][a-z0-9-]*$/u;
|
|
7
6
|
function assertValidPatternRelativePath(label, value, usage) {
|
|
8
7
|
const normalizedPath = value.trim().replace(/\\/gu, "/");
|
|
9
8
|
if (normalizedPath.length === 0 ||
|
|
@@ -41,11 +40,24 @@ function resolvePatternScope(scope) {
|
|
|
41
40
|
}
|
|
42
41
|
throw new Error(`Pattern scope must be one of: ${PATTERN_CATALOG_SCOPE_IDS.join(", ")}.`);
|
|
43
42
|
}
|
|
44
|
-
|
|
43
|
+
/**
|
|
44
|
+
* Normalize and validate a raw pattern section role before catalog generation.
|
|
45
|
+
* Non-empty values are normalized with normalizeBlockSlug; valid roles start
|
|
46
|
+
* with a lowercase letter and then use lowercase letters, numbers, or hyphens.
|
|
47
|
+
*
|
|
48
|
+
* @param value Raw section-role input from CLI or programmatic callers.
|
|
49
|
+
* @returns Normalized role slug, or undefined when the input is empty.
|
|
50
|
+
* @throws When the normalized role does not match the shared section-role pattern.
|
|
51
|
+
*/
|
|
52
|
+
function normalizePatternSectionRole(value) {
|
|
45
53
|
if (value === undefined || value.trim() === "") {
|
|
46
54
|
return undefined;
|
|
47
55
|
}
|
|
48
|
-
|
|
56
|
+
const sectionRole = normalizeBlockSlug(value);
|
|
57
|
+
if (!PATTERN_SECTION_ROLE_PATTERN.test(sectionRole)) {
|
|
58
|
+
throw new Error("Pattern section role must start with a lowercase letter and contain only lowercase letters, numbers, and hyphens. Section roles apply only with `--scope section`.");
|
|
59
|
+
}
|
|
60
|
+
return sectionRole;
|
|
49
61
|
}
|
|
50
62
|
function normalizePatternTags(tags) {
|
|
51
63
|
const rawTags = typeof tags === "string"
|
|
@@ -91,12 +103,12 @@ function resolvePatternContentFile(patternSlug, patternScope, contentFile) {
|
|
|
91
103
|
*/
|
|
92
104
|
export function resolvePatternCatalogOptions(patternSlug, options) {
|
|
93
105
|
const patternScope = resolvePatternScope(options.patternScope);
|
|
94
|
-
const sectionRole =
|
|
106
|
+
const sectionRole = normalizePatternSectionRole(options.sectionRole);
|
|
95
107
|
if (patternScope === "section" && !sectionRole) {
|
|
96
|
-
throw new Error("`wp-typia add pattern --scope section` requires --section-role <role
|
|
108
|
+
throw new Error("`wp-typia add pattern --scope section` requires --section-role <role> because section-scoped patterns need a typed catalog section role.");
|
|
97
109
|
}
|
|
98
110
|
if (patternScope !== "section" && sectionRole) {
|
|
99
|
-
throw new Error("`--section-role`
|
|
111
|
+
throw new Error("`--section-role` only applies with `--scope section`. Use `--scope section --section-role <role>` or omit `--section-role` for full patterns.");
|
|
100
112
|
}
|
|
101
113
|
const title = options.catalogTitle && options.catalogTitle.trim() !== ""
|
|
102
114
|
? options.catalogTitle.trim()
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - `cli-add-block` for built-in block scaffolding
|
|
8
8
|
* - `cli-add-workspace` for workspace mutation commands
|
|
9
9
|
*/
|
|
10
|
-
export { ADD_BLOCK_TEMPLATE_IDS, ADD_KIND_IDS, EDITOR_PLUGIN_SLOT_IDS, formatAddHelpText, isAddBlockTemplateId, PATTERN_CATALOG_SCOPE_IDS, suggestAddBlockTemplateId, } from "./cli-add-shared.js";
|
|
10
|
+
export { ADD_BLOCK_TEMPLATE_IDS, ADD_KIND_IDS, EDITOR_PLUGIN_SLOT_IDS, formatAddHelpText, isAddBlockTemplateId, normalizeBlockSlug, PATTERN_CATALOG_SCOPE_IDS, PATTERN_SECTION_ROLE_PATTERN, PATTERN_TAG_PATTERN, suggestAddBlockTemplateId, } from "./cli-add-shared.js";
|
|
11
11
|
export type { AddBlockTemplateId, AddKindId, EditorPluginSlotId, PatternCatalogScope, } from "./cli-add-shared.js";
|
|
12
12
|
export { runAddBlockCommand, seedWorkspaceMigrationProject, } from "./cli-add-block.js";
|
|
13
13
|
export { runAddAdminViewCommand, runAddAbilityCommand, runAddAiFeatureCommand, runAddBindingSourceCommand, runAddBlockStyleCommand, runAddBlockTransformCommand, runAddContractCommand, runAddCoreVariationCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddIntegrationEnvCommand, runAddPatternCommand, runAddPostMetaCommand, runAddRestResourceCommand, runAddVariationCommand, } from "./cli-add-workspace.js";
|
package/dist/runtime/cli-add.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* - `cli-add-block` for built-in block scaffolding
|
|
8
8
|
* - `cli-add-workspace` for workspace mutation commands
|
|
9
9
|
*/
|
|
10
|
-
export { ADD_BLOCK_TEMPLATE_IDS, ADD_KIND_IDS, EDITOR_PLUGIN_SLOT_IDS, formatAddHelpText, isAddBlockTemplateId, PATTERN_CATALOG_SCOPE_IDS, suggestAddBlockTemplateId, } from "./cli-add-shared.js";
|
|
10
|
+
export { ADD_BLOCK_TEMPLATE_IDS, ADD_KIND_IDS, EDITOR_PLUGIN_SLOT_IDS, formatAddHelpText, isAddBlockTemplateId, normalizeBlockSlug, PATTERN_CATALOG_SCOPE_IDS, PATTERN_SECTION_ROLE_PATTERN, PATTERN_TAG_PATTERN, suggestAddBlockTemplateId, } from "./cli-add-shared.js";
|
|
11
11
|
export { runAddBlockCommand, seedWorkspaceMigrationProject, } from "./cli-add-block.js";
|
|
12
12
|
export { runAddAdminViewCommand, runAddAbilityCommand, runAddAiFeatureCommand, runAddBindingSourceCommand, runAddBlockStyleCommand, runAddBlockTransformCommand, runAddContractCommand, runAddCoreVariationCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddIntegrationEnvCommand, runAddPatternCommand, runAddPostMetaCommand, runAddRestResourceCommand, runAddVariationCommand, } from "./cli-add-workspace.js";
|
|
13
13
|
export { getWorkspaceBlockSelectOptions, getWorkspaceBlockSelectOptionsAsync, } from "./workspace-inventory.js";
|
package/dist/runtime/cli-help.js
CHANGED
|
@@ -27,7 +27,7 @@ export function formatHelpText() {
|
|
|
27
27
|
wp-typia add variation <name> --block <block-slug>
|
|
28
28
|
wp-typia add style <name> --block <block-slug>
|
|
29
29
|
wp-typia add transform <name> --from <namespace/block> --to <block-slug|namespace/block-slug>
|
|
30
|
-
wp-typia add pattern <name> [--scope <full|section>] [--section-role <role>] [--catalog-title <title>] [--tags <tag
|
|
30
|
+
wp-typia add pattern <name> [--scope <full|section>] [--section-role <role>] [--catalog-title <title>] [--tags <tag,...>] [--tag <tag>...] [--thumbnail-url <url>]
|
|
31
31
|
wp-typia add binding-source <name> [--block <block-slug|namespace/block-slug> --attribute <attribute>] [--from-post-meta|--post-meta <post-meta> [--meta-path <field>]]
|
|
32
32
|
wp-typia add rest-resource <name> [--namespace <vendor/v1>] [--methods <method[,method...]>]
|
|
33
33
|
wp-typia add rest-resource <name> --manual [--namespace <vendor/v1>] [--method <GET|POST|PUT|PATCH|DELETE>] [--auth <public|authenticated|public-write-protected>] [--path <route-pattern>|--route-pattern <route-pattern>] [--permission-callback <callback>] [--controller-class <ClassName>] [--controller-extends <BaseClass>] [--query-type <Type>] [--body-type <Type>] [--response-type <Type>] [--secret-field <field>] [--secret-state-field|--secret-has-value-field <field>] [--secret-preserve-on-empty <true|false>]
|
|
@@ -68,7 +68,7 @@ Notes:
|
|
|
68
68
|
\`add variation\` uses an existing workspace block from \`scripts/block-config.ts\`.
|
|
69
69
|
\`add style\` registers a Block Styles option for an existing generated block.
|
|
70
70
|
\`add transform\` adds a block-to-block transform into an existing generated block.
|
|
71
|
-
\`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/full/\` or \`src/patterns/sections/\`; pass \`--catalog-title "Hero Photo"\` to override the generated catalog title,
|
|
71
|
+
\`add pattern\` scaffolds a namespaced PHP pattern shell under \`src/patterns/full/\` or \`src/patterns/sections/\`; pass \`--catalog-title "Hero Photo"\` to override the generated catalog title, pass \`--tags hero,landing\` for a comma-separated tag list, and repeat \`--tag hero --tag landing\` for single tag values.
|
|
72
72
|
\`add binding-source\` scaffolds shared PHP and editor registration under \`src/bindings/\`; pass \`--block\` and \`--attribute\` together to declare a bindable generated-block attribute. Pass \`--from-post-meta\` or \`--post-meta\` to back the source from a typed post-meta contract and \`--meta-path\` to choose its default top-level field.
|
|
73
73
|
\`add rest-resource\` scaffolds plugin-level TypeScript REST contracts under \`src/rest/\` and PHP route glue under \`inc/rest/\`.
|
|
74
74
|
\`add rest-resource --manual\` tracks an external/provider REST route with typed schemas, OpenAPI, clients, and drift checks without generating PHP route/controller files while still allowing route-owner metadata such as permission callbacks and controller classes. Settings contracts can add \`--secret-field\` plus \`--secret-preserve-on-empty\` to model write-only credentials and preserve blank submissions.
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { scaffoldProject } from "./scaffold.js";
|
|
2
|
+
import type { PackageManagerId } from "./package-managers.js";
|
|
3
|
+
import type { ScaffoldProgressEvent } from "./scaffold.js";
|
|
4
|
+
type ScaffoldProjectOptions = Parameters<typeof scaffoldProject>[0];
|
|
5
|
+
/**
|
|
6
|
+
* Dependency installation hook accepted by scaffold emission.
|
|
7
|
+
*/
|
|
8
|
+
export type ScaffoldInstallDependencies = ScaffoldProjectOptions["installDependencies"];
|
|
9
|
+
/**
|
|
10
|
+
* Dry-run metadata returned after rendering a scaffold into a preview directory.
|
|
11
|
+
*/
|
|
12
|
+
export interface ScaffoldDryRunPlan {
|
|
13
|
+
/**
|
|
14
|
+
* Whether dependency installation would run or is skipped by --no-install.
|
|
15
|
+
*/
|
|
16
|
+
dependencyInstall: "skipped-by-flag" | "would-install";
|
|
17
|
+
/**
|
|
18
|
+
* Sorted project-relative paths that would be written by the scaffold.
|
|
19
|
+
*/
|
|
20
|
+
files: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Normalized scaffold emission options shared by real and dry-run flows.
|
|
24
|
+
*/
|
|
25
|
+
export interface ScaffoldEmissionOptions {
|
|
26
|
+
/**
|
|
27
|
+
* Whether an existing target directory may be reused.
|
|
28
|
+
*/
|
|
29
|
+
allowExistingDir: boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Optional alternate render target specification for supported templates.
|
|
32
|
+
*/
|
|
33
|
+
alternateRenderTargets?: ScaffoldProjectOptions["alternateRenderTargets"];
|
|
34
|
+
/**
|
|
35
|
+
* Resolved scaffold answers used by template variable generation.
|
|
36
|
+
*/
|
|
37
|
+
answers: ScaffoldProjectOptions["answers"];
|
|
38
|
+
/**
|
|
39
|
+
* Caller working directory used to resolve relative template inputs.
|
|
40
|
+
*/
|
|
41
|
+
cwd: string;
|
|
42
|
+
/**
|
|
43
|
+
* Persistence storage mode for templates that support storage options.
|
|
44
|
+
*/
|
|
45
|
+
dataStorageMode?: ScaffoldProjectOptions["dataStorageMode"];
|
|
46
|
+
/**
|
|
47
|
+
* Optional public root id selected from an external layer package.
|
|
48
|
+
*/
|
|
49
|
+
externalLayerId?: string;
|
|
50
|
+
/**
|
|
51
|
+
* Optional external layer source package, path, or locator.
|
|
52
|
+
*/
|
|
53
|
+
externalLayerSource?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Display label for the external layer source before path resolution.
|
|
56
|
+
*/
|
|
57
|
+
externalLayerSourceLabel?: string;
|
|
58
|
+
/**
|
|
59
|
+
* Optional dependency installer override used by tests and callers.
|
|
60
|
+
*/
|
|
61
|
+
installDependencies?: ScaffoldProjectOptions["installDependencies"];
|
|
62
|
+
/**
|
|
63
|
+
* Whether generated projects should skip dependency installation.
|
|
64
|
+
*/
|
|
65
|
+
noInstall: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Optional callback for scaffold progress events.
|
|
68
|
+
*/
|
|
69
|
+
onProgress?: ((event: ScaffoldProgressEvent) => void | Promise<void>) | undefined;
|
|
70
|
+
/**
|
|
71
|
+
* Package manager used for generated metadata and follow-up commands.
|
|
72
|
+
*/
|
|
73
|
+
packageManager: PackageManagerId;
|
|
74
|
+
/**
|
|
75
|
+
* Persistence access policy for templates that support server storage.
|
|
76
|
+
*/
|
|
77
|
+
persistencePolicy?: ScaffoldProjectOptions["persistencePolicy"];
|
|
78
|
+
/**
|
|
79
|
+
* Optional create profile that enables preset groups such as plugin QA.
|
|
80
|
+
*/
|
|
81
|
+
profile?: ScaffoldProjectOptions["profile"];
|
|
82
|
+
/**
|
|
83
|
+
* Absolute target directory for the generated project.
|
|
84
|
+
*/
|
|
85
|
+
projectDir: string;
|
|
86
|
+
/**
|
|
87
|
+
* Resolved template id or external template locator to render.
|
|
88
|
+
*/
|
|
89
|
+
templateId: string;
|
|
90
|
+
/**
|
|
91
|
+
* Optional built-in or external template variant id.
|
|
92
|
+
*/
|
|
93
|
+
variant?: string;
|
|
94
|
+
/**
|
|
95
|
+
* Whether migration UI support should be added when supported.
|
|
96
|
+
*/
|
|
97
|
+
withMigrationUi: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* Whether scaffold test presets should be emitted.
|
|
100
|
+
*/
|
|
101
|
+
withTestPreset: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Whether local wp-env support should be emitted.
|
|
104
|
+
*/
|
|
105
|
+
withWpEnv: boolean;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Emit scaffold files into the target project directory.
|
|
109
|
+
*
|
|
110
|
+
* @param options Normalized scaffold emission options.
|
|
111
|
+
* @returns The scaffold result produced by the runtime renderer.
|
|
112
|
+
*/
|
|
113
|
+
export declare function emitScaffoldProject(options: ScaffoldEmissionOptions): Promise<Awaited<ReturnType<typeof scaffoldProject>>>;
|
|
114
|
+
/**
|
|
115
|
+
* Build a dry-run scaffold plan without mutating the requested target directory.
|
|
116
|
+
*
|
|
117
|
+
* @param options Normalized scaffold emission options.
|
|
118
|
+
* @returns Preview metadata and the scaffold result from the temp render.
|
|
119
|
+
*/
|
|
120
|
+
export declare function buildScaffoldDryRunPlan(options: ScaffoldEmissionOptions): Promise<{
|
|
121
|
+
plan: ScaffoldDryRunPlan;
|
|
122
|
+
result: Awaited<ReturnType<typeof scaffoldProject>>;
|
|
123
|
+
}>;
|
|
124
|
+
export {};
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { assertDryRunTargetDirectoryReady, listRelativeProjectFiles, } from "./cli-scaffold-files.js";
|
|
3
|
+
import { scaffoldProject } from "./scaffold.js";
|
|
4
|
+
import { createManagedTempRoot } from "./temp-roots.js";
|
|
5
|
+
/**
|
|
6
|
+
* Emit scaffold files into the target project directory.
|
|
7
|
+
*
|
|
8
|
+
* @param options Normalized scaffold emission options.
|
|
9
|
+
* @returns The scaffold result produced by the runtime renderer.
|
|
10
|
+
*/
|
|
11
|
+
export async function emitScaffoldProject(options) {
|
|
12
|
+
return scaffoldProject(options);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Build a dry-run scaffold plan without mutating the requested target directory.
|
|
16
|
+
*
|
|
17
|
+
* @param options Normalized scaffold emission options.
|
|
18
|
+
* @returns Preview metadata and the scaffold result from the temp render.
|
|
19
|
+
*/
|
|
20
|
+
export async function buildScaffoldDryRunPlan(options) {
|
|
21
|
+
await assertDryRunTargetDirectoryReady(options.projectDir, options.allowExistingDir);
|
|
22
|
+
const { path: tempRoot, cleanup } = await createManagedTempRoot("wp-typia-scaffold-plan-");
|
|
23
|
+
const previewProjectDir = path.join(tempRoot, "preview-project");
|
|
24
|
+
try {
|
|
25
|
+
const result = await emitScaffoldProject({
|
|
26
|
+
...options,
|
|
27
|
+
allowExistingDir: false,
|
|
28
|
+
noInstall: true,
|
|
29
|
+
projectDir: previewProjectDir,
|
|
30
|
+
});
|
|
31
|
+
const files = await listRelativeProjectFiles(previewProjectDir);
|
|
32
|
+
return {
|
|
33
|
+
plan: {
|
|
34
|
+
dependencyInstall: options.noInstall
|
|
35
|
+
? "skipped-by-flag"
|
|
36
|
+
: "would-install",
|
|
37
|
+
files,
|
|
38
|
+
},
|
|
39
|
+
result,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
await cleanup();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* List every file emitted under a scaffold project using POSIX-style paths.
|
|
3
|
+
*
|
|
4
|
+
* @param rootDir Root project directory to scan recursively.
|
|
5
|
+
* @returns Sorted relative file paths suitable for dry-run preview output.
|
|
6
|
+
*/
|
|
7
|
+
export declare function listRelativeProjectFiles(rootDir: string): Promise<string[]>;
|
|
8
|
+
/**
|
|
9
|
+
* Ensure a dry-run target would be legal before rendering into a temp preview.
|
|
10
|
+
*
|
|
11
|
+
* @param projectDir Real target project directory requested by the user.
|
|
12
|
+
* @param allowExistingDir Whether existing target directories are allowed.
|
|
13
|
+
* @throws Error when the target exists, is non-empty, and is not allowed.
|
|
14
|
+
*/
|
|
15
|
+
export declare function assertDryRunTargetDirectoryReady(projectDir: string, allowExistingDir: boolean): Promise<void>;
|
|
16
|
+
/**
|
|
17
|
+
* Read script names from the package manifest emitted by a scaffold run.
|
|
18
|
+
*
|
|
19
|
+
* @param projectDir Generated project directory containing package.json.
|
|
20
|
+
* @returns Script names, or undefined when the manifest is absent or invalid.
|
|
21
|
+
*/
|
|
22
|
+
export declare function readGeneratedPackageScripts(projectDir: string): Promise<string[] | undefined>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { promises as fsp } from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { formatNonEmptyTargetDirectoryError } from "./scaffold-bootstrap.js";
|
|
4
|
+
import { pathExists } from "./fs-async.js";
|
|
5
|
+
import { readJsonFile } from "./json-utils.js";
|
|
6
|
+
/**
|
|
7
|
+
* List every file emitted under a scaffold project using POSIX-style paths.
|
|
8
|
+
*
|
|
9
|
+
* @param rootDir Root project directory to scan recursively.
|
|
10
|
+
* @returns Sorted relative file paths suitable for dry-run preview output.
|
|
11
|
+
*/
|
|
12
|
+
export async function listRelativeProjectFiles(rootDir) {
|
|
13
|
+
const relativeFiles = [];
|
|
14
|
+
async function visit(currentDir) {
|
|
15
|
+
const entries = await fsp.readdir(currentDir, { withFileTypes: true });
|
|
16
|
+
for (const entry of entries) {
|
|
17
|
+
const absolutePath = path.join(currentDir, entry.name);
|
|
18
|
+
if (entry.isDirectory()) {
|
|
19
|
+
await visit(absolutePath);
|
|
20
|
+
continue;
|
|
21
|
+
}
|
|
22
|
+
relativeFiles.push(path
|
|
23
|
+
.relative(rootDir, absolutePath)
|
|
24
|
+
.replace(path.sep === "\\" ? /\\/gu : /\//gu, "/"));
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
await visit(rootDir);
|
|
28
|
+
return relativeFiles.sort((left, right) => left.localeCompare(right));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Ensure a dry-run target would be legal before rendering into a temp preview.
|
|
32
|
+
*
|
|
33
|
+
* @param projectDir Real target project directory requested by the user.
|
|
34
|
+
* @param allowExistingDir Whether existing target directories are allowed.
|
|
35
|
+
* @throws Error when the target exists, is non-empty, and is not allowed.
|
|
36
|
+
*/
|
|
37
|
+
export async function assertDryRunTargetDirectoryReady(projectDir, allowExistingDir) {
|
|
38
|
+
if (!(await pathExists(projectDir)) || allowExistingDir) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const entries = await fsp.readdir(projectDir);
|
|
42
|
+
if (entries.length > 0) {
|
|
43
|
+
throw new Error(formatNonEmptyTargetDirectoryError(projectDir));
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Read script names from the package manifest emitted by a scaffold run.
|
|
48
|
+
*
|
|
49
|
+
* @param projectDir Generated project directory containing package.json.
|
|
50
|
+
* @returns Script names, or undefined when the manifest is absent or invalid.
|
|
51
|
+
*/
|
|
52
|
+
export async function readGeneratedPackageScripts(projectDir) {
|
|
53
|
+
try {
|
|
54
|
+
const parsedPackageJson = await readJsonFile(path.join(projectDir, "package.json"), {
|
|
55
|
+
context: "generated package manifest",
|
|
56
|
+
});
|
|
57
|
+
const scripts = parsedPackageJson.scripts &&
|
|
58
|
+
typeof parsedPackageJson.scripts === "object" &&
|
|
59
|
+
!Array.isArray(parsedPackageJson.scripts)
|
|
60
|
+
? parsedPackageJson.scripts
|
|
61
|
+
: {};
|
|
62
|
+
return Object.entries(scripts)
|
|
63
|
+
.filter(([, value]) => typeof value === "string")
|
|
64
|
+
.map(([scriptName]) => scriptName);
|
|
65
|
+
}
|
|
66
|
+
catch {
|
|
67
|
+
return undefined;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import type { PackageManagerId } from "./package-managers.js";
|
|
2
|
+
/**
|
|
3
|
+
* Inputs used to build CLI next-step commands after scaffolding succeeds.
|
|
4
|
+
*/
|
|
5
|
+
export interface ScaffoldNextStepsOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Whether install instructions should be printed because install was skipped.
|
|
8
|
+
*/
|
|
9
|
+
noInstall: boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Package manager used to format install and run commands.
|
|
12
|
+
*/
|
|
13
|
+
packageManager: PackageManagerId;
|
|
14
|
+
/**
|
|
15
|
+
* Absolute scaffold target directory.
|
|
16
|
+
*/
|
|
17
|
+
projectDir: string;
|
|
18
|
+
/**
|
|
19
|
+
* Project path exactly as provided to the CLI.
|
|
20
|
+
*/
|
|
21
|
+
projectInput: string;
|
|
22
|
+
/**
|
|
23
|
+
* Resolved template id used to choose the primary development script.
|
|
24
|
+
*/
|
|
25
|
+
templateId: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Inputs used to compute optional onboarding guidance after scaffolding.
|
|
29
|
+
*/
|
|
30
|
+
export interface ScaffoldOptionalOnboardingOptions {
|
|
31
|
+
/**
|
|
32
|
+
* Script names discovered from the generated package manifest.
|
|
33
|
+
*/
|
|
34
|
+
availableScripts?: string[];
|
|
35
|
+
/**
|
|
36
|
+
* Package manager used to format optional commands.
|
|
37
|
+
*/
|
|
38
|
+
packageManager: PackageManagerId;
|
|
39
|
+
/**
|
|
40
|
+
* Resolved template id used to select template-specific guidance.
|
|
41
|
+
*/
|
|
42
|
+
templateId: string;
|
|
43
|
+
/**
|
|
44
|
+
* Whether compound persistence support is present in generated variables.
|
|
45
|
+
*/
|
|
46
|
+
compoundPersistenceEnabled?: boolean;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* User-facing optional onboarding copy and command list.
|
|
50
|
+
*/
|
|
51
|
+
export interface OptionalOnboardingGuidance {
|
|
52
|
+
/**
|
|
53
|
+
* Full note shown in the detailed completion output.
|
|
54
|
+
*/
|
|
55
|
+
note: string;
|
|
56
|
+
/**
|
|
57
|
+
* Short note shown in compact completion output.
|
|
58
|
+
*/
|
|
59
|
+
shortNote: string;
|
|
60
|
+
/**
|
|
61
|
+
* Optional follow-up commands to show after next steps.
|
|
62
|
+
*/
|
|
63
|
+
steps: string[];
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Build the printed next-step commands for a scaffolded project.
|
|
67
|
+
*
|
|
68
|
+
* @param options Project location and package-manager details used to format
|
|
69
|
+
* next-step commands.
|
|
70
|
+
* @returns Ordered shell commands shown after scaffolding succeeds.
|
|
71
|
+
*/
|
|
72
|
+
export declare function getNextSteps({ projectInput, projectDir, packageManager, noInstall, templateId, }: ScaffoldNextStepsOptions): string[];
|
|
73
|
+
/**
|
|
74
|
+
* Compute optional onboarding guidance shown after scaffolding completes.
|
|
75
|
+
*
|
|
76
|
+
* @param options Package-manager and template context for optional guidance.
|
|
77
|
+
* @returns Optional onboarding note and step list.
|
|
78
|
+
*/
|
|
79
|
+
export declare function getOptionalOnboarding({ availableScripts, packageManager, templateId, compoundPersistenceEnabled, }: ScaffoldOptionalOnboardingOptions): OptionalOnboardingGuidance;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { formatInstallCommand, formatRunScript, } from "./package-managers.js";
|
|
3
|
+
import { getOptionalOnboardingNote, getOptionalOnboardingShortNote, getOptionalOnboardingSteps, } from "./scaffold-onboarding.js";
|
|
4
|
+
import { getPrimaryDevelopmentScript } from "./local-dev-presets.js";
|
|
5
|
+
function quoteShellValue(value) {
|
|
6
|
+
if (!value.startsWith("-") &&
|
|
7
|
+
/^[A-Za-z0-9._/@:-]+(?:\/[A-Za-z0-9._@:-]+)*$/.test(value)) {
|
|
8
|
+
return value;
|
|
9
|
+
}
|
|
10
|
+
return `'${value.replace(/'/g, `'"'"'`)}'`;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Build the printed next-step commands for a scaffolded project.
|
|
14
|
+
*
|
|
15
|
+
* @param options Project location and package-manager details used to format
|
|
16
|
+
* next-step commands.
|
|
17
|
+
* @returns Ordered shell commands shown after scaffolding succeeds.
|
|
18
|
+
*/
|
|
19
|
+
export function getNextSteps({ projectInput, projectDir, packageManager, noInstall, templateId, }) {
|
|
20
|
+
const cdTarget = path.isAbsolute(projectInput) ? projectDir : projectInput;
|
|
21
|
+
const steps = [`cd ${quoteShellValue(cdTarget)}`];
|
|
22
|
+
if (noInstall) {
|
|
23
|
+
steps.push(formatInstallCommand(packageManager));
|
|
24
|
+
}
|
|
25
|
+
steps.push(formatRunScript(packageManager, getPrimaryDevelopmentScript(templateId)));
|
|
26
|
+
return steps;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Compute optional onboarding guidance shown after scaffolding completes.
|
|
30
|
+
*
|
|
31
|
+
* @param options Package-manager and template context for optional guidance.
|
|
32
|
+
* @returns Optional onboarding note and step list.
|
|
33
|
+
*/
|
|
34
|
+
export function getOptionalOnboarding({ availableScripts, packageManager, templateId, compoundPersistenceEnabled = false, }) {
|
|
35
|
+
return {
|
|
36
|
+
note: getOptionalOnboardingNote(packageManager, templateId, {
|
|
37
|
+
availableScripts,
|
|
38
|
+
compoundPersistenceEnabled,
|
|
39
|
+
}),
|
|
40
|
+
shortNote: getOptionalOnboardingShortNote(packageManager, templateId, {
|
|
41
|
+
availableScripts,
|
|
42
|
+
compoundPersistenceEnabled,
|
|
43
|
+
}),
|
|
44
|
+
steps: getOptionalOnboardingSteps(packageManager, templateId, {
|
|
45
|
+
availableScripts,
|
|
46
|
+
compoundPersistenceEnabled,
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Validate the project directory argument before template resolution.
|
|
3
|
+
*
|
|
4
|
+
* @param projectInput Raw project directory input from the CLI.
|
|
5
|
+
* @throws Error when the input is empty or points at the current/parent directory.
|
|
6
|
+
*/
|
|
7
|
+
export declare function validateCreateProjectInput(projectInput: string): void;
|
|
8
|
+
/**
|
|
9
|
+
* Collect warnings for project directory names that are awkward in shells.
|
|
10
|
+
*
|
|
11
|
+
* @param projectDir Absolute target project directory.
|
|
12
|
+
* @returns User-facing warning messages for non-fatal directory concerns.
|
|
13
|
+
*/
|
|
14
|
+
export declare function collectProjectDirectoryWarnings(projectDir: string): string[];
|
|
15
|
+
/**
|
|
16
|
+
* Determine whether a template should resolve persistence-related options.
|
|
17
|
+
*
|
|
18
|
+
* @param templateId Resolved template id.
|
|
19
|
+
* @param options Explicit persistence flags provided by the caller.
|
|
20
|
+
* @returns True when persistence defaults or prompts should be applied.
|
|
21
|
+
*/
|
|
22
|
+
export declare function templateUsesPersistenceSettings(templateId: string, options: {
|
|
23
|
+
dataStorageMode?: string;
|
|
24
|
+
persistencePolicy?: string;
|
|
25
|
+
}): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Collect warnings for flags that do not apply to the selected template.
|
|
28
|
+
*
|
|
29
|
+
* @param options Template id and raw CLI flags that may be ignored.
|
|
30
|
+
* @returns User-facing warnings for non-fatal capability mismatches.
|
|
31
|
+
*/
|
|
32
|
+
export declare function collectTemplateCapabilityWarnings(options: {
|
|
33
|
+
queryPostType?: string;
|
|
34
|
+
templateId: string;
|
|
35
|
+
withMigrationUi?: boolean;
|
|
36
|
+
}): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Validate create flags that depend on the selected template capability set.
|
|
39
|
+
*
|
|
40
|
+
* @param options Raw create flags plus the resolved template id.
|
|
41
|
+
* @throws Error when a flag is unsupported for the selected template.
|
|
42
|
+
*/
|
|
43
|
+
export declare function validateCreateFlagContract(options: {
|
|
44
|
+
alternateRenderTargets?: string;
|
|
45
|
+
dataStorageMode?: string;
|
|
46
|
+
innerBlocksPreset?: string;
|
|
47
|
+
persistencePolicy?: string;
|
|
48
|
+
templateId: string;
|
|
49
|
+
variant?: string;
|
|
50
|
+
}): void;
|
|
51
|
+
/**
|
|
52
|
+
* Resolve an optional string selection from explicit input, prompts, or defaults.
|
|
53
|
+
*
|
|
54
|
+
* @param options Selection configuration including allowed values and prompt hooks.
|
|
55
|
+
* @returns The resolved value, or undefined when resolution is disabled.
|
|
56
|
+
* @throws Error when an explicit value is not in the allowed set.
|
|
57
|
+
*/
|
|
58
|
+
export declare function resolveOptionalSelection<T extends string>({ defaultValue, explicitValue, isInteractive, isValue, label, allowedValues, select, shouldResolve, yes, }: {
|
|
59
|
+
defaultValue: T;
|
|
60
|
+
explicitValue?: string;
|
|
61
|
+
isInteractive: boolean;
|
|
62
|
+
isValue: (input: string) => input is T;
|
|
63
|
+
label: string;
|
|
64
|
+
allowedValues: readonly T[];
|
|
65
|
+
select?: () => Promise<T>;
|
|
66
|
+
shouldResolve?: boolean;
|
|
67
|
+
yes: boolean;
|
|
68
|
+
}): Promise<T | undefined>;
|
|
69
|
+
/**
|
|
70
|
+
* Resolve an optional boolean flag from explicit input, prompts, or defaults.
|
|
71
|
+
*
|
|
72
|
+
* @param options Boolean selection configuration and optional prompt hook.
|
|
73
|
+
* @returns The resolved boolean value.
|
|
74
|
+
*/
|
|
75
|
+
export declare function resolveOptionalBooleanFlag({ defaultValue, disabled, explicitValue, isInteractive, select, yes, }: {
|
|
76
|
+
defaultValue?: boolean;
|
|
77
|
+
disabled?: boolean;
|
|
78
|
+
explicitValue?: boolean;
|
|
79
|
+
isInteractive: boolean;
|
|
80
|
+
select?: () => Promise<boolean>;
|
|
81
|
+
yes: boolean;
|
|
82
|
+
}): Promise<boolean>;
|