@wp-typia/project-tools 0.19.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/runtime/block-generator-service-spec.js +206 -2
- package/dist/runtime/built-in-block-artifacts.js +3 -1
- package/dist/runtime/built-in-block-code-artifacts.js +3 -1
- package/dist/runtime/cli-add-block.js +11 -5
- package/dist/runtime/cli-diagnostics.d.ts +26 -0
- package/dist/runtime/cli-diagnostics.js +107 -0
- package/dist/runtime/cli-doctor-workspace.js +4 -4
- package/dist/runtime/cli-scaffold.js +3 -3
- package/dist/runtime/index.d.ts +3 -1
- package/dist/runtime/index.js +2 -1
- package/dist/runtime/scaffold-bootstrap.js +5 -1
- package/dist/runtime/scaffold-documents.js +11 -8
- package/dist/runtime/scaffold-template-variable-groups.d.ts +154 -0
- package/dist/runtime/scaffold-template-variable-groups.js +13 -0
- package/dist/runtime/scaffold-template-variables.js +58 -1
- package/dist/runtime/scaffold.d.ts +5 -1
- package/dist/runtime/scaffold.js +5 -1
- package/dist/runtime/temp-roots.d.ts +44 -0
- package/dist/runtime/temp-roots.js +129 -0
- package/dist/runtime/template-builtins.js +4 -6
- package/dist/runtime/template-registry.d.ts +8 -0
- package/dist/runtime/template-registry.js +34 -1
- package/dist/runtime/template-source-external.d.ts +1 -0
- package/dist/runtime/template-source-external.js +4 -7
- package/dist/runtime/template-source-remote.js +44 -23
- package/dist/runtime/template-source-seeds.js +3 -9
- package/dist/runtime/template-source.d.ts +2 -3
- package/dist/runtime/template-source.js +8 -2
- package/package.json +6 -1
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
/// <reference path="./external-template-modules.d.ts" />
|
|
2
2
|
import fs from 'node:fs';
|
|
3
|
-
import { promises as fsp } from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
3
|
import path from 'node:path';
|
|
6
4
|
import { pathToFileURL } from 'node:url';
|
|
7
5
|
import { isPlainObject } from './object-utils.js';
|
|
8
6
|
import { toSegmentPascalCase } from './string-case.js';
|
|
7
|
+
import { createManagedTempRoot } from './temp-roots.js';
|
|
9
8
|
import { copyRawDirectory, copyRenderedDirectory } from './template-render.js';
|
|
10
9
|
/**
|
|
11
10
|
* Candidate filenames for official external template config entrypoints.
|
|
@@ -15,6 +14,7 @@ export const EXTERNAL_TEMPLATE_ENTRY_CANDIDATES = [
|
|
|
15
14
|
'index.cjs',
|
|
16
15
|
'index.mjs',
|
|
17
16
|
];
|
|
17
|
+
export const EXTERNAL_TEMPLATE_TRUST_WARNING = 'External template configs execute trusted JavaScript during scaffolding. Review the template source before using local paths, GitHub repos, or npm packages you do not already trust.';
|
|
18
18
|
const TEMPLATE_WARNING_MESSAGE = 'wp-typia owns package/tooling/sync setup for generated projects, so this external template setting is ignored.';
|
|
19
19
|
function getTemplateWarning(key) {
|
|
20
20
|
return `Ignoring external template config key "${key}": ${TEMPLATE_WARNING_MESSAGE}`;
|
|
@@ -53,7 +53,7 @@ async function loadExternalTemplateConfig(sourceDir) {
|
|
|
53
53
|
if (!isPlainObject(loadedConfig)) {
|
|
54
54
|
throw new Error(`External template config must export an object: ${entryPath}`);
|
|
55
55
|
}
|
|
56
|
-
const warnings = [];
|
|
56
|
+
const warnings = [EXTERNAL_TEMPLATE_TRUST_WARNING];
|
|
57
57
|
for (const ignoredKey of [
|
|
58
58
|
'wpScripts',
|
|
59
59
|
'wpEnv',
|
|
@@ -174,10 +174,7 @@ export async function renderCreateBlockExternalTemplate(sourceDir, context, requ
|
|
|
174
174
|
const { config, warnings } = await loadExternalTemplateConfig(sourceDir);
|
|
175
175
|
const { selectedVariant, variantConfig } = getVariantConfig(config, requestedVariant);
|
|
176
176
|
const { folderName, formatHint, templatePath } = resolveConfiguredTemplatePath(config, variantConfig);
|
|
177
|
-
const tempRoot = await
|
|
178
|
-
const cleanup = async () => {
|
|
179
|
-
await fsp.rm(tempRoot, { force: true, recursive: true });
|
|
180
|
-
};
|
|
177
|
+
const { path: tempRoot, cleanup } = await createManagedTempRoot('wp-typia-create-block-external-');
|
|
181
178
|
try {
|
|
182
179
|
const renderedRoot = path.join(tempRoot, 'rendered');
|
|
183
180
|
const blockDir = resolveSourceSubpath(renderedRoot, folderName);
|
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { promises as fsp } from 'node:fs';
|
|
3
|
-
import os from 'node:os';
|
|
4
3
|
import path from 'node:path';
|
|
5
4
|
import { getBuiltInTemplateLayerDirs, isOmittableBuiltInTemplateLayerDir, } from './template-builtins.js';
|
|
6
5
|
import { copyRawDirectory } from './template-render.js';
|
|
6
|
+
import { createManagedTempRoot } from './temp-roots.js';
|
|
7
|
+
async function cleanupSeedRootPair(cleanup, seedCleanup) {
|
|
8
|
+
let cleanupError;
|
|
9
|
+
try {
|
|
10
|
+
await cleanup();
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
cleanupError = error;
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
await seedCleanup?.();
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
cleanupError ?? (cleanupError = error);
|
|
20
|
+
}
|
|
21
|
+
if (cleanupError !== undefined) {
|
|
22
|
+
throw cleanupError;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
7
25
|
function getDefaultCategoryFromBlockJson(blockJson) {
|
|
8
26
|
return typeof blockJson.category === 'string' &&
|
|
9
27
|
blockJson.category.trim().length > 0
|
|
@@ -48,10 +66,14 @@ function readTemplatePackageJson(sourceDir) {
|
|
|
48
66
|
continue;
|
|
49
67
|
}
|
|
50
68
|
try {
|
|
51
|
-
return
|
|
69
|
+
return {
|
|
70
|
+
packageJson: JSON.parse(fs.readFileSync(candidate, 'utf8')),
|
|
71
|
+
sourcePath: candidate,
|
|
72
|
+
};
|
|
52
73
|
}
|
|
53
|
-
catch {
|
|
54
|
-
|
|
74
|
+
catch (error) {
|
|
75
|
+
const message = error instanceof Error ? error.message : 'Unknown parse failure';
|
|
76
|
+
throw new Error(`Failed to parse template metadata file "${candidate}": ${message}`);
|
|
55
77
|
}
|
|
56
78
|
}
|
|
57
79
|
return null;
|
|
@@ -61,10 +83,18 @@ function readTemplatePackageJson(sourceDir) {
|
|
|
61
83
|
* manifest and return it when present.
|
|
62
84
|
*/
|
|
63
85
|
export function getTemplateProjectType(sourceDir) {
|
|
64
|
-
const
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
86
|
+
const packageJsonEntry = readTemplatePackageJson(sourceDir);
|
|
87
|
+
if (!packageJsonEntry) {
|
|
88
|
+
return null;
|
|
89
|
+
}
|
|
90
|
+
const projectType = packageJsonEntry.packageJson.wpTypia?.projectType;
|
|
91
|
+
if (projectType === undefined) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
if (typeof projectType !== 'string' || projectType.trim().length === 0) {
|
|
95
|
+
throw new Error(`Template metadata file "${packageJsonEntry.sourcePath}" defines wpTypia.projectType, but it must be a non-empty string.`);
|
|
96
|
+
}
|
|
97
|
+
return projectType;
|
|
68
98
|
}
|
|
69
99
|
/**
|
|
70
100
|
* Copy a wp-typia seed into a normalized temporary template directory.
|
|
@@ -73,7 +103,7 @@ export function getTemplateProjectType(sourceDir) {
|
|
|
73
103
|
* @returns A cloned seed whose cleanup removes the temp root and original seed.
|
|
74
104
|
*/
|
|
75
105
|
export async function normalizeWpTypiaTemplateSeed(seed) {
|
|
76
|
-
const tempRoot = await
|
|
106
|
+
const { path: tempRoot, cleanup } = await createManagedTempRoot('wp-typia-template-source-');
|
|
77
107
|
const normalizedDir = path.join(tempRoot, 'template');
|
|
78
108
|
try {
|
|
79
109
|
await copyRawDirectory(seed.blockDir, normalizedDir, {
|
|
@@ -92,15 +122,12 @@ export async function normalizeWpTypiaTemplateSeed(seed) {
|
|
|
92
122
|
}
|
|
93
123
|
}
|
|
94
124
|
catch (error) {
|
|
95
|
-
await
|
|
125
|
+
await Promise.allSettled([cleanup(), seed.cleanup?.()]);
|
|
96
126
|
throw error;
|
|
97
127
|
}
|
|
98
128
|
return {
|
|
99
129
|
blockDir: normalizedDir,
|
|
100
|
-
cleanup: async () =>
|
|
101
|
-
await fsp.rm(tempRoot, { force: true, recursive: true });
|
|
102
|
-
await seed.cleanup?.();
|
|
103
|
-
},
|
|
130
|
+
cleanup: async () => cleanupSeedRootPair(cleanup, seed.cleanup),
|
|
104
131
|
rootDir: normalizedDir,
|
|
105
132
|
selectedVariant: seed.selectedVariant,
|
|
106
133
|
warnings: seed.warnings,
|
|
@@ -296,7 +323,7 @@ async function removeSeedEntryConflicts(templateDir) {
|
|
|
296
323
|
* @returns A normalized template source rooted in a temporary directory.
|
|
297
324
|
*/
|
|
298
325
|
export async function normalizeCreateBlockSubset(seed, context) {
|
|
299
|
-
const tempRoot = await
|
|
326
|
+
const { path: tempRoot, cleanup } = await createManagedTempRoot('wp-typia-remote-template-');
|
|
300
327
|
try {
|
|
301
328
|
const templateDir = path.join(tempRoot, 'template');
|
|
302
329
|
const blockJson = readRemoteBlockJson(seed.blockDir);
|
|
@@ -353,17 +380,11 @@ export async function normalizeCreateBlockSubset(seed, context) {
|
|
|
353
380
|
selectedVariant: seed.selectedVariant ?? null,
|
|
354
381
|
templateDir,
|
|
355
382
|
warnings: seed.warnings ?? [],
|
|
356
|
-
cleanup: async () =>
|
|
357
|
-
await fsp.rm(tempRoot, { force: true, recursive: true });
|
|
358
|
-
if (seed.cleanup) {
|
|
359
|
-
await seed.cleanup();
|
|
360
|
-
}
|
|
361
|
-
},
|
|
383
|
+
cleanup: async () => cleanupSeedRootPair(cleanup, seed.cleanup),
|
|
362
384
|
};
|
|
363
385
|
}
|
|
364
386
|
catch (error) {
|
|
365
|
-
await
|
|
366
|
-
await seed.cleanup?.();
|
|
387
|
+
await Promise.allSettled([cleanup(), seed.cleanup?.()]);
|
|
367
388
|
throw error;
|
|
368
389
|
}
|
|
369
390
|
}
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import { promises as fsp } from 'node:fs';
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
|
-
import os from 'node:os';
|
|
5
4
|
import path from 'node:path';
|
|
6
5
|
import { execFileSync } from 'node:child_process';
|
|
7
6
|
import semver from 'semver';
|
|
8
7
|
import { x as extractTarball } from 'tar';
|
|
9
8
|
import { OFFICIAL_WORKSPACE_TEMPLATE_PACKAGE, PROJECT_TOOLS_PACKAGE_ROOT, } from './template-registry.js';
|
|
10
9
|
import { isPlainObject } from './object-utils.js';
|
|
10
|
+
import { createManagedTempRoot } from './temp-roots.js';
|
|
11
11
|
function selectRegistryVersion(metadata, locator) {
|
|
12
12
|
const distTags = isPlainObject(metadata['dist-tags'])
|
|
13
13
|
? metadata['dist-tags']
|
|
@@ -58,10 +58,7 @@ async function fetchNpmTemplateSource(locator) {
|
|
|
58
58
|
if (typeof tarballUrl !== 'string' || tarballUrl.length === 0) {
|
|
59
59
|
throw new Error(`npm template metadata is missing tarball URL for ${locator.raw}@${resolvedVersion}.`);
|
|
60
60
|
}
|
|
61
|
-
const tempRoot = await
|
|
62
|
-
const cleanup = async () => {
|
|
63
|
-
await fsp.rm(tempRoot, { force: true, recursive: true });
|
|
64
|
-
};
|
|
61
|
+
const { path: tempRoot, cleanup } = await createManagedTempRoot('wp-typia-template-source-');
|
|
65
62
|
try {
|
|
66
63
|
const tarballResponse = await fetch(tarballUrl);
|
|
67
64
|
if (!tarballResponse.ok) {
|
|
@@ -178,10 +175,7 @@ export async function assertNoSymlinks(sourceDir) {
|
|
|
178
175
|
}
|
|
179
176
|
}
|
|
180
177
|
async function resolveGitHubTemplateSource(locator) {
|
|
181
|
-
const remoteRoot = await
|
|
182
|
-
const cleanup = async () => {
|
|
183
|
-
await fsp.rm(remoteRoot, { force: true, recursive: true });
|
|
184
|
-
};
|
|
178
|
+
const { path: remoteRoot, cleanup } = await createManagedTempRoot('wp-typia-template-source-');
|
|
185
179
|
const checkoutDir = path.join(remoteRoot, 'source');
|
|
186
180
|
try {
|
|
187
181
|
const args = ['clone', '--depth', '1'];
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { ResolvedTemplateSource } from './template-source-contracts.js';
|
|
2
|
+
import type { ScaffoldTemplateVariables } from './scaffold.js';
|
|
2
3
|
export type { GitHubTemplateLocator, NpmTemplateLocator, RemoteTemplateLocator, ResolvedTemplateSource, TemplateSourceFormat, TemplateVariableContext, } from './template-source-contracts.js';
|
|
3
4
|
export { parseGitHubTemplateLocator, parseNpmTemplateLocator, parseTemplateLocator, } from './template-source-locators.js';
|
|
4
5
|
export { resolveTemplateSeed } from './template-source-seeds.js';
|
|
5
|
-
export declare function resolveTemplateSource(templateId: string, cwd: string, variables:
|
|
6
|
-
[key: string]: string;
|
|
7
|
-
}, variant?: string): Promise<ResolvedTemplateSource>;
|
|
6
|
+
export declare function resolveTemplateSource(templateId: string, cwd: string, variables: ScaffoldTemplateVariables, variant?: string): Promise<ResolvedTemplateSource>;
|
|
@@ -4,17 +4,23 @@ import { parseTemplateLocator, } from './template-source-locators.js';
|
|
|
4
4
|
import { detectTemplateSourceFormat, getTemplateProjectType, getDefaultCategory, getTemplateVariableContext, normalizeCreateBlockSubset, normalizeWpTypiaTemplateSeed, renderCreateBlockExternalTemplate, } from './template-source-normalization.js';
|
|
5
5
|
import { isOfficialWorkspaceTemplateSeed, resolveTemplateSeed, } from './template-source-seeds.js';
|
|
6
6
|
import { assertBuiltInTemplateVariantAllowed, } from './cli-validation.js';
|
|
7
|
+
import { getScaffoldTemplateVariableGroups } from './scaffold-template-variable-groups.js';
|
|
7
8
|
export { parseGitHubTemplateLocator, parseNpmTemplateLocator, parseTemplateLocator, } from './template-source-locators.js';
|
|
8
9
|
export { resolveTemplateSeed } from './template-source-seeds.js';
|
|
9
10
|
export async function resolveTemplateSource(templateId, cwd, variables, variant) {
|
|
10
11
|
if (isBuiltInTemplateId(templateId)) {
|
|
12
|
+
const variableGroups = getScaffoldTemplateVariableGroups(variables);
|
|
11
13
|
assertBuiltInTemplateVariantAllowed({
|
|
12
14
|
templateId,
|
|
13
15
|
variant,
|
|
14
16
|
});
|
|
15
17
|
return resolveBuiltInTemplateSource(templateId, {
|
|
16
|
-
persistenceEnabled:
|
|
17
|
-
|
|
18
|
+
persistenceEnabled: variableGroups.compound.enabled &&
|
|
19
|
+
variableGroups.compound.persistenceEnabled,
|
|
20
|
+
persistencePolicy: variableGroups.persistence.enabled &&
|
|
21
|
+
variableGroups.persistence.policy === 'public'
|
|
22
|
+
? 'public'
|
|
23
|
+
: 'authenticated',
|
|
18
24
|
});
|
|
19
25
|
}
|
|
20
26
|
const locator = parseTemplateLocator(templateId);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wp-typia/project-tools",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Project orchestration and programmatic tooling for wp-typia",
|
|
5
5
|
"packageManager": "bun@1.3.11",
|
|
6
6
|
"type": "module",
|
|
@@ -67,6 +67,11 @@
|
|
|
67
67
|
"import": "./dist/runtime/schema-core.js",
|
|
68
68
|
"default": "./dist/runtime/schema-core.js"
|
|
69
69
|
},
|
|
70
|
+
"./temp-roots": {
|
|
71
|
+
"types": "./dist/runtime/temp-roots.d.ts",
|
|
72
|
+
"import": "./dist/runtime/temp-roots.js",
|
|
73
|
+
"default": "./dist/runtime/temp-roots.js"
|
|
74
|
+
},
|
|
70
75
|
"./workspace-project": {
|
|
71
76
|
"types": "./dist/runtime/workspace-project.d.ts",
|
|
72
77
|
"import": "./dist/runtime/workspace-project.js",
|