@jskit-ai/jskit-cli 0.2.27 → 0.2.28
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/package.json +3 -2
- package/src/server/cliRuntime/appState.js +226 -0
- package/src/server/cliRuntime/capabilitySupport.js +194 -0
- package/src/server/cliRuntime/descriptorValidation.js +150 -0
- package/src/server/cliRuntime/ioAndMigrations.js +381 -0
- package/src/server/cliRuntime/localPackageSupport.js +390 -0
- package/src/server/cliRuntime/mutationApplication.js +9 -0
- package/src/server/cliRuntime/mutationWhen.js +285 -0
- package/src/server/cliRuntime/mutations/fileMutations.js +247 -0
- package/src/server/cliRuntime/mutations/installMigrationMutation.js +213 -0
- package/src/server/cliRuntime/mutations/mutationPathUtils.js +12 -0
- package/src/server/cliRuntime/mutations/surfaceTargets.js +155 -0
- package/src/server/cliRuntime/mutations/templateContext.js +171 -0
- package/src/server/cliRuntime/mutations/textMutations.js +250 -0
- package/src/server/cliRuntime/packageInstallFlow.js +489 -0
- package/src/server/cliRuntime/packageIntrospection/exportEntries.js +259 -0
- package/src/server/cliRuntime/packageIntrospection/exportedSymbols.js +216 -0
- package/src/server/cliRuntime/packageIntrospection/placementNormalization.js +98 -0
- package/src/server/cliRuntime/packageIntrospection/providerBindingIntrospection.js +377 -0
- package/src/server/cliRuntime/packageIntrospection.js +137 -0
- package/src/server/cliRuntime/packageOptions.js +299 -0
- package/src/server/cliRuntime/packageRegistries.js +343 -0
- package/src/server/cliRuntime/packageTemplateResolution.js +131 -0
- package/src/server/cliRuntime/viteProxy.js +356 -0
- package/src/server/commandHandlers/health.js +292 -0
- package/src/server/commandHandlers/list.js +292 -0
- package/src/server/commandHandlers/package.js +23 -0
- package/src/server/commandHandlers/packageCommands/add.js +282 -0
- package/src/server/commandHandlers/packageCommands/create.js +155 -0
- package/src/server/commandHandlers/packageCommands/generate.js +116 -0
- package/src/server/commandHandlers/packageCommands/migrations.js +155 -0
- package/src/server/commandHandlers/packageCommands/position.js +103 -0
- package/src/server/commandHandlers/packageCommands/remove.js +181 -0
- package/src/server/commandHandlers/packageCommands/update.js +40 -0
- package/src/server/commandHandlers/shared.js +314 -0
- package/src/server/commandHandlers/show/payloads.js +92 -0
- package/src/server/commandHandlers/show/renderBundleText.js +16 -0
- package/src/server/commandHandlers/show/renderHelpers.js +82 -0
- package/src/server/commandHandlers/show/renderPackageCapabilities.js +124 -0
- package/src/server/commandHandlers/show/renderPackageExports.js +203 -0
- package/src/server/commandHandlers/show/renderPackageText.js +332 -0
- package/src/server/commandHandlers/show.js +114 -0
- package/src/server/core/argParser.js +144 -0
- package/src/server/{runtimeDeps.js → core/buildCommandDeps.js} +2 -1
- package/src/server/core/commandCatalog.js +47 -0
- package/src/server/core/createCliRunner.js +150 -0
- package/src/server/core/createCommandHandlers.js +43 -0
- package/src/server/{runCli.js → core/dispatchCli.js} +14 -1
- package/src/server/core/usageHelp.js +344 -0
- package/src/server/index.js +1 -1
- package/src/server/{optionInterpolation.js → shared/optionInterpolation.js} +12 -1
- package/src/server/{pathResolution.js → shared/pathResolution.js} +1 -1
- package/src/server/argParser.js +0 -206
- package/src/server/cliRuntime.js +0 -4956
- package/src/server/commandHandlers.js +0 -2109
- /package/src/server/{cliError.js → shared/cliError.js} +0 -0
- /package/src/server/{collectionUtils.js → shared/collectionUtils.js} +0 -0
- /package/src/server/{outputFormatting.js → shared/outputFormatting.js} +0 -0
- /package/src/server/{packageIdHelpers.js → shared/packageIdHelpers.js} +0 -0
|
@@ -1,2109 +0,0 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
|
-
import {
|
|
3
|
-
ensureArray,
|
|
4
|
-
ensureObject,
|
|
5
|
-
sortStrings
|
|
6
|
-
} from "./collectionUtils.js";
|
|
7
|
-
|
|
8
|
-
function createCommandHandlers(deps) {
|
|
9
|
-
const {
|
|
10
|
-
createCliError,
|
|
11
|
-
createColorFormatter,
|
|
12
|
-
resolveWrapWidth,
|
|
13
|
-
writeWrappedItems,
|
|
14
|
-
normalizeRelativePath,
|
|
15
|
-
normalizeRelativePosixPath,
|
|
16
|
-
resolveAppRootFromCwd,
|
|
17
|
-
loadLockFile,
|
|
18
|
-
loadPackageRegistry,
|
|
19
|
-
loadBundleRegistry,
|
|
20
|
-
loadAppLocalPackageRegistry,
|
|
21
|
-
mergePackageRegistries,
|
|
22
|
-
resolvePackageIdInput,
|
|
23
|
-
resolveInstalledPackageIdInput,
|
|
24
|
-
resolveInstalledNodeModulePackageEntry,
|
|
25
|
-
hydratePackageRegistryFromInstalledNodeModules,
|
|
26
|
-
validateInlineOptionsForPackage,
|
|
27
|
-
resolveLocalDependencyOrder,
|
|
28
|
-
validatePlannedCapabilityClosure,
|
|
29
|
-
resolvePackageOptions,
|
|
30
|
-
applyPackageInstall,
|
|
31
|
-
applyPackageMigrationsOnly,
|
|
32
|
-
applyPackagePositioning,
|
|
33
|
-
adoptAppLocalPackageDependencies,
|
|
34
|
-
loadAppPackageJson,
|
|
35
|
-
resolveLocalPackageId,
|
|
36
|
-
createLocalPackageScaffoldFiles,
|
|
37
|
-
fileExists,
|
|
38
|
-
applyPackageJsonField,
|
|
39
|
-
toFileDependencySpecifier,
|
|
40
|
-
writeJsonFile,
|
|
41
|
-
writeFile,
|
|
42
|
-
mkdir,
|
|
43
|
-
path,
|
|
44
|
-
inspectPackageOfferings,
|
|
45
|
-
buildFileWriteGroups,
|
|
46
|
-
listDeclaredCapabilities,
|
|
47
|
-
buildCapabilityDetailsForPackage,
|
|
48
|
-
formatPackageSubpathImport,
|
|
49
|
-
normalizePlacementOutlets,
|
|
50
|
-
normalizePlacementContributions,
|
|
51
|
-
shouldShowPackageExportTarget,
|
|
52
|
-
classifyExportedSymbols,
|
|
53
|
-
deriveProviderDisplayName,
|
|
54
|
-
restorePackageJsonField,
|
|
55
|
-
readFileBufferIfExists,
|
|
56
|
-
removeEnvValue,
|
|
57
|
-
removeManagedViteProxyEntries,
|
|
58
|
-
hashBuffer,
|
|
59
|
-
rm
|
|
60
|
-
} = deps;
|
|
61
|
-
|
|
62
|
-
function renderResolvedSummary(commandType, targetId, resolvedPackageIds, touchedFiles, appRoot, lockPath, externalDependencies) {
|
|
63
|
-
const lines = [];
|
|
64
|
-
lines.push(`${commandType} ${targetId}.`);
|
|
65
|
-
lines.push(`Resolved packages (${resolvedPackageIds.length}):`);
|
|
66
|
-
for (const packageId of resolvedPackageIds) {
|
|
67
|
-
lines.push(`- ${packageId}`);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (externalDependencies.length > 0) {
|
|
71
|
-
lines.push(`External dependencies (${externalDependencies.length}):`);
|
|
72
|
-
for (const dependencyId of externalDependencies) {
|
|
73
|
-
lines.push(`- ${dependencyId}`);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
lines.push(`Touched files (${touchedFiles.length}):`);
|
|
78
|
-
for (const touchedFile of touchedFiles) {
|
|
79
|
-
lines.push(`- ${touchedFile}`);
|
|
80
|
-
}
|
|
81
|
-
lines.push(`Lock file: ${normalizeRelativePath(appRoot, lockPath)}`);
|
|
82
|
-
return lines.join("\n");
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
async function runNpmInstall(appRoot, stderr) {
|
|
86
|
-
await new Promise((resolve, reject) => {
|
|
87
|
-
const child = spawn("npm", ["install"], {
|
|
88
|
-
cwd: appRoot,
|
|
89
|
-
stdio: "inherit"
|
|
90
|
-
});
|
|
91
|
-
|
|
92
|
-
child.on("error", reject);
|
|
93
|
-
child.on("exit", (code) => {
|
|
94
|
-
if (code === 0) {
|
|
95
|
-
resolve();
|
|
96
|
-
} else {
|
|
97
|
-
reject(createCliError(`npm install failed with exit code ${code}.`));
|
|
98
|
-
}
|
|
99
|
-
});
|
|
100
|
-
}).catch((error) => {
|
|
101
|
-
stderr.write(`npm install failed: ${error.message}\n`);
|
|
102
|
-
throw error;
|
|
103
|
-
});
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
function getInstalledDependents(lock, packageId, packageRegistry) {
|
|
107
|
-
const dependents = [];
|
|
108
|
-
const installedPackageIds = Object.keys(ensureObject(lock.installedPackages));
|
|
109
|
-
|
|
110
|
-
for (const installedId of installedPackageIds) {
|
|
111
|
-
if (installedId === packageId) {
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
const packageEntry = packageRegistry.get(installedId);
|
|
115
|
-
if (!packageEntry) {
|
|
116
|
-
continue;
|
|
117
|
-
}
|
|
118
|
-
const dependencies = ensureArray(packageEntry.descriptor.dependsOn).map((value) => String(value));
|
|
119
|
-
if (dependencies.includes(packageId)) {
|
|
120
|
-
dependents.push(installedId);
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
return sortStrings(dependents);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
function resolvePackageKind(packageEntry) {
|
|
128
|
-
const descriptor = ensureObject(packageEntry?.descriptor);
|
|
129
|
-
const normalizedKind = String(descriptor.kind || "").trim().toLowerCase();
|
|
130
|
-
if (normalizedKind === "runtime" || normalizedKind === "generator") {
|
|
131
|
-
return normalizedKind;
|
|
132
|
-
}
|
|
133
|
-
const packageId = String(packageEntry?.packageId || descriptor.packageId || "unknown-package").trim();
|
|
134
|
-
throw createCliError(
|
|
135
|
-
`Invalid package descriptor for ${packageId}: missing/invalid kind (expected runtime or generator).`
|
|
136
|
-
);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function resolvePackageOptionNames(packageEntry) {
|
|
140
|
-
const optionSchemas = ensureObject(packageEntry?.descriptor?.options);
|
|
141
|
-
return Object.keys(optionSchemas);
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function resolveBundleInlineOptionsForPackage(packageEntry, inlineOptions) {
|
|
145
|
-
const allowedOptionNames = new Set(resolvePackageOptionNames(packageEntry));
|
|
146
|
-
const resolved = {};
|
|
147
|
-
|
|
148
|
-
for (const [optionName, optionValue] of Object.entries(ensureObject(inlineOptions))) {
|
|
149
|
-
if (!allowedOptionNames.has(optionName)) {
|
|
150
|
-
continue;
|
|
151
|
-
}
|
|
152
|
-
resolved[optionName] = String(optionValue || "").trim();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
return resolved;
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
function validateInlineOptionsForBundle({
|
|
159
|
-
bundleId,
|
|
160
|
-
inlineOptions,
|
|
161
|
-
packageIds,
|
|
162
|
-
packageRegistry
|
|
163
|
-
}) {
|
|
164
|
-
const providedOptionNames = Object.keys(ensureObject(inlineOptions));
|
|
165
|
-
if (providedOptionNames.length < 1) {
|
|
166
|
-
return;
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
const allowedOptionNames = new Set();
|
|
170
|
-
for (const packageId of ensureArray(packageIds).map((value) => String(value || "").trim()).filter(Boolean)) {
|
|
171
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
172
|
-
if (!packageEntry) {
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
for (const optionName of resolvePackageOptionNames(packageEntry)) {
|
|
176
|
-
allowedOptionNames.add(optionName);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
const unknownOptionNames = providedOptionNames.filter((optionName) => !allowedOptionNames.has(optionName));
|
|
181
|
-
if (unknownOptionNames.length < 1) {
|
|
182
|
-
return;
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const sortedUnknown = sortStrings(unknownOptionNames);
|
|
186
|
-
const sortedAllowed = sortStrings([...allowedOptionNames]);
|
|
187
|
-
const suffix = sortedAllowed.length > 0
|
|
188
|
-
? ` Allowed options: ${sortedAllowed.join(", ")}.`
|
|
189
|
-
: " This bundle does not accept inline options.";
|
|
190
|
-
throw createCliError(`Unknown option(s) for bundle ${bundleId}: ${sortedUnknown.join(", ")}.${suffix}`);
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
function collectDescriptorContainerTokens({ packageId, side, values, issues }) {
|
|
194
|
-
const declaredTokens = new Set();
|
|
195
|
-
const duplicateTokens = new Set();
|
|
196
|
-
let invalidCount = 0;
|
|
197
|
-
|
|
198
|
-
for (const rawValue of ensureArray(values)) {
|
|
199
|
-
if (typeof rawValue !== "string") {
|
|
200
|
-
invalidCount += 1;
|
|
201
|
-
continue;
|
|
202
|
-
}
|
|
203
|
-
const token = rawValue.trim();
|
|
204
|
-
if (!token) {
|
|
205
|
-
invalidCount += 1;
|
|
206
|
-
continue;
|
|
207
|
-
}
|
|
208
|
-
if (declaredTokens.has(token)) {
|
|
209
|
-
duplicateTokens.add(token);
|
|
210
|
-
continue;
|
|
211
|
-
}
|
|
212
|
-
declaredTokens.add(token);
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
if (invalidCount > 0) {
|
|
216
|
-
issues.push({
|
|
217
|
-
packageId,
|
|
218
|
-
side,
|
|
219
|
-
code: "descriptor-token-invalid",
|
|
220
|
-
message: `${packageId} (${side}): metadata.apiSummary.containerTokens includes ${invalidCount} non-string or empty token value(s).`
|
|
221
|
-
});
|
|
222
|
-
}
|
|
223
|
-
for (const token of sortStrings([...duplicateTokens])) {
|
|
224
|
-
issues.push({
|
|
225
|
-
packageId,
|
|
226
|
-
side,
|
|
227
|
-
code: "descriptor-token-duplicate",
|
|
228
|
-
token,
|
|
229
|
-
message: `${packageId} (${side}): descriptor token is declared more than once: ${token}.`
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
return declaredTokens;
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
function collectUsedContainerTokens({ packageId, side, bindings, issues }) {
|
|
237
|
-
const usedTokens = new Set();
|
|
238
|
-
for (const rawBinding of ensureArray(bindings)) {
|
|
239
|
-
const binding = ensureObject(rawBinding);
|
|
240
|
-
const tokenExpression = String(binding.tokenExpression || "").trim();
|
|
241
|
-
const token = String(binding.token || "").trim();
|
|
242
|
-
const location = String(binding.location || "").trim();
|
|
243
|
-
if (binding.tokenResolved !== true || !token) {
|
|
244
|
-
const expressionLabel = tokenExpression || "<empty>";
|
|
245
|
-
const locationSuffix = location ? ` at ${location}` : "";
|
|
246
|
-
issues.push({
|
|
247
|
-
packageId,
|
|
248
|
-
side,
|
|
249
|
-
code: "binding-token-unresolved",
|
|
250
|
-
tokenExpression: expressionLabel,
|
|
251
|
-
location,
|
|
252
|
-
message: `${packageId} (${side}): unresolved DI token expression "${expressionLabel}"${locationSuffix}.`
|
|
253
|
-
});
|
|
254
|
-
continue;
|
|
255
|
-
}
|
|
256
|
-
usedTokens.add(token);
|
|
257
|
-
}
|
|
258
|
-
return usedTokens;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
function collectProviderIntrospectionIssues({ packageId, packageInsights, issues }) {
|
|
262
|
-
const introspection = ensureObject(packageInsights);
|
|
263
|
-
if (!introspection.available) {
|
|
264
|
-
issues.push({
|
|
265
|
-
packageId,
|
|
266
|
-
side: "",
|
|
267
|
-
code: "provider-introspection-unavailable",
|
|
268
|
-
message: `${packageId}: provider source introspection is unavailable, so DI token parity cannot be verified.`
|
|
269
|
-
});
|
|
270
|
-
return;
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
const notes = ensureArray(introspection.notes).map((value) => String(value || "").trim()).filter(Boolean);
|
|
274
|
-
for (const note of notes) {
|
|
275
|
-
if (
|
|
276
|
-
note.startsWith("Skipped wildcard provider entrypoint during introspection:") ||
|
|
277
|
-
note.startsWith("Provider file missing during introspection:") ||
|
|
278
|
-
note.startsWith("Failed reading provider ")
|
|
279
|
-
) {
|
|
280
|
-
issues.push({
|
|
281
|
-
packageId,
|
|
282
|
-
side: "",
|
|
283
|
-
code: "provider-introspection-incomplete",
|
|
284
|
-
message: `${packageId}: ${note}`
|
|
285
|
-
});
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function collectDiLabelParityIssuesForPackage({ packageEntry, packageInsights }) {
|
|
291
|
-
const packageId = String(packageEntry?.packageId || "").trim();
|
|
292
|
-
const descriptor = ensureObject(packageEntry?.descriptor);
|
|
293
|
-
const metadataApiSummary = ensureObject(ensureObject(descriptor.metadata).apiSummary);
|
|
294
|
-
const descriptorTokenSummary = ensureObject(metadataApiSummary.containerTokens);
|
|
295
|
-
const bindingSections = ensureObject(ensureObject(packageInsights).containerBindings);
|
|
296
|
-
const issues = [];
|
|
297
|
-
const sides = ["server", "client"];
|
|
298
|
-
|
|
299
|
-
collectProviderIntrospectionIssues({ packageId, packageInsights, issues });
|
|
300
|
-
|
|
301
|
-
for (const side of sides) {
|
|
302
|
-
const declaredTokens = collectDescriptorContainerTokens({
|
|
303
|
-
packageId,
|
|
304
|
-
side,
|
|
305
|
-
values: descriptorTokenSummary[side],
|
|
306
|
-
issues
|
|
307
|
-
});
|
|
308
|
-
const usedTokens = collectUsedContainerTokens({
|
|
309
|
-
packageId,
|
|
310
|
-
side,
|
|
311
|
-
bindings: bindingSections[side],
|
|
312
|
-
issues
|
|
313
|
-
});
|
|
314
|
-
|
|
315
|
-
for (const token of sortStrings([...usedTokens])) {
|
|
316
|
-
if (!declaredTokens.has(token)) {
|
|
317
|
-
issues.push({
|
|
318
|
-
packageId,
|
|
319
|
-
side,
|
|
320
|
-
code: "binding-token-undeclared",
|
|
321
|
-
token,
|
|
322
|
-
message: `${packageId} (${side}): token is used by providers but missing from metadata.apiSummary.containerTokens.${side}: ${token}.`
|
|
323
|
-
});
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
for (const token of sortStrings([...declaredTokens])) {
|
|
327
|
-
if (!usedTokens.has(token)) {
|
|
328
|
-
issues.push({
|
|
329
|
-
packageId,
|
|
330
|
-
side,
|
|
331
|
-
code: "descriptor-token-unused",
|
|
332
|
-
token,
|
|
333
|
-
message: `${packageId} (${side}): token is declared in metadata.apiSummary.containerTokens.${side} but never bound by providers: ${token}.`
|
|
334
|
-
});
|
|
335
|
-
}
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
|
|
339
|
-
return issues;
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
async function commandList({ positional, options, cwd, stdout }) {
|
|
343
|
-
const packageRegistry = await loadPackageRegistry();
|
|
344
|
-
const bundleRegistry = await loadBundleRegistry();
|
|
345
|
-
|
|
346
|
-
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
347
|
-
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
348
|
-
const { lock } = await loadLockFile(appRoot);
|
|
349
|
-
const installedPackageEntries = ensureObject(lock.installedPackages);
|
|
350
|
-
const installedPackages = new Set(Object.keys(installedPackageEntries));
|
|
351
|
-
const installedUnknownPackageIds = sortStrings(
|
|
352
|
-
[...installedPackages].filter((packageId) => !packageRegistry.has(packageId))
|
|
353
|
-
);
|
|
354
|
-
const installedLocalPackageIds = sortStrings(
|
|
355
|
-
installedUnknownPackageIds.filter((packageId) => {
|
|
356
|
-
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
357
|
-
const sourceType = String(ensureObject(lockEntry.source).type || "").trim();
|
|
358
|
-
return sourceType === "local-package" || sourceType === "app-local-package" || appLocalRegistry.has(packageId);
|
|
359
|
-
})
|
|
360
|
-
);
|
|
361
|
-
const installedExternalPackageIds = sortStrings(
|
|
362
|
-
installedUnknownPackageIds.filter((packageId) => !installedLocalPackageIds.includes(packageId))
|
|
363
|
-
);
|
|
364
|
-
const availableLocalPackageIds = sortStrings(
|
|
365
|
-
[...appLocalRegistry.keys()].filter((packageId) => !installedPackages.has(packageId))
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
const mode = String(positional[0] || "").trim();
|
|
369
|
-
const shouldListBundles = !mode || mode === "bundles";
|
|
370
|
-
const shouldListPackages = !mode || mode === "packages";
|
|
371
|
-
const shouldListGenerators = !mode || mode === "generators";
|
|
372
|
-
|
|
373
|
-
if (!shouldListBundles && !shouldListPackages && !shouldListGenerators) {
|
|
374
|
-
throw createCliError(`Unknown list mode: ${mode}`, { showUsage: true });
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
const color = createColorFormatter(stdout);
|
|
378
|
-
const lines = [];
|
|
379
|
-
if (shouldListBundles) {
|
|
380
|
-
lines.push(color.heading("Available bundles:"));
|
|
381
|
-
const bundleIds = sortStrings([...bundleRegistry.keys()]);
|
|
382
|
-
for (const bundleId of bundleIds) {
|
|
383
|
-
const bundle = bundleRegistry.get(bundleId);
|
|
384
|
-
const packageIds = ensureArray(bundle.packages).map((value) => String(value));
|
|
385
|
-
const isInstalled = packageIds.length > 0 && packageIds.every((packageId) => installedPackages.has(packageId));
|
|
386
|
-
const providerLabel = Number(bundle.provider) === 1 ? " [provider]" : "";
|
|
387
|
-
const installedLabel = isInstalled ? " (installed)" : "";
|
|
388
|
-
lines.push(
|
|
389
|
-
`- ${color.item(bundle.bundleId)} ${color.version(`(${bundle.version})`)}${isInstalled ? color.installed(installedLabel) : installedLabel}${providerLabel ? color.provider(providerLabel) : providerLabel}: ${String(bundle.description || "")}`
|
|
390
|
-
);
|
|
391
|
-
if (options.full || options.expanded) {
|
|
392
|
-
for (const packageId of packageIds) {
|
|
393
|
-
lines.push(` - ${color.dim(packageId)}`);
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
|
|
399
|
-
if (shouldListPackages) {
|
|
400
|
-
if (lines.length > 0) {
|
|
401
|
-
lines.push("");
|
|
402
|
-
}
|
|
403
|
-
lines.push(color.heading("Available runtime packages:"));
|
|
404
|
-
const packageIds = sortStrings([...packageRegistry.keys()].filter((packageId) => {
|
|
405
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
406
|
-
return resolvePackageKind(packageEntry) === "runtime";
|
|
407
|
-
}));
|
|
408
|
-
for (const packageId of packageIds) {
|
|
409
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
410
|
-
const installedLabel = installedPackages.has(packageId) ? " (installed)" : "";
|
|
411
|
-
lines.push(
|
|
412
|
-
`- ${color.item(packageId)} ${color.version(`(${packageEntry.version})`)}${installedLabel ? color.installed(installedLabel) : ""}`
|
|
413
|
-
);
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (installedLocalPackageIds.length > 0) {
|
|
417
|
-
lines.push("");
|
|
418
|
-
lines.push(color.heading("Installed local packages:"));
|
|
419
|
-
for (const packageId of installedLocalPackageIds) {
|
|
420
|
-
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
421
|
-
const version = String(lockEntry.version || "").trim();
|
|
422
|
-
const versionLabel = version ? ` ${color.version(`(${version})`)}` : "";
|
|
423
|
-
lines.push(`- ${color.item(packageId)}${versionLabel}${color.installed(" (installed)")}`);
|
|
424
|
-
}
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
if (installedExternalPackageIds.length > 0) {
|
|
428
|
-
lines.push("");
|
|
429
|
-
lines.push(color.heading("Installed external packages:"));
|
|
430
|
-
for (const packageId of installedExternalPackageIds) {
|
|
431
|
-
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
432
|
-
const version = String(lockEntry.version || "").trim();
|
|
433
|
-
const versionLabel = version ? ` ${color.version(`(${version})`)}` : "";
|
|
434
|
-
lines.push(`- ${color.item(packageId)}${versionLabel}${color.installed(" (installed)")}`);
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
if (availableLocalPackageIds.length > 0) {
|
|
439
|
-
lines.push("");
|
|
440
|
-
lines.push(color.heading("Available local packages (not installed):"));
|
|
441
|
-
for (const packageId of availableLocalPackageIds) {
|
|
442
|
-
const packageEntry = appLocalRegistry.get(packageId);
|
|
443
|
-
const version = String(packageEntry?.version || "").trim();
|
|
444
|
-
const versionLabel = version ? ` ${color.version(`(${version})`)}` : "";
|
|
445
|
-
lines.push(`- ${color.item(packageId)}${versionLabel}`);
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
}
|
|
449
|
-
|
|
450
|
-
if (shouldListGenerators) {
|
|
451
|
-
if (lines.length > 0) {
|
|
452
|
-
lines.push("");
|
|
453
|
-
}
|
|
454
|
-
lines.push(color.heading("Available generators:"));
|
|
455
|
-
const packageIds = sortStrings([...packageRegistry.keys()].filter((packageId) => {
|
|
456
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
457
|
-
return resolvePackageKind(packageEntry) === "generator";
|
|
458
|
-
}));
|
|
459
|
-
for (const packageId of packageIds) {
|
|
460
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
461
|
-
const installedLabel = installedPackages.has(packageId) ? " (installed)" : "";
|
|
462
|
-
lines.push(
|
|
463
|
-
`- ${color.item(packageId)} ${color.version(`(${packageEntry.version})`)}${installedLabel ? color.installed(installedLabel) : ""}`
|
|
464
|
-
);
|
|
465
|
-
}
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
if (options.json) {
|
|
469
|
-
const payload = {
|
|
470
|
-
bundles: shouldListBundles
|
|
471
|
-
? sortStrings([...bundleRegistry.keys()]).map((bundleId) => {
|
|
472
|
-
const bundle = bundleRegistry.get(bundleId);
|
|
473
|
-
const packageIds = ensureArray(bundle.packages).map((value) => String(value));
|
|
474
|
-
return {
|
|
475
|
-
bundleId: bundle.bundleId,
|
|
476
|
-
version: bundle.version,
|
|
477
|
-
description: bundle.description || "",
|
|
478
|
-
provider: Number(bundle.provider) === 1,
|
|
479
|
-
installed: packageIds.length > 0 && packageIds.every((packageId) => installedPackages.has(packageId)),
|
|
480
|
-
packages: packageIds
|
|
481
|
-
};
|
|
482
|
-
})
|
|
483
|
-
: [],
|
|
484
|
-
packages: shouldListPackages
|
|
485
|
-
? sortStrings([...packageRegistry.keys()])
|
|
486
|
-
.filter((packageId) => resolvePackageKind(packageRegistry.get(packageId)) === "runtime")
|
|
487
|
-
.map((packageId) => {
|
|
488
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
489
|
-
return {
|
|
490
|
-
packageId,
|
|
491
|
-
version: packageEntry.version,
|
|
492
|
-
installed: installedPackages.has(packageId)
|
|
493
|
-
};
|
|
494
|
-
})
|
|
495
|
-
: [],
|
|
496
|
-
runtimePackages: shouldListPackages
|
|
497
|
-
? sortStrings([...packageRegistry.keys()]).map((packageId) => {
|
|
498
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
499
|
-
if (resolvePackageKind(packageEntry) !== "runtime") {
|
|
500
|
-
return null;
|
|
501
|
-
}
|
|
502
|
-
return {
|
|
503
|
-
packageId,
|
|
504
|
-
version: packageEntry.version,
|
|
505
|
-
installed: installedPackages.has(packageId)
|
|
506
|
-
};
|
|
507
|
-
}).filter(Boolean)
|
|
508
|
-
: [],
|
|
509
|
-
generators: shouldListGenerators
|
|
510
|
-
? sortStrings([...packageRegistry.keys()]).map((packageId) => {
|
|
511
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
512
|
-
if (resolvePackageKind(packageEntry) !== "generator") {
|
|
513
|
-
return null;
|
|
514
|
-
}
|
|
515
|
-
return {
|
|
516
|
-
packageId,
|
|
517
|
-
version: packageEntry.version,
|
|
518
|
-
installed: installedPackages.has(packageId)
|
|
519
|
-
};
|
|
520
|
-
}).filter(Boolean)
|
|
521
|
-
: [],
|
|
522
|
-
installedLocalPackages: shouldListPackages
|
|
523
|
-
? installedLocalPackageIds.map((packageId) => {
|
|
524
|
-
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
525
|
-
return {
|
|
526
|
-
packageId,
|
|
527
|
-
version: String(lockEntry.version || "").trim()
|
|
528
|
-
};
|
|
529
|
-
})
|
|
530
|
-
: [],
|
|
531
|
-
installedExternalPackages: shouldListPackages
|
|
532
|
-
? installedExternalPackageIds.map((packageId) => {
|
|
533
|
-
const lockEntry = ensureObject(installedPackageEntries[packageId]);
|
|
534
|
-
return {
|
|
535
|
-
packageId,
|
|
536
|
-
version: String(lockEntry.version || "").trim(),
|
|
537
|
-
source: ensureObject(lockEntry.source)
|
|
538
|
-
};
|
|
539
|
-
})
|
|
540
|
-
: [],
|
|
541
|
-
availableLocalPackages: shouldListPackages
|
|
542
|
-
? availableLocalPackageIds.map((packageId) => {
|
|
543
|
-
const packageEntry = appLocalRegistry.get(packageId);
|
|
544
|
-
return {
|
|
545
|
-
packageId,
|
|
546
|
-
version: String(packageEntry?.version || "").trim(),
|
|
547
|
-
packagePath: normalizeRelativePosixPath(String(packageEntry?.relativeDir || ""))
|
|
548
|
-
};
|
|
549
|
-
})
|
|
550
|
-
: []
|
|
551
|
-
};
|
|
552
|
-
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
553
|
-
} else {
|
|
554
|
-
stdout.write(`${lines.join("\n")}\n`);
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
return 0;
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
async function commandShow({ positional, options, stdout }) {
|
|
561
|
-
const id = String(positional[0] || "").trim();
|
|
562
|
-
if (!id) {
|
|
563
|
-
throw createCliError("show requires an id.", { showUsage: true });
|
|
564
|
-
}
|
|
565
|
-
|
|
566
|
-
const packageRegistry = await loadPackageRegistry();
|
|
567
|
-
const bundleRegistry = await loadBundleRegistry();
|
|
568
|
-
const color = createColorFormatter(stdout);
|
|
569
|
-
const writeField = (label, value, formatValue = (raw) => raw) => {
|
|
570
|
-
stdout.write(`${color.dim(`${label}:`)} ${formatValue(String(value || ""))}\n`);
|
|
571
|
-
};
|
|
572
|
-
const writeBindingsSection = (side, bindings) => {
|
|
573
|
-
const sectionSide = String(side || "").trim().toLowerCase();
|
|
574
|
-
const bindingEntries = ensureArray(bindings);
|
|
575
|
-
stdout.write(`${color.heading(`Container bindings ${sectionSide} (${bindingEntries.length}):`)}\n`);
|
|
576
|
-
if (bindingEntries.length < 1) {
|
|
577
|
-
stdout.write(`- ${color.dim("none detected")}\n`);
|
|
578
|
-
return;
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
for (const bindingRecord of bindingEntries) {
|
|
582
|
-
const binding = ensureObject(bindingRecord);
|
|
583
|
-
const token = String(binding.token || "").trim();
|
|
584
|
-
const tokenExpression = String(binding.tokenExpression || "").trim();
|
|
585
|
-
const tokenLabel = binding.tokenResolved === true
|
|
586
|
-
? token
|
|
587
|
-
: token || tokenExpression;
|
|
588
|
-
const bindingMethod = String(binding.binding || "").trim();
|
|
589
|
-
const providerName = deriveProviderDisplayName(binding);
|
|
590
|
-
const lifecycle = String(binding.lifecycle || "").trim();
|
|
591
|
-
const lifecycleSuffix = lifecycle && lifecycle !== "unknown" ? ` ${color.dim(`(${lifecycle})`)}` : "";
|
|
592
|
-
const unresolvedSuffix = binding.tokenResolved === true ? "" : color.dim(" [unresolved token]");
|
|
593
|
-
stdout.write(
|
|
594
|
-
`- ${color.item(tokenLabel)} ${color.installed(`[${bindingMethod}]`)} ${color.dim("by")} ${color.item(providerName)}${lifecycleSuffix}${unresolvedSuffix}\n`
|
|
595
|
-
);
|
|
596
|
-
if (options.details) {
|
|
597
|
-
const location = String(binding.location || "").trim();
|
|
598
|
-
if (location) {
|
|
599
|
-
stdout.write(` ${color.dim(`source: ${location}`)}\n`);
|
|
600
|
-
}
|
|
601
|
-
const providerLabel = String(binding.provider || "").trim();
|
|
602
|
-
if (providerLabel) {
|
|
603
|
-
stdout.write(` ${color.dim(`provider: ${providerLabel}`)}\n`);
|
|
604
|
-
}
|
|
605
|
-
if (binding.tokenResolved !== true && tokenExpression) {
|
|
606
|
-
stdout.write(` ${color.dim(`token expression: ${tokenExpression}`)}\n`);
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
};
|
|
611
|
-
const writeRuntimeProviders = (side, providers) => {
|
|
612
|
-
const sectionSide = String(side || "").trim().toLowerCase();
|
|
613
|
-
const providerEntries = ensureArray(providers);
|
|
614
|
-
if (providerEntries.length < 1) {
|
|
615
|
-
return;
|
|
616
|
-
}
|
|
617
|
-
|
|
618
|
-
stdout.write(`${color.heading(`Runtime ${sectionSide} providers (${providerEntries.length}):`)}\n`);
|
|
619
|
-
for (const provider of providerEntries) {
|
|
620
|
-
const record = ensureObject(provider);
|
|
621
|
-
const entrypoint = String(record.entrypoint || "").trim();
|
|
622
|
-
const exportName = String(record.export || "").trim();
|
|
623
|
-
const label = exportName ? `${entrypoint}#${exportName}` : entrypoint;
|
|
624
|
-
stdout.write(`- ${color.item(label)}\n`);
|
|
625
|
-
}
|
|
626
|
-
};
|
|
627
|
-
const resolvedPackageId = resolvePackageIdInput(id, packageRegistry);
|
|
628
|
-
|
|
629
|
-
if (resolvedPackageId) {
|
|
630
|
-
const packageEntry = packageRegistry.get(resolvedPackageId);
|
|
631
|
-
const descriptor = packageEntry.descriptor;
|
|
632
|
-
const fileWriteGroups = buildFileWriteGroups(
|
|
633
|
-
ensureArray(ensureObject(descriptor.mutations).files),
|
|
634
|
-
{ packageId: descriptor.packageId }
|
|
635
|
-
);
|
|
636
|
-
const fileWriteCount = fileWriteGroups.reduce((total, group) => total + ensureArray(group.files).length, 0);
|
|
637
|
-
const capabilities = ensureObject(descriptor.capabilities);
|
|
638
|
-
const runtime = ensureObject(descriptor.runtime);
|
|
639
|
-
const metadata = ensureObject(descriptor.metadata);
|
|
640
|
-
const mutations = ensureObject(descriptor.mutations);
|
|
641
|
-
const runtimeMutations = ensureObject(ensureObject(mutations.dependencies).runtime);
|
|
642
|
-
const devMutations = ensureObject(ensureObject(mutations.dependencies).dev);
|
|
643
|
-
const scriptMutations = ensureObject(ensureObject(mutations.packageJson).scripts);
|
|
644
|
-
const textMutations = ensureArray(mutations.text);
|
|
645
|
-
const packageInsights = await inspectPackageOfferings({ packageEntry });
|
|
646
|
-
const payload = {
|
|
647
|
-
kind: "package",
|
|
648
|
-
packageId: descriptor.packageId,
|
|
649
|
-
version: descriptor.version,
|
|
650
|
-
description: String(descriptor.description || ""),
|
|
651
|
-
dependsOn: ensureArray(descriptor.dependsOn).map((value) => String(value)),
|
|
652
|
-
capabilities,
|
|
653
|
-
options: ensureObject(descriptor.options),
|
|
654
|
-
runtime,
|
|
655
|
-
metadata,
|
|
656
|
-
mutations,
|
|
657
|
-
fileWritePlan: {
|
|
658
|
-
groupCount: fileWriteGroups.length,
|
|
659
|
-
fileCount: fileWriteCount,
|
|
660
|
-
groups: fileWriteGroups
|
|
661
|
-
},
|
|
662
|
-
descriptorPath: packageEntry.descriptorRelativePath,
|
|
663
|
-
introspection: {
|
|
664
|
-
available: Boolean(packageInsights.available),
|
|
665
|
-
notes: ensureArray(packageInsights.notes)
|
|
666
|
-
},
|
|
667
|
-
packageExports: ensureArray(packageInsights.packageExports),
|
|
668
|
-
containerBindings: ensureObject(packageInsights.containerBindings),
|
|
669
|
-
exportedSymbols: ensureArray(packageInsights.exportedSymbols)
|
|
670
|
-
};
|
|
671
|
-
const provides = listDeclaredCapabilities(payload.capabilities, "provides");
|
|
672
|
-
const requires = listDeclaredCapabilities(payload.capabilities, "requires");
|
|
673
|
-
const capabilityDetails = options.details
|
|
674
|
-
? buildCapabilityDetailsForPackage({
|
|
675
|
-
packageRegistry,
|
|
676
|
-
packageId: payload.packageId,
|
|
677
|
-
dependsOn: payload.dependsOn,
|
|
678
|
-
provides,
|
|
679
|
-
requires
|
|
680
|
-
})
|
|
681
|
-
: null;
|
|
682
|
-
if (capabilityDetails) {
|
|
683
|
-
payload.capabilityDetails = capabilityDetails;
|
|
684
|
-
}
|
|
685
|
-
if (options.json) {
|
|
686
|
-
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
687
|
-
} else {
|
|
688
|
-
const runtimeMutationEntries = Object.entries(runtimeMutations);
|
|
689
|
-
const devMutationEntries = Object.entries(devMutations);
|
|
690
|
-
const scriptMutationEntries = Object.entries(scriptMutations);
|
|
691
|
-
const wrapWidth = resolveWrapWidth(stdout, 80);
|
|
692
|
-
const introspection = ensureObject(payload.introspection);
|
|
693
|
-
const introspectionAvailable = introspection.available === true;
|
|
694
|
-
const introspectionNotes = ensureArray(introspection.notes)
|
|
695
|
-
.map((value) => String(value || "").trim())
|
|
696
|
-
.filter(Boolean);
|
|
697
|
-
const metadataApiSummary = ensureObject(ensureObject(payload.metadata).apiSummary);
|
|
698
|
-
const metadataUi = ensureObject(ensureObject(payload.metadata).ui);
|
|
699
|
-
const summarySurfaces = ensureArray(metadataApiSummary.surfaces)
|
|
700
|
-
.map((entry) => {
|
|
701
|
-
const record = ensureObject(entry);
|
|
702
|
-
return {
|
|
703
|
-
subpath: String(record.subpath || "").trim(),
|
|
704
|
-
summary: String(record.summary || "").trim()
|
|
705
|
-
};
|
|
706
|
-
})
|
|
707
|
-
.filter((entry) => entry.subpath && entry.summary);
|
|
708
|
-
const containerTokenSummary = ensureObject(metadataApiSummary.containerTokens);
|
|
709
|
-
const quickServerTokens = ensureArray(containerTokenSummary.server).map((value) => String(value || "").trim()).filter(Boolean);
|
|
710
|
-
const quickClientTokens = ensureArray(containerTokenSummary.client).map((value) => String(value || "").trim()).filter(Boolean);
|
|
711
|
-
const metadataUiPlacements = ensureObject(metadataUi.placements);
|
|
712
|
-
const placementOutlets = normalizePlacementOutlets(metadataUiPlacements.outlets);
|
|
713
|
-
const placementContributions = normalizePlacementContributions(metadataUiPlacements.contributions);
|
|
714
|
-
const packageExports = ensureArray(payload.packageExports);
|
|
715
|
-
const exportedSymbols = ensureArray(payload.exportedSymbols);
|
|
716
|
-
const exportedSymbolsByFile = new Map(
|
|
717
|
-
exportedSymbols
|
|
718
|
-
.map((entry) => ensureObject(entry))
|
|
719
|
-
.map((entry) => {
|
|
720
|
-
const file = normalizeRelativePosixPath(String(entry.file || "").trim());
|
|
721
|
-
return file ? [file, entry] : null;
|
|
722
|
-
})
|
|
723
|
-
.filter(Boolean)
|
|
724
|
-
);
|
|
725
|
-
const bindingSections = ensureObject(payload.containerBindings);
|
|
726
|
-
const serverBindings = ensureArray(bindingSections.server);
|
|
727
|
-
const clientBindings = ensureArray(bindingSections.client);
|
|
728
|
-
stdout.write(`${color.heading("Information")}\n`);
|
|
729
|
-
writeField("Package", payload.packageId, color.item);
|
|
730
|
-
writeField("Version", payload.version, color.installed);
|
|
731
|
-
if (payload.description) {
|
|
732
|
-
writeField("Description", payload.description);
|
|
733
|
-
}
|
|
734
|
-
writeField("Descriptor", payload.descriptorPath, color.dim);
|
|
735
|
-
if (summarySurfaces.length > 0) {
|
|
736
|
-
stdout.write(`${color.heading("Summary:")}\n`);
|
|
737
|
-
for (const summaryEntry of summarySurfaces) {
|
|
738
|
-
const importPath = formatPackageSubpathImport(payload.packageId, summaryEntry.subpath);
|
|
739
|
-
stdout.write(`- ${color.item(`${importPath}:`)}\n`);
|
|
740
|
-
stdout.write(` ${summaryEntry.summary}\n`);
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
if (quickServerTokens.length > 0 || quickClientTokens.length > 0) {
|
|
744
|
-
stdout.write(`${color.heading("Container tokens")} ${color.dim("-- app.make('...'):")}\n`);
|
|
745
|
-
if (quickServerTokens.length > 0) {
|
|
746
|
-
stdout.write(`- ${color.installed("server")}: ${quickServerTokens.map((token) => color.item(token)).join(", ")}\n`);
|
|
747
|
-
}
|
|
748
|
-
if (quickClientTokens.length > 0) {
|
|
749
|
-
stdout.write(`- ${color.installed("client")}: ${quickClientTokens.map((token) => color.item(token)).join(", ")}\n`);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
if (placementOutlets.length > 0) {
|
|
753
|
-
stdout.write(`${color.heading(`Placement outlets (accepted host/position pairs) (${placementOutlets.length}):`)}\n`);
|
|
754
|
-
for (const outlet of placementOutlets) {
|
|
755
|
-
const surfaces = ensureArray(outlet.surfaces).map((value) => String(value || "").trim()).filter(Boolean);
|
|
756
|
-
const surfacesLabel = surfaces.length > 0 ? ` ${color.installed(`[surfaces:${surfaces.join(", ")}]`)}` : "";
|
|
757
|
-
const description = String(outlet.description || "").trim();
|
|
758
|
-
const descriptionSuffix = description ? `: ${description}` : "";
|
|
759
|
-
stdout.write(`- ${color.item(`${outlet.host}.${outlet.position}`)}${surfacesLabel}${descriptionSuffix}\n`);
|
|
760
|
-
if (options.details) {
|
|
761
|
-
const sourceLabel = String(outlet.source || "").trim();
|
|
762
|
-
if (sourceLabel) {
|
|
763
|
-
stdout.write(` ${color.dim(`source: ${sourceLabel}`)}\n`);
|
|
764
|
-
}
|
|
765
|
-
}
|
|
766
|
-
}
|
|
767
|
-
}
|
|
768
|
-
if (placementContributions.length > 0) {
|
|
769
|
-
stdout.write(`${color.heading(`Placement contributions (default entries) (${placementContributions.length}):`)}\n`);
|
|
770
|
-
for (const contribution of placementContributions) {
|
|
771
|
-
const surfaces = ensureArray(contribution.surfaces).map((value) => String(value || "").trim()).filter(Boolean);
|
|
772
|
-
const surfacesLabel = surfaces.length > 0 ? surfaces.join(", ") : "*";
|
|
773
|
-
const orderSuffix = Number.isFinite(contribution.order) ? ` ${color.installed(`[order:${contribution.order}]`)}` : "";
|
|
774
|
-
const componentToken = String(contribution.componentToken || "").trim();
|
|
775
|
-
const componentSuffix = componentToken ? ` ${color.dim(`component:${componentToken}`)}` : "";
|
|
776
|
-
const description = String(contribution.description || "").trim();
|
|
777
|
-
const descriptionSuffix = description ? `: ${description}` : "";
|
|
778
|
-
stdout.write(
|
|
779
|
-
`- ${color.item(contribution.id)} ${color.dim("->")} ${color.item(`${contribution.host}.${contribution.position}`)} ${color.installed(`[surfaces:${surfacesLabel}]`)}${orderSuffix}${componentSuffix}${descriptionSuffix}\n`
|
|
780
|
-
);
|
|
781
|
-
if (options.details) {
|
|
782
|
-
const when = String(contribution.when || "").trim();
|
|
783
|
-
if (when) {
|
|
784
|
-
stdout.write(` ${color.dim(`when: ${when}`)}\n`);
|
|
785
|
-
}
|
|
786
|
-
const sourceLabel = String(contribution.source || "").trim();
|
|
787
|
-
if (sourceLabel) {
|
|
788
|
-
stdout.write(` ${color.dim(`source: ${sourceLabel}`)}\n`);
|
|
789
|
-
}
|
|
790
|
-
}
|
|
791
|
-
}
|
|
792
|
-
}
|
|
793
|
-
if (introspectionAvailable) {
|
|
794
|
-
writeBindingsSection("server", serverBindings);
|
|
795
|
-
writeBindingsSection("client", clientBindings);
|
|
796
|
-
}
|
|
797
|
-
if (introspectionAvailable) {
|
|
798
|
-
stdout.write(`${color.heading(`Package exports (${packageExports.length}):`)}\n`);
|
|
799
|
-
if (packageExports.length < 1) {
|
|
800
|
-
stdout.write(`- ${color.dim("none declared")}\n`);
|
|
801
|
-
} else {
|
|
802
|
-
const symbolDetailsShown = new Set();
|
|
803
|
-
for (const packageExport of packageExports) {
|
|
804
|
-
const record = ensureObject(packageExport);
|
|
805
|
-
const subpath = String(record.subpath || ".").trim() || ".";
|
|
806
|
-
const condition = String(record.condition || "default").trim() || "default";
|
|
807
|
-
const target = String(record.target || "").trim();
|
|
808
|
-
const targetType = String(record.targetType || "").trim();
|
|
809
|
-
const conditionSuffix = condition !== "default" ? ` ${color.installed(`[${condition}]`)}` : "";
|
|
810
|
-
const status = targetType === "file"
|
|
811
|
-
? record.targetExists === true
|
|
812
|
-
? color.installed("[ok]")
|
|
813
|
-
: color.provider("[missing]")
|
|
814
|
-
: targetType === "pattern"
|
|
815
|
-
? color.dim("[pattern]")
|
|
816
|
-
: color.dim("[external]");
|
|
817
|
-
const showTarget = shouldShowPackageExportTarget({ subpath, target, targetType });
|
|
818
|
-
const targetSuffix = showTarget ? ` -> ${color.item(target)}` : "";
|
|
819
|
-
const subpathLabel = options.details ? color.white(subpath) : color.item(subpath);
|
|
820
|
-
stdout.write(`- ${subpathLabel}${conditionSuffix}${targetSuffix} ${status}\n`);
|
|
821
|
-
|
|
822
|
-
if (!options.details) {
|
|
823
|
-
continue;
|
|
824
|
-
}
|
|
825
|
-
if (targetType !== "file" || !target.startsWith("./")) {
|
|
826
|
-
continue;
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
const normalizedTarget = normalizeRelativePosixPath(target.slice(2));
|
|
830
|
-
const summary = ensureObject(exportedSymbolsByFile.get(normalizedTarget));
|
|
831
|
-
if (!summary || Object.keys(summary).length < 1) {
|
|
832
|
-
continue;
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
const detailKey = `${subpath}::${normalizedTarget}`;
|
|
836
|
-
if (symbolDetailsShown.has(detailKey)) {
|
|
837
|
-
continue;
|
|
838
|
-
}
|
|
839
|
-
symbolDetailsShown.add(detailKey);
|
|
840
|
-
|
|
841
|
-
const symbols = ensureArray(summary.symbols).map((value) => String(value)).filter(Boolean);
|
|
842
|
-
const classifiedSymbols = classifyExportedSymbols(symbols);
|
|
843
|
-
const writeClassifiedSymbols = (label, entries) => {
|
|
844
|
-
const items = ensureArray(entries).map((entry) => String(entry || "").trim()).filter(Boolean);
|
|
845
|
-
if (items.length < 1) {
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
writeWrappedItems({
|
|
849
|
-
stdout,
|
|
850
|
-
heading: ` ${color.installed(`${label} (${items.length}):`)}`,
|
|
851
|
-
lineIndent: " ",
|
|
852
|
-
wrapWidth,
|
|
853
|
-
items: items.map((symbol) => ({
|
|
854
|
-
text: symbol,
|
|
855
|
-
rendered: color.item(symbol)
|
|
856
|
-
}))
|
|
857
|
-
});
|
|
858
|
-
};
|
|
859
|
-
writeClassifiedSymbols("providers", classifiedSymbols.providers);
|
|
860
|
-
writeClassifiedSymbols("functions/helpers", classifiedSymbols.functions);
|
|
861
|
-
writeClassifiedSymbols("constants", classifiedSymbols.constants);
|
|
862
|
-
writeClassifiedSymbols("classes/types", classifiedSymbols.classesOrTypes);
|
|
863
|
-
writeClassifiedSymbols("internal/test hooks", classifiedSymbols.internals);
|
|
864
|
-
writeClassifiedSymbols("other symbols", classifiedSymbols.others);
|
|
865
|
-
|
|
866
|
-
if (summary.hasDefaultExport === true) {
|
|
867
|
-
stdout.write(` ${color.installed("default export: yes")}\n`);
|
|
868
|
-
}
|
|
869
|
-
const starReExports = ensureArray(summary.starReExports).map((value) => String(value)).filter(Boolean);
|
|
870
|
-
const namedReExports = ensureArray(summary.namedReExports).map((value) => String(value)).filter(Boolean);
|
|
871
|
-
const reExportSummary = [];
|
|
872
|
-
if (namedReExports.length > 0) {
|
|
873
|
-
reExportSummary.push(`named from ${namedReExports.length} files`);
|
|
874
|
-
}
|
|
875
|
-
if (starReExports.length > 0) {
|
|
876
|
-
reExportSummary.push(`star from ${starReExports.length} files`);
|
|
877
|
-
}
|
|
878
|
-
if (options.debugExports && reExportSummary.length > 0) {
|
|
879
|
-
stdout.write(` ${color.dim(`re-export sources: ${reExportSummary.join(", ")}`)}\n`);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
if (options.debugExports && starReExports.length > 0) {
|
|
883
|
-
writeWrappedItems({
|
|
884
|
-
stdout,
|
|
885
|
-
heading: ` ${color.installed(`star re-exports (${starReExports.length}):`)}`,
|
|
886
|
-
lineIndent: " ",
|
|
887
|
-
wrapWidth,
|
|
888
|
-
items: starReExports.map((specifier) => ({
|
|
889
|
-
text: specifier,
|
|
890
|
-
rendered: color.item(specifier)
|
|
891
|
-
}))
|
|
892
|
-
});
|
|
893
|
-
}
|
|
894
|
-
if (options.debugExports && namedReExports.length > 0) {
|
|
895
|
-
writeWrappedItems({
|
|
896
|
-
stdout,
|
|
897
|
-
heading: ` ${color.installed(`named re-exports (${namedReExports.length}):`)}`,
|
|
898
|
-
lineIndent: " ",
|
|
899
|
-
wrapWidth,
|
|
900
|
-
items: namedReExports.map((specifier) => ({
|
|
901
|
-
text: specifier,
|
|
902
|
-
rendered: color.item(specifier)
|
|
903
|
-
}))
|
|
904
|
-
});
|
|
905
|
-
}
|
|
906
|
-
}
|
|
907
|
-
}
|
|
908
|
-
} else {
|
|
909
|
-
stdout.write(`${color.heading("Code introspection:")}\n`);
|
|
910
|
-
stdout.write(`- ${color.dim("Source files unavailable (descriptor metadata only).")}\n`);
|
|
911
|
-
}
|
|
912
|
-
if (payload.dependsOn.length > 0) {
|
|
913
|
-
writeWrappedItems({
|
|
914
|
-
stdout,
|
|
915
|
-
heading: `${color.heading("Depends on")} ${color.installed(`(${payload.dependsOn.length})`)}:`,
|
|
916
|
-
wrapWidth,
|
|
917
|
-
items: payload.dependsOn.map((dependencyId) => {
|
|
918
|
-
const text = String(dependencyId);
|
|
919
|
-
return {
|
|
920
|
-
text,
|
|
921
|
-
rendered: color.item(text)
|
|
922
|
-
};
|
|
923
|
-
})
|
|
924
|
-
});
|
|
925
|
-
}
|
|
926
|
-
if (runtimeMutationEntries.length > 0) {
|
|
927
|
-
writeWrappedItems({
|
|
928
|
-
stdout,
|
|
929
|
-
heading: color.heading(`Dependency mutations runtime (${runtimeMutationEntries.length}):`),
|
|
930
|
-
wrapWidth,
|
|
931
|
-
items: runtimeMutationEntries.map(([dependencyId, versionSpec]) => {
|
|
932
|
-
const dependencyText = String(dependencyId);
|
|
933
|
-
const versionText = String(versionSpec);
|
|
934
|
-
return {
|
|
935
|
-
text: `${dependencyText} ${versionText}`,
|
|
936
|
-
rendered: `${color.item(dependencyText)} ${color.installed(versionText)}`
|
|
937
|
-
};
|
|
938
|
-
})
|
|
939
|
-
});
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
if (provides.length > 0 || requires.length > 0) {
|
|
943
|
-
stdout.write(`${color.heading("Capabilities:")}\n`);
|
|
944
|
-
if (provides.length > 0) {
|
|
945
|
-
const providesText = provides.map((capabilityId) => color.item(capabilityId)).join(" ");
|
|
946
|
-
stdout.write(`${color.installed("Provides:")} ${providesText}\n`);
|
|
947
|
-
}
|
|
948
|
-
if (requires.length > 0) {
|
|
949
|
-
const requiresText = requires.map((capabilityId) => color.item(capabilityId)).join(" ");
|
|
950
|
-
stdout.write(`${color.installed("Requires:")} ${requiresText}\n`);
|
|
951
|
-
}
|
|
952
|
-
}
|
|
953
|
-
if (capabilityDetails && (capabilityDetails.provides.length > 0 || capabilityDetails.requires.length > 0)) {
|
|
954
|
-
const formatPackageSummary = (detail) => {
|
|
955
|
-
const packageId = String(detail?.packageId || "").trim();
|
|
956
|
-
const version = String(detail?.version || "").trim();
|
|
957
|
-
const descriptorPath = String(detail?.descriptorPath || "").trim();
|
|
958
|
-
const versionSuffix = version ? `@${version}` : "";
|
|
959
|
-
const pathSuffix = descriptorPath ? ` [${descriptorPath}]` : "";
|
|
960
|
-
return `${packageId}${versionSuffix}${pathSuffix}`;
|
|
961
|
-
};
|
|
962
|
-
|
|
963
|
-
const writeCapabilityRecord = ({ heading, records, includeDependsOnProviders = false }) => {
|
|
964
|
-
if (records.length < 1) {
|
|
965
|
-
return;
|
|
966
|
-
}
|
|
967
|
-
stdout.write(`${color.heading(heading)}\n`);
|
|
968
|
-
for (const record of records) {
|
|
969
|
-
const capabilityId = String(record.capabilityId || "").trim();
|
|
970
|
-
stdout.write(`- ${color.item(capabilityId)}\n`);
|
|
971
|
-
|
|
972
|
-
const providerItems = ensureArray(record.providerDetails).map((detail) => ({
|
|
973
|
-
text: formatPackageSummary(detail),
|
|
974
|
-
rendered: color.item(formatPackageSummary(detail))
|
|
975
|
-
}));
|
|
976
|
-
if (providerItems.length > 0) {
|
|
977
|
-
writeWrappedItems({
|
|
978
|
-
stdout,
|
|
979
|
-
heading: ` ${color.installed(`providers (${providerItems.length}):`)}`,
|
|
980
|
-
lineIndent: " ",
|
|
981
|
-
wrapWidth,
|
|
982
|
-
items: providerItems
|
|
983
|
-
});
|
|
984
|
-
}
|
|
985
|
-
|
|
986
|
-
if (includeDependsOnProviders) {
|
|
987
|
-
const providersInDependsOn = ensureArray(record.providersInDependsOn).map((packageId) => ({
|
|
988
|
-
text: String(packageId),
|
|
989
|
-
rendered: color.item(String(packageId))
|
|
990
|
-
}));
|
|
991
|
-
if (providersInDependsOn.length > 0) {
|
|
992
|
-
writeWrappedItems({
|
|
993
|
-
stdout,
|
|
994
|
-
heading: ` ${color.installed(`providers in dependsOn (${providersInDependsOn.length}):`)}`,
|
|
995
|
-
lineIndent: " ",
|
|
996
|
-
wrapWidth,
|
|
997
|
-
items: providersInDependsOn
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
|
|
1002
|
-
const requirerItems = ensureArray(record.requirerDetails).map((detail) => ({
|
|
1003
|
-
text: formatPackageSummary(detail),
|
|
1004
|
-
rendered: color.item(formatPackageSummary(detail))
|
|
1005
|
-
}));
|
|
1006
|
-
if (requirerItems.length > 0) {
|
|
1007
|
-
writeWrappedItems({
|
|
1008
|
-
stdout,
|
|
1009
|
-
heading: ` ${color.installed(`required by (${requirerItems.length}):`)}`,
|
|
1010
|
-
lineIndent: " ",
|
|
1011
|
-
wrapWidth,
|
|
1012
|
-
items: requirerItems
|
|
1013
|
-
});
|
|
1014
|
-
}
|
|
1015
|
-
}
|
|
1016
|
-
};
|
|
1017
|
-
|
|
1018
|
-
stdout.write(`${color.heading("Capability details:")}\n`);
|
|
1019
|
-
writeCapabilityRecord({
|
|
1020
|
-
heading: `Provides detail (${capabilityDetails.provides.length}):`,
|
|
1021
|
-
records: capabilityDetails.provides,
|
|
1022
|
-
includeDependsOnProviders: false
|
|
1023
|
-
});
|
|
1024
|
-
writeCapabilityRecord({
|
|
1025
|
-
heading: `Requires detail (${capabilityDetails.requires.length}):`,
|
|
1026
|
-
records: capabilityDetails.requires,
|
|
1027
|
-
includeDependsOnProviders: true
|
|
1028
|
-
});
|
|
1029
|
-
}
|
|
1030
|
-
|
|
1031
|
-
const uiRoutes = ensureArray(ensureObject(payload.metadata.ui).routes);
|
|
1032
|
-
if (uiRoutes.length > 0) {
|
|
1033
|
-
stdout.write(`${color.heading(`UI routes (${uiRoutes.length}):`)}\n`);
|
|
1034
|
-
for (const route of uiRoutes) {
|
|
1035
|
-
const record = ensureObject(route);
|
|
1036
|
-
const routePath = String(record.path || "").trim();
|
|
1037
|
-
const scope = String(record.scope || "").trim();
|
|
1038
|
-
const routeId = String(record.id || record.name || "").trim();
|
|
1039
|
-
const purpose = String(record.purpose || "").trim();
|
|
1040
|
-
const modeLabel = record.autoRegister === false ? "advisory" : "auto";
|
|
1041
|
-
const scopeLabel = scope ? ` (${scope})` : "";
|
|
1042
|
-
const modePart = ` ${color.installed(`[${modeLabel}]`)}`;
|
|
1043
|
-
const purposePart = purpose ? ` ${purpose}` : "";
|
|
1044
|
-
const idPart = routeId ? ` ${color.installed(`(id:${routeId})`)}` : "";
|
|
1045
|
-
stdout.write(`- ${color.item(routePath)}${color.installed(scopeLabel)}${modePart}${purposePart}${idPart}\n`);
|
|
1046
|
-
}
|
|
1047
|
-
}
|
|
1048
|
-
|
|
1049
|
-
const serverRoutes = ensureArray(ensureObject(payload.metadata.server).routes);
|
|
1050
|
-
if (serverRoutes.length > 0) {
|
|
1051
|
-
stdout.write(`${color.heading(`Server routes (${serverRoutes.length}):`)}\n`);
|
|
1052
|
-
for (const route of serverRoutes) {
|
|
1053
|
-
const record = ensureObject(route);
|
|
1054
|
-
const method = String(record.method || "").trim().toUpperCase();
|
|
1055
|
-
const routePath = String(record.path || "").trim();
|
|
1056
|
-
const summary = String(record.summary || "").trim();
|
|
1057
|
-
const routeLabel = `${method} ${routePath}`.trim();
|
|
1058
|
-
const summarySuffix = summary ? `: ${summary}` : "";
|
|
1059
|
-
stdout.write(`- ${color.item(routeLabel)}${summarySuffix}\n`);
|
|
1060
|
-
}
|
|
1061
|
-
}
|
|
1062
|
-
|
|
1063
|
-
const optionNames = Object.keys(payload.options);
|
|
1064
|
-
if (optionNames.length > 0) {
|
|
1065
|
-
stdout.write(`${color.heading(`Options (${optionNames.length}):`)}\n`);
|
|
1066
|
-
for (const optionName of optionNames) {
|
|
1067
|
-
const schema = ensureObject(payload.options[optionName]);
|
|
1068
|
-
const required = schema.required ? "required" : "optional";
|
|
1069
|
-
const defaultSuffix = schema.defaultValue ? ` (default: ${schema.defaultValue})` : "";
|
|
1070
|
-
stdout.write(`- ${color.item(optionName)} ${color.installed(`[${required}]`)}${color.dim(defaultSuffix)}\n`);
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
if (devMutationEntries.length > 0) {
|
|
1075
|
-
writeWrappedItems({
|
|
1076
|
-
stdout,
|
|
1077
|
-
heading: color.heading(`Dependency mutations dev (${devMutationEntries.length}):`),
|
|
1078
|
-
wrapWidth,
|
|
1079
|
-
items: devMutationEntries.map(([dependencyId, versionSpec]) => {
|
|
1080
|
-
const dependencyText = String(dependencyId);
|
|
1081
|
-
const versionText = String(versionSpec);
|
|
1082
|
-
return {
|
|
1083
|
-
text: `${dependencyText} ${versionText}`,
|
|
1084
|
-
rendered: `${color.item(dependencyText)} ${color.installed(versionText)}`
|
|
1085
|
-
};
|
|
1086
|
-
})
|
|
1087
|
-
});
|
|
1088
|
-
}
|
|
1089
|
-
if (scriptMutationEntries.length > 0) {
|
|
1090
|
-
stdout.write(`${color.heading(`Script mutations (${scriptMutationEntries.length}):`)}\n`);
|
|
1091
|
-
for (const [scriptName, scriptValue] of scriptMutationEntries) {
|
|
1092
|
-
stdout.write(`- ${color.item(scriptName)}: ${String(scriptValue)}\n`);
|
|
1093
|
-
}
|
|
1094
|
-
}
|
|
1095
|
-
if (textMutations.length > 0) {
|
|
1096
|
-
stdout.write(`${color.heading(`Text mutations (${textMutations.length}):`)}\n`);
|
|
1097
|
-
for (const mutation of textMutations) {
|
|
1098
|
-
const record = ensureObject(mutation);
|
|
1099
|
-
const op = String(record.op || "").trim();
|
|
1100
|
-
const file = String(record.file || "").trim();
|
|
1101
|
-
const key = String(record.key || "").trim();
|
|
1102
|
-
const position = String(record.position || "").trim();
|
|
1103
|
-
const reason = String(record.reason || "").trim();
|
|
1104
|
-
const reasonSuffix = reason ? `: ${reason}` : "";
|
|
1105
|
-
let mutationLabel = `${op} ${file} ${key}`.trim();
|
|
1106
|
-
if (op === "append-text") {
|
|
1107
|
-
mutationLabel = `${op} ${file}`;
|
|
1108
|
-
if (position) {
|
|
1109
|
-
mutationLabel = `${mutationLabel} [${position}]`;
|
|
1110
|
-
}
|
|
1111
|
-
}
|
|
1112
|
-
stdout.write(`- ${color.item(mutationLabel)}${reasonSuffix}\n`);
|
|
1113
|
-
}
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
if (payload.fileWritePlan.fileCount > 0) {
|
|
1117
|
-
stdout.write(`${color.heading(`File writes (${payload.fileWritePlan.fileCount}):`)}\n`);
|
|
1118
|
-
for (const group of payload.fileWritePlan.groups) {
|
|
1119
|
-
const groupId = String(group.id || "").trim();
|
|
1120
|
-
const category = String(group.category || "").trim();
|
|
1121
|
-
const reason = String(group.reason || "").trim();
|
|
1122
|
-
const files = ensureArray(group.files);
|
|
1123
|
-
let marker = "";
|
|
1124
|
-
if (groupId) {
|
|
1125
|
-
marker = `id:${groupId}`;
|
|
1126
|
-
} else if (category) {
|
|
1127
|
-
marker = `category:${category}`;
|
|
1128
|
-
}
|
|
1129
|
-
const markerSuffix = marker ? ` (${marker})` : "";
|
|
1130
|
-
for (const file of files) {
|
|
1131
|
-
const targetPath = String(ensureObject(file).to || "").trim();
|
|
1132
|
-
if (!targetPath) {
|
|
1133
|
-
continue;
|
|
1134
|
-
}
|
|
1135
|
-
stdout.write(`- ${color.item(targetPath)}${color.installed(markerSuffix)}:\n`);
|
|
1136
|
-
if (reason) {
|
|
1137
|
-
stdout.write(` ${reason}\n`);
|
|
1138
|
-
}
|
|
1139
|
-
}
|
|
1140
|
-
}
|
|
1141
|
-
}
|
|
1142
|
-
|
|
1143
|
-
const serverProviders = ensureArray(ensureObject(payload.runtime.server).providers);
|
|
1144
|
-
const clientProviders = ensureArray(ensureObject(payload.runtime.client).providers);
|
|
1145
|
-
writeRuntimeProviders("server", serverProviders);
|
|
1146
|
-
writeRuntimeProviders("client", clientProviders);
|
|
1147
|
-
if (introspectionNotes.length > 0) {
|
|
1148
|
-
stdout.write(`${color.heading(`Introspection notes (${introspectionNotes.length}):`)}\n`);
|
|
1149
|
-
for (const note of introspectionNotes) {
|
|
1150
|
-
stdout.write(`- ${color.dim(note)}\n`);
|
|
1151
|
-
}
|
|
1152
|
-
}
|
|
1153
|
-
}
|
|
1154
|
-
return 0;
|
|
1155
|
-
}
|
|
1156
|
-
|
|
1157
|
-
if (bundleRegistry.has(id)) {
|
|
1158
|
-
const bundle = bundleRegistry.get(id);
|
|
1159
|
-
const payload = {
|
|
1160
|
-
kind: "bundle",
|
|
1161
|
-
bundleId: bundle.bundleId,
|
|
1162
|
-
version: bundle.version,
|
|
1163
|
-
description: String(bundle.description || ""),
|
|
1164
|
-
provider: Number(bundle.provider) === 1,
|
|
1165
|
-
curated: Number(bundle.curated) === 1,
|
|
1166
|
-
packages: ensureArray(bundle.packages).map((value) => String(value))
|
|
1167
|
-
};
|
|
1168
|
-
if (options.json) {
|
|
1169
|
-
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
1170
|
-
} else {
|
|
1171
|
-
stdout.write(`${color.heading("Information")}\n`);
|
|
1172
|
-
writeField("Bundle", payload.bundleId, color.item);
|
|
1173
|
-
writeField("Version", payload.version, color.installed);
|
|
1174
|
-
if (payload.description) {
|
|
1175
|
-
writeField("Description", payload.description);
|
|
1176
|
-
}
|
|
1177
|
-
stdout.write(`${color.heading(`Packages (${payload.packages.length}):`)}\n`);
|
|
1178
|
-
for (const packageId of payload.packages) {
|
|
1179
|
-
stdout.write(`- ${color.item(packageId)}\n`);
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
return 0;
|
|
1183
|
-
}
|
|
1184
|
-
|
|
1185
|
-
throw createCliError(`Unknown package or bundle: ${id}`);
|
|
1186
|
-
}
|
|
1187
|
-
|
|
1188
|
-
async function commandCreate({ positional, options, cwd, io }) {
|
|
1189
|
-
const targetType = String(positional[0] || "").trim();
|
|
1190
|
-
const rawName = String(positional[1] || "").trim();
|
|
1191
|
-
if (targetType !== "package" || !rawName) {
|
|
1192
|
-
throw createCliError("create requires: create package <name>", { showUsage: true });
|
|
1193
|
-
}
|
|
1194
|
-
|
|
1195
|
-
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
1196
|
-
const { packageJsonPath, packageJson } = await loadAppPackageJson(appRoot);
|
|
1197
|
-
const { lockPath, lock } = await loadLockFile(appRoot);
|
|
1198
|
-
const installedPackages = ensureObject(lock.installedPackages);
|
|
1199
|
-
const dependencies = ensureObject(packageJson.dependencies);
|
|
1200
|
-
const devDependencies = ensureObject(packageJson.devDependencies);
|
|
1201
|
-
|
|
1202
|
-
const { packageId, packageDirName } = resolveLocalPackageId({
|
|
1203
|
-
rawName,
|
|
1204
|
-
appPackageName: packageJson.name,
|
|
1205
|
-
inlineOptions: options.inlineOptions
|
|
1206
|
-
});
|
|
1207
|
-
const localPackagesRoot = path.join(appRoot, "packages");
|
|
1208
|
-
const packageRoot = path.join(localPackagesRoot, packageDirName);
|
|
1209
|
-
const packageRelativePath = normalizeRelativePath(appRoot, packageRoot);
|
|
1210
|
-
const descriptorRelativePath = `${normalizeRelativePosixPath(packageRelativePath)}/package.descriptor.mjs`;
|
|
1211
|
-
const localDependencySpecifier = toFileDependencySpecifier(packageRelativePath);
|
|
1212
|
-
const packageDescription = String(options.inlineOptions.description || "").trim() || `App-local package ${packageId}.`;
|
|
1213
|
-
|
|
1214
|
-
if (await fileExists(packageRoot)) {
|
|
1215
|
-
throw createCliError(`Package directory already exists: ${normalizeRelativePath(appRoot, packageRoot)}`);
|
|
1216
|
-
}
|
|
1217
|
-
if (Object.prototype.hasOwnProperty.call(installedPackages, packageId)) {
|
|
1218
|
-
throw createCliError(`Package is already present in lock file: ${packageId}`);
|
|
1219
|
-
}
|
|
1220
|
-
if (Object.prototype.hasOwnProperty.call(dependencies, packageId)) {
|
|
1221
|
-
throw createCliError(`package.json dependencies already contains ${packageId}.`);
|
|
1222
|
-
}
|
|
1223
|
-
if (Object.prototype.hasOwnProperty.call(devDependencies, packageId)) {
|
|
1224
|
-
throw createCliError(`package.json devDependencies already contains ${packageId}.`);
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
const scaffoldFiles = createLocalPackageScaffoldFiles({
|
|
1228
|
-
packageId,
|
|
1229
|
-
packageDescription
|
|
1230
|
-
});
|
|
1231
|
-
const touchedFiles = new Set(["package.json", normalizeRelativePath(appRoot, lockPath)]);
|
|
1232
|
-
for (const scaffoldFile of scaffoldFiles) {
|
|
1233
|
-
touchedFiles.add(`${normalizeRelativePosixPath(packageRelativePath)}/${normalizeRelativePosixPath(scaffoldFile.relativePath)}`);
|
|
1234
|
-
}
|
|
1235
|
-
|
|
1236
|
-
if (!options.dryRun) {
|
|
1237
|
-
for (const scaffoldFile of scaffoldFiles) {
|
|
1238
|
-
const absoluteFilePath = path.join(packageRoot, scaffoldFile.relativePath);
|
|
1239
|
-
await mkdir(path.dirname(absoluteFilePath), { recursive: true });
|
|
1240
|
-
await writeFile(absoluteFilePath, String(scaffoldFile.content || ""), "utf8");
|
|
1241
|
-
}
|
|
1242
|
-
}
|
|
1243
|
-
|
|
1244
|
-
const dependencyApplied = applyPackageJsonField(packageJson, "dependencies", packageId, localDependencySpecifier);
|
|
1245
|
-
const managedRecord = {
|
|
1246
|
-
packageId,
|
|
1247
|
-
version: "0.1.0",
|
|
1248
|
-
source: {
|
|
1249
|
-
type: "local-package",
|
|
1250
|
-
packagePath: normalizeRelativePosixPath(packageRelativePath),
|
|
1251
|
-
descriptorPath: descriptorRelativePath
|
|
1252
|
-
},
|
|
1253
|
-
managed: {
|
|
1254
|
-
packageJson: {
|
|
1255
|
-
dependencies: {},
|
|
1256
|
-
devDependencies: {},
|
|
1257
|
-
scripts: {}
|
|
1258
|
-
},
|
|
1259
|
-
text: {},
|
|
1260
|
-
vite: {},
|
|
1261
|
-
files: [],
|
|
1262
|
-
migrations: []
|
|
1263
|
-
},
|
|
1264
|
-
options: {},
|
|
1265
|
-
installedAt: new Date().toISOString()
|
|
1266
|
-
};
|
|
1267
|
-
if (dependencyApplied.changed) {
|
|
1268
|
-
managedRecord.managed.packageJson.dependencies[packageId] = dependencyApplied.managed;
|
|
1269
|
-
}
|
|
1270
|
-
lock.installedPackages[packageId] = managedRecord;
|
|
1271
|
-
|
|
1272
|
-
const touchedFileList = sortStrings([...touchedFiles]);
|
|
1273
|
-
if (!options.dryRun) {
|
|
1274
|
-
await writeJsonFile(packageJsonPath, packageJson);
|
|
1275
|
-
await writeJsonFile(lockPath, lock);
|
|
1276
|
-
if (!options.noInstall) {
|
|
1277
|
-
await runNpmInstall(appRoot, io.stderr);
|
|
1278
|
-
}
|
|
1279
|
-
}
|
|
1280
|
-
|
|
1281
|
-
if (options.json) {
|
|
1282
|
-
io.stdout.write(
|
|
1283
|
-
`${JSON.stringify(
|
|
1284
|
-
{
|
|
1285
|
-
targetType: "package",
|
|
1286
|
-
packageId,
|
|
1287
|
-
packageDirectory: normalizeRelativePosixPath(packageRelativePath),
|
|
1288
|
-
descriptorPath: descriptorRelativePath,
|
|
1289
|
-
dependency: localDependencySpecifier,
|
|
1290
|
-
touchedFiles: touchedFileList,
|
|
1291
|
-
lockPath: normalizeRelativePath(appRoot, lockPath),
|
|
1292
|
-
dryRun: options.dryRun
|
|
1293
|
-
},
|
|
1294
|
-
null,
|
|
1295
|
-
2
|
|
1296
|
-
)}\n`
|
|
1297
|
-
);
|
|
1298
|
-
} else {
|
|
1299
|
-
io.stdout.write(`Created local package ${packageId}.\n`);
|
|
1300
|
-
io.stdout.write(`Directory: ${normalizeRelativePosixPath(packageRelativePath)}\n`);
|
|
1301
|
-
io.stdout.write(`Dependency: ${packageId} -> ${localDependencySpecifier}\n`);
|
|
1302
|
-
io.stdout.write(`Descriptor: ${descriptorRelativePath}\n`);
|
|
1303
|
-
io.stdout.write(`Touched files (${touchedFileList.length}):\n`);
|
|
1304
|
-
for (const touchedFile of touchedFileList) {
|
|
1305
|
-
io.stdout.write(`- ${touchedFile}\n`);
|
|
1306
|
-
}
|
|
1307
|
-
io.stdout.write(`Lock file: ${normalizeRelativePath(appRoot, lockPath)}\n`);
|
|
1308
|
-
if (options.dryRun) {
|
|
1309
|
-
io.stdout.write("Dry run enabled: no files were written.\n");
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
|
|
1313
|
-
return 0;
|
|
1314
|
-
}
|
|
1315
|
-
|
|
1316
|
-
async function commandAdd({ positional, options, cwd, io }) {
|
|
1317
|
-
const invocationMode = options?.commandMode === "generate" ? "generate" : "add";
|
|
1318
|
-
const targetType = String(positional[0] || "").trim();
|
|
1319
|
-
const targetId = String(positional[1] || "").trim();
|
|
1320
|
-
|
|
1321
|
-
if (!targetType || !targetId) {
|
|
1322
|
-
if (invocationMode === "generate") {
|
|
1323
|
-
throw createCliError("generate requires a package id (generate <packageId>).", {
|
|
1324
|
-
showUsage: true
|
|
1325
|
-
});
|
|
1326
|
-
}
|
|
1327
|
-
throw createCliError("add requires target type and id (add bundle <id> | add package <id>).", {
|
|
1328
|
-
showUsage: true
|
|
1329
|
-
});
|
|
1330
|
-
}
|
|
1331
|
-
if (targetType !== "bundle" && targetType !== "package") {
|
|
1332
|
-
throw createCliError(`Unsupported add target type: ${targetType}`, { showUsage: true });
|
|
1333
|
-
}
|
|
1334
|
-
if (invocationMode === "generate" && targetType !== "package") {
|
|
1335
|
-
throw createCliError("generate requires a package id (generate <packageId>).", {
|
|
1336
|
-
showUsage: true
|
|
1337
|
-
});
|
|
1338
|
-
}
|
|
1339
|
-
|
|
1340
|
-
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
1341
|
-
const packageRegistry = await loadPackageRegistry();
|
|
1342
|
-
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
1343
|
-
const bundleRegistry = await loadBundleRegistry();
|
|
1344
|
-
const combinedPackageRegistry = mergePackageRegistries(packageRegistry, appLocalRegistry);
|
|
1345
|
-
const { packageJsonPath, packageJson } = await loadAppPackageJson(appRoot);
|
|
1346
|
-
const { lockPath, lock } = await loadLockFile(appRoot);
|
|
1347
|
-
let resolvedTargetPackageId = targetType === "package" ? resolvePackageIdInput(targetId, combinedPackageRegistry) : "";
|
|
1348
|
-
if (targetType === "package") {
|
|
1349
|
-
const packageIdForNodeModulesLookup = resolvedTargetPackageId || targetId;
|
|
1350
|
-
const installedNodeModuleEntry = await resolveInstalledNodeModulePackageEntry({
|
|
1351
|
-
appRoot,
|
|
1352
|
-
packageId: packageIdForNodeModulesLookup
|
|
1353
|
-
});
|
|
1354
|
-
if (installedNodeModuleEntry) {
|
|
1355
|
-
combinedPackageRegistry.set(installedNodeModuleEntry.packageId, installedNodeModuleEntry);
|
|
1356
|
-
resolvedTargetPackageId = installedNodeModuleEntry.packageId;
|
|
1357
|
-
}
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
const targetPackageIds = targetType === "bundle"
|
|
1361
|
-
? ensureArray(bundleRegistry.get(targetId)?.packages).map((value) => String(value))
|
|
1362
|
-
: [resolvedTargetPackageId];
|
|
1363
|
-
if (targetType === "bundle" && targetPackageIds.length === 0) {
|
|
1364
|
-
throw createCliError(`Unknown bundle: ${targetId}`);
|
|
1365
|
-
}
|
|
1366
|
-
if (targetType === "package" && !resolvedTargetPackageId) {
|
|
1367
|
-
throw createCliError(
|
|
1368
|
-
`Unknown package: ${targetId}. Install an external module first (npm install ${targetId}) if you want to adopt it into lock.`
|
|
1369
|
-
);
|
|
1370
|
-
}
|
|
1371
|
-
|
|
1372
|
-
await hydratePackageRegistryFromInstalledNodeModules({
|
|
1373
|
-
appRoot,
|
|
1374
|
-
packageRegistry: combinedPackageRegistry,
|
|
1375
|
-
seedPackageIds: targetPackageIds
|
|
1376
|
-
});
|
|
1377
|
-
|
|
1378
|
-
if (targetType === "package") {
|
|
1379
|
-
const targetPackageEntry = combinedPackageRegistry.get(resolvedTargetPackageId);
|
|
1380
|
-
if (!targetPackageEntry) {
|
|
1381
|
-
throw createCliError(`Unknown package: ${targetId}`);
|
|
1382
|
-
}
|
|
1383
|
-
const packageKind = resolvePackageKind(targetPackageEntry);
|
|
1384
|
-
if (invocationMode === "add" && packageKind === "generator") {
|
|
1385
|
-
throw createCliError(
|
|
1386
|
-
`Package ${resolvedTargetPackageId} is a generator. Use: jskit generate ${resolvedTargetPackageId}`
|
|
1387
|
-
);
|
|
1388
|
-
}
|
|
1389
|
-
if (invocationMode === "generate" && packageKind !== "generator") {
|
|
1390
|
-
throw createCliError(
|
|
1391
|
-
`Package ${resolvedTargetPackageId} is a runtime package. Use: jskit add package ${resolvedTargetPackageId}`
|
|
1392
|
-
);
|
|
1393
|
-
}
|
|
1394
|
-
validateInlineOptionsForPackage(targetPackageEntry, options.inlineOptions);
|
|
1395
|
-
}
|
|
1396
|
-
|
|
1397
|
-
const { ordered: resolvedPackageIds, externalDependencies } = resolveLocalDependencyOrder(
|
|
1398
|
-
targetPackageIds,
|
|
1399
|
-
combinedPackageRegistry
|
|
1400
|
-
);
|
|
1401
|
-
if (invocationMode === "add" && targetType === "bundle") {
|
|
1402
|
-
const bundledGenerators = resolvedPackageIds.filter((packageId) => {
|
|
1403
|
-
const packageEntry = combinedPackageRegistry.get(packageId);
|
|
1404
|
-
return resolvePackageKind(packageEntry) === "generator";
|
|
1405
|
-
});
|
|
1406
|
-
if (bundledGenerators.length > 0) {
|
|
1407
|
-
throw createCliError(
|
|
1408
|
-
`Bundle ${targetId} includes generator package(s): ${bundledGenerators.join(", ")}. Use: jskit generate <packageId>`
|
|
1409
|
-
);
|
|
1410
|
-
}
|
|
1411
|
-
}
|
|
1412
|
-
const plannedInstalledPackageIds = sortStrings([
|
|
1413
|
-
...new Set([
|
|
1414
|
-
...Object.keys(ensureObject(lock.installedPackages)).map((value) => String(value || "").trim()).filter(Boolean),
|
|
1415
|
-
...resolvedPackageIds
|
|
1416
|
-
])
|
|
1417
|
-
]);
|
|
1418
|
-
validatePlannedCapabilityClosure(
|
|
1419
|
-
plannedInstalledPackageIds,
|
|
1420
|
-
combinedPackageRegistry,
|
|
1421
|
-
`${invocationMode} ${targetType} ${targetId}`
|
|
1422
|
-
);
|
|
1423
|
-
|
|
1424
|
-
if (targetType === "bundle") {
|
|
1425
|
-
validateInlineOptionsForBundle({
|
|
1426
|
-
bundleId: targetId,
|
|
1427
|
-
inlineOptions: options.inlineOptions,
|
|
1428
|
-
packageIds: resolvedPackageIds,
|
|
1429
|
-
packageRegistry: combinedPackageRegistry
|
|
1430
|
-
});
|
|
1431
|
-
}
|
|
1432
|
-
|
|
1433
|
-
const packagesToInstall = [];
|
|
1434
|
-
const resolvedOptionsByPackage = {};
|
|
1435
|
-
const forceReapplyTarget = options?.forceReapplyTarget === true;
|
|
1436
|
-
const hasInlineOptions = Object.keys(ensureObject(options.inlineOptions)).length > 0;
|
|
1437
|
-
for (const packageId of resolvedPackageIds) {
|
|
1438
|
-
const packageEntry = combinedPackageRegistry.get(packageId);
|
|
1439
|
-
const existingInstall = ensureObject(lock.installedPackages[packageId]);
|
|
1440
|
-
const existingVersion = String(existingInstall.version || "").trim();
|
|
1441
|
-
const isDirectTargetPackage = targetType === "package" && packageId === resolvedTargetPackageId;
|
|
1442
|
-
const packageInlineOptions = targetType === "bundle"
|
|
1443
|
-
? resolveBundleInlineOptionsForPackage(packageEntry, options.inlineOptions)
|
|
1444
|
-
: isDirectTargetPackage
|
|
1445
|
-
? ensureObject(options.inlineOptions)
|
|
1446
|
-
: {};
|
|
1447
|
-
const hasPackageInlineOptions = Object.keys(packageInlineOptions).length > 0;
|
|
1448
|
-
const shouldReapplyInstalledPackage =
|
|
1449
|
-
(isDirectTargetPackage && (forceReapplyTarget || hasInlineOptions)) ||
|
|
1450
|
-
(targetType === "bundle" && hasPackageInlineOptions);
|
|
1451
|
-
if (existingVersion && existingVersion === packageEntry.version && !shouldReapplyInstalledPackage) {
|
|
1452
|
-
continue;
|
|
1453
|
-
}
|
|
1454
|
-
packagesToInstall.push(packageId);
|
|
1455
|
-
const lockEntryOptions = ensureObject(existingInstall.options);
|
|
1456
|
-
resolvedOptionsByPackage[packageId] = await resolvePackageOptions(
|
|
1457
|
-
packageEntry,
|
|
1458
|
-
{
|
|
1459
|
-
...lockEntryOptions,
|
|
1460
|
-
...packageInlineOptions
|
|
1461
|
-
},
|
|
1462
|
-
io,
|
|
1463
|
-
{ appRoot }
|
|
1464
|
-
);
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1467
|
-
const touchedFiles = new Set();
|
|
1468
|
-
const installedPackageRecords = [];
|
|
1469
|
-
|
|
1470
|
-
for (const packageId of packagesToInstall) {
|
|
1471
|
-
const packageEntry = combinedPackageRegistry.get(packageId);
|
|
1472
|
-
const managedRecord = await applyPackageInstall({
|
|
1473
|
-
packageEntry,
|
|
1474
|
-
packageOptions: resolvedOptionsByPackage[packageId],
|
|
1475
|
-
appRoot,
|
|
1476
|
-
appPackageJson: packageJson,
|
|
1477
|
-
lock,
|
|
1478
|
-
packageRegistry: combinedPackageRegistry,
|
|
1479
|
-
touchedFiles
|
|
1480
|
-
});
|
|
1481
|
-
installedPackageRecords.push(managedRecord);
|
|
1482
|
-
}
|
|
1483
|
-
|
|
1484
|
-
const {
|
|
1485
|
-
appLocalRegistry: refreshedAppLocalRegistry,
|
|
1486
|
-
adoptedPackageIds
|
|
1487
|
-
} = await adoptAppLocalPackageDependencies({
|
|
1488
|
-
appRoot,
|
|
1489
|
-
appPackageJson: packageJson,
|
|
1490
|
-
lock
|
|
1491
|
-
});
|
|
1492
|
-
for (const [packageId, packageEntry] of refreshedAppLocalRegistry.entries()) {
|
|
1493
|
-
combinedPackageRegistry.set(packageId, packageEntry);
|
|
1494
|
-
}
|
|
1495
|
-
if (adoptedPackageIds.length > 0) {
|
|
1496
|
-
const postInstallPackageIds = sortStrings(Object.keys(ensureObject(lock.installedPackages)));
|
|
1497
|
-
validatePlannedCapabilityClosure(
|
|
1498
|
-
postInstallPackageIds,
|
|
1499
|
-
combinedPackageRegistry,
|
|
1500
|
-
`${invocationMode} ${targetType} ${targetId}`
|
|
1501
|
-
);
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
const finalResolvedPackageIds = sortStrings([...resolvedPackageIds, ...adoptedPackageIds]);
|
|
1505
|
-
|
|
1506
|
-
const touchedFileList = sortStrings([...touchedFiles]);
|
|
1507
|
-
const successLabel = invocationMode === "generate"
|
|
1508
|
-
? "Generated with"
|
|
1509
|
-
: targetType === "bundle"
|
|
1510
|
-
? "Added bundle"
|
|
1511
|
-
: "Added package";
|
|
1512
|
-
const installWarnings = installedPackageRecords
|
|
1513
|
-
.flatMap((record) => ensureArray(ensureObject(record).warnings))
|
|
1514
|
-
.map((value) => String(value || "").trim())
|
|
1515
|
-
.filter(Boolean);
|
|
1516
|
-
|
|
1517
|
-
if (!options.dryRun) {
|
|
1518
|
-
await writeJsonFile(packageJsonPath, packageJson);
|
|
1519
|
-
await writeJsonFile(lockPath, lock);
|
|
1520
|
-
if (!options.noInstall) {
|
|
1521
|
-
await runNpmInstall(appRoot, io.stderr);
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
|
|
1525
|
-
if (options.json) {
|
|
1526
|
-
io.stdout.write(`${JSON.stringify({
|
|
1527
|
-
targetType: invocationMode === "generate" ? "generator" : targetType,
|
|
1528
|
-
targetId,
|
|
1529
|
-
resolvedPackages: finalResolvedPackageIds,
|
|
1530
|
-
touchedFiles: touchedFileList,
|
|
1531
|
-
lockPath: normalizeRelativePath(appRoot, lockPath),
|
|
1532
|
-
externalDependencies,
|
|
1533
|
-
dryRun: options.dryRun,
|
|
1534
|
-
installed: installedPackageRecords,
|
|
1535
|
-
warnings: installWarnings
|
|
1536
|
-
}, null, 2)}\n`);
|
|
1537
|
-
} else {
|
|
1538
|
-
io.stdout.write(
|
|
1539
|
-
`${renderResolvedSummary(
|
|
1540
|
-
`${successLabel}`,
|
|
1541
|
-
targetId,
|
|
1542
|
-
finalResolvedPackageIds,
|
|
1543
|
-
touchedFileList,
|
|
1544
|
-
appRoot,
|
|
1545
|
-
lockPath,
|
|
1546
|
-
externalDependencies
|
|
1547
|
-
)}\n`
|
|
1548
|
-
);
|
|
1549
|
-
if (installWarnings.length > 0) {
|
|
1550
|
-
io.stdout.write(`Warnings (${installWarnings.length}):\n`);
|
|
1551
|
-
for (const warning of installWarnings) {
|
|
1552
|
-
io.stdout.write(`- ${warning}\n`);
|
|
1553
|
-
}
|
|
1554
|
-
}
|
|
1555
|
-
if (options.dryRun) {
|
|
1556
|
-
io.stdout.write("Dry run enabled: no files were written.\n");
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1559
|
-
|
|
1560
|
-
return 0;
|
|
1561
|
-
}
|
|
1562
|
-
|
|
1563
|
-
async function commandGenerate({ positional, options, cwd, io }) {
|
|
1564
|
-
const firstToken = String(positional[0] || "").trim();
|
|
1565
|
-
const secondToken = String(positional[1] || "").trim();
|
|
1566
|
-
if (firstToken === "bundle") {
|
|
1567
|
-
throw createCliError("generate supports packages only (generate <packageId>).", {
|
|
1568
|
-
showUsage: true
|
|
1569
|
-
});
|
|
1570
|
-
}
|
|
1571
|
-
const targetId = firstToken === "package" ? secondToken : firstToken;
|
|
1572
|
-
if (!targetId) {
|
|
1573
|
-
throw createCliError("generate requires a package id (generate <packageId>).", {
|
|
1574
|
-
showUsage: true
|
|
1575
|
-
});
|
|
1576
|
-
}
|
|
1577
|
-
|
|
1578
|
-
return commandAdd({
|
|
1579
|
-
positional: ["package", targetId],
|
|
1580
|
-
options: {
|
|
1581
|
-
...options,
|
|
1582
|
-
commandMode: "generate"
|
|
1583
|
-
},
|
|
1584
|
-
cwd,
|
|
1585
|
-
io
|
|
1586
|
-
});
|
|
1587
|
-
}
|
|
1588
|
-
|
|
1589
|
-
async function commandUpdate({ positional, options, cwd, io }) {
|
|
1590
|
-
const targetType = String(positional[0] || "").trim();
|
|
1591
|
-
const targetId = String(positional[1] || "").trim();
|
|
1592
|
-
if (targetType !== "package" || !targetId) {
|
|
1593
|
-
throw createCliError("update requires: update package <packageId>", { showUsage: true });
|
|
1594
|
-
}
|
|
1595
|
-
|
|
1596
|
-
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
1597
|
-
const { lock } = await loadLockFile(appRoot);
|
|
1598
|
-
const installedPackages = ensureObject(lock.installedPackages);
|
|
1599
|
-
const resolvedTargetId = resolveInstalledPackageIdInput(targetId, installedPackages);
|
|
1600
|
-
if (!resolvedTargetId) {
|
|
1601
|
-
throw createCliError(`Package is not installed: ${targetId}`);
|
|
1602
|
-
}
|
|
1603
|
-
|
|
1604
|
-
return commandAdd({
|
|
1605
|
-
positional: ["package", resolvedTargetId],
|
|
1606
|
-
options: {
|
|
1607
|
-
...options,
|
|
1608
|
-
forceReapplyTarget: true
|
|
1609
|
-
},
|
|
1610
|
-
cwd,
|
|
1611
|
-
io
|
|
1612
|
-
});
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
async function commandMigrations({ positional, options, cwd, io }) {
|
|
1616
|
-
const scope = String(positional[0] || "").trim().toLowerCase();
|
|
1617
|
-
const targetId = String(positional[1] || "").trim();
|
|
1618
|
-
if (!scope || (scope !== "all" && scope !== "changed" && scope !== "package")) {
|
|
1619
|
-
throw createCliError("migrations requires: migrations <all|changed|package <packageId>>", {
|
|
1620
|
-
showUsage: true
|
|
1621
|
-
});
|
|
1622
|
-
}
|
|
1623
|
-
if (scope === "package" && !targetId) {
|
|
1624
|
-
throw createCliError("migrations package requires a package id.", {
|
|
1625
|
-
showUsage: true
|
|
1626
|
-
});
|
|
1627
|
-
}
|
|
1628
|
-
if (scope !== "package" && Object.keys(ensureObject(options.inlineOptions)).length > 0) {
|
|
1629
|
-
throw createCliError("Inline options are only supported with: migrations package <packageId>.");
|
|
1630
|
-
}
|
|
1631
|
-
|
|
1632
|
-
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
1633
|
-
const packageRegistry = await loadPackageRegistry();
|
|
1634
|
-
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
1635
|
-
const combinedPackageRegistry = mergePackageRegistries(packageRegistry, appLocalRegistry);
|
|
1636
|
-
const { lockPath, lock } = await loadLockFile(appRoot);
|
|
1637
|
-
const installedPackages = ensureObject(lock.installedPackages);
|
|
1638
|
-
const installedPackageIds = sortStrings(Object.keys(installedPackages));
|
|
1639
|
-
await hydratePackageRegistryFromInstalledNodeModules({
|
|
1640
|
-
appRoot,
|
|
1641
|
-
packageRegistry: combinedPackageRegistry,
|
|
1642
|
-
seedPackageIds: installedPackageIds
|
|
1643
|
-
});
|
|
1644
|
-
|
|
1645
|
-
let requestedPackageIds = [];
|
|
1646
|
-
if (scope === "all") {
|
|
1647
|
-
requestedPackageIds = installedPackageIds;
|
|
1648
|
-
} else if (scope === "package") {
|
|
1649
|
-
const resolvedTargetId = resolveInstalledPackageIdInput(targetId, installedPackages);
|
|
1650
|
-
if (!resolvedTargetId) {
|
|
1651
|
-
throw createCliError(`Package is not installed: ${targetId}`);
|
|
1652
|
-
}
|
|
1653
|
-
requestedPackageIds = [resolvedTargetId];
|
|
1654
|
-
} else {
|
|
1655
|
-
requestedPackageIds = installedPackageIds.filter((packageId) => {
|
|
1656
|
-
const packageEntry = combinedPackageRegistry.get(packageId);
|
|
1657
|
-
if (!packageEntry) {
|
|
1658
|
-
return true;
|
|
1659
|
-
}
|
|
1660
|
-
const lockEntry = ensureObject(installedPackages[packageId]);
|
|
1661
|
-
const migrationSyncVersion = String(lockEntry.migrationSyncVersion || "").trim();
|
|
1662
|
-
return migrationSyncVersion !== String(packageEntry.version || "").trim();
|
|
1663
|
-
});
|
|
1664
|
-
}
|
|
1665
|
-
|
|
1666
|
-
const touchedFiles = new Set();
|
|
1667
|
-
const migratedRecords = [];
|
|
1668
|
-
const migrationWarnings = [];
|
|
1669
|
-
for (const packageId of requestedPackageIds) {
|
|
1670
|
-
const packageEntry = combinedPackageRegistry.get(packageId);
|
|
1671
|
-
if (!packageEntry) {
|
|
1672
|
-
throw createCliError(
|
|
1673
|
-
`Installed package descriptor not found: ${packageId}. Ensure it is available in catalog, app packages/, or node_modules.`
|
|
1674
|
-
);
|
|
1675
|
-
}
|
|
1676
|
-
validateInlineOptionsForPackage(packageEntry, options.inlineOptions);
|
|
1677
|
-
const installedRecord = ensureObject(installedPackages[packageId]);
|
|
1678
|
-
const mergedInlineOptions = scope === "package" ? ensureObject(options.inlineOptions) : {};
|
|
1679
|
-
const resolvedOptions = await resolvePackageOptions(
|
|
1680
|
-
packageEntry,
|
|
1681
|
-
{
|
|
1682
|
-
...ensureObject(installedRecord.options),
|
|
1683
|
-
...mergedInlineOptions
|
|
1684
|
-
},
|
|
1685
|
-
io,
|
|
1686
|
-
{ appRoot }
|
|
1687
|
-
);
|
|
1688
|
-
|
|
1689
|
-
const managedRecord = await applyPackageMigrationsOnly({
|
|
1690
|
-
packageEntry,
|
|
1691
|
-
packageOptions: resolvedOptions,
|
|
1692
|
-
appRoot,
|
|
1693
|
-
lock,
|
|
1694
|
-
touchedFiles
|
|
1695
|
-
});
|
|
1696
|
-
migratedRecords.push(managedRecord);
|
|
1697
|
-
for (const warning of ensureArray(ensureObject(managedRecord).warnings)) {
|
|
1698
|
-
const normalizedWarning = String(warning || "").trim();
|
|
1699
|
-
if (!normalizedWarning) {
|
|
1700
|
-
continue;
|
|
1701
|
-
}
|
|
1702
|
-
migrationWarnings.push(normalizedWarning);
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
|
|
1706
|
-
const touchedFileList = sortStrings([...touchedFiles]);
|
|
1707
|
-
if (!options.dryRun) {
|
|
1708
|
-
await writeJsonFile(lockPath, lock);
|
|
1709
|
-
}
|
|
1710
|
-
|
|
1711
|
-
if (options.json) {
|
|
1712
|
-
io.stdout.write(`${JSON.stringify({
|
|
1713
|
-
targetType: "migrations",
|
|
1714
|
-
scope,
|
|
1715
|
-
requestedPackages: requestedPackageIds,
|
|
1716
|
-
touchedFiles: touchedFileList,
|
|
1717
|
-
lockPath: normalizeRelativePath(appRoot, lockPath),
|
|
1718
|
-
dryRun: options.dryRun,
|
|
1719
|
-
migrated: migratedRecords,
|
|
1720
|
-
warnings: migrationWarnings
|
|
1721
|
-
}, null, 2)}\n`);
|
|
1722
|
-
} else {
|
|
1723
|
-
io.stdout.write(`Generated migrations (${scope}).\n`);
|
|
1724
|
-
io.stdout.write(`Resolved packages (${requestedPackageIds.length}):\n`);
|
|
1725
|
-
for (const packageId of requestedPackageIds) {
|
|
1726
|
-
io.stdout.write(`- ${packageId}\n`);
|
|
1727
|
-
}
|
|
1728
|
-
io.stdout.write(`Touched files (${touchedFileList.length}):\n`);
|
|
1729
|
-
for (const touchedFile of touchedFileList) {
|
|
1730
|
-
io.stdout.write(`- ${touchedFile}\n`);
|
|
1731
|
-
}
|
|
1732
|
-
io.stdout.write(`Lock file: ${normalizeRelativePath(appRoot, lockPath)}\n`);
|
|
1733
|
-
if (options.verbose && migrationWarnings.length > 0) {
|
|
1734
|
-
io.stdout.write(`Warnings (${migrationWarnings.length}):\n`);
|
|
1735
|
-
for (const warning of migrationWarnings) {
|
|
1736
|
-
io.stdout.write(`- ${warning}\n`);
|
|
1737
|
-
}
|
|
1738
|
-
}
|
|
1739
|
-
if (options.dryRun) {
|
|
1740
|
-
io.stdout.write("Dry run enabled: no files were written.\n");
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
|
|
1744
|
-
return 0;
|
|
1745
|
-
}
|
|
1746
|
-
|
|
1747
|
-
async function commandPosition({ positional, options, cwd, io }) {
|
|
1748
|
-
const targetType = String(positional[0] || "").trim();
|
|
1749
|
-
const targetId = String(positional[1] || "").trim();
|
|
1750
|
-
if (targetType !== "element" || !targetId) {
|
|
1751
|
-
throw createCliError("position requires: position element <packageId>", { showUsage: true });
|
|
1752
|
-
}
|
|
1753
|
-
|
|
1754
|
-
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
1755
|
-
const packageRegistry = await loadPackageRegistry();
|
|
1756
|
-
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
1757
|
-
const combinedPackageRegistry = mergePackageRegistries(packageRegistry, appLocalRegistry);
|
|
1758
|
-
const { lockPath, lock } = await loadLockFile(appRoot);
|
|
1759
|
-
const installedPackages = ensureObject(lock.installedPackages);
|
|
1760
|
-
const resolvedTargetId = resolveInstalledPackageIdInput(targetId, installedPackages);
|
|
1761
|
-
if (!resolvedTargetId) {
|
|
1762
|
-
throw createCliError(`Element is not installed: ${targetId}`);
|
|
1763
|
-
}
|
|
1764
|
-
|
|
1765
|
-
await hydratePackageRegistryFromInstalledNodeModules({
|
|
1766
|
-
appRoot,
|
|
1767
|
-
packageRegistry: combinedPackageRegistry,
|
|
1768
|
-
seedPackageIds: [resolvedTargetId]
|
|
1769
|
-
});
|
|
1770
|
-
const packageEntry = combinedPackageRegistry.get(resolvedTargetId);
|
|
1771
|
-
if (!packageEntry) {
|
|
1772
|
-
throw createCliError(
|
|
1773
|
-
`Installed element descriptor not found: ${resolvedTargetId}. Ensure it exists in catalog, app packages/, or node_modules.`
|
|
1774
|
-
);
|
|
1775
|
-
}
|
|
1776
|
-
validateInlineOptionsForPackage(packageEntry, options.inlineOptions);
|
|
1777
|
-
|
|
1778
|
-
const installedRecord = ensureObject(installedPackages[resolvedTargetId]);
|
|
1779
|
-
const resolvedOptions = await resolvePackageOptions(
|
|
1780
|
-
packageEntry,
|
|
1781
|
-
{
|
|
1782
|
-
...ensureObject(installedRecord.options),
|
|
1783
|
-
...ensureObject(options.inlineOptions)
|
|
1784
|
-
},
|
|
1785
|
-
io,
|
|
1786
|
-
{ appRoot }
|
|
1787
|
-
);
|
|
1788
|
-
|
|
1789
|
-
const touchedFiles = new Set();
|
|
1790
|
-
const positionedRecord = await applyPackagePositioning({
|
|
1791
|
-
packageEntry,
|
|
1792
|
-
packageOptions: resolvedOptions,
|
|
1793
|
-
appRoot,
|
|
1794
|
-
lock,
|
|
1795
|
-
touchedFiles
|
|
1796
|
-
});
|
|
1797
|
-
const touchedFileList = sortStrings([...touchedFiles]);
|
|
1798
|
-
|
|
1799
|
-
if (!options.dryRun) {
|
|
1800
|
-
await writeJsonFile(lockPath, lock);
|
|
1801
|
-
}
|
|
1802
|
-
|
|
1803
|
-
if (options.json) {
|
|
1804
|
-
io.stdout.write(`${JSON.stringify({
|
|
1805
|
-
targetType: "element",
|
|
1806
|
-
elementId: resolvedTargetId,
|
|
1807
|
-
packageId: resolvedTargetId,
|
|
1808
|
-
touchedFiles: touchedFileList,
|
|
1809
|
-
lockPath: normalizeRelativePath(appRoot, lockPath),
|
|
1810
|
-
dryRun: options.dryRun,
|
|
1811
|
-
positioned: positionedRecord
|
|
1812
|
-
}, null, 2)}\n`);
|
|
1813
|
-
} else {
|
|
1814
|
-
io.stdout.write(`Positioned element ${resolvedTargetId}.\n`);
|
|
1815
|
-
io.stdout.write(`Touched files (${touchedFileList.length}):\n`);
|
|
1816
|
-
for (const touchedFile of touchedFileList) {
|
|
1817
|
-
io.stdout.write(`- ${touchedFile}\n`);
|
|
1818
|
-
}
|
|
1819
|
-
io.stdout.write(`Lock file: ${normalizeRelativePath(appRoot, lockPath)}\n`);
|
|
1820
|
-
if (options.dryRun) {
|
|
1821
|
-
io.stdout.write("Dry run enabled: no files were written.\n");
|
|
1822
|
-
}
|
|
1823
|
-
}
|
|
1824
|
-
|
|
1825
|
-
return 0;
|
|
1826
|
-
}
|
|
1827
|
-
|
|
1828
|
-
async function commandRemove({ positional, options, cwd, io }) {
|
|
1829
|
-
const targetType = String(positional[0] || "").trim();
|
|
1830
|
-
const targetId = String(positional[1] || "").trim();
|
|
1831
|
-
if (targetType !== "package" || !targetId) {
|
|
1832
|
-
throw createCliError("remove requires: remove package <packageId>", { showUsage: true });
|
|
1833
|
-
}
|
|
1834
|
-
|
|
1835
|
-
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
1836
|
-
const packageRegistry = await loadPackageRegistry();
|
|
1837
|
-
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
1838
|
-
const combinedPackageRegistry = mergePackageRegistries(packageRegistry, appLocalRegistry);
|
|
1839
|
-
const { packageJsonPath, packageJson } = await loadAppPackageJson(appRoot);
|
|
1840
|
-
const { lockPath, lock } = await loadLockFile(appRoot);
|
|
1841
|
-
const installed = ensureObject(lock.installedPackages);
|
|
1842
|
-
await hydratePackageRegistryFromInstalledNodeModules({
|
|
1843
|
-
appRoot,
|
|
1844
|
-
packageRegistry: combinedPackageRegistry,
|
|
1845
|
-
seedPackageIds: Object.keys(installed)
|
|
1846
|
-
});
|
|
1847
|
-
const resolvedTargetId = resolveInstalledPackageIdInput(targetId, installed);
|
|
1848
|
-
|
|
1849
|
-
if (!resolvedTargetId) {
|
|
1850
|
-
throw createCliError(`Package is not installed: ${targetId}`);
|
|
1851
|
-
}
|
|
1852
|
-
|
|
1853
|
-
const dependents = getInstalledDependents(lock, resolvedTargetId, combinedPackageRegistry);
|
|
1854
|
-
if (dependents.length > 0) {
|
|
1855
|
-
throw createCliError(
|
|
1856
|
-
`Cannot remove ${resolvedTargetId}; installed packages depend on it: ${dependents.join(", ")}`
|
|
1857
|
-
);
|
|
1858
|
-
}
|
|
1859
|
-
|
|
1860
|
-
const lockEntry = ensureObject(installed[resolvedTargetId]);
|
|
1861
|
-
const managed = ensureObject(lockEntry.managed);
|
|
1862
|
-
const touchedFiles = new Set();
|
|
1863
|
-
|
|
1864
|
-
const managedPackageJson = ensureObject(managed.packageJson);
|
|
1865
|
-
for (const [dependencyId, managedChange] of Object.entries(ensureObject(managedPackageJson.dependencies))) {
|
|
1866
|
-
if (restorePackageJsonField(packageJson, "dependencies", dependencyId, managedChange)) {
|
|
1867
|
-
touchedFiles.add("package.json");
|
|
1868
|
-
}
|
|
1869
|
-
}
|
|
1870
|
-
for (const [dependencyId, managedChange] of Object.entries(ensureObject(managedPackageJson.devDependencies))) {
|
|
1871
|
-
if (restorePackageJsonField(packageJson, "devDependencies", dependencyId, managedChange)) {
|
|
1872
|
-
touchedFiles.add("package.json");
|
|
1873
|
-
}
|
|
1874
|
-
}
|
|
1875
|
-
for (const [scriptName, managedChange] of Object.entries(ensureObject(managedPackageJson.scripts))) {
|
|
1876
|
-
if (restorePackageJsonField(packageJson, "scripts", scriptName, managedChange)) {
|
|
1877
|
-
touchedFiles.add("package.json");
|
|
1878
|
-
}
|
|
1879
|
-
}
|
|
1880
|
-
|
|
1881
|
-
const managedText = ensureObject(managed.text);
|
|
1882
|
-
for (const change of Object.values(managedText)) {
|
|
1883
|
-
const changeRecord = ensureObject(change);
|
|
1884
|
-
if (String(changeRecord.op || "") !== "upsert-env") {
|
|
1885
|
-
continue;
|
|
1886
|
-
}
|
|
1887
|
-
const relativeFile = String(changeRecord.file || "").trim();
|
|
1888
|
-
if (!relativeFile) {
|
|
1889
|
-
continue;
|
|
1890
|
-
}
|
|
1891
|
-
const absoluteFile = path.join(appRoot, relativeFile);
|
|
1892
|
-
const existing = await readFileBufferIfExists(absoluteFile);
|
|
1893
|
-
if (!existing.exists) {
|
|
1894
|
-
continue;
|
|
1895
|
-
}
|
|
1896
|
-
const updated = removeEnvValue(
|
|
1897
|
-
existing.buffer.toString("utf8"),
|
|
1898
|
-
String(changeRecord.key || ""),
|
|
1899
|
-
String(changeRecord.value || ""),
|
|
1900
|
-
{
|
|
1901
|
-
hadPrevious: Boolean(changeRecord.hadPrevious),
|
|
1902
|
-
previousValue: String(changeRecord.previousValue || "")
|
|
1903
|
-
}
|
|
1904
|
-
);
|
|
1905
|
-
if (updated.changed) {
|
|
1906
|
-
await writeFile(absoluteFile, updated.content, "utf8");
|
|
1907
|
-
touchedFiles.add(normalizeRelativePath(appRoot, absoluteFile));
|
|
1908
|
-
}
|
|
1909
|
-
}
|
|
1910
|
-
|
|
1911
|
-
await removeManagedViteProxyEntries({
|
|
1912
|
-
appRoot,
|
|
1913
|
-
packageId: resolvedTargetId,
|
|
1914
|
-
managedViteChanges: ensureObject(managed.vite),
|
|
1915
|
-
touchedFiles
|
|
1916
|
-
});
|
|
1917
|
-
|
|
1918
|
-
for (const fileChange of ensureArray(managed.files)) {
|
|
1919
|
-
const changeRecord = ensureObject(fileChange);
|
|
1920
|
-
if (changeRecord.preserveOnRemove === true) {
|
|
1921
|
-
continue;
|
|
1922
|
-
}
|
|
1923
|
-
const relativeFile = String(changeRecord.path || "").trim();
|
|
1924
|
-
if (!relativeFile) {
|
|
1925
|
-
continue;
|
|
1926
|
-
}
|
|
1927
|
-
const absoluteFile = path.join(appRoot, relativeFile);
|
|
1928
|
-
const existing = await readFileBufferIfExists(absoluteFile);
|
|
1929
|
-
if (!existing.exists) {
|
|
1930
|
-
continue;
|
|
1931
|
-
}
|
|
1932
|
-
if (hashBuffer(existing.buffer) !== String(changeRecord.hash || "")) {
|
|
1933
|
-
continue;
|
|
1934
|
-
}
|
|
1935
|
-
|
|
1936
|
-
if (changeRecord.hadPrevious) {
|
|
1937
|
-
const previousBuffer = Buffer.from(String(changeRecord.previousContentBase64 || ""), "base64");
|
|
1938
|
-
await writeFile(absoluteFile, previousBuffer);
|
|
1939
|
-
} else {
|
|
1940
|
-
await rm(absoluteFile);
|
|
1941
|
-
}
|
|
1942
|
-
touchedFiles.add(relativeFile);
|
|
1943
|
-
}
|
|
1944
|
-
|
|
1945
|
-
delete installed[resolvedTargetId];
|
|
1946
|
-
const touchedFileList = sortStrings([...touchedFiles]);
|
|
1947
|
-
|
|
1948
|
-
if (!options.dryRun) {
|
|
1949
|
-
await writeJsonFile(packageJsonPath, packageJson);
|
|
1950
|
-
await writeJsonFile(lockPath, lock);
|
|
1951
|
-
if (!options.noInstall) {
|
|
1952
|
-
await runNpmInstall(appRoot, io.stderr);
|
|
1953
|
-
}
|
|
1954
|
-
}
|
|
1955
|
-
|
|
1956
|
-
if (options.json) {
|
|
1957
|
-
io.stdout.write(`${JSON.stringify({
|
|
1958
|
-
removedPackage: resolvedTargetId,
|
|
1959
|
-
touchedFiles: touchedFileList,
|
|
1960
|
-
lockPath: normalizeRelativePath(appRoot, lockPath),
|
|
1961
|
-
dryRun: options.dryRun
|
|
1962
|
-
}, null, 2)}\n`);
|
|
1963
|
-
} else {
|
|
1964
|
-
io.stdout.write(`Removed package ${resolvedTargetId}.\n`);
|
|
1965
|
-
io.stdout.write(`Touched files (${touchedFileList.length}):\n`);
|
|
1966
|
-
for (const touchedFile of touchedFileList) {
|
|
1967
|
-
io.stdout.write(`- ${touchedFile}\n`);
|
|
1968
|
-
}
|
|
1969
|
-
io.stdout.write(`Lock file: ${normalizeRelativePath(appRoot, lockPath)}\n`);
|
|
1970
|
-
if (options.dryRun) {
|
|
1971
|
-
io.stdout.write("Dry run enabled: no files were written.\n");
|
|
1972
|
-
}
|
|
1973
|
-
}
|
|
1974
|
-
|
|
1975
|
-
return 0;
|
|
1976
|
-
}
|
|
1977
|
-
|
|
1978
|
-
async function commandDoctor({ cwd, options, stdout }) {
|
|
1979
|
-
const appRoot = await resolveAppRootFromCwd(cwd);
|
|
1980
|
-
const { lock } = await loadLockFile(appRoot);
|
|
1981
|
-
const packageRegistry = await loadPackageRegistry();
|
|
1982
|
-
const appLocalRegistry = await loadAppLocalPackageRegistry(appRoot);
|
|
1983
|
-
const combinedPackageRegistry = mergePackageRegistries(packageRegistry, appLocalRegistry);
|
|
1984
|
-
const issues = [];
|
|
1985
|
-
const installed = ensureObject(lock.installedPackages);
|
|
1986
|
-
await hydratePackageRegistryFromInstalledNodeModules({
|
|
1987
|
-
appRoot,
|
|
1988
|
-
packageRegistry: combinedPackageRegistry,
|
|
1989
|
-
seedPackageIds: Object.keys(installed)
|
|
1990
|
-
});
|
|
1991
|
-
|
|
1992
|
-
for (const [packageId, lockEntryValue] of Object.entries(installed)) {
|
|
1993
|
-
const lockEntry = ensureObject(lockEntryValue);
|
|
1994
|
-
if (!combinedPackageRegistry.has(packageId)) {
|
|
1995
|
-
issues.push(`Installed package not found in package registry: ${packageId}`);
|
|
1996
|
-
continue;
|
|
1997
|
-
}
|
|
1998
|
-
|
|
1999
|
-
const managed = ensureObject(lockEntry.managed);
|
|
2000
|
-
for (const fileChange of ensureArray(managed.files)) {
|
|
2001
|
-
const changeRecord = ensureObject(fileChange);
|
|
2002
|
-
const relativePath = String(changeRecord.path || "").trim();
|
|
2003
|
-
const absolutePath = path.join(appRoot, relativePath);
|
|
2004
|
-
if (!(await fileExists(absolutePath))) {
|
|
2005
|
-
issues.push(`${packageId}: managed file missing: ${relativePath}`);
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
}
|
|
2009
|
-
|
|
2010
|
-
const payload = {
|
|
2011
|
-
appRoot,
|
|
2012
|
-
lockVersion: lock.lockVersion,
|
|
2013
|
-
installedPackages: sortStrings(Object.keys(installed)),
|
|
2014
|
-
issues
|
|
2015
|
-
};
|
|
2016
|
-
|
|
2017
|
-
if (options.json) {
|
|
2018
|
-
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
2019
|
-
} else {
|
|
2020
|
-
stdout.write(`App root: ${appRoot}\n`);
|
|
2021
|
-
stdout.write(`Installed packages: ${payload.installedPackages.length}\n`);
|
|
2022
|
-
if (issues.length === 0) {
|
|
2023
|
-
stdout.write("Doctor status: healthy\n");
|
|
2024
|
-
} else {
|
|
2025
|
-
stdout.write(`Doctor status: unhealthy (${issues.length} issue(s))\n`);
|
|
2026
|
-
for (const issue of issues) {
|
|
2027
|
-
stdout.write(`- ${issue}\n`);
|
|
2028
|
-
}
|
|
2029
|
-
}
|
|
2030
|
-
}
|
|
2031
|
-
|
|
2032
|
-
return issues.length === 0 ? 0 : 1;
|
|
2033
|
-
}
|
|
2034
|
-
|
|
2035
|
-
async function commandLintDescriptors({ options, stdout }) {
|
|
2036
|
-
const packageRegistry = await loadPackageRegistry();
|
|
2037
|
-
const bundleRegistry = await loadBundleRegistry();
|
|
2038
|
-
const shouldCheckDiLabels = options.checkDiLabels === true;
|
|
2039
|
-
let diLabelIssues = [];
|
|
2040
|
-
if (shouldCheckDiLabels) {
|
|
2041
|
-
const issues = [];
|
|
2042
|
-
for (const packageId of sortStrings([...packageRegistry.keys()])) {
|
|
2043
|
-
const packageEntry = packageRegistry.get(packageId);
|
|
2044
|
-
if (!packageEntry) {
|
|
2045
|
-
continue;
|
|
2046
|
-
}
|
|
2047
|
-
const packageInsights = await inspectPackageOfferings({ packageEntry });
|
|
2048
|
-
issues.push(...collectDiLabelParityIssuesForPackage({ packageEntry, packageInsights }));
|
|
2049
|
-
}
|
|
2050
|
-
diLabelIssues = issues;
|
|
2051
|
-
}
|
|
2052
|
-
const payload = {
|
|
2053
|
-
packageCount: packageRegistry.size,
|
|
2054
|
-
bundleCount: bundleRegistry.size,
|
|
2055
|
-
packages: sortStrings([...packageRegistry.keys()]),
|
|
2056
|
-
bundles: sortStrings([...bundleRegistry.keys()]),
|
|
2057
|
-
diLabelCheck: shouldCheckDiLabels
|
|
2058
|
-
? {
|
|
2059
|
-
enabled: true,
|
|
2060
|
-
issueCount: diLabelIssues.length,
|
|
2061
|
-
issues: diLabelIssues
|
|
2062
|
-
}
|
|
2063
|
-
: {
|
|
2064
|
-
enabled: false
|
|
2065
|
-
}
|
|
2066
|
-
};
|
|
2067
|
-
|
|
2068
|
-
if (options.json) {
|
|
2069
|
-
stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
|
|
2070
|
-
} else {
|
|
2071
|
-
const descriptorStatus = shouldCheckDiLabels && diLabelIssues.length > 0 ? "failed" : "passed";
|
|
2072
|
-
stdout.write(`Descriptor lint ${descriptorStatus}.\n`);
|
|
2073
|
-
stdout.write(`Packages: ${payload.packageCount}\n`);
|
|
2074
|
-
stdout.write(`Bundles: ${payload.bundleCount}\n`);
|
|
2075
|
-
if (shouldCheckDiLabels) {
|
|
2076
|
-
if (diLabelIssues.length === 0) {
|
|
2077
|
-
stdout.write("DI label parity check passed.\n");
|
|
2078
|
-
} else {
|
|
2079
|
-
stdout.write(`DI label parity check failed (${diLabelIssues.length} issue(s)).\n`);
|
|
2080
|
-
for (const issue of diLabelIssues) {
|
|
2081
|
-
const code = String(issue?.code || "").trim();
|
|
2082
|
-
const codeLabel = code ? `[${code}] ` : "";
|
|
2083
|
-
stdout.write(`- ${codeLabel}${String(issue?.message || "").trim()}\n`);
|
|
2084
|
-
}
|
|
2085
|
-
}
|
|
2086
|
-
}
|
|
2087
|
-
}
|
|
2088
|
-
if (shouldCheckDiLabels && diLabelIssues.length > 0) {
|
|
2089
|
-
return 1;
|
|
2090
|
-
}
|
|
2091
|
-
return 0;
|
|
2092
|
-
}
|
|
2093
|
-
|
|
2094
|
-
return {
|
|
2095
|
-
commandList,
|
|
2096
|
-
commandShow,
|
|
2097
|
-
commandCreate,
|
|
2098
|
-
commandAdd,
|
|
2099
|
-
commandGenerate,
|
|
2100
|
-
commandMigrations,
|
|
2101
|
-
commandPosition,
|
|
2102
|
-
commandUpdate,
|
|
2103
|
-
commandRemove,
|
|
2104
|
-
commandDoctor,
|
|
2105
|
-
commandLintDescriptors
|
|
2106
|
-
};
|
|
2107
|
-
}
|
|
2108
|
-
|
|
2109
|
-
export { createCommandHandlers };
|