sdtk-wiki-kit 0.2.0 → 0.2.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/assets/atlas/build_atlas.py +775 -775
- package/assets/atlas/doc_atlas_viewer_template.html +3796 -3796
- package/assets/atlas/vendor/mermaid.min.js +2029 -2029
- package/bin/sdtk-wiki.js +0 -0
- package/package.json +45 -45
- package/src/commands/context.js +67 -67
- package/src/commands/help.js +7 -0
- package/src/commands/update.js +11 -0
- package/src/index.js +111 -107
- package/src/lib/update.js +217 -0
- package/src/lib/wiki-context-pack.js +267 -267
|
@@ -0,0 +1,217 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { spawn } = require("child_process");
|
|
4
|
+
const path = require("path");
|
|
5
|
+
const { parseFlags } = require("./args");
|
|
6
|
+
const { CliError, ValidationError } = require("./errors");
|
|
7
|
+
|
|
8
|
+
const PACKAGE_NAME = "sdtk-wiki-kit";
|
|
9
|
+
const PRODUCT_NAME = "SDTK-WIKI";
|
|
10
|
+
const NPM_BIN = process.platform === "win32" ? "npm.cmd" : "npm";
|
|
11
|
+
const NPM_DISPLAY = "npm";
|
|
12
|
+
const NPM_VIEW_ARGS = ["view", PACKAGE_NAME, "version"];
|
|
13
|
+
const VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
14
|
+
const FLAG_DEFS = {
|
|
15
|
+
version: { type: "string" },
|
|
16
|
+
"project-path": { type: "string" },
|
|
17
|
+
"check-only": { type: "boolean" },
|
|
18
|
+
"skip-project-files": { type: "boolean" },
|
|
19
|
+
verbose: { type: "boolean" },
|
|
20
|
+
};
|
|
21
|
+
const pkg = require("../../package.json");
|
|
22
|
+
|
|
23
|
+
let commandExecutor = defaultCommandExecutor;
|
|
24
|
+
|
|
25
|
+
function defaultCommandExecutor(command, args, options = {}) {
|
|
26
|
+
return new Promise((resolve, reject) => {
|
|
27
|
+
const child = spawn(command, args, {
|
|
28
|
+
cwd: options.cwd || process.cwd(),
|
|
29
|
+
env: options.env || process.env,
|
|
30
|
+
shell: options.shell || false,
|
|
31
|
+
windowsHide: true,
|
|
32
|
+
});
|
|
33
|
+
let stdout = "";
|
|
34
|
+
let stderr = "";
|
|
35
|
+
|
|
36
|
+
child.stdout.on("data", (chunk) => {
|
|
37
|
+
const text = chunk.toString();
|
|
38
|
+
stdout += text;
|
|
39
|
+
if (options.verbose) process.stdout.write(text);
|
|
40
|
+
});
|
|
41
|
+
child.stderr.on("data", (chunk) => {
|
|
42
|
+
const text = chunk.toString();
|
|
43
|
+
stderr += text;
|
|
44
|
+
if (options.verbose) process.stderr.write(text);
|
|
45
|
+
});
|
|
46
|
+
child.on("error", (error) => {
|
|
47
|
+
if (error && error.code === "ENOENT") {
|
|
48
|
+
reject(new CliError(`Required command not found in PATH: ${command}`));
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
reject(error);
|
|
52
|
+
});
|
|
53
|
+
child.on("close", (exitCode) => {
|
|
54
|
+
resolve({ exitCode: typeof exitCode === "number" ? exitCode : 1, stdout, stderr });
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function setCommandExecutorForTests(executor) {
|
|
60
|
+
commandExecutor = executor || defaultCommandExecutor;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function resetCommandExecutorForTests() {
|
|
64
|
+
commandExecutor = defaultCommandExecutor;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function quote(value) {
|
|
68
|
+
const text = String(value);
|
|
69
|
+
return /[\s"]/u.test(text) ? JSON.stringify(text) : text;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function formatCommand(command, args) {
|
|
73
|
+
return [command, ...args].map((value) => quote(value)).join(" ");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function validateVersion(targetVersion) {
|
|
77
|
+
if (targetVersion !== "latest" && !VERSION_PATTERN.test(targetVersion)) {
|
|
78
|
+
throw new ValidationError(`Invalid value for --version: "${targetVersion}". Must be "latest" or x.y.z.`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function extractResolvedVersion(stdout) {
|
|
83
|
+
const lines = String(stdout || "")
|
|
84
|
+
.split(/\r?\n/u)
|
|
85
|
+
.map((line) => line.trim())
|
|
86
|
+
.filter(Boolean);
|
|
87
|
+
const candidate = (lines[lines.length - 1] || "").replace(/^['"]|['"]$/gu, "");
|
|
88
|
+
if (!VERSION_PATTERN.test(candidate)) {
|
|
89
|
+
throw new CliError(`npm registry lookup returned an invalid version for ${PACKAGE_NAME}: "${candidate || "<empty>"}"`);
|
|
90
|
+
}
|
|
91
|
+
return candidate;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
async function resolveTargetVersion(options) {
|
|
95
|
+
if (options.requestedVersion !== "latest") {
|
|
96
|
+
return options.requestedVersion;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
let result;
|
|
100
|
+
try {
|
|
101
|
+
result = await commandExecutor(NPM_BIN, NPM_VIEW_ARGS, {
|
|
102
|
+
verbose: options.verbose,
|
|
103
|
+
shell: process.platform === "win32",
|
|
104
|
+
});
|
|
105
|
+
} catch (error) {
|
|
106
|
+
throw new CliError(`npm registry lookup failed for ${PACKAGE_NAME} while resolving --version latest.\n${error.message}`, error.exitCode || 4);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
if (result.exitCode !== 0) {
|
|
110
|
+
const detail = (result.stderr || result.stdout || "").trim();
|
|
111
|
+
throw new CliError(`npm registry lookup failed for ${PACKAGE_NAME} while resolving --version latest (exit code ${result.exitCode}).${detail ? `\n${detail}` : ""}`);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
try {
|
|
115
|
+
return extractResolvedVersion(result.stdout);
|
|
116
|
+
} catch (error) {
|
|
117
|
+
throw new CliError(`npm registry lookup failed for ${PACKAGE_NAME} while resolving --version latest.\n${error.message}`, error.exitCode || 4);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
function buildPlan(options) {
|
|
122
|
+
const npmArgs = ["install", "-g", `${PACKAGE_NAME}@${options.targetVersion}`];
|
|
123
|
+
return {
|
|
124
|
+
installedVersion: pkg.version,
|
|
125
|
+
requestedVersion: options.requestedVersion,
|
|
126
|
+
targetVersion: options.targetVersion,
|
|
127
|
+
updateNeeded: pkg.version !== options.targetVersion,
|
|
128
|
+
npmArgs,
|
|
129
|
+
npmCommand: formatCommand(NPM_DISPLAY, npmArgs),
|
|
130
|
+
projectPath: options.projectPath,
|
|
131
|
+
checkOnly: options.checkOnly,
|
|
132
|
+
skipProjectFiles: options.skipProjectFiles,
|
|
133
|
+
projectRefreshCommand: options.skipProjectFiles
|
|
134
|
+
? "skipped (--skip-project-files)"
|
|
135
|
+
: "skipped (R1 package-only update; project files are never mutated)",
|
|
136
|
+
runtimeRefreshCommand: "skipped (no runtime asset update in R1)",
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function parseUpdateOptions(args) {
|
|
141
|
+
const { flags, positional } = parseFlags(args || [], FLAG_DEFS);
|
|
142
|
+
|
|
143
|
+
if (positional.length > 0) {
|
|
144
|
+
throw new ValidationError(`Unexpected arguments: ${positional.join(" ")}`);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const requestedVersion = flags.version || "latest";
|
|
148
|
+
validateVersion(requestedVersion);
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
requestedVersion,
|
|
152
|
+
projectPath: path.resolve(flags["project-path"] || process.cwd()),
|
|
153
|
+
checkOnly: Boolean(flags["check-only"]),
|
|
154
|
+
skipProjectFiles: Boolean(flags["skip-project-files"]),
|
|
155
|
+
verbose: Boolean(flags.verbose),
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function printPlan(plan) {
|
|
160
|
+
console.log(`${PRODUCT_NAME} update plan`);
|
|
161
|
+
console.log(` Installed package version: ${plan.installedVersion}`);
|
|
162
|
+
console.log(` Requested package version: ${plan.requestedVersion}`);
|
|
163
|
+
console.log(` Target package version: ${plan.targetVersion}`);
|
|
164
|
+
console.log(` Package update needed: ${plan.updateNeeded ? "yes" : `no (already installed: ${plan.installedVersion})`}`);
|
|
165
|
+
console.log(` Package refresh command: ${plan.npmCommand}`);
|
|
166
|
+
console.log(` Project path: ${plan.projectPath}`);
|
|
167
|
+
console.log(` Project file refresh: ${plan.projectRefreshCommand}`);
|
|
168
|
+
console.log(` Runtime asset refresh: ${plan.runtimeRefreshCommand}`);
|
|
169
|
+
console.log(` Mode: ${plan.checkOnly ? "check-only (no changes applied)" : "apply"}`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
async function runCommand(label, command, args, options) {
|
|
173
|
+
const result = await commandExecutor(command, args, options);
|
|
174
|
+
if (result.exitCode !== 0) {
|
|
175
|
+
const detail = (result.stderr || result.stdout || "").trim();
|
|
176
|
+
throw new CliError(`${label} failed (exit code ${result.exitCode}).${detail ? `\n${detail}` : ""}`);
|
|
177
|
+
}
|
|
178
|
+
return result;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
async function applyPlan(plan, options) {
|
|
182
|
+
console.log("");
|
|
183
|
+
console.log(`Applying ${PRODUCT_NAME} update...`);
|
|
184
|
+
console.log(` npm refresh: ${plan.npmCommand}`);
|
|
185
|
+
await runCommand("npm package refresh", NPM_BIN, plan.npmArgs, {
|
|
186
|
+
verbose: options.verbose,
|
|
187
|
+
shell: process.platform === "win32",
|
|
188
|
+
});
|
|
189
|
+
console.log(` project refresh: ${plan.projectRefreshCommand}`);
|
|
190
|
+
console.log(` runtime refresh: ${plan.runtimeRefreshCommand}`);
|
|
191
|
+
console.log("");
|
|
192
|
+
console.log(`${PRODUCT_NAME} update completed successfully.`);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
async function executeUpdate(args) {
|
|
196
|
+
const options = parseUpdateOptions(args);
|
|
197
|
+
const targetVersion = await resolveTargetVersion(options);
|
|
198
|
+
const plan = buildPlan({ ...options, targetVersion });
|
|
199
|
+
printPlan(plan);
|
|
200
|
+
|
|
201
|
+
if (options.checkOnly) {
|
|
202
|
+
return 0;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
await applyPlan(plan, options);
|
|
206
|
+
return 0;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
module.exports = {
|
|
210
|
+
buildPlan,
|
|
211
|
+
executeUpdate,
|
|
212
|
+
formatCommand,
|
|
213
|
+
parseUpdateOptions,
|
|
214
|
+
resetCommandExecutorForTests,
|
|
215
|
+
resolveTargetVersion,
|
|
216
|
+
setCommandExecutorForTests,
|
|
217
|
+
};
|