@wp-typia/project-tools 0.16.13 → 0.16.14
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/README.md +0 -1
- package/dist/runtime/cli-prompt.js +78 -19
- package/dist/runtime/scaffold-answer-resolution.d.ts +37 -0
- package/dist/runtime/scaffold-answer-resolution.js +138 -0
- package/dist/runtime/scaffold-apply-utils.d.ts +1 -16
- package/dist/runtime/scaffold-apply-utils.js +4 -128
- package/dist/runtime/scaffold-documents.d.ts +34 -0
- package/dist/runtime/scaffold-documents.js +144 -0
- package/dist/runtime/scaffold-template-variables.d.ts +9 -0
- package/dist/runtime/scaffold-template-variables.js +111 -0
- package/dist/runtime/scaffold.d.ts +11 -9
- package/dist/runtime/scaffold.js +6 -202
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -12,7 +12,6 @@ Package roles:
|
|
|
12
12
|
templates no longer ship structural, TS/TSX, style, or block-local `render.php`
|
|
13
13
|
Mustache files.
|
|
14
14
|
- `@wp-typia/block-runtime/*` owns generated-project runtime helpers.
|
|
15
|
-
- `@wp-typia/create` is the deprecated legacy package shell.
|
|
16
15
|
|
|
17
16
|
Supported public imports:
|
|
18
17
|
|
|
@@ -18,18 +18,17 @@ export function createReadlinePrompt() {
|
|
|
18
18
|
* retry behavior without stubbing global stdin/stdout.
|
|
19
19
|
*/
|
|
20
20
|
export function createReadlinePromptWithInterface(rl) {
|
|
21
|
+
const askQuestion = (query) => new Promise((resolve) => {
|
|
22
|
+
rl.question(query, resolve);
|
|
23
|
+
});
|
|
21
24
|
return {
|
|
22
25
|
async text(message, defaultValue, validate) {
|
|
23
|
-
const suffix = defaultValue ? ` (${defaultValue})` : "";
|
|
24
26
|
while (true) {
|
|
25
|
-
const
|
|
26
|
-
rl.question(`${message}${suffix}: `, resolve);
|
|
27
|
-
});
|
|
28
|
-
const value = String(answer).trim() || defaultValue;
|
|
27
|
+
const value = normalizePromptAnswer(await askQuestion(formatTextPrompt(message, defaultValue))) || defaultValue;
|
|
29
28
|
if (validate) {
|
|
30
29
|
const result = validate(value);
|
|
31
30
|
if (result !== true) {
|
|
32
|
-
console.error(
|
|
31
|
+
console.error(formatValidationError(message, result, defaultValue));
|
|
33
32
|
continue;
|
|
34
33
|
}
|
|
35
34
|
}
|
|
@@ -40,22 +39,22 @@ export function createReadlinePromptWithInterface(rl) {
|
|
|
40
39
|
if (options.length === 0) {
|
|
41
40
|
throw new Error(`select() requires at least one option for prompt: ${message}`);
|
|
42
41
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
const hint = option.hint ? ` - ${option.hint}` : "";
|
|
46
|
-
console.log(` ${index + 1}. ${option.label}${hint}`);
|
|
47
|
-
});
|
|
42
|
+
const resolvedDefaultIndex = getResolvedDefaultIndex(options, defaultValue);
|
|
43
|
+
renderSelectPrompt(message, options, resolvedDefaultIndex);
|
|
48
44
|
while (true) {
|
|
49
|
-
const answer = await
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
45
|
+
const answer = normalizePromptAnswer(await askQuestion(formatChoicePrompt(resolvedDefaultIndex)));
|
|
46
|
+
if (answer.length === 0) {
|
|
47
|
+
return options[resolvedDefaultIndex].value;
|
|
48
|
+
}
|
|
49
|
+
const selection = resolvePromptSelection(options, answer);
|
|
50
|
+
if (selection) {
|
|
51
|
+
return selection.value;
|
|
53
52
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
53
|
+
if (isPromptHelpToken(answer)) {
|
|
54
|
+
renderSelectPrompt(message, options, resolvedDefaultIndex);
|
|
55
|
+
continue;
|
|
57
56
|
}
|
|
58
|
-
console.error(
|
|
57
|
+
console.error(formatInvalidSelectionError(answer, options, resolvedDefaultIndex));
|
|
59
58
|
}
|
|
60
59
|
},
|
|
61
60
|
close() {
|
|
@@ -63,3 +62,63 @@ export function createReadlinePromptWithInterface(rl) {
|
|
|
63
62
|
},
|
|
64
63
|
};
|
|
65
64
|
}
|
|
65
|
+
function normalizePromptAnswer(value) {
|
|
66
|
+
return String(value).trim();
|
|
67
|
+
}
|
|
68
|
+
function normalizePromptToken(value) {
|
|
69
|
+
return value.trim().toLowerCase();
|
|
70
|
+
}
|
|
71
|
+
function getResolvedDefaultIndex(options, defaultValue) {
|
|
72
|
+
const candidateIndex = Number.isInteger(defaultValue) ? defaultValue - 1 : -1;
|
|
73
|
+
return options[candidateIndex] ? candidateIndex : 0;
|
|
74
|
+
}
|
|
75
|
+
function formatTextPrompt(message, defaultValue) {
|
|
76
|
+
const suffix = defaultValue.length > 0 ? ` [default: ${defaultValue}]` : "";
|
|
77
|
+
return `${message}${suffix}: `;
|
|
78
|
+
}
|
|
79
|
+
function formatValidationError(message, result, defaultValue) {
|
|
80
|
+
const detail = typeof result === "string" ? result : "Invalid input";
|
|
81
|
+
const retryHint = defaultValue.length > 0 ? ` Press Enter to keep "${defaultValue}".` : "";
|
|
82
|
+
return `❌ ${message}: ${detail}.${retryHint}`;
|
|
83
|
+
}
|
|
84
|
+
function formatChoicePrompt(defaultIndex) {
|
|
85
|
+
return `Choice [default: ${defaultIndex + 1}, ? for options]: `;
|
|
86
|
+
}
|
|
87
|
+
function renderSelectPrompt(message, options, defaultIndex) {
|
|
88
|
+
console.log(message);
|
|
89
|
+
console.log(" Enter a number, option label, or option value. Press Enter to keep the default, or type ? to list choices again.");
|
|
90
|
+
options.forEach((option, index) => {
|
|
91
|
+
const defaultMarker = index === defaultIndex ? " (default)" : "";
|
|
92
|
+
const valueHint = normalizePromptToken(option.label) === normalizePromptToken(option.value)
|
|
93
|
+
? ""
|
|
94
|
+
: ` [${option.value}]`;
|
|
95
|
+
console.log(` ${index + 1}. ${option.label}${valueHint}${defaultMarker}`);
|
|
96
|
+
if (option.hint) {
|
|
97
|
+
console.log(` ${option.hint}`);
|
|
98
|
+
}
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
function isPromptHelpToken(answer) {
|
|
102
|
+
const normalized = normalizePromptToken(answer);
|
|
103
|
+
return normalized === "?" || normalized === "help" || normalized === "list";
|
|
104
|
+
}
|
|
105
|
+
function resolvePromptSelection(options, answer) {
|
|
106
|
+
const numericChoice = Number(answer);
|
|
107
|
+
if (!Number.isNaN(numericChoice) && options[numericChoice - 1]) {
|
|
108
|
+
return options[numericChoice - 1];
|
|
109
|
+
}
|
|
110
|
+
const normalizedAnswer = normalizePromptToken(answer);
|
|
111
|
+
return options.find((option) => {
|
|
112
|
+
const normalizedLabel = normalizePromptToken(option.label);
|
|
113
|
+
const normalizedValue = normalizePromptToken(option.value);
|
|
114
|
+
return normalizedAnswer === normalizedLabel || normalizedAnswer === normalizedValue;
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
function formatInvalidSelectionError(answer, options, defaultIndex) {
|
|
118
|
+
const optionValues = options.map((option) => option.value).join(", ");
|
|
119
|
+
return [
|
|
120
|
+
`❌ Invalid selection: ${answer}.`,
|
|
121
|
+
`Enter 1-${options.length}, one of: ${optionValues},`,
|
|
122
|
+
`or press Enter for "${options[defaultIndex].label}".`,
|
|
123
|
+
].join(" ");
|
|
124
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { PackageManagerId } from './package-managers.js';
|
|
2
|
+
import type { CollectScaffoldAnswersOptions, ResolvePackageManagerOptions, ResolveTemplateOptions, ScaffoldAnswers } from './scaffold.js';
|
|
3
|
+
/**
|
|
4
|
+
* Detect the current author name from local Git config.
|
|
5
|
+
*
|
|
6
|
+
* @returns The configured Git author name, or `"Your Name"` when unavailable.
|
|
7
|
+
*/
|
|
8
|
+
export declare function detectAuthor(): string;
|
|
9
|
+
/**
|
|
10
|
+
* Compute the default scaffold answers for one project and template pair.
|
|
11
|
+
*
|
|
12
|
+
* @param projectName User-supplied project directory or block name seed.
|
|
13
|
+
* @param templateId Selected scaffold template identifier.
|
|
14
|
+
* @returns Normalized default answers for scaffold prompts and non-interactive flows.
|
|
15
|
+
*/
|
|
16
|
+
export declare function getDefaultAnswers(projectName: string, templateId: string): ScaffoldAnswers;
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the scaffold template id from flags, defaults, and interactive selection.
|
|
19
|
+
*
|
|
20
|
+
* @param options Template resolution options for interactive and non-interactive flows.
|
|
21
|
+
* @returns The normalized template identifier to scaffold.
|
|
22
|
+
*/
|
|
23
|
+
export declare function resolveTemplateId({ templateId, yes, isInteractive, selectTemplate, }: ResolveTemplateOptions): Promise<string>;
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the package manager id from flags, defaults, and interactive selection.
|
|
26
|
+
*
|
|
27
|
+
* @param options Package manager resolution options for interactive and non-interactive flows.
|
|
28
|
+
* @returns The normalized package manager id.
|
|
29
|
+
*/
|
|
30
|
+
export declare function resolvePackageManagerId({ packageManager, yes, isInteractive, selectPackageManager, }: ResolvePackageManagerOptions): Promise<PackageManagerId>;
|
|
31
|
+
/**
|
|
32
|
+
* Collect scaffold answers from defaults, CLI overrides, and optional prompts.
|
|
33
|
+
*
|
|
34
|
+
* @param options Answer collection inputs including prompt callbacks and explicit overrides.
|
|
35
|
+
* @returns The normalized scaffold answers used for rendering and file generation.
|
|
36
|
+
*/
|
|
37
|
+
export declare function collectScaffoldAnswers({ projectName, templateId, yes, dataStorageMode, namespace, persistencePolicy, phpPrefix, promptText, textDomain, }: CollectScaffoldAnswersOptions): Promise<ScaffoldAnswers>;
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { PACKAGE_MANAGER_IDS, getPackageManager, } from './package-managers.js';
|
|
2
|
+
import { normalizeBlockSlug, resolveScaffoldIdentifiers, validateBlockSlug, validateNamespace, } from './scaffold-identifiers.js';
|
|
3
|
+
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, TEMPLATE_IDS, getTemplateById, isBuiltInTemplateId, } from './template-registry.js';
|
|
4
|
+
import { getRemovedBuiltInTemplateMessage, isRemovedBuiltInTemplateId, } from './template-defaults.js';
|
|
5
|
+
import { toSnakeCase, toTitleCase, } from './string-case.js';
|
|
6
|
+
const WORKSPACE_TEMPLATE_ALIAS = 'workspace';
|
|
7
|
+
/**
|
|
8
|
+
* Detect the current author name from local Git config.
|
|
9
|
+
*
|
|
10
|
+
* @returns The configured Git author name, or `"Your Name"` when unavailable.
|
|
11
|
+
*/
|
|
12
|
+
export function detectAuthor() {
|
|
13
|
+
try {
|
|
14
|
+
return (execSync('git config user.name', {
|
|
15
|
+
encoding: 'utf8',
|
|
16
|
+
stdio: ['ignore', 'pipe', 'ignore'],
|
|
17
|
+
}).trim() || 'Your Name');
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
return 'Your Name';
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Compute the default scaffold answers for one project and template pair.
|
|
25
|
+
*
|
|
26
|
+
* @param projectName User-supplied project directory or block name seed.
|
|
27
|
+
* @param templateId Selected scaffold template identifier.
|
|
28
|
+
* @returns Normalized default answers for scaffold prompts and non-interactive flows.
|
|
29
|
+
*/
|
|
30
|
+
export function getDefaultAnswers(projectName, templateId) {
|
|
31
|
+
const template = isBuiltInTemplateId(templateId) ? getTemplateById(templateId) : null;
|
|
32
|
+
const slugDefault = normalizeBlockSlug(projectName) || 'my-wp-typia-block';
|
|
33
|
+
return {
|
|
34
|
+
author: detectAuthor(),
|
|
35
|
+
dataStorageMode: templateId === 'persistence' ? 'custom-table' : undefined,
|
|
36
|
+
description: template?.description ?? 'A WordPress block scaffolded from a remote template',
|
|
37
|
+
namespace: slugDefault,
|
|
38
|
+
persistencePolicy: templateId === 'persistence' ? 'authenticated' : undefined,
|
|
39
|
+
phpPrefix: toSnakeCase(slugDefault),
|
|
40
|
+
slug: slugDefault,
|
|
41
|
+
textDomain: slugDefault,
|
|
42
|
+
title: toTitleCase(slugDefault),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function normalizeTemplateSelection(templateId) {
|
|
46
|
+
return templateId === WORKSPACE_TEMPLATE_ALIAS
|
|
47
|
+
? OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
|
|
48
|
+
: templateId;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve the scaffold template id from flags, defaults, and interactive selection.
|
|
52
|
+
*
|
|
53
|
+
* @param options Template resolution options for interactive and non-interactive flows.
|
|
54
|
+
* @returns The normalized template identifier to scaffold.
|
|
55
|
+
*/
|
|
56
|
+
export async function resolveTemplateId({ templateId, yes = false, isInteractive = false, selectTemplate, }) {
|
|
57
|
+
if (templateId) {
|
|
58
|
+
const normalizedTemplateId = normalizeTemplateSelection(templateId);
|
|
59
|
+
if (isRemovedBuiltInTemplateId(templateId)) {
|
|
60
|
+
throw new Error(getRemovedBuiltInTemplateMessage(templateId));
|
|
61
|
+
}
|
|
62
|
+
if (isBuiltInTemplateId(normalizedTemplateId)) {
|
|
63
|
+
return getTemplateById(normalizedTemplateId).id;
|
|
64
|
+
}
|
|
65
|
+
return normalizedTemplateId;
|
|
66
|
+
}
|
|
67
|
+
if (yes) {
|
|
68
|
+
return 'basic';
|
|
69
|
+
}
|
|
70
|
+
if (!isInteractive || !selectTemplate) {
|
|
71
|
+
throw new Error(`Template is required in non-interactive mode. Use --template <${TEMPLATE_IDS.join('|')}|./path|github:owner/repo/path[#ref]|npm-package>.`);
|
|
72
|
+
}
|
|
73
|
+
return normalizeTemplateSelection(await selectTemplate());
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Resolve the package manager id from flags, defaults, and interactive selection.
|
|
77
|
+
*
|
|
78
|
+
* @param options Package manager resolution options for interactive and non-interactive flows.
|
|
79
|
+
* @returns The normalized package manager id.
|
|
80
|
+
*/
|
|
81
|
+
export async function resolvePackageManagerId({ packageManager, yes = false, isInteractive = false, selectPackageManager, }) {
|
|
82
|
+
if (packageManager) {
|
|
83
|
+
return getPackageManager(packageManager).id;
|
|
84
|
+
}
|
|
85
|
+
if (yes) {
|
|
86
|
+
return 'npm';
|
|
87
|
+
}
|
|
88
|
+
if (!isInteractive || !selectPackageManager) {
|
|
89
|
+
throw new Error(`Package manager is required in non-interactive mode. Use --package-manager <${PACKAGE_MANAGER_IDS.join('|')}>.`);
|
|
90
|
+
}
|
|
91
|
+
return selectPackageManager();
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Collect scaffold answers from defaults, CLI overrides, and optional prompts.
|
|
95
|
+
*
|
|
96
|
+
* @param options Answer collection inputs including prompt callbacks and explicit overrides.
|
|
97
|
+
* @returns The normalized scaffold answers used for rendering and file generation.
|
|
98
|
+
*/
|
|
99
|
+
export async function collectScaffoldAnswers({ projectName, templateId, yes = false, dataStorageMode, namespace, persistencePolicy, phpPrefix, promptText, textDomain, }) {
|
|
100
|
+
const defaults = getDefaultAnswers(projectName, templateId);
|
|
101
|
+
if (yes) {
|
|
102
|
+
const identifiers = resolveScaffoldIdentifiers({
|
|
103
|
+
namespace: namespace ?? defaults.namespace,
|
|
104
|
+
phpPrefix,
|
|
105
|
+
slug: defaults.slug,
|
|
106
|
+
textDomain,
|
|
107
|
+
});
|
|
108
|
+
return {
|
|
109
|
+
...defaults,
|
|
110
|
+
dataStorageMode: dataStorageMode ?? defaults.dataStorageMode,
|
|
111
|
+
namespace: identifiers.namespace,
|
|
112
|
+
persistencePolicy: persistencePolicy ?? defaults.persistencePolicy,
|
|
113
|
+
phpPrefix: identifiers.phpPrefix,
|
|
114
|
+
textDomain: identifiers.textDomain,
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
if (!promptText) {
|
|
118
|
+
throw new Error('Interactive answers require a promptText callback.');
|
|
119
|
+
}
|
|
120
|
+
const identifiers = resolveScaffoldIdentifiers({
|
|
121
|
+
namespace: namespace ?? (await promptText('Namespace', defaults.namespace, validateNamespace)),
|
|
122
|
+
phpPrefix,
|
|
123
|
+
slug: await promptText('Block slug', defaults.slug, validateBlockSlug),
|
|
124
|
+
textDomain,
|
|
125
|
+
});
|
|
126
|
+
return {
|
|
127
|
+
author: await promptText('Author', defaults.author),
|
|
128
|
+
dataStorageMode: dataStorageMode ?? defaults.dataStorageMode,
|
|
129
|
+
description: await promptText('Description', defaults.description),
|
|
130
|
+
namespace: identifiers.namespace,
|
|
131
|
+
persistencePolicy: persistencePolicy ?? defaults.persistencePolicy,
|
|
132
|
+
phpPrefix: identifiers.phpPrefix,
|
|
133
|
+
slug: identifiers.slug,
|
|
134
|
+
textDomain: identifiers.textDomain,
|
|
135
|
+
title: await promptText('Block title', toTitleCase(identifiers.slug)),
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
import { execSync } from 'node:child_process';
|
|
@@ -3,27 +3,12 @@ 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
5
|
import type { ScaffoldTemplateVariables } from "./scaffold.js";
|
|
6
|
+
export { buildGitignore, buildReadme, mergeTextLines, } from "./scaffold-documents.js";
|
|
6
7
|
export interface InstallDependenciesOptions {
|
|
7
8
|
packageManager: PackageManagerId;
|
|
8
9
|
projectDir: string;
|
|
9
10
|
}
|
|
10
11
|
export declare function ensureDirectory(targetDir: string, allowExisting?: boolean): Promise<void>;
|
|
11
|
-
/**
|
|
12
|
-
* Builds the generated README markdown for one scaffolded project.
|
|
13
|
-
*
|
|
14
|
-
* @param templateId Scaffold template family or template identifier.
|
|
15
|
-
* @param variables Interpolated scaffold variables used in generated content.
|
|
16
|
-
* @param packageManager Package manager used to format install and script commands.
|
|
17
|
-
* @param options Optional README sections enabled by scaffold presets.
|
|
18
|
-
* @returns Markdown README content for the generated project root.
|
|
19
|
-
*/
|
|
20
|
-
export declare function buildReadme(templateId: string, variables: ScaffoldTemplateVariables, packageManager: PackageManagerId, { withMigrationUi, withTestPreset, withWpEnv, }?: {
|
|
21
|
-
withMigrationUi?: boolean;
|
|
22
|
-
withTestPreset?: boolean;
|
|
23
|
-
withWpEnv?: boolean;
|
|
24
|
-
}): string;
|
|
25
|
-
export declare function buildGitignore(): string;
|
|
26
|
-
export declare function mergeTextLines(primaryContent: string, existingContent: string): string;
|
|
27
12
|
export declare function writeStarterManifestFiles(targetDir: string, templateId: string, variables: ScaffoldTemplateVariables, artifacts?: readonly BuiltInBlockArtifact[]): Promise<void>;
|
|
28
13
|
/**
|
|
29
14
|
* Seed REST-derived persistence artifacts into a newly scaffolded built-in
|
|
@@ -3,18 +3,19 @@ import { promises as fsp } from "node:fs";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { execSync } from "node:child_process";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { applyGeneratedProjectDxPackageJson, applyLocalDevPresetFiles,
|
|
6
|
+
import { applyGeneratedProjectDxPackageJson, applyLocalDevPresetFiles, } from "./local-dev-presets.js";
|
|
7
7
|
import { applyMigrationUiCapability } from "./migration-ui-capability.js";
|
|
8
8
|
import { getPackageVersions } from "./package-versions.js";
|
|
9
9
|
import { ensureMigrationDirectories, writeInitialMigrationScaffold, writeMigrationConfig, } from "./migration-project.js";
|
|
10
10
|
import { syncPersistenceRestArtifacts, } from "./persistence-rest-artifacts.js";
|
|
11
|
-
import {
|
|
11
|
+
import { buildGitignore, buildReadme, mergeTextLines, } from "./scaffold-documents.js";
|
|
12
12
|
import { getStarterManifestFiles, stringifyStarterManifest, } from "./starter-manifests.js";
|
|
13
13
|
import { stringifyBuiltInBlockJsonDocument, } from "./built-in-block-artifacts.js";
|
|
14
14
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, } from "./template-registry.js";
|
|
15
15
|
import { copyInterpolatedDirectory } from "./template-render.js";
|
|
16
|
-
import { formatInstallCommand, formatPackageExecCommand,
|
|
16
|
+
import { formatInstallCommand, formatPackageExecCommand, getPackageManager, transformPackageManagerText, } from "./package-managers.js";
|
|
17
17
|
import { replaceRepositoryReferencePlaceholders, resolveScaffoldRepositoryReference, } from "./scaffold-repository-reference.js";
|
|
18
|
+
export { buildGitignore, buildReadme, mergeTextLines, } from "./scaffold-documents.js";
|
|
18
19
|
const EPHEMERAL_NODE_MODULES_LINK_TYPE = process.platform === "win32" ? "junction" : "dir";
|
|
19
20
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
20
21
|
const LOCKFILES = {
|
|
@@ -36,131 +37,6 @@ export async function ensureDirectory(targetDir, allowExisting = false) {
|
|
|
36
37
|
throw new Error(`Target directory is not empty: ${targetDir}`);
|
|
37
38
|
}
|
|
38
39
|
}
|
|
39
|
-
/**
|
|
40
|
-
* Builds the generated README markdown for one scaffolded project.
|
|
41
|
-
*
|
|
42
|
-
* @param templateId Scaffold template family or template identifier.
|
|
43
|
-
* @param variables Interpolated scaffold variables used in generated content.
|
|
44
|
-
* @param packageManager Package manager used to format install and script commands.
|
|
45
|
-
* @param options Optional README sections enabled by scaffold presets.
|
|
46
|
-
* @returns Markdown README content for the generated project root.
|
|
47
|
-
*/
|
|
48
|
-
export function buildReadme(templateId, variables, packageManager, { withMigrationUi = false, withTestPreset = false, withWpEnv = false, } = {}) {
|
|
49
|
-
const optionalOnboardingSteps = getOptionalOnboardingSteps(packageManager, templateId, {
|
|
50
|
-
compoundPersistenceEnabled: variables.compoundPersistenceEnabled === "true",
|
|
51
|
-
});
|
|
52
|
-
const initialCommitCommands = getInitialCommitCommands();
|
|
53
|
-
const sourceOfTruthNote = getTemplateSourceOfTruthNote(templateId, {
|
|
54
|
-
compoundPersistenceEnabled: variables.compoundPersistenceEnabled === "true",
|
|
55
|
-
});
|
|
56
|
-
const compoundPersistenceEnabled = variables.compoundPersistenceEnabled === "true";
|
|
57
|
-
const publicPersistencePolicyNote = variables.isPublicPersistencePolicy === "true"
|
|
58
|
-
? "Public persistence writes use signed short-lived tokens, per-request ids, and coarse rate limiting by default. Add application-specific abuse controls before using the same pattern for high-value metrics or experiments."
|
|
59
|
-
: null;
|
|
60
|
-
const compoundExtensionWorkflowSection = getCompoundExtensionWorkflowSection(packageManager, templateId);
|
|
61
|
-
const phpRestExtensionPointsSection = getPhpRestExtensionPointsSection(templateId, {
|
|
62
|
-
compoundPersistenceEnabled,
|
|
63
|
-
slug: variables.slug,
|
|
64
|
-
});
|
|
65
|
-
const developmentScript = getPrimaryDevelopmentScript(templateId);
|
|
66
|
-
const wpEnvSection = withWpEnv
|
|
67
|
-
? `## Local WordPress\n\n\`\`\`bash\n${formatRunScript(packageManager, "wp-env:start")}\n${formatRunScript(packageManager, "wp-env:stop")}\n${formatRunScript(packageManager, "wp-env:reset")}\n\`\`\``
|
|
68
|
-
: "";
|
|
69
|
-
const testPresetSection = withTestPreset
|
|
70
|
-
? `## Local Test Preset\n\n\`\`\`bash\n${formatRunScript(packageManager, "wp-env:start:test")}\n${formatRunScript(packageManager, "wp-env:wait:test")}\n${formatRunScript(packageManager, "test:e2e")}\n\`\`\`\n\nThe generated smoke test uses \`.wp-env.test.json\` and verifies that the scaffolded block registers in the WordPress editor.`
|
|
71
|
-
: "";
|
|
72
|
-
const migrationSection = withMigrationUi
|
|
73
|
-
? `## Migration UI\n\nThis scaffold already includes an initialized migration workspace at \`v1\`, generated deprecated/runtime artifacts, and an editor-embedded migration dashboard. Migration versions are schema lineage labels and are separate from your package or plugin release version. Use the existing CLI commands to snapshot, diff, scaffold, verify, and fuzz future schema changes.\n\n\`\`\`bash\n${formatRunScript(packageManager, "migration:doctor")}\n${formatRunScript(packageManager, "migration:verify")}\n${formatRunScript(packageManager, "migration:fuzz")}\n\`\`\`\n\nRun \`migration:init\` only when retrofitting migration support into an older project that was not scaffolded with \`--with-migration-ui\`.`
|
|
74
|
-
: "";
|
|
75
|
-
return `# ${variables.title}
|
|
76
|
-
|
|
77
|
-
${variables.description}
|
|
78
|
-
|
|
79
|
-
## Template
|
|
80
|
-
|
|
81
|
-
${templateId}
|
|
82
|
-
|
|
83
|
-
## Quick Start
|
|
84
|
-
|
|
85
|
-
\`\`\`bash
|
|
86
|
-
${formatInstallCommand(packageManager)}
|
|
87
|
-
${formatRunScript(packageManager, developmentScript)}
|
|
88
|
-
\`\`\`
|
|
89
|
-
|
|
90
|
-
${getQuickStartWorkflowNote(packageManager, templateId, {
|
|
91
|
-
compoundPersistenceEnabled,
|
|
92
|
-
})}
|
|
93
|
-
|
|
94
|
-
## Build and Verify
|
|
95
|
-
|
|
96
|
-
\`\`\`bash
|
|
97
|
-
${formatRunScript(packageManager, "build")}
|
|
98
|
-
${formatRunScript(packageManager, "typecheck")}
|
|
99
|
-
\`\`\`
|
|
100
|
-
|
|
101
|
-
## Advanced Sync
|
|
102
|
-
|
|
103
|
-
\`\`\`bash
|
|
104
|
-
${optionalOnboardingSteps.join("\n")}
|
|
105
|
-
\`\`\`
|
|
106
|
-
|
|
107
|
-
${getOptionalOnboardingNote(packageManager, templateId, {
|
|
108
|
-
compoundPersistenceEnabled,
|
|
109
|
-
})}
|
|
110
|
-
|
|
111
|
-
## Before First Commit
|
|
112
|
-
|
|
113
|
-
\`\`\`bash
|
|
114
|
-
${initialCommitCommands.join("\n")}
|
|
115
|
-
\`\`\`
|
|
116
|
-
|
|
117
|
-
${getInitialCommitNote()}
|
|
118
|
-
|
|
119
|
-
${sourceOfTruthNote}${publicPersistencePolicyNote ? `\n\n${publicPersistencePolicyNote}` : ""}${migrationSection ? `\n\n${migrationSection}` : ""}${compoundExtensionWorkflowSection ? `\n\n${compoundExtensionWorkflowSection}` : ""}${wpEnvSection ? `\n\n${wpEnvSection}` : ""}${testPresetSection ? `\n\n${testPresetSection}` : ""}${phpRestExtensionPointsSection ? `\n\n${phpRestExtensionPointsSection}` : ""}
|
|
120
|
-
`;
|
|
121
|
-
}
|
|
122
|
-
export function buildGitignore() {
|
|
123
|
-
return `# Dependencies
|
|
124
|
-
node_modules/
|
|
125
|
-
.yarn/
|
|
126
|
-
.pnp.*
|
|
127
|
-
|
|
128
|
-
# Build
|
|
129
|
-
build/
|
|
130
|
-
dist/
|
|
131
|
-
|
|
132
|
-
# Editor
|
|
133
|
-
.vscode/
|
|
134
|
-
.idea/
|
|
135
|
-
|
|
136
|
-
# OS
|
|
137
|
-
.DS_Store
|
|
138
|
-
Thumbs.db
|
|
139
|
-
|
|
140
|
-
# WordPress
|
|
141
|
-
*.log
|
|
142
|
-
.wp-env/
|
|
143
|
-
`;
|
|
144
|
-
}
|
|
145
|
-
export function mergeTextLines(primaryContent, existingContent) {
|
|
146
|
-
const normalizedPrimary = primaryContent.replace(/\r\n/g, "\n").trimEnd();
|
|
147
|
-
const normalizedExisting = existingContent.replace(/\r\n/g, "\n").trimEnd();
|
|
148
|
-
const mergedLines = [];
|
|
149
|
-
const seen = new Set();
|
|
150
|
-
for (const line of [...normalizedPrimary.split("\n"), ...normalizedExisting.split("\n")]) {
|
|
151
|
-
if (line.length === 0 && mergedLines[mergedLines.length - 1] === "") {
|
|
152
|
-
continue;
|
|
153
|
-
}
|
|
154
|
-
if (line.length > 0 && seen.has(line)) {
|
|
155
|
-
continue;
|
|
156
|
-
}
|
|
157
|
-
if (line.length > 0) {
|
|
158
|
-
seen.add(line);
|
|
159
|
-
}
|
|
160
|
-
mergedLines.push(line);
|
|
161
|
-
}
|
|
162
|
-
return `${mergedLines.join("\n").replace(/\n{3,}/g, "\n\n")}\n`;
|
|
163
|
-
}
|
|
164
40
|
export async function writeStarterManifestFiles(targetDir, templateId, variables, artifacts) {
|
|
165
41
|
const manifests = artifacts
|
|
166
42
|
? artifacts.map((artifact) => ({
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { PackageManagerId } from './package-managers.js';
|
|
2
|
+
import type { ScaffoldTemplateVariables } from './scaffold.js';
|
|
3
|
+
/**
|
|
4
|
+
* Builds the generated README markdown for one scaffolded project.
|
|
5
|
+
*
|
|
6
|
+
* @param templateId Scaffold template family or template identifier.
|
|
7
|
+
* @param variables Interpolated scaffold variables used in generated content.
|
|
8
|
+
* @param packageManager Package manager used to format install and script commands.
|
|
9
|
+
* @param options Optional README sections enabled by scaffold presets.
|
|
10
|
+
* @returns Markdown README content for the generated project root.
|
|
11
|
+
*/
|
|
12
|
+
export declare function buildReadme(templateId: string, variables: ScaffoldTemplateVariables, packageManager: PackageManagerId, { withMigrationUi, withTestPreset, withWpEnv, }?: {
|
|
13
|
+
withMigrationUi?: boolean;
|
|
14
|
+
withTestPreset?: boolean;
|
|
15
|
+
withWpEnv?: boolean;
|
|
16
|
+
}): string;
|
|
17
|
+
/**
|
|
18
|
+
* Build the default `.gitignore` contents for a scaffolded project.
|
|
19
|
+
*
|
|
20
|
+
* @returns A newline-terminated `.gitignore` string covering dependency, build, editor, OS, and WordPress artifacts.
|
|
21
|
+
*/
|
|
22
|
+
export declare function buildGitignore(): string;
|
|
23
|
+
/**
|
|
24
|
+
* Merge generated and existing text files while keeping line order stable.
|
|
25
|
+
*
|
|
26
|
+
* Existing unique lines are appended after the primary content, duplicate
|
|
27
|
+
* non-empty lines are removed, and runs of more than two blank lines collapse
|
|
28
|
+
* to a single empty separator.
|
|
29
|
+
*
|
|
30
|
+
* @param primaryContent Newly generated text that should appear first.
|
|
31
|
+
* @param existingContent Existing file contents preserved after unique generated lines.
|
|
32
|
+
* @returns The merged text block with a trailing newline.
|
|
33
|
+
*/
|
|
34
|
+
export declare function mergeTextLines(primaryContent: string, existingContent: string): string;
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import { getPrimaryDevelopmentScript } from './local-dev-presets.js';
|
|
2
|
+
import { getCompoundExtensionWorkflowSection, getInitialCommitCommands, getInitialCommitNote, getOptionalOnboardingNote, getOptionalOnboardingSteps, getQuickStartWorkflowNote, getPhpRestExtensionPointsSection, getTemplateSourceOfTruthNote, } from './scaffold-onboarding.js';
|
|
3
|
+
import { formatInstallCommand, formatRunScript, } from './package-managers.js';
|
|
4
|
+
/**
|
|
5
|
+
* Builds the generated README markdown for one scaffolded project.
|
|
6
|
+
*
|
|
7
|
+
* @param templateId Scaffold template family or template identifier.
|
|
8
|
+
* @param variables Interpolated scaffold variables used in generated content.
|
|
9
|
+
* @param packageManager Package manager used to format install and script commands.
|
|
10
|
+
* @param options Optional README sections enabled by scaffold presets.
|
|
11
|
+
* @returns Markdown README content for the generated project root.
|
|
12
|
+
*/
|
|
13
|
+
export function buildReadme(templateId, variables, packageManager, { withMigrationUi = false, withTestPreset = false, withWpEnv = false, } = {}) {
|
|
14
|
+
const optionalOnboardingSteps = getOptionalOnboardingSteps(packageManager, templateId, {
|
|
15
|
+
compoundPersistenceEnabled: variables.compoundPersistenceEnabled === 'true',
|
|
16
|
+
});
|
|
17
|
+
const initialCommitCommands = getInitialCommitCommands();
|
|
18
|
+
const sourceOfTruthNote = getTemplateSourceOfTruthNote(templateId, {
|
|
19
|
+
compoundPersistenceEnabled: variables.compoundPersistenceEnabled === 'true',
|
|
20
|
+
});
|
|
21
|
+
const compoundPersistenceEnabled = variables.compoundPersistenceEnabled === 'true';
|
|
22
|
+
const publicPersistencePolicyNote = variables.isPublicPersistencePolicy === 'true'
|
|
23
|
+
? 'Public persistence writes use signed short-lived tokens, per-request ids, and coarse rate limiting by default. Add application-specific abuse controls before using the same pattern for high-value metrics or experiments.'
|
|
24
|
+
: null;
|
|
25
|
+
const compoundExtensionWorkflowSection = getCompoundExtensionWorkflowSection(packageManager, templateId);
|
|
26
|
+
const phpRestExtensionPointsSection = getPhpRestExtensionPointsSection(templateId, {
|
|
27
|
+
compoundPersistenceEnabled,
|
|
28
|
+
slug: variables.slug,
|
|
29
|
+
});
|
|
30
|
+
const developmentScript = getPrimaryDevelopmentScript(templateId);
|
|
31
|
+
const wpEnvSection = withWpEnv
|
|
32
|
+
? `## Local WordPress\n\n\`\`\`bash\n${formatRunScript(packageManager, 'wp-env:start')}\n${formatRunScript(packageManager, 'wp-env:stop')}\n${formatRunScript(packageManager, 'wp-env:reset')}\n\`\`\``
|
|
33
|
+
: '';
|
|
34
|
+
const testPresetSection = withTestPreset
|
|
35
|
+
? `## Local Test Preset\n\n\`\`\`bash\n${formatRunScript(packageManager, 'wp-env:start:test')}\n${formatRunScript(packageManager, 'wp-env:wait:test')}\n${formatRunScript(packageManager, 'test:e2e')}\n\`\`\`\n\nThe generated smoke test uses \`.wp-env.test.json\` and verifies that the scaffolded block registers in the WordPress editor.`
|
|
36
|
+
: '';
|
|
37
|
+
const migrationSection = withMigrationUi
|
|
38
|
+
? `## Migration UI\n\nThis scaffold already includes an initialized migration workspace at \`v1\`, generated deprecated/runtime artifacts, and an editor-embedded migration dashboard. Migration versions are schema lineage labels and are separate from your package or plugin release version. Use the existing CLI commands to snapshot, diff, scaffold, verify, and fuzz future schema changes.\n\n\`\`\`bash\n${formatRunScript(packageManager, 'migration:doctor')}\n${formatRunScript(packageManager, 'migration:verify')}\n${formatRunScript(packageManager, 'migration:fuzz')}\n\`\`\`\n\nRun \`migration:init\` only when retrofitting migration support into an older project that was not scaffolded with \`--with-migration-ui\`.`
|
|
39
|
+
: '';
|
|
40
|
+
return `# ${variables.title}
|
|
41
|
+
|
|
42
|
+
${variables.description}
|
|
43
|
+
|
|
44
|
+
## Template
|
|
45
|
+
|
|
46
|
+
${templateId}
|
|
47
|
+
|
|
48
|
+
## Quick Start
|
|
49
|
+
|
|
50
|
+
\`\`\`bash
|
|
51
|
+
${formatInstallCommand(packageManager)}
|
|
52
|
+
${formatRunScript(packageManager, developmentScript)}
|
|
53
|
+
\`\`\`
|
|
54
|
+
|
|
55
|
+
${getQuickStartWorkflowNote(packageManager, templateId, {
|
|
56
|
+
compoundPersistenceEnabled,
|
|
57
|
+
})}
|
|
58
|
+
|
|
59
|
+
## Build and Verify
|
|
60
|
+
|
|
61
|
+
\`\`\`bash
|
|
62
|
+
${formatRunScript(packageManager, 'build')}
|
|
63
|
+
${formatRunScript(packageManager, 'typecheck')}
|
|
64
|
+
\`\`\`
|
|
65
|
+
|
|
66
|
+
## Advanced Sync
|
|
67
|
+
|
|
68
|
+
\`\`\`bash
|
|
69
|
+
${optionalOnboardingSteps.join('\n')}
|
|
70
|
+
\`\`\`
|
|
71
|
+
|
|
72
|
+
${getOptionalOnboardingNote(packageManager, templateId, {
|
|
73
|
+
compoundPersistenceEnabled,
|
|
74
|
+
})}
|
|
75
|
+
|
|
76
|
+
## Before First Commit
|
|
77
|
+
|
|
78
|
+
\`\`\`bash
|
|
79
|
+
${initialCommitCommands.join('\n')}
|
|
80
|
+
\`\`\`
|
|
81
|
+
|
|
82
|
+
${getInitialCommitNote()}
|
|
83
|
+
|
|
84
|
+
${sourceOfTruthNote}${publicPersistencePolicyNote ? `\n\n${publicPersistencePolicyNote}` : ''}${migrationSection ? `\n\n${migrationSection}` : ''}${compoundExtensionWorkflowSection ? `\n\n${compoundExtensionWorkflowSection}` : ''}${wpEnvSection ? `\n\n${wpEnvSection}` : ''}${testPresetSection ? `\n\n${testPresetSection}` : ''}${phpRestExtensionPointsSection ? `\n\n${phpRestExtensionPointsSection}` : ''}
|
|
85
|
+
`;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Build the default `.gitignore` contents for a scaffolded project.
|
|
89
|
+
*
|
|
90
|
+
* @returns A newline-terminated `.gitignore` string covering dependency, build, editor, OS, and WordPress artifacts.
|
|
91
|
+
*/
|
|
92
|
+
export function buildGitignore() {
|
|
93
|
+
return `# Dependencies
|
|
94
|
+
node_modules/
|
|
95
|
+
.yarn/
|
|
96
|
+
.pnp.*
|
|
97
|
+
|
|
98
|
+
# Build
|
|
99
|
+
build/
|
|
100
|
+
dist/
|
|
101
|
+
|
|
102
|
+
# Editor
|
|
103
|
+
.vscode/
|
|
104
|
+
.idea/
|
|
105
|
+
|
|
106
|
+
# OS
|
|
107
|
+
.DS_Store
|
|
108
|
+
Thumbs.db
|
|
109
|
+
|
|
110
|
+
# WordPress
|
|
111
|
+
*.log
|
|
112
|
+
.wp-env/
|
|
113
|
+
`;
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* Merge generated and existing text files while keeping line order stable.
|
|
117
|
+
*
|
|
118
|
+
* Existing unique lines are appended after the primary content, duplicate
|
|
119
|
+
* non-empty lines are removed, and runs of more than two blank lines collapse
|
|
120
|
+
* to a single empty separator.
|
|
121
|
+
*
|
|
122
|
+
* @param primaryContent Newly generated text that should appear first.
|
|
123
|
+
* @param existingContent Existing file contents preserved after unique generated lines.
|
|
124
|
+
* @returns The merged text block with a trailing newline.
|
|
125
|
+
*/
|
|
126
|
+
export function mergeTextLines(primaryContent, existingContent) {
|
|
127
|
+
const normalizedPrimary = primaryContent.replace(/\r\n/g, '\n').trimEnd();
|
|
128
|
+
const normalizedExisting = existingContent.replace(/\r\n/g, '\n').trimEnd();
|
|
129
|
+
const mergedLines = [];
|
|
130
|
+
const seen = new Set();
|
|
131
|
+
for (const line of [...normalizedPrimary.split('\n'), ...normalizedExisting.split('\n')]) {
|
|
132
|
+
if (line.length === 0 && mergedLines[mergedLines.length - 1] === '') {
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (line.length > 0 && seen.has(line)) {
|
|
136
|
+
continue;
|
|
137
|
+
}
|
|
138
|
+
if (line.length > 0) {
|
|
139
|
+
seen.add(line);
|
|
140
|
+
}
|
|
141
|
+
mergedLines.push(line);
|
|
142
|
+
}
|
|
143
|
+
return `${mergedLines.join('\n').replace(/\n{3,}/g, '\n\n')}\n`;
|
|
144
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ScaffoldAnswers, ScaffoldTemplateVariables } from './scaffold.js';
|
|
2
|
+
/**
|
|
3
|
+
* Build the normalized template variables used by scaffold rendering.
|
|
4
|
+
*
|
|
5
|
+
* @param templateId Selected scaffold template identifier.
|
|
6
|
+
* @param answers Normalized scaffold answers collected from defaults, flags, and prompts.
|
|
7
|
+
* @returns Template variables ready for file interpolation and generated artifacts.
|
|
8
|
+
*/
|
|
9
|
+
export declare function getTemplateVariables(templateId: string, answers: ScaffoldAnswers): ScaffoldTemplateVariables;
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { buildTemplateVariablesFromBlockSpec, createBuiltInBlockSpec, } from './block-generator-service.js';
|
|
2
|
+
import { getPackageVersions } from './package-versions.js';
|
|
3
|
+
import { buildBlockCssClassName, buildFrontendCssClassName, resolveScaffoldIdentifiers, } from './scaffold-identifiers.js';
|
|
4
|
+
import { BUILTIN_BLOCK_METADATA_VERSION, COMPOUND_CHILD_BLOCK_METADATA_DEFAULTS, getBuiltInTemplateMetadataDefaults, } from './template-defaults.js';
|
|
5
|
+
import { getTemplateById, isBuiltInTemplateId, } from './template-registry.js';
|
|
6
|
+
import { toPascalCase, toSnakeCase, } from './string-case.js';
|
|
7
|
+
/**
|
|
8
|
+
* Build the normalized template variables used by scaffold rendering.
|
|
9
|
+
*
|
|
10
|
+
* @param templateId Selected scaffold template identifier.
|
|
11
|
+
* @param answers Normalized scaffold answers collected from defaults, flags, and prompts.
|
|
12
|
+
* @returns Template variables ready for file interpolation and generated artifacts.
|
|
13
|
+
*/
|
|
14
|
+
export function getTemplateVariables(templateId, answers) {
|
|
15
|
+
if (isBuiltInTemplateId(templateId)) {
|
|
16
|
+
return buildTemplateVariablesFromBlockSpec(createBuiltInBlockSpec({
|
|
17
|
+
answers,
|
|
18
|
+
dataStorageMode: answers.dataStorageMode,
|
|
19
|
+
persistencePolicy: answers.persistencePolicy,
|
|
20
|
+
templateId,
|
|
21
|
+
}));
|
|
22
|
+
}
|
|
23
|
+
const { apiClientPackageVersion, blockRuntimePackageVersion, blockTypesPackageVersion, projectToolsPackageVersion, restPackageVersion, } = getPackageVersions();
|
|
24
|
+
const template = isBuiltInTemplateId(templateId) ? getTemplateById(templateId) : null;
|
|
25
|
+
const metadataDefaults = isBuiltInTemplateId(templateId)
|
|
26
|
+
? getBuiltInTemplateMetadataDefaults(templateId)
|
|
27
|
+
: null;
|
|
28
|
+
const identifiers = resolveScaffoldIdentifiers({
|
|
29
|
+
namespace: answers.namespace,
|
|
30
|
+
phpPrefix: answers.phpPrefix,
|
|
31
|
+
slug: answers.slug,
|
|
32
|
+
textDomain: answers.textDomain,
|
|
33
|
+
});
|
|
34
|
+
const slug = identifiers.slug;
|
|
35
|
+
const slugSnakeCase = toSnakeCase(slug);
|
|
36
|
+
const pascalCase = toPascalCase(slug);
|
|
37
|
+
const title = answers.title.trim();
|
|
38
|
+
const namespace = identifiers.namespace;
|
|
39
|
+
const description = answers.description.trim();
|
|
40
|
+
const textDomain = identifiers.textDomain;
|
|
41
|
+
const phpPrefix = identifiers.phpPrefix;
|
|
42
|
+
const phpPrefixUpper = phpPrefix.toUpperCase();
|
|
43
|
+
const compoundChildTitle = `${title} Item`;
|
|
44
|
+
const cssClassName = buildBlockCssClassName(namespace, slug);
|
|
45
|
+
const compoundChildCssClassName = buildBlockCssClassName(namespace, `${slug}-item`);
|
|
46
|
+
const compoundPersistenceEnabled = templateId === 'persistence'
|
|
47
|
+
? true
|
|
48
|
+
: templateId === 'compound'
|
|
49
|
+
? Boolean(answers.dataStorageMode || answers.persistencePolicy)
|
|
50
|
+
: false;
|
|
51
|
+
const dataStorageMode = templateId === 'persistence' || compoundPersistenceEnabled
|
|
52
|
+
? answers.dataStorageMode ?? 'custom-table'
|
|
53
|
+
: 'custom-table';
|
|
54
|
+
const persistencePolicy = templateId === 'persistence' || compoundPersistenceEnabled
|
|
55
|
+
? answers.persistencePolicy ?? 'authenticated'
|
|
56
|
+
: 'authenticated';
|
|
57
|
+
return {
|
|
58
|
+
apiClientPackageVersion,
|
|
59
|
+
author: answers.author.trim(),
|
|
60
|
+
blockRuntimePackageVersion,
|
|
61
|
+
blockMetadataVersion: BUILTIN_BLOCK_METADATA_VERSION,
|
|
62
|
+
blockTypesPackageVersion,
|
|
63
|
+
category: metadataDefaults?.category ?? template?.defaultCategory ?? 'widgets',
|
|
64
|
+
icon: metadataDefaults?.icon ?? 'smiley',
|
|
65
|
+
compoundChildTitle,
|
|
66
|
+
compoundChildCategory: COMPOUND_CHILD_BLOCK_METADATA_DEFAULTS.category,
|
|
67
|
+
compoundChildCssClassName,
|
|
68
|
+
compoundChildIcon: COMPOUND_CHILD_BLOCK_METADATA_DEFAULTS.icon,
|
|
69
|
+
compoundChildTitleJson: JSON.stringify(compoundChildTitle),
|
|
70
|
+
compoundPersistenceEnabled: compoundPersistenceEnabled ? 'true' : 'false',
|
|
71
|
+
projectToolsPackageVersion,
|
|
72
|
+
cssClassName,
|
|
73
|
+
dataStorageMode,
|
|
74
|
+
dashCase: slug,
|
|
75
|
+
description,
|
|
76
|
+
frontendCssClassName: buildFrontendCssClassName(cssClassName),
|
|
77
|
+
isAuthenticatedPersistencePolicy: persistencePolicy === 'authenticated' ? 'true' : 'false',
|
|
78
|
+
isPublicPersistencePolicy: persistencePolicy === 'public' ? 'true' : 'false',
|
|
79
|
+
bootstrapCredentialDeclarations: persistencePolicy === 'public'
|
|
80
|
+
? "publicWriteExpiresAt?: number & tags.Type< 'uint32' >;\n\tpublicWriteToken?: string & tags.MinLength< 1 > & tags.MaxLength< 512 >;"
|
|
81
|
+
: "restNonce?: string & tags.MinLength< 1 > & tags.MaxLength< 128 >;",
|
|
82
|
+
persistencePolicyDescriptionJson: JSON.stringify(persistencePolicy === 'authenticated'
|
|
83
|
+
? 'Writes require a logged-in user and a valid REST nonce.'
|
|
84
|
+
: 'Anonymous writes use signed short-lived public tokens, per-request ids, and coarse rate limiting.'),
|
|
85
|
+
keyword: slug.replace(/-/g, ' '),
|
|
86
|
+
namespace,
|
|
87
|
+
needsMigration: '{{needsMigration}}',
|
|
88
|
+
pascalCase,
|
|
89
|
+
phpPrefix,
|
|
90
|
+
phpPrefixUpper,
|
|
91
|
+
restPackageVersion,
|
|
92
|
+
publicWriteRequestIdDeclaration: persistencePolicy === 'public'
|
|
93
|
+
? "publicWriteRequestId: string & tags.MinLength< 1 > & tags.MaxLength< 128 >;"
|
|
94
|
+
: "publicWriteRequestId?: string & tags.MinLength< 1 > & tags.MaxLength< 128 >;",
|
|
95
|
+
restWriteAuthIntent: persistencePolicy === 'public'
|
|
96
|
+
? 'public-write-protected'
|
|
97
|
+
: 'authenticated',
|
|
98
|
+
restWriteAuthMechanism: persistencePolicy === 'public' ? 'public-signed-token' : 'rest-nonce',
|
|
99
|
+
restWriteAuthMode: persistencePolicy === 'public' ? 'public-signed-token' : 'authenticated-rest-nonce',
|
|
100
|
+
slug,
|
|
101
|
+
slugCamelCase: pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1),
|
|
102
|
+
slugKebabCase: slug,
|
|
103
|
+
slugSnakeCase,
|
|
104
|
+
textDomain,
|
|
105
|
+
textdomain: textDomain,
|
|
106
|
+
title,
|
|
107
|
+
titleJson: JSON.stringify(title),
|
|
108
|
+
titleCase: pascalCase,
|
|
109
|
+
persistencePolicy,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
@@ -81,19 +81,25 @@ export interface ScaffoldTemplateVariables extends Record<string, string> {
|
|
|
81
81
|
* can surface custom ids. Downstream code uses `isBuiltInTemplateId()` to
|
|
82
82
|
* distinguish built-in templates from custom sources.
|
|
83
83
|
*/
|
|
84
|
-
interface ResolveTemplateOptions {
|
|
84
|
+
export interface ResolveTemplateOptions {
|
|
85
85
|
isInteractive?: boolean;
|
|
86
86
|
selectTemplate?: () => Promise<string>;
|
|
87
87
|
templateId?: string;
|
|
88
88
|
yes?: boolean;
|
|
89
89
|
}
|
|
90
|
-
|
|
90
|
+
/**
|
|
91
|
+
* Options for resolving the package manager in CLI and interactive scaffold flows.
|
|
92
|
+
*/
|
|
93
|
+
export interface ResolvePackageManagerOptions {
|
|
91
94
|
isInteractive?: boolean;
|
|
92
95
|
packageManager?: string;
|
|
93
96
|
selectPackageManager?: () => Promise<PackageManagerId>;
|
|
94
97
|
yes?: boolean;
|
|
95
98
|
}
|
|
96
|
-
|
|
99
|
+
/**
|
|
100
|
+
* Options for collecting scaffold answers from defaults, overrides, and prompts.
|
|
101
|
+
*/
|
|
102
|
+
export interface CollectScaffoldAnswersOptions {
|
|
97
103
|
dataStorageMode?: DataStorageMode;
|
|
98
104
|
namespace?: string;
|
|
99
105
|
phpPrefix?: string;
|
|
@@ -139,12 +145,8 @@ export interface ScaffoldProjectResult {
|
|
|
139
145
|
warnings: string[];
|
|
140
146
|
}
|
|
141
147
|
export { buildBlockCssClassName } from "./scaffold-identifiers.js";
|
|
148
|
+
export { collectScaffoldAnswers, detectAuthor, getDefaultAnswers, resolvePackageManagerId, resolveTemplateId, } from "./scaffold-answer-resolution.js";
|
|
149
|
+
export { getTemplateVariables } from "./scaffold-template-variables.js";
|
|
142
150
|
export declare function isDataStorageMode(value: string): value is DataStorageMode;
|
|
143
151
|
export declare function isPersistencePolicy(value: string): value is PersistencePolicy;
|
|
144
|
-
export declare function detectAuthor(): string;
|
|
145
|
-
export declare function getDefaultAnswers(projectName: string, templateId: string): ScaffoldAnswers;
|
|
146
|
-
export declare function resolveTemplateId({ templateId, yes, isInteractive, selectTemplate, }: ResolveTemplateOptions): Promise<string>;
|
|
147
|
-
export declare function resolvePackageManagerId({ packageManager, yes, isInteractive, selectPackageManager, }: ResolvePackageManagerOptions): Promise<PackageManagerId>;
|
|
148
|
-
export declare function collectScaffoldAnswers({ projectName, templateId, yes, dataStorageMode, namespace, persistencePolicy, phpPrefix, promptText, textDomain, }: CollectScaffoldAnswersOptions): Promise<ScaffoldAnswers>;
|
|
149
|
-
export declare function getTemplateVariables(templateId: string, answers: ScaffoldAnswers): ScaffoldTemplateVariables;
|
|
150
152
|
export declare function scaffoldProject({ projectDir, templateId, answers, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, repositoryReference, cwd, allowExistingDir, noInstall, installDependencies, variant, withMigrationUi, withTestPreset, withWpEnv, }: ScaffoldProjectOptions): Promise<ScaffoldProjectResult>;
|
package/dist/runtime/scaffold.js
CHANGED
|
@@ -1,230 +1,34 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import { promises as fsp } from "node:fs";
|
|
3
3
|
import path from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import { PACKAGE_MANAGER_IDS, getPackageManager, } from "./package-managers.js";
|
|
4
|
+
import { getPackageManager } from "./package-managers.js";
|
|
6
5
|
import { buildGitignore, buildReadme, mergeTextLines, replaceTextRecursively, } from "./scaffold-apply-utils.js";
|
|
7
|
-
import { buildBlockCssClassName, buildFrontendCssClassName, normalizeBlockSlug, resolveScaffoldIdentifiers, validateBlockSlug, validateNamespace, } from "./scaffold-identifiers.js";
|
|
8
6
|
import { applyGeneratedProjectDxPackageJson, applyLocalDevPresetFiles, } from "./local-dev-presets.js";
|
|
9
7
|
import { applyMigrationUiCapability } from "./migration-ui-capability.js";
|
|
10
|
-
import { getPackageVersions } from "./package-versions.js";
|
|
11
8
|
import { applyWorkspaceMigrationCapability, ensureScaffoldDirectory, isOfficialWorkspaceProject, seedBuiltInPersistenceArtifacts, writeStarterManifestFiles, } from "./scaffold-bootstrap.js";
|
|
12
9
|
import { defaultInstallDependencies, normalizePackageJson, normalizePackageManagerFiles, removeUnexpectedLockfiles, } from "./scaffold-package-manager-files.js";
|
|
13
|
-
import { toPascalCase, toSnakeCase, toTitleCase, } from "./string-case.js";
|
|
14
|
-
import { BUILTIN_BLOCK_METADATA_VERSION, COMPOUND_CHILD_BLOCK_METADATA_DEFAULTS, getBuiltInTemplateMetadataDefaults, getRemovedBuiltInTemplateMessage, isRemovedBuiltInTemplateId, } from "./template-defaults.js";
|
|
15
10
|
import { copyInterpolatedDirectory } from "./template-render.js";
|
|
16
|
-
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE,
|
|
11
|
+
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, isBuiltInTemplateId, } from "./template-registry.js";
|
|
17
12
|
import { resolveTemplateSource } from "./template-source.js";
|
|
18
|
-
import { BlockGeneratorService,
|
|
13
|
+
import { BlockGeneratorService, } from "./block-generator-service.js";
|
|
14
|
+
import { getTemplateVariables } from "./scaffold-template-variables.js";
|
|
19
15
|
const WORKSPACE_TEMPLATE_ALIAS = "workspace";
|
|
20
16
|
export const DATA_STORAGE_MODES = ["post-meta", "custom-table"];
|
|
21
17
|
export const PERSISTENCE_POLICIES = ["authenticated", "public"];
|
|
22
18
|
export { buildBlockCssClassName } from "./scaffold-identifiers.js";
|
|
19
|
+
export { collectScaffoldAnswers, detectAuthor, getDefaultAnswers, resolvePackageManagerId, resolveTemplateId, } from "./scaffold-answer-resolution.js";
|
|
20
|
+
export { getTemplateVariables } from "./scaffold-template-variables.js";
|
|
23
21
|
export function isDataStorageMode(value) {
|
|
24
22
|
return DATA_STORAGE_MODES.includes(value);
|
|
25
23
|
}
|
|
26
24
|
export function isPersistencePolicy(value) {
|
|
27
25
|
return PERSISTENCE_POLICIES.includes(value);
|
|
28
26
|
}
|
|
29
|
-
export function detectAuthor() {
|
|
30
|
-
try {
|
|
31
|
-
return (execSync("git config user.name", {
|
|
32
|
-
encoding: "utf8",
|
|
33
|
-
stdio: ["ignore", "pipe", "ignore"],
|
|
34
|
-
}).trim() || "Your Name");
|
|
35
|
-
}
|
|
36
|
-
catch {
|
|
37
|
-
return "Your Name";
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
export function getDefaultAnswers(projectName, templateId) {
|
|
41
|
-
const template = isBuiltInTemplateId(templateId) ? getTemplateById(templateId) : null;
|
|
42
|
-
const slugDefault = normalizeBlockSlug(projectName) || "my-wp-typia-block";
|
|
43
|
-
return {
|
|
44
|
-
author: detectAuthor(),
|
|
45
|
-
dataStorageMode: templateId === "persistence" ? "custom-table" : undefined,
|
|
46
|
-
description: template?.description ?? "A WordPress block scaffolded from a remote template",
|
|
47
|
-
namespace: slugDefault,
|
|
48
|
-
persistencePolicy: templateId === "persistence" ? "authenticated" : undefined,
|
|
49
|
-
phpPrefix: toSnakeCase(slugDefault),
|
|
50
|
-
slug: slugDefault,
|
|
51
|
-
textDomain: slugDefault,
|
|
52
|
-
title: toTitleCase(slugDefault),
|
|
53
|
-
};
|
|
54
|
-
}
|
|
55
27
|
function normalizeTemplateSelection(templateId) {
|
|
56
28
|
return templateId === WORKSPACE_TEMPLATE_ALIAS
|
|
57
29
|
? OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
|
|
58
30
|
: templateId;
|
|
59
31
|
}
|
|
60
|
-
export async function resolveTemplateId({ templateId, yes = false, isInteractive = false, selectTemplate, }) {
|
|
61
|
-
if (templateId) {
|
|
62
|
-
const normalizedTemplateId = normalizeTemplateSelection(templateId);
|
|
63
|
-
if (isRemovedBuiltInTemplateId(templateId)) {
|
|
64
|
-
throw new Error(getRemovedBuiltInTemplateMessage(templateId));
|
|
65
|
-
}
|
|
66
|
-
if (isBuiltInTemplateId(normalizedTemplateId)) {
|
|
67
|
-
return getTemplateById(normalizedTemplateId).id;
|
|
68
|
-
}
|
|
69
|
-
return normalizedTemplateId;
|
|
70
|
-
}
|
|
71
|
-
if (yes) {
|
|
72
|
-
return "basic";
|
|
73
|
-
}
|
|
74
|
-
if (!isInteractive || !selectTemplate) {
|
|
75
|
-
throw new Error(`Template is required in non-interactive mode. Use --template <${TEMPLATE_IDS.join("|")}|./path|github:owner/repo/path[#ref]|npm-package>.`);
|
|
76
|
-
}
|
|
77
|
-
return normalizeTemplateSelection(await selectTemplate());
|
|
78
|
-
}
|
|
79
|
-
export async function resolvePackageManagerId({ packageManager, yes = false, isInteractive = false, selectPackageManager, }) {
|
|
80
|
-
if (packageManager) {
|
|
81
|
-
return getPackageManager(packageManager).id;
|
|
82
|
-
}
|
|
83
|
-
if (yes) {
|
|
84
|
-
return "npm";
|
|
85
|
-
}
|
|
86
|
-
if (!isInteractive || !selectPackageManager) {
|
|
87
|
-
throw new Error(`Package manager is required in non-interactive mode. Use --package-manager <${PACKAGE_MANAGER_IDS.join("|")}>.`);
|
|
88
|
-
}
|
|
89
|
-
return selectPackageManager();
|
|
90
|
-
}
|
|
91
|
-
export async function collectScaffoldAnswers({ projectName, templateId, yes = false, dataStorageMode, namespace, persistencePolicy, phpPrefix, promptText, textDomain, }) {
|
|
92
|
-
const defaults = getDefaultAnswers(projectName, templateId);
|
|
93
|
-
if (yes) {
|
|
94
|
-
const identifiers = resolveScaffoldIdentifiers({
|
|
95
|
-
namespace: namespace ?? defaults.namespace,
|
|
96
|
-
phpPrefix,
|
|
97
|
-
slug: defaults.slug,
|
|
98
|
-
textDomain,
|
|
99
|
-
});
|
|
100
|
-
return {
|
|
101
|
-
...defaults,
|
|
102
|
-
dataStorageMode: dataStorageMode ?? defaults.dataStorageMode,
|
|
103
|
-
namespace: identifiers.namespace,
|
|
104
|
-
persistencePolicy: persistencePolicy ?? defaults.persistencePolicy,
|
|
105
|
-
phpPrefix: identifiers.phpPrefix,
|
|
106
|
-
textDomain: identifiers.textDomain,
|
|
107
|
-
};
|
|
108
|
-
}
|
|
109
|
-
if (!promptText) {
|
|
110
|
-
throw new Error("Interactive answers require a promptText callback.");
|
|
111
|
-
}
|
|
112
|
-
const identifiers = resolveScaffoldIdentifiers({
|
|
113
|
-
namespace: namespace ?? (await promptText("Namespace", defaults.namespace, validateNamespace)),
|
|
114
|
-
phpPrefix,
|
|
115
|
-
slug: await promptText("Block slug", defaults.slug, validateBlockSlug),
|
|
116
|
-
textDomain,
|
|
117
|
-
});
|
|
118
|
-
return {
|
|
119
|
-
author: await promptText("Author", defaults.author),
|
|
120
|
-
dataStorageMode: dataStorageMode ?? defaults.dataStorageMode,
|
|
121
|
-
description: await promptText("Description", defaults.description),
|
|
122
|
-
namespace: identifiers.namespace,
|
|
123
|
-
persistencePolicy: persistencePolicy ?? defaults.persistencePolicy,
|
|
124
|
-
phpPrefix: identifiers.phpPrefix,
|
|
125
|
-
slug: identifiers.slug,
|
|
126
|
-
textDomain: identifiers.textDomain,
|
|
127
|
-
title: await promptText("Block title", toTitleCase(identifiers.slug)),
|
|
128
|
-
};
|
|
129
|
-
}
|
|
130
|
-
export function getTemplateVariables(templateId, answers) {
|
|
131
|
-
if (isBuiltInTemplateId(templateId)) {
|
|
132
|
-
return buildTemplateVariablesFromBlockSpec(createBuiltInBlockSpec({
|
|
133
|
-
answers,
|
|
134
|
-
dataStorageMode: answers.dataStorageMode,
|
|
135
|
-
persistencePolicy: answers.persistencePolicy,
|
|
136
|
-
templateId,
|
|
137
|
-
}));
|
|
138
|
-
}
|
|
139
|
-
const { apiClientPackageVersion, blockRuntimePackageVersion, blockTypesPackageVersion, projectToolsPackageVersion, restPackageVersion, } = getPackageVersions();
|
|
140
|
-
const template = isBuiltInTemplateId(templateId) ? getTemplateById(templateId) : null;
|
|
141
|
-
const metadataDefaults = isBuiltInTemplateId(templateId)
|
|
142
|
-
? getBuiltInTemplateMetadataDefaults(templateId)
|
|
143
|
-
: null;
|
|
144
|
-
const identifiers = resolveScaffoldIdentifiers({
|
|
145
|
-
namespace: answers.namespace,
|
|
146
|
-
phpPrefix: answers.phpPrefix,
|
|
147
|
-
slug: answers.slug,
|
|
148
|
-
textDomain: answers.textDomain,
|
|
149
|
-
});
|
|
150
|
-
const slug = identifiers.slug;
|
|
151
|
-
const slugSnakeCase = toSnakeCase(slug);
|
|
152
|
-
const pascalCase = toPascalCase(slug);
|
|
153
|
-
const title = answers.title.trim();
|
|
154
|
-
const namespace = identifiers.namespace;
|
|
155
|
-
const description = answers.description.trim();
|
|
156
|
-
const textDomain = identifiers.textDomain;
|
|
157
|
-
const phpPrefix = identifiers.phpPrefix;
|
|
158
|
-
const phpPrefixUpper = phpPrefix.toUpperCase();
|
|
159
|
-
const compoundChildTitle = `${title} Item`;
|
|
160
|
-
const cssClassName = buildBlockCssClassName(namespace, slug);
|
|
161
|
-
const compoundChildCssClassName = buildBlockCssClassName(namespace, `${slug}-item`);
|
|
162
|
-
const compoundPersistenceEnabled = templateId === "persistence"
|
|
163
|
-
? true
|
|
164
|
-
: templateId === "compound"
|
|
165
|
-
? Boolean(answers.dataStorageMode || answers.persistencePolicy)
|
|
166
|
-
: false;
|
|
167
|
-
const dataStorageMode = templateId === "persistence" || compoundPersistenceEnabled
|
|
168
|
-
? answers.dataStorageMode ?? "custom-table"
|
|
169
|
-
: "custom-table";
|
|
170
|
-
const persistencePolicy = templateId === "persistence" || compoundPersistenceEnabled
|
|
171
|
-
? answers.persistencePolicy ?? "authenticated"
|
|
172
|
-
: "authenticated";
|
|
173
|
-
return {
|
|
174
|
-
apiClientPackageVersion,
|
|
175
|
-
author: answers.author.trim(),
|
|
176
|
-
blockRuntimePackageVersion,
|
|
177
|
-
blockMetadataVersion: BUILTIN_BLOCK_METADATA_VERSION,
|
|
178
|
-
blockTypesPackageVersion,
|
|
179
|
-
category: metadataDefaults?.category ?? template?.defaultCategory ?? "widgets",
|
|
180
|
-
icon: metadataDefaults?.icon ?? "smiley",
|
|
181
|
-
compoundChildTitle,
|
|
182
|
-
compoundChildCategory: COMPOUND_CHILD_BLOCK_METADATA_DEFAULTS.category,
|
|
183
|
-
compoundChildCssClassName,
|
|
184
|
-
compoundChildIcon: COMPOUND_CHILD_BLOCK_METADATA_DEFAULTS.icon,
|
|
185
|
-
compoundChildTitleJson: JSON.stringify(compoundChildTitle),
|
|
186
|
-
compoundPersistenceEnabled: compoundPersistenceEnabled ? "true" : "false",
|
|
187
|
-
projectToolsPackageVersion,
|
|
188
|
-
cssClassName,
|
|
189
|
-
dataStorageMode,
|
|
190
|
-
dashCase: slug,
|
|
191
|
-
description,
|
|
192
|
-
frontendCssClassName: buildFrontendCssClassName(cssClassName),
|
|
193
|
-
isAuthenticatedPersistencePolicy: persistencePolicy === "authenticated" ? "true" : "false",
|
|
194
|
-
isPublicPersistencePolicy: persistencePolicy === "public" ? "true" : "false",
|
|
195
|
-
bootstrapCredentialDeclarations: persistencePolicy === "public"
|
|
196
|
-
? "publicWriteExpiresAt?: number & tags.Type< 'uint32' >;\n\tpublicWriteToken?: string & tags.MinLength< 1 > & tags.MaxLength< 512 >;"
|
|
197
|
-
: "restNonce?: string & tags.MinLength< 1 > & tags.MaxLength< 128 >;",
|
|
198
|
-
persistencePolicyDescriptionJson: JSON.stringify(persistencePolicy === "authenticated"
|
|
199
|
-
? "Writes require a logged-in user and a valid REST nonce."
|
|
200
|
-
: "Anonymous writes use signed short-lived public tokens, per-request ids, and coarse rate limiting."),
|
|
201
|
-
keyword: slug.replace(/-/g, " "),
|
|
202
|
-
namespace,
|
|
203
|
-
needsMigration: "{{needsMigration}}",
|
|
204
|
-
pascalCase,
|
|
205
|
-
phpPrefix,
|
|
206
|
-
phpPrefixUpper,
|
|
207
|
-
restPackageVersion,
|
|
208
|
-
publicWriteRequestIdDeclaration: persistencePolicy === "public"
|
|
209
|
-
? "publicWriteRequestId: string & tags.MinLength< 1 > & tags.MaxLength< 128 >;"
|
|
210
|
-
: "publicWriteRequestId?: string & tags.MinLength< 1 > & tags.MaxLength< 128 >;",
|
|
211
|
-
restWriteAuthIntent: persistencePolicy === "public"
|
|
212
|
-
? "public-write-protected"
|
|
213
|
-
: "authenticated",
|
|
214
|
-
restWriteAuthMechanism: persistencePolicy === "public" ? "public-signed-token" : "rest-nonce",
|
|
215
|
-
restWriteAuthMode: persistencePolicy === "public" ? "public-signed-token" : "authenticated-rest-nonce",
|
|
216
|
-
slug,
|
|
217
|
-
slugCamelCase: pascalCase.charAt(0).toLowerCase() + pascalCase.slice(1),
|
|
218
|
-
slugKebabCase: slug,
|
|
219
|
-
slugSnakeCase,
|
|
220
|
-
textDomain,
|
|
221
|
-
textdomain: textDomain,
|
|
222
|
-
title,
|
|
223
|
-
titleJson: JSON.stringify(title),
|
|
224
|
-
titleCase: pascalCase,
|
|
225
|
-
persistencePolicy,
|
|
226
|
-
};
|
|
227
|
-
}
|
|
228
32
|
export async function scaffoldProject({ projectDir, templateId, answers, dataStorageMode, persistencePolicy, packageManager, externalLayerId, externalLayerSource, externalLayerSourceLabel, repositoryReference, cwd = process.cwd(), allowExistingDir = false, noInstall = false, installDependencies = undefined, variant, withMigrationUi = false, withTestPreset = false, withWpEnv = false, }) {
|
|
229
33
|
const resolvedTemplateId = normalizeTemplateSelection(templateId);
|
|
230
34
|
const resolvedPackageManager = getPackageManager(packageManager).id;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wp-typia/project-tools",
|
|
3
|
-
"version": "0.16.
|
|
3
|
+
"version": "0.16.14",
|
|
4
4
|
"description": "Project orchestration and programmatic tooling for wp-typia",
|
|
5
5
|
"packageManager": "bun@1.3.11",
|
|
6
6
|
"type": "module",
|
|
@@ -120,8 +120,8 @@
|
|
|
120
120
|
},
|
|
121
121
|
"dependencies": {
|
|
122
122
|
"@wp-typia/api-client": "^0.4.5",
|
|
123
|
-
"@wp-typia/block-runtime": "^0.4.
|
|
124
|
-
"@wp-typia/rest": "^0.3.
|
|
123
|
+
"@wp-typia/block-runtime": "^0.4.10",
|
|
124
|
+
"@wp-typia/rest": "^0.3.10",
|
|
125
125
|
"@wp-typia/block-types": "^0.2.4",
|
|
126
126
|
"mustache": "^4.2.0",
|
|
127
127
|
"npm-package-arg": "^13.0.0",
|