@wp-typia/project-tools 0.20.1 → 0.20.2
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.
|
@@ -281,7 +281,7 @@ export async function runAddBlockCommand({ alternateRenderTargets, blockName, cw
|
|
|
281
281
|
throw new Error("`wp-typia add block --template query-loop` is not supported. Query Loop is a create-time `core/query` variation scaffold, so use `wp-typia create <project-dir> --template query-loop` instead.");
|
|
282
282
|
}
|
|
283
283
|
if (!isAddBlockTemplateId(templateId)) {
|
|
284
|
-
throw new Error(`Unknown add-block template "${templateId}". Expected one of: ${ADD_BLOCK_TEMPLATE_IDS.join(", ")}
|
|
284
|
+
throw new Error(`Unknown add-block template "${templateId}". Expected one of: ${ADD_BLOCK_TEMPLATE_IDS.join(", ")}. Run \`wp-typia templates list\` to inspect available templates.`);
|
|
285
285
|
}
|
|
286
286
|
const resolvedTemplateId = templateId;
|
|
287
287
|
assertPersistenceFlagsAllowed(resolvedTemplateId, {
|
|
@@ -19,6 +19,7 @@ export declare const CLI_DIAGNOSTIC_CODES: {
|
|
|
19
19
|
readonly OUTSIDE_PROJECT_ROOT: "outside-project-root";
|
|
20
20
|
readonly TEMPLATE_SOURCE_TIMEOUT: "template-source-timeout";
|
|
21
21
|
readonly TEMPLATE_SOURCE_TOO_LARGE: "template-source-too-large";
|
|
22
|
+
readonly UNKNOWN_TEMPLATE: "unknown-template";
|
|
22
23
|
readonly UNSUPPORTED_COMMAND: "unsupported-command";
|
|
23
24
|
};
|
|
24
25
|
export type CliDiagnosticCode = (typeof CLI_DIAGNOSTIC_CODES)[keyof typeof CLI_DIAGNOSTIC_CODES];
|
|
@@ -10,6 +10,7 @@ export const CLI_DIAGNOSTIC_CODES = {
|
|
|
10
10
|
OUTSIDE_PROJECT_ROOT: "outside-project-root",
|
|
11
11
|
TEMPLATE_SOURCE_TIMEOUT: "template-source-timeout",
|
|
12
12
|
TEMPLATE_SOURCE_TOO_LARGE: "template-source-too-large",
|
|
13
|
+
UNKNOWN_TEMPLATE: "unknown-template",
|
|
13
14
|
UNSUPPORTED_COMMAND: "unsupported-command",
|
|
14
15
|
};
|
|
15
16
|
const DEFAULT_CLI_FAILURE_SUMMARIES = {
|
|
@@ -183,7 +184,10 @@ function inferCliDiagnosticCode(options) {
|
|
|
183
184
|
if (/requires <|requires --|requires a value/u.test(haystack)) {
|
|
184
185
|
return CLI_DIAGNOSTIC_CODES.MISSING_ARGUMENT;
|
|
185
186
|
}
|
|
186
|
-
if (/Unknown
|
|
187
|
+
if (/Unknown (?:add-block )?template\s+(?:"|\\")/u.test(haystack)) {
|
|
188
|
+
return CLI_DIAGNOSTIC_CODES.UNKNOWN_TEMPLATE;
|
|
189
|
+
}
|
|
190
|
+
if (/Unknown .*subcommand|Unknown add kind|removed in favor|does not support|The Bun-free fallback runtime does not support|The positional alias only accepts/u.test(haystack)) {
|
|
187
191
|
return haystack.includes("does not support") ||
|
|
188
192
|
haystack.includes("The Bun-free fallback runtime does not support")
|
|
189
193
|
? CLI_DIAGNOSTIC_CODES.UNSUPPORTED_COMMAND
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { execSync } from 'node:child_process';
|
|
2
|
+
import path from 'node:path';
|
|
2
3
|
import { PACKAGE_MANAGER_IDS, getPackageManager, } from './package-managers.js';
|
|
3
4
|
import { normalizeBlockSlug, resolveScaffoldIdentifiers, validateBlockSlug, validateNamespace, } from './scaffold-identifiers.js';
|
|
4
5
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, TEMPLATE_IDS, getTemplateById, isBuiltInTemplateId, } from './template-registry.js';
|
|
5
6
|
import { getRemovedBuiltInTemplateMessage, isRemovedBuiltInTemplateId, } from './template-defaults.js';
|
|
7
|
+
import { parseNpmTemplateLocator } from './template-source-locators.js';
|
|
6
8
|
import { toSnakeCase, toTitleCase, } from './string-case.js';
|
|
7
9
|
const WORKSPACE_TEMPLATE_ALIAS = 'workspace';
|
|
8
10
|
const TEMPLATE_SELECTION_HINT = `--template <${[
|
|
@@ -11,6 +13,10 @@ const TEMPLATE_SELECTION_HINT = `--template <${[
|
|
|
11
13
|
].join('|')}|./path|github:owner/repo/path[#ref]|npm-package>`;
|
|
12
14
|
const TEMPLATE_SUGGESTION_IDS = [...TEMPLATE_IDS, WORKSPACE_TEMPLATE_ALIAS];
|
|
13
15
|
const QUERY_POST_TYPE_RULE = 'Use lowercase, 1-20 chars, and only a-z, 0-9, "_" or "-".';
|
|
16
|
+
const USER_FACING_TEMPLATE_IDS = [
|
|
17
|
+
...TEMPLATE_IDS,
|
|
18
|
+
WORKSPACE_TEMPLATE_ALIAS,
|
|
19
|
+
];
|
|
14
20
|
/**
|
|
15
21
|
* Detect the current author name from local Git config.
|
|
16
22
|
*
|
|
@@ -78,14 +84,22 @@ function normalizeTemplateSelection(templateId) {
|
|
|
78
84
|
? OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE
|
|
79
85
|
: templateId;
|
|
80
86
|
}
|
|
81
|
-
function
|
|
82
|
-
return (templateId.
|
|
87
|
+
function looksLikeWindowsAbsoluteTemplatePath(templateId) {
|
|
88
|
+
return /^[a-z]:[\\/]/iu.test(templateId) || /^\\\\[^\\]+\\[^\\]+/u.test(templateId);
|
|
89
|
+
}
|
|
90
|
+
function looksLikeExplicitNonNpmExternalTemplateLocator(templateId) {
|
|
91
|
+
return (path.isAbsolute(templateId) ||
|
|
92
|
+
looksLikeWindowsAbsoluteTemplatePath(templateId) ||
|
|
93
|
+
templateId.startsWith('./') ||
|
|
83
94
|
templateId.startsWith('../') ||
|
|
84
|
-
templateId.startsWith('/') ||
|
|
85
95
|
templateId.startsWith('@') ||
|
|
86
96
|
templateId.startsWith('github:') ||
|
|
87
97
|
templateId.includes('/'));
|
|
88
98
|
}
|
|
99
|
+
function looksLikeExplicitExternalTemplateLocator(templateId) {
|
|
100
|
+
return (looksLikeExplicitNonNpmExternalTemplateLocator(templateId) ||
|
|
101
|
+
parseNpmTemplateLocator(templateId) !== null);
|
|
102
|
+
}
|
|
89
103
|
function getEditDistance(left, right) {
|
|
90
104
|
const previous = Array.from({ length: right.length + 1 }, (_, index) => index);
|
|
91
105
|
const current = new Array(right.length + 1);
|
|
@@ -104,7 +118,7 @@ function getEditDistance(left, right) {
|
|
|
104
118
|
function findMistypedBuiltInTemplateSuggestion(templateId) {
|
|
105
119
|
const normalizedTemplateId = templateId.trim().toLowerCase();
|
|
106
120
|
if (normalizedTemplateId.length === 0 ||
|
|
107
|
-
|
|
121
|
+
looksLikeExplicitNonNpmExternalTemplateLocator(normalizedTemplateId)) {
|
|
108
122
|
return null;
|
|
109
123
|
}
|
|
110
124
|
let bestCandidate = null;
|
|
@@ -132,6 +146,13 @@ function getMistypedBuiltInTemplateMessage(templateId) {
|
|
|
132
146
|
: 'built-in scaffold';
|
|
133
147
|
return `Unknown template "${templateId}". Did you mean "${suggestion}"? Use \`--template ${suggestion}\` for the ${suggestionDescription}, or pass a local path, \`github:owner/repo/path[#ref]\`, or an npm package spec for an external template.`;
|
|
134
148
|
}
|
|
149
|
+
function getUnknownTemplateMessage(templateId) {
|
|
150
|
+
return [
|
|
151
|
+
`Unknown template "${templateId}". Expected one of: ${USER_FACING_TEMPLATE_IDS.join(', ')}.`,
|
|
152
|
+
'Run `wp-typia templates list` to inspect available templates.',
|
|
153
|
+
'Pass an explicit external template locator such as `./path`, `github:owner/repo/path[#ref]`, or `@scope/template` for custom templates.',
|
|
154
|
+
].join(' ');
|
|
155
|
+
}
|
|
135
156
|
/**
|
|
136
157
|
* Resolve the scaffold template id from flags, defaults, and interactive selection.
|
|
137
158
|
*
|
|
@@ -154,6 +175,9 @@ export async function resolveTemplateId({ templateId, yes = false, isInteractive
|
|
|
154
175
|
if (mistypedBuiltInTemplateMessage) {
|
|
155
176
|
throw new Error(mistypedBuiltInTemplateMessage);
|
|
156
177
|
}
|
|
178
|
+
if (!looksLikeExplicitExternalTemplateLocator(normalizedTemplateId)) {
|
|
179
|
+
throw new Error(getUnknownTemplateMessage(templateId));
|
|
180
|
+
}
|
|
157
181
|
return normalizedTemplateId;
|
|
158
182
|
}
|
|
159
183
|
if (yes) {
|
|
@@ -190,7 +214,7 @@ export async function resolvePackageManagerId({ packageManager, yes = false, isI
|
|
|
190
214
|
*/
|
|
191
215
|
export async function collectScaffoldAnswers({ projectName, templateId, yes = false, dataStorageMode, namespace, persistencePolicy, phpPrefix, promptText, queryPostType, textDomain, }) {
|
|
192
216
|
const defaults = getDefaultAnswers(projectName, templateId);
|
|
193
|
-
if (yes) {
|
|
217
|
+
if (yes || (!isBuiltInTemplateId(templateId) && !promptText)) {
|
|
194
218
|
const identifiers = resolveScaffoldIdentifiers({
|
|
195
219
|
namespace: namespace ?? defaults.namespace,
|
|
196
220
|
phpPrefix,
|
|
@@ -6,9 +6,20 @@ import { spawnSync } from 'node:child_process';
|
|
|
6
6
|
import semver from 'semver';
|
|
7
7
|
import { x as extractTarball } from 'tar';
|
|
8
8
|
import { createExternalTemplateTimeoutError, fetchWithExternalTemplateTimeout, getExternalTemplateMetadataMaxBytes, getExternalTemplateTarballMaxBytes, getExternalTemplateTimeoutMs, readBufferResponseWithLimit, readJsonResponseWithLimit, } from './external-template-guards.js';
|
|
9
|
-
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, PROJECT_TOOLS_PACKAGE_ROOT, } from './template-registry.js';
|
|
9
|
+
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, OFFICIAL_WORKSPACE_TEMPLATE_ALIAS, PROJECT_TOOLS_PACKAGE_ROOT, TEMPLATE_IDS, } from './template-registry.js';
|
|
10
10
|
import { isPlainObject } from './object-utils.js';
|
|
11
11
|
import { createManagedTempRoot } from './temp-roots.js';
|
|
12
|
+
const USER_FACING_TEMPLATE_IDS = [
|
|
13
|
+
...TEMPLATE_IDS,
|
|
14
|
+
OFFICIAL_WORKSPACE_TEMPLATE_ALIAS,
|
|
15
|
+
];
|
|
16
|
+
function getUnknownNpmTemplateMessage(templateId) {
|
|
17
|
+
return [
|
|
18
|
+
`Unknown template "${templateId}". Expected one of: ${USER_FACING_TEMPLATE_IDS.join(', ')}.`,
|
|
19
|
+
'Run `wp-typia templates list` to inspect available templates.',
|
|
20
|
+
'If you meant an npm template package, verify the package name and configured npm registry.',
|
|
21
|
+
].join(' ');
|
|
22
|
+
}
|
|
12
23
|
function selectRegistryVersion(metadata, locator) {
|
|
13
24
|
const distTags = isPlainObject(metadata['dist-tags'])
|
|
14
25
|
? metadata['dist-tags']
|
|
@@ -49,6 +60,9 @@ async function fetchNpmTemplateSource(locator) {
|
|
|
49
60
|
label: metadataLabel,
|
|
50
61
|
});
|
|
51
62
|
if (!metadataResponse.ok) {
|
|
63
|
+
if (metadataResponse.status === 404) {
|
|
64
|
+
throw new Error(getUnknownNpmTemplateMessage(locator.raw));
|
|
65
|
+
}
|
|
52
66
|
throw new Error(`Failed to fetch npm template metadata for ${locator.raw}: ${metadataResponse.status}`);
|
|
53
67
|
}
|
|
54
68
|
const metadata = await readJsonResponseWithLimit(metadataResponse, {
|