@wp-typia/project-tools 0.22.3 → 0.22.5
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-block-json.d.ts +31 -0
- package/dist/runtime/cli-add-block-json.js +65 -0
- package/dist/runtime/cli-add-collision.d.ts +129 -0
- package/dist/runtime/cli-add-collision.js +293 -0
- package/dist/runtime/cli-add-filesystem.d.ts +29 -0
- package/dist/runtime/cli-add-filesystem.js +77 -0
- package/dist/runtime/cli-add-help.d.ts +4 -0
- package/dist/runtime/cli-add-help.js +41 -0
- package/dist/runtime/cli-add-shared.d.ts +6 -304
- package/dist/runtime/cli-add-shared.js +6 -524
- package/dist/runtime/cli-add-types.d.ts +247 -0
- package/dist/runtime/cli-add-types.js +64 -0
- package/dist/runtime/cli-add-validation.d.ts +87 -0
- package/dist/runtime/cli-add-validation.js +147 -0
- package/dist/runtime/cli-add-workspace-ability-scaffold.js +46 -72
- package/dist/runtime/cli-add-workspace-admin-view-scaffold.js +35 -61
- package/dist/runtime/cli-add-workspace-ai-anchors.js +3 -24
- package/dist/runtime/cli-add-workspace-ai-scaffold.js +53 -57
- package/dist/runtime/cli-add-workspace-ai-templates.js +2 -0
- package/dist/runtime/cli-add-workspace-assets.js +7 -50
- package/dist/runtime/cli-add-workspace-mutation.d.ts +30 -0
- package/dist/runtime/cli-add-workspace-mutation.js +60 -0
- package/dist/runtime/cli-add-workspace-rest-anchors.js +3 -24
- package/dist/runtime/cli-add-workspace.js +1 -79
- package/dist/runtime/cli-add.d.ts +2 -2
- package/dist/runtime/cli-add.js +2 -2
- package/dist/runtime/cli-doctor-workspace-blocks.js +1 -66
- package/dist/runtime/index.d.ts +2 -0
- package/dist/runtime/index.js +1 -0
- package/dist/runtime/migration-utils.d.ts +2 -1
- package/dist/runtime/migration-utils.js +3 -11
- package/dist/runtime/package-managers.d.ts +19 -0
- package/dist/runtime/package-managers.js +62 -0
- package/dist/runtime/template-source-cache.d.ts +59 -0
- package/dist/runtime/template-source-cache.js +160 -0
- package/dist/runtime/ts-source-masking.d.ts +28 -0
- package/dist/runtime/ts-source-masking.js +104 -0
- package/dist/runtime/typia-llm.d.ts +9 -1
- package/dist/runtime/typia-llm.js +20 -5
- package/dist/runtime/workspace-inventory.js +368 -284
- package/dist/runtime/workspace-project.d.ts +1 -1
- package/dist/runtime/workspace-project.js +2 -10
- package/package.json +2 -2
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { rollbackWorkspaceMutation, snapshotWorkspaceFiles, } from "./cli-add-shared.js";
|
|
2
|
+
const DEFAULT_PHP_SNIPPET_INSERTION_ANCHORS = [
|
|
3
|
+
/add_action\(\s*["']init["']\s*,\s*["'][^"']+_load_textdomain["']\s*\);\s*\n/u,
|
|
4
|
+
/\?>\s*$/u,
|
|
5
|
+
];
|
|
6
|
+
/**
|
|
7
|
+
* Error thrown when the mutation and its rollback both fail.
|
|
8
|
+
*/
|
|
9
|
+
export class WorkspaceMutationRollbackError extends Error {
|
|
10
|
+
constructor(mutationError, rollbackError) {
|
|
11
|
+
super("Workspace mutation failed and rollback also failed.");
|
|
12
|
+
this.name = "WorkspaceMutationRollbackError";
|
|
13
|
+
this.mutationError = mutationError;
|
|
14
|
+
this.rollbackError = rollbackError;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Execute a workspace add mutation with rollback on any failure.
|
|
19
|
+
*/
|
|
20
|
+
export async function executeWorkspaceMutationPlan({ filePaths, run, snapshotDirs = [], targetPaths = [], }) {
|
|
21
|
+
const mutationSnapshot = {
|
|
22
|
+
fileSources: await snapshotWorkspaceFiles(filePaths),
|
|
23
|
+
snapshotDirs: [...snapshotDirs],
|
|
24
|
+
targetPaths: [...targetPaths],
|
|
25
|
+
};
|
|
26
|
+
try {
|
|
27
|
+
return await run();
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
try {
|
|
31
|
+
await rollbackWorkspaceMutation(mutationSnapshot);
|
|
32
|
+
}
|
|
33
|
+
catch (rollbackError) {
|
|
34
|
+
throw new WorkspaceMutationRollbackError(error, rollbackError);
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Insert a PHP snippet before the workspace textdomain hook or closing tag.
|
|
41
|
+
*/
|
|
42
|
+
export function insertPhpSnippetBeforeWorkspaceAnchors(source, snippet) {
|
|
43
|
+
for (const anchor of DEFAULT_PHP_SNIPPET_INSERTION_ANCHORS) {
|
|
44
|
+
const candidate = source.replace(anchor, (match) => `${snippet}\n${match}`);
|
|
45
|
+
if (candidate !== source) {
|
|
46
|
+
return candidate;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return `${source.trimEnd()}\n${snippet}\n`;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Append a PHP snippet before the closing tag when one is present.
|
|
53
|
+
*/
|
|
54
|
+
export function appendPhpSnippetBeforeClosingTag(source, snippet) {
|
|
55
|
+
const closingTagPattern = /\?>\s*$/u;
|
|
56
|
+
if (closingTagPattern.test(source)) {
|
|
57
|
+
return source.replace(closingTagPattern, `${snippet}\n?>`);
|
|
58
|
+
}
|
|
59
|
+
return `${source.trimEnd()}\n${snippet}\n`;
|
|
60
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
2
|
import { getWorkspaceBootstrapPath, patchFile, } from "./cli-add-shared.js";
|
|
3
|
+
import { appendPhpSnippetBeforeClosingTag, insertPhpSnippetBeforeWorkspaceAnchors, } from "./cli-add-workspace-mutation.js";
|
|
3
4
|
import { hasPhpFunctionDefinition } from "./php-utils.js";
|
|
4
5
|
const REST_RESOURCE_SERVER_GLOB = "/inc/rest/*.php";
|
|
5
6
|
export async function ensureRestResourceBootstrapAnchors(workspace) {
|
|
@@ -16,30 +17,8 @@ function ${registerFunctionName}() {
|
|
|
16
17
|
\t}
|
|
17
18
|
}
|
|
18
19
|
`;
|
|
19
|
-
const insertionAnchors = [
|
|
20
|
-
/add_action\(\s*["']init["']\s*,\s*["'][^"']+_load_textdomain["']\s*\);\s*\n/u,
|
|
21
|
-
/\?>\s*$/u,
|
|
22
|
-
];
|
|
23
|
-
const insertPhpSnippet = (snippet) => {
|
|
24
|
-
for (const anchor of insertionAnchors) {
|
|
25
|
-
const candidate = nextSource.replace(anchor, (match) => `${snippet}\n${match}`);
|
|
26
|
-
if (candidate !== nextSource) {
|
|
27
|
-
nextSource = candidate;
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
nextSource = `${nextSource.trimEnd()}\n${snippet}\n`;
|
|
32
|
-
};
|
|
33
|
-
const appendPhpSnippet = (snippet) => {
|
|
34
|
-
const closingTagPattern = /\?>\s*$/u;
|
|
35
|
-
if (closingTagPattern.test(nextSource)) {
|
|
36
|
-
nextSource = nextSource.replace(closingTagPattern, `${snippet}\n?>`);
|
|
37
|
-
return;
|
|
38
|
-
}
|
|
39
|
-
nextSource = `${nextSource.trimEnd()}\n${snippet}\n`;
|
|
40
|
-
};
|
|
41
20
|
if (!hasPhpFunctionDefinition(nextSource, registerFunctionName)) {
|
|
42
|
-
|
|
21
|
+
nextSource = insertPhpSnippetBeforeWorkspaceAnchors(nextSource, registerFunction);
|
|
43
22
|
}
|
|
44
23
|
else if (!nextSource.includes(REST_RESOURCE_SERVER_GLOB)) {
|
|
45
24
|
throw new Error([
|
|
@@ -49,7 +28,7 @@ function ${registerFunctionName}() {
|
|
|
49
28
|
].join(" "));
|
|
50
29
|
}
|
|
51
30
|
if (!nextSource.includes(registerHook)) {
|
|
52
|
-
|
|
31
|
+
nextSource = appendPhpSnippetBeforeClosingTag(nextSource, registerHook);
|
|
53
32
|
}
|
|
54
33
|
return nextSource;
|
|
55
34
|
});
|
|
@@ -5,6 +5,7 @@ import { resolveWorkspaceProject } from "./workspace-project.js";
|
|
|
5
5
|
import { appendWorkspaceInventoryEntries, readWorkspaceInventory } from "./workspace-inventory.js";
|
|
6
6
|
import { toKebabCase, toSnakeCase, toTitleCase } from "./string-case.js";
|
|
7
7
|
import { assertBlockStyleDoesNotExist, assertBlockTransformDoesNotExist, assertValidGeneratedSlug, assertValidHookAnchor, assertValidHookedBlockPosition, assertVariationDoesNotExist, getMutableBlockHooks, normalizeBlockSlug, patchFile, quoteTsString, readWorkspaceBlockJson, resolveWorkspaceBlock, rollbackWorkspaceMutation, snapshotWorkspaceFiles, } from "./cli-add-shared.js";
|
|
8
|
+
import { findExecutablePatternMatch, hasExecutablePattern, hasUncommentedPattern, maskTypeScriptCommentsAndLiterals, } from "./ts-source-masking.js";
|
|
8
9
|
const VARIATIONS_IMPORT_LINE = "import { registerWorkspaceVariations } from './variations';";
|
|
9
10
|
const VARIATIONS_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceVariations\s*\}\s*from\s*["']\.\/variations["']\s*;?\s*$/mu;
|
|
10
11
|
const VARIATIONS_CALL_LINE = "registerWorkspaceVariations();";
|
|
@@ -19,85 +20,6 @@ const BLOCK_TRANSFORMS_CALL_LINE = "applyWorkspaceBlockTransforms(registration.s
|
|
|
19
20
|
const BLOCK_TRANSFORMS_CALL_PATTERN = /applyWorkspaceBlockTransforms\s*\(\s*registration\s*\.\s*settings\s*\)\s*;?/u;
|
|
20
21
|
const SCAFFOLD_REGISTRATION_SETTINGS_CALL_PATTERN = /registerScaffoldBlockType\s*\(\s*registration\s*\.\s*name\s*,\s*registration\s*\.\s*settings\s*\)\s*;?/u;
|
|
21
22
|
const FULL_BLOCK_NAME_PATTERN = /^[a-z0-9-]+\/[a-z0-9-]+$/u;
|
|
22
|
-
function maskSourceSegment(segment) {
|
|
23
|
-
return segment.replace(/[^\n\r]/gu, " ");
|
|
24
|
-
}
|
|
25
|
-
function maskTypeScriptComments(source) {
|
|
26
|
-
return source
|
|
27
|
-
.replace(/\/\*[\s\S]*?\*\//gu, maskSourceSegment)
|
|
28
|
-
.replace(/\/\/[^\n\r]*/gu, maskSourceSegment);
|
|
29
|
-
}
|
|
30
|
-
// Preserve source offsets so executable-code match indexes still map to the original file.
|
|
31
|
-
function maskTypeScriptCommentsAndLiterals(source) {
|
|
32
|
-
let maskedSource = "";
|
|
33
|
-
let index = 0;
|
|
34
|
-
while (index < source.length) {
|
|
35
|
-
const current = source[index];
|
|
36
|
-
const next = source[index + 1];
|
|
37
|
-
if (current === "/" && next === "/") {
|
|
38
|
-
const start = index;
|
|
39
|
-
index += 2;
|
|
40
|
-
while (index < source.length &&
|
|
41
|
-
source[index] !== "\n" &&
|
|
42
|
-
source[index] !== "\r") {
|
|
43
|
-
index += 1;
|
|
44
|
-
}
|
|
45
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
46
|
-
continue;
|
|
47
|
-
}
|
|
48
|
-
if (current === "/" && next === "*") {
|
|
49
|
-
const start = index;
|
|
50
|
-
index += 2;
|
|
51
|
-
while (index < source.length &&
|
|
52
|
-
!(source[index] === "*" && source[index + 1] === "/")) {
|
|
53
|
-
index += 1;
|
|
54
|
-
}
|
|
55
|
-
index = Math.min(index + 2, source.length);
|
|
56
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
57
|
-
continue;
|
|
58
|
-
}
|
|
59
|
-
if (current === "'" || current === '"' || current === "`") {
|
|
60
|
-
const start = index;
|
|
61
|
-
const quote = current;
|
|
62
|
-
index += 1;
|
|
63
|
-
while (index < source.length) {
|
|
64
|
-
const char = source[index];
|
|
65
|
-
if (char === "\\") {
|
|
66
|
-
index += 2;
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
index += 1;
|
|
70
|
-
if (char === quote) {
|
|
71
|
-
break;
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
maskedSource += current;
|
|
78
|
-
index += 1;
|
|
79
|
-
}
|
|
80
|
-
return maskedSource;
|
|
81
|
-
}
|
|
82
|
-
function hasExecutablePattern(source, pattern) {
|
|
83
|
-
return pattern.test(maskTypeScriptCommentsAndLiterals(source));
|
|
84
|
-
}
|
|
85
|
-
function hasUncommentedPattern(source, pattern) {
|
|
86
|
-
return pattern.test(maskTypeScriptComments(source));
|
|
87
|
-
}
|
|
88
|
-
function findExecutablePatternMatch(source, patterns) {
|
|
89
|
-
const maskedSource = maskTypeScriptCommentsAndLiterals(source);
|
|
90
|
-
for (const pattern of patterns) {
|
|
91
|
-
const match = pattern.exec(maskedSource);
|
|
92
|
-
if (match && match.index !== undefined) {
|
|
93
|
-
return {
|
|
94
|
-
end: match.index + match[0].length,
|
|
95
|
-
start: match.index,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
return undefined;
|
|
100
|
-
}
|
|
101
23
|
function isIdentifierBoundary(source, index) {
|
|
102
24
|
if (index < 0 || index >= source.length) {
|
|
103
25
|
return true;
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The canonical CLI surface stays stable here while the implementation lives
|
|
5
5
|
* in focused internal modules:
|
|
6
|
-
* - `cli-add-shared`
|
|
6
|
+
* - `cli-add-shared` as a compatibility barrel around focused add helpers
|
|
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, } from "./cli-add-shared.js";
|
|
10
|
+
export { ADD_BLOCK_TEMPLATE_IDS, ADD_KIND_IDS, EDITOR_PLUGIN_SLOT_IDS, formatAddHelpText, isAddBlockTemplateId, } from "./cli-add-shared.js";
|
|
11
11
|
export type { AddBlockTemplateId, AddKindId, EditorPluginSlotId, } from "./cli-add-shared.js";
|
|
12
12
|
export { runAddBlockCommand, seedWorkspaceMigrationProject, } from "./cli-add-block.js";
|
|
13
13
|
export { runAddAdminViewCommand, runAddAbilityCommand, runAddAiFeatureCommand, runAddBindingSourceCommand, runAddBlockStyleCommand, runAddBlockTransformCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runAddRestResourceCommand, runAddVariationCommand, } from "./cli-add-workspace.js";
|
package/dist/runtime/cli-add.js
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
*
|
|
4
4
|
* The canonical CLI surface stays stable here while the implementation lives
|
|
5
5
|
* in focused internal modules:
|
|
6
|
-
* - `cli-add-shared`
|
|
6
|
+
* - `cli-add-shared` as a compatibility barrel around focused add helpers
|
|
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, } from "./cli-add-shared.js";
|
|
10
|
+
export { ADD_BLOCK_TEMPLATE_IDS, ADD_KIND_IDS, EDITOR_PLUGIN_SLOT_IDS, formatAddHelpText, isAddBlockTemplateId, } from "./cli-add-shared.js";
|
|
11
11
|
export { runAddBlockCommand, seedWorkspaceMigrationProject, } from "./cli-add-block.js";
|
|
12
12
|
export { runAddAdminViewCommand, runAddAbilityCommand, runAddAiFeatureCommand, runAddBindingSourceCommand, runAddBlockStyleCommand, runAddBlockTransformCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runAddRestResourceCommand, runAddVariationCommand, } from "./cli-add-workspace.js";
|
|
13
13
|
export { getWorkspaceBlockSelectOptions } from "./workspace-inventory.js";
|
|
@@ -3,6 +3,7 @@ import path from "node:path";
|
|
|
3
3
|
import { parseScaffoldBlockMetadata } from "@wp-typia/block-runtime/blocks";
|
|
4
4
|
import { checkExistingFiles, createDoctorCheck, WORKSPACE_FULL_BLOCK_NAME_PATTERN, WORKSPACE_GENERATED_BLOCK_ARTIFACTS, } from "./cli-doctor-workspace-shared.js";
|
|
5
5
|
import { HOOKED_BLOCK_ANCHOR_PATTERN, HOOKED_BLOCK_POSITION_SET, } from "./hooked-blocks.js";
|
|
6
|
+
import { hasExecutablePattern, hasUncommentedPattern, maskTypeScriptCommentsAndLiterals, } from "./ts-source-masking.js";
|
|
6
7
|
const WORKSPACE_COLLECTION_IMPORT_LINE = "import '../../collection';";
|
|
7
8
|
const WORKSPACE_COLLECTION_IMPORT_PATTERN = /^\s*import\s+["']\.\.\/\.\.\/collection["']\s*;?\s*$/m;
|
|
8
9
|
const WORKSPACE_VARIATIONS_IMPORT_PATTERN = /^\s*import\s*\{\s*registerWorkspaceVariations\s*\}\s*from\s*["']\.\/variations["']\s*;?\s*$/mu;
|
|
@@ -40,72 +41,6 @@ const WORKSPACE_BLOCK_LOCAL_STYLE_FILES = [
|
|
|
40
41
|
];
|
|
41
42
|
const WORKSPACE_BLOCK_IFRAME_GLOBAL_DOM_PATTERN = /\b(?:document|window)\b|\b(?:parent|top)\b(?!\s*:)/gu;
|
|
42
43
|
const WORKSPACE_BLOCK_PROPS_PATTERN = /\buse(?:Block|InnerBlocks)Props(?:\.save)?\s*\(/u;
|
|
43
|
-
function maskSourceSegment(segment) {
|
|
44
|
-
return segment.replace(/[^\n\r]/gu, " ");
|
|
45
|
-
}
|
|
46
|
-
function maskTypeScriptComments(source) {
|
|
47
|
-
return source
|
|
48
|
-
.replace(/\/\*[\s\S]*?\*\//gu, maskSourceSegment)
|
|
49
|
-
.replace(/\/\/[^\n\r]*/gu, maskSourceSegment);
|
|
50
|
-
}
|
|
51
|
-
// Preserve offsets while hiding non-executable text from hook checks.
|
|
52
|
-
function maskTypeScriptCommentsAndLiterals(source) {
|
|
53
|
-
let maskedSource = "";
|
|
54
|
-
let index = 0;
|
|
55
|
-
while (index < source.length) {
|
|
56
|
-
const current = source[index];
|
|
57
|
-
const next = source[index + 1];
|
|
58
|
-
if (current === "/" && next === "/") {
|
|
59
|
-
const start = index;
|
|
60
|
-
index += 2;
|
|
61
|
-
while (index < source.length &&
|
|
62
|
-
source[index] !== "\n" &&
|
|
63
|
-
source[index] !== "\r") {
|
|
64
|
-
index += 1;
|
|
65
|
-
}
|
|
66
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
if (current === "/" && next === "*") {
|
|
70
|
-
const start = index;
|
|
71
|
-
index += 2;
|
|
72
|
-
while (index < source.length &&
|
|
73
|
-
!(source[index] === "*" && source[index + 1] === "/")) {
|
|
74
|
-
index += 1;
|
|
75
|
-
}
|
|
76
|
-
index = Math.min(index + 2, source.length);
|
|
77
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
if (current === "'" || current === '"' || current === "`") {
|
|
81
|
-
const start = index;
|
|
82
|
-
const quote = current;
|
|
83
|
-
index += 1;
|
|
84
|
-
while (index < source.length) {
|
|
85
|
-
const char = source[index];
|
|
86
|
-
if (char === "\\") {
|
|
87
|
-
index += 2;
|
|
88
|
-
continue;
|
|
89
|
-
}
|
|
90
|
-
index += 1;
|
|
91
|
-
if (char === quote) {
|
|
92
|
-
break;
|
|
93
|
-
}
|
|
94
|
-
}
|
|
95
|
-
maskedSource += maskSourceSegment(source.slice(start, index));
|
|
96
|
-
continue;
|
|
97
|
-
}
|
|
98
|
-
maskedSource += current;
|
|
99
|
-
index += 1;
|
|
100
|
-
}
|
|
101
|
-
return maskedSource;
|
|
102
|
-
}
|
|
103
|
-
function hasUncommentedPattern(source, pattern) {
|
|
104
|
-
return pattern.test(maskTypeScriptComments(source));
|
|
105
|
-
}
|
|
106
|
-
function hasExecutablePattern(source, pattern) {
|
|
107
|
-
return pattern.test(maskTypeScriptCommentsAndLiterals(source));
|
|
108
|
-
}
|
|
109
44
|
function normalizePathSeparators(relativePath) {
|
|
110
45
|
return relativePath.split(path.sep).join("/");
|
|
111
46
|
}
|
package/dist/runtime/index.d.ts
CHANGED
|
@@ -32,6 +32,8 @@ export { PACKAGE_MANAGER_IDS, PACKAGE_MANAGERS, formatPackageExecCommand, format
|
|
|
32
32
|
export { clearPackageVersionsCache, getPackageVersions, invalidatePackageVersionsCache, } from "./package-versions.js";
|
|
33
33
|
export type { PackageVersions } from "./package-versions.js";
|
|
34
34
|
export { TEMPLATE_IDS, TEMPLATE_REGISTRY, getTemplateById, getTemplateSelectOptions, listTemplates, } from "./template-registry.js";
|
|
35
|
+
export { EXTERNAL_TEMPLATE_CACHE_TTL_DAYS_ENV, pruneExternalTemplateCache, } from "./template-source-cache.js";
|
|
36
|
+
export type { ExternalTemplateCachePruneOptions, ExternalTemplateCachePruneResult, } from "./template-source-cache.js";
|
|
35
37
|
export { STALE_TEMP_ROOT_MAX_AGE_MS, WP_TYPIA_TEMP_ROOT_PREFIX, cleanupManagedTempRoot, cleanupStaleTempRoots, createManagedTempRoot, getTrackedTempRoots, } from "./temp-roots.js";
|
|
36
38
|
export { createReadlinePrompt, createCliCommandError, createCliDiagnosticCodeError, CliDiagnosticError, CLI_DIAGNOSTIC_CODES, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, EDITOR_PLUGIN_SLOT_IDS, isCliDiagnosticError, runAddAdminViewCommand, runAddAbilityCommand, runAddAiFeatureCommand, runAddBindingSourceCommand, runAddBlockCommand, runAddBlockStyleCommand, runAddBlockTransformCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
37
39
|
export type { CliDiagnosticCode, CliDiagnosticCodeError, CliDiagnosticMessage, DoctorCheck, EditorPluginSlotId, HookedBlockPositionId, ReadlinePrompt, } from "./cli-core.js";
|
package/dist/runtime/index.js
CHANGED
|
@@ -25,5 +25,6 @@ export { buildCompoundChildStarterManifestDocument, getStarterManifestFiles, str
|
|
|
25
25
|
export { PACKAGE_MANAGER_IDS, PACKAGE_MANAGERS, formatPackageExecCommand, formatInstallCommand, formatRunScript, getPackageManager, getPackageManagerSelectOptions, transformPackageManagerText, } from "./package-managers.js";
|
|
26
26
|
export { clearPackageVersionsCache, getPackageVersions, invalidatePackageVersionsCache, } from "./package-versions.js";
|
|
27
27
|
export { TEMPLATE_IDS, TEMPLATE_REGISTRY, getTemplateById, getTemplateSelectOptions, listTemplates, } from "./template-registry.js";
|
|
28
|
+
export { EXTERNAL_TEMPLATE_CACHE_TTL_DAYS_ENV, pruneExternalTemplateCache, } from "./template-source-cache.js";
|
|
28
29
|
export { STALE_TEMP_ROOT_MAX_AGE_MS, WP_TYPIA_TEMP_ROOT_PREFIX, cleanupManagedTempRoot, cleanupStaleTempRoots, createManagedTempRoot, getTrackedTempRoots, } from "./temp-roots.js";
|
|
29
30
|
export { createReadlinePrompt, createCliCommandError, createCliDiagnosticCodeError, CliDiagnosticError, CLI_DIAGNOSTIC_CODES, formatCliDiagnosticError, formatAddHelpText, formatDoctorCheckLine, formatDoctorSummaryLine, formatHelpText, formatTemplateDetails, formatTemplateFeatures, formatTemplateSummary, getDoctorChecks, getDoctorFailureDetailLines, getFailingDoctorChecks, getNextSteps, getOptionalOnboarding, getWorkspaceBlockSelectOptions, HOOKED_BLOCK_POSITION_IDS, EDITOR_PLUGIN_SLOT_IDS, isCliDiagnosticError, runAddAdminViewCommand, runAddAbilityCommand, runAddAiFeatureCommand, runAddBindingSourceCommand, runAddBlockCommand, runAddBlockStyleCommand, runAddBlockTransformCommand, runAddEditorPluginCommand, runAddHookedBlockCommand, runAddPatternCommand, runDoctor, runAddVariationCommand, runScaffoldFlow, } from "./cli-core.js";
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type PackageManagerId } from './package-managers.js';
|
|
1
2
|
import type { JsonValue, ManifestAttribute, JsonObject } from './migration-types.js';
|
|
2
3
|
import { type UnknownRecord } from './object-utils.js';
|
|
3
4
|
export { cloneJsonValue } from './json-utils.js';
|
|
@@ -12,7 +13,7 @@ export declare function copyFile(sourcePath: string, targetPath: string): void;
|
|
|
12
13
|
export declare function sanitizeSaveSnapshotSource(source: string): string;
|
|
13
14
|
export declare function sanitizeSnapshotBlockJson(blockJson: JsonObject): JsonObject;
|
|
14
15
|
export declare function runProjectScriptIfPresent(projectDir: string, scriptName: string): void;
|
|
15
|
-
export declare function detectPackageManagerId(projectDir: string):
|
|
16
|
+
export declare function detectPackageManagerId(projectDir: string): PackageManagerId;
|
|
16
17
|
export declare function getLocalTsxBinary(projectDir: string): string;
|
|
17
18
|
/**
|
|
18
19
|
* Returns whether isInteractiveTerminal() is running with both stdin and stdout
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import fs from 'node:fs';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
|
-
import { formatRunScript } from './package-managers.js';
|
|
4
|
+
import { formatRunScript, inferPackageManagerId, parsePackageManagerField, } from './package-managers.js';
|
|
5
5
|
import { isPlainObject } from './object-utils.js';
|
|
6
6
|
export { cloneJsonValue } from './json-utils.js';
|
|
7
7
|
const MIGRATION_VERSION_LABEL_PATTERN = /^v([1-9]\d*)$/;
|
|
@@ -141,16 +141,8 @@ export function runProjectScriptIfPresent(projectDir, scriptName) {
|
|
|
141
141
|
}
|
|
142
142
|
export function detectPackageManagerId(projectDir) {
|
|
143
143
|
const packageJson = readJson(path.join(projectDir, 'package.json'));
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
return 'bun';
|
|
147
|
-
if (field.startsWith('npm@'))
|
|
148
|
-
return 'npm';
|
|
149
|
-
if (field.startsWith('pnpm@'))
|
|
150
|
-
return 'pnpm';
|
|
151
|
-
if (field.startsWith('yarn@'))
|
|
152
|
-
return 'yarn';
|
|
153
|
-
return 'bun';
|
|
144
|
+
return (parsePackageManagerField(packageJson.packageManager) ??
|
|
145
|
+
inferPackageManagerId(projectDir));
|
|
154
146
|
}
|
|
155
147
|
export function getLocalTsxBinary(projectDir) {
|
|
156
148
|
const filename = process.platform === 'win32' ? 'tsx.cmd' : 'tsx';
|
|
@@ -9,6 +9,25 @@ export interface PackageManagerDefinition {
|
|
|
9
9
|
export declare const PACKAGE_MANAGER_IDS: PackageManagerId[];
|
|
10
10
|
export declare const PACKAGE_MANAGERS: Readonly<Record<PackageManagerId, PackageManagerDefinition>>;
|
|
11
11
|
export declare function getPackageManager(id: string): PackageManagerDefinition;
|
|
12
|
+
/**
|
|
13
|
+
* Parse a normalized package-manager id from a package.json `packageManager` field.
|
|
14
|
+
*
|
|
15
|
+
* @param packageManagerField Raw field value such as `pnpm@8.3.1`.
|
|
16
|
+
* @returns A supported package manager id, or null when the field is missing or unsupported.
|
|
17
|
+
*/
|
|
18
|
+
export declare function parsePackageManagerField(packageManagerField: string | undefined): PackageManagerId | null;
|
|
19
|
+
/**
|
|
20
|
+
* Infer the package manager used by a project from package.json and lockfile signals.
|
|
21
|
+
*
|
|
22
|
+
* `packageManager` fields take precedence over lockfiles, then lockfile and PnP
|
|
23
|
+
* markers are checked in Bun, pnpm, Yarn, npm order. npm remains the fallback so
|
|
24
|
+
* generated projects without explicit metadata keep the historical CLI default.
|
|
25
|
+
*
|
|
26
|
+
* @param projectDir Project root to inspect.
|
|
27
|
+
* @param packageManagerField Optional already-read package.json field.
|
|
28
|
+
* @returns The inferred package manager id.
|
|
29
|
+
*/
|
|
30
|
+
export declare function inferPackageManagerId(projectDir: string, packageManagerField?: string): PackageManagerId;
|
|
12
31
|
export declare function getPackageManagerSelectOptions(): Array<{
|
|
13
32
|
label: string;
|
|
14
33
|
value: PackageManagerId;
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
1
3
|
const PACKAGE_MANAGER_DATA = [
|
|
2
4
|
{
|
|
3
5
|
id: "bun",
|
|
@@ -28,6 +30,15 @@ const PACKAGE_MANAGER_DATA = [
|
|
|
28
30
|
frozenInstallCommand: "yarn install --frozen-lockfile",
|
|
29
31
|
},
|
|
30
32
|
];
|
|
33
|
+
const PACKAGE_MANAGER_LOCKFILE_SIGNALS = [
|
|
34
|
+
{ id: "bun", filenames: ["bun.lock", "bun.lockb"] },
|
|
35
|
+
{ id: "pnpm", filenames: ["pnpm-lock.yaml"] },
|
|
36
|
+
{
|
|
37
|
+
id: "yarn",
|
|
38
|
+
filenames: ["yarn.lock", ".pnp.cjs", ".pnp.loader.mjs", ".yarnrc.yml"],
|
|
39
|
+
},
|
|
40
|
+
{ id: "npm", filenames: ["package-lock.json", "npm-shrinkwrap.json"] },
|
|
41
|
+
];
|
|
31
42
|
export const PACKAGE_MANAGER_IDS = PACKAGE_MANAGER_DATA.map((manager) => manager.id);
|
|
32
43
|
export const PACKAGE_MANAGERS = Object.freeze(Object.fromEntries(PACKAGE_MANAGER_DATA.map((manager) => [manager.id, manager])));
|
|
33
44
|
const DEV_INSTALL_FLAGS = {
|
|
@@ -44,6 +55,57 @@ export function getPackageManager(id) {
|
|
|
44
55
|
}
|
|
45
56
|
return manager;
|
|
46
57
|
}
|
|
58
|
+
/**
|
|
59
|
+
* Parse a normalized package-manager id from a package.json `packageManager` field.
|
|
60
|
+
*
|
|
61
|
+
* @param packageManagerField Raw field value such as `pnpm@8.3.1`.
|
|
62
|
+
* @returns A supported package manager id, or null when the field is missing or unsupported.
|
|
63
|
+
*/
|
|
64
|
+
export function parsePackageManagerField(packageManagerField) {
|
|
65
|
+
const packageManagerId = packageManagerField?.split("@", 1)[0];
|
|
66
|
+
return PACKAGE_MANAGER_IDS.includes(packageManagerId)
|
|
67
|
+
? packageManagerId
|
|
68
|
+
: null;
|
|
69
|
+
}
|
|
70
|
+
function readPackageManagerField(projectDir) {
|
|
71
|
+
try {
|
|
72
|
+
const packageJsonPath = path.join(projectDir, "package.json");
|
|
73
|
+
if (!fs.existsSync(packageJsonPath)) {
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
const manifest = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
|
|
77
|
+
return typeof manifest.packageManager === "string"
|
|
78
|
+
? manifest.packageManager
|
|
79
|
+
: undefined;
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Infer the package manager used by a project from package.json and lockfile signals.
|
|
87
|
+
*
|
|
88
|
+
* `packageManager` fields take precedence over lockfiles, then lockfile and PnP
|
|
89
|
+
* markers are checked in Bun, pnpm, Yarn, npm order. npm remains the fallback so
|
|
90
|
+
* generated projects without explicit metadata keep the historical CLI default.
|
|
91
|
+
*
|
|
92
|
+
* @param projectDir Project root to inspect.
|
|
93
|
+
* @param packageManagerField Optional already-read package.json field.
|
|
94
|
+
* @returns The inferred package manager id.
|
|
95
|
+
*/
|
|
96
|
+
export function inferPackageManagerId(projectDir, packageManagerField) {
|
|
97
|
+
const fieldPackageManager = parsePackageManagerField(packageManagerField) ??
|
|
98
|
+
parsePackageManagerField(readPackageManagerField(projectDir));
|
|
99
|
+
if (fieldPackageManager) {
|
|
100
|
+
return fieldPackageManager;
|
|
101
|
+
}
|
|
102
|
+
for (const signal of PACKAGE_MANAGER_LOCKFILE_SIGNALS) {
|
|
103
|
+
if (signal.filenames.some((filename) => fs.existsSync(path.join(projectDir, filename)))) {
|
|
104
|
+
return signal.id;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return "npm";
|
|
108
|
+
}
|
|
47
109
|
export function getPackageManagerSelectOptions() {
|
|
48
110
|
return PACKAGE_MANAGER_DATA.map((manager) => ({
|
|
49
111
|
label: manager.label,
|
|
@@ -8,6 +8,12 @@ export declare const EXTERNAL_TEMPLATE_CACHE_ENV = "WP_TYPIA_EXTERNAL_TEMPLATE_C
|
|
|
8
8
|
* Environment variable that overrides the external template cache root.
|
|
9
9
|
*/
|
|
10
10
|
export declare const EXTERNAL_TEMPLATE_CACHE_DIR_ENV = "WP_TYPIA_EXTERNAL_TEMPLATE_CACHE_DIR";
|
|
11
|
+
/**
|
|
12
|
+
* Environment variable that enables TTL-based external template cache pruning.
|
|
13
|
+
*
|
|
14
|
+
* Unset, empty, zero, negative, and non-numeric values keep pruning disabled.
|
|
15
|
+
*/
|
|
16
|
+
export declare const EXTERNAL_TEMPLATE_CACHE_TTL_DAYS_ENV = "WP_TYPIA_EXTERNAL_TEMPLATE_CACHE_TTL_DAYS";
|
|
11
17
|
/**
|
|
12
18
|
* Serializable metadata recorded in the cache marker for diagnostics.
|
|
13
19
|
*/
|
|
@@ -58,6 +64,48 @@ export interface ExternalTemplateCacheLookupDescriptor {
|
|
|
58
64
|
*/
|
|
59
65
|
namespace: string;
|
|
60
66
|
}
|
|
67
|
+
/**
|
|
68
|
+
* Options for best-effort external template cache pruning.
|
|
69
|
+
*/
|
|
70
|
+
export interface ExternalTemplateCachePruneOptions {
|
|
71
|
+
/**
|
|
72
|
+
* Environment object to inspect, defaulting to `process.env`.
|
|
73
|
+
*/
|
|
74
|
+
env?: NodeJS.ProcessEnv;
|
|
75
|
+
/**
|
|
76
|
+
* Clock override for deterministic tests.
|
|
77
|
+
*/
|
|
78
|
+
now?: Date | number;
|
|
79
|
+
/**
|
|
80
|
+
* TTL override in days. When omitted, the TTL environment variable is used.
|
|
81
|
+
*/
|
|
82
|
+
ttlDays?: number;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Summary returned after external template cache pruning.
|
|
86
|
+
*/
|
|
87
|
+
export interface ExternalTemplateCachePruneResult {
|
|
88
|
+
/**
|
|
89
|
+
* Absolute cache root inspected by the pruning helper.
|
|
90
|
+
*/
|
|
91
|
+
cacheRoot: string;
|
|
92
|
+
/**
|
|
93
|
+
* Entries removed because their marker timestamp exceeded the TTL.
|
|
94
|
+
*/
|
|
95
|
+
prunedEntries: number;
|
|
96
|
+
/**
|
|
97
|
+
* Candidate cache entry directories inspected.
|
|
98
|
+
*/
|
|
99
|
+
scannedEntries: number;
|
|
100
|
+
/**
|
|
101
|
+
* Candidate directories skipped because they were malformed or unsafe.
|
|
102
|
+
*/
|
|
103
|
+
skippedEntries: number;
|
|
104
|
+
/**
|
|
105
|
+
* Resolved TTL in milliseconds, or `null` when pruning was disabled.
|
|
106
|
+
*/
|
|
107
|
+
ttlMs: number | null;
|
|
108
|
+
}
|
|
61
109
|
/**
|
|
62
110
|
* Checks whether remote external template source caching is enabled.
|
|
63
111
|
*
|
|
@@ -86,6 +134,17 @@ export declare function getExternalTemplateCacheRoot(env?: NodeJS.ProcessEnv): s
|
|
|
86
134
|
* @returns SHA-256 hex digest of the JSON-serialized key parts.
|
|
87
135
|
*/
|
|
88
136
|
export declare function createExternalTemplateCacheKey(keyParts: readonly string[]): string;
|
|
137
|
+
/**
|
|
138
|
+
* Removes stale external template cache entries when a positive TTL is configured.
|
|
139
|
+
*
|
|
140
|
+
* The helper is best-effort: malformed cache directories are skipped, cache
|
|
141
|
+
* roots must remain private and non-symlinked, and deletes are constrained to
|
|
142
|
+
* deterministic entry directories under the configured cache root.
|
|
143
|
+
*
|
|
144
|
+
* @param options Optional TTL, clock, and environment overrides.
|
|
145
|
+
* @returns Pruning summary with counts for inspected, skipped, and removed entries.
|
|
146
|
+
*/
|
|
147
|
+
export declare function pruneExternalTemplateCache(options?: ExternalTemplateCachePruneOptions): Promise<ExternalTemplateCachePruneResult>;
|
|
89
148
|
/**
|
|
90
149
|
* Finds a reusable cache entry whose marker metadata includes the expected fields.
|
|
91
150
|
*
|