@getmonoceros/workbench 1.9.4 → 1.9.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin.js +181 -162
- package/dist/bin.js.map +1 -1
- package/package.json +1 -1
package/dist/bin.js
CHANGED
|
@@ -311,7 +311,7 @@ import { consola as consola2 } from "consola";
|
|
|
311
311
|
import { promises as fs8 } from "fs";
|
|
312
312
|
import { consola } from "consola";
|
|
313
313
|
import { createPatch } from "diff";
|
|
314
|
-
import
|
|
314
|
+
import path8 from "path";
|
|
315
315
|
|
|
316
316
|
// src/config/io.ts
|
|
317
317
|
import { promises as fs } from "fs";
|
|
@@ -2237,6 +2237,153 @@ import {
|
|
|
2237
2237
|
YAMLMap as YAMLMap2,
|
|
2238
2238
|
YAMLSeq
|
|
2239
2239
|
} from "yaml";
|
|
2240
|
+
|
|
2241
|
+
// src/init/manifest.ts
|
|
2242
|
+
import { existsSync as existsSync4, readFileSync as readFileSync2 } from "fs";
|
|
2243
|
+
import path7 from "path";
|
|
2244
|
+
function resolveManifestPath(name, checkoutRoot) {
|
|
2245
|
+
if (checkoutRoot) {
|
|
2246
|
+
const checkoutPath = path7.join(
|
|
2247
|
+
checkoutRoot,
|
|
2248
|
+
"images",
|
|
2249
|
+
"features",
|
|
2250
|
+
name,
|
|
2251
|
+
"devcontainer-feature.json"
|
|
2252
|
+
);
|
|
2253
|
+
if (existsSync4(checkoutPath)) return checkoutPath;
|
|
2254
|
+
}
|
|
2255
|
+
const bundlePath = path7.join(
|
|
2256
|
+
bundledFeaturesDir(),
|
|
2257
|
+
name,
|
|
2258
|
+
"devcontainer-feature.json"
|
|
2259
|
+
);
|
|
2260
|
+
if (existsSync4(bundlePath)) return bundlePath;
|
|
2261
|
+
return null;
|
|
2262
|
+
}
|
|
2263
|
+
function loadFeatureManifestSummary(ref, checkoutRoot = workbenchCheckoutRoot()) {
|
|
2264
|
+
const match = matchMonocerosFeature(ref);
|
|
2265
|
+
if (!match) return void 0;
|
|
2266
|
+
const manifestPath = resolveManifestPath(match.name, checkoutRoot);
|
|
2267
|
+
if (!manifestPath) return void 0;
|
|
2268
|
+
try {
|
|
2269
|
+
const text = readFileSync2(manifestPath, "utf8");
|
|
2270
|
+
const parsed = JSON.parse(text);
|
|
2271
|
+
const rawHints = parsed["x-monoceros"]?.optionHints;
|
|
2272
|
+
const optionHints = Array.isArray(rawHints) ? rawHints.filter(
|
|
2273
|
+
(x) => typeof x === "string" && x.length > 0
|
|
2274
|
+
) : [];
|
|
2275
|
+
const rawNotes = parsed["x-monoceros"]?.usageNotes;
|
|
2276
|
+
const usageNotes = Array.isArray(rawNotes) ? rawNotes.filter(
|
|
2277
|
+
(x) => typeof x === "string" && x.length > 0
|
|
2278
|
+
) : [];
|
|
2279
|
+
const optionDescriptions = {};
|
|
2280
|
+
const optionTypes = {};
|
|
2281
|
+
const optionNames = [];
|
|
2282
|
+
if (parsed.options) {
|
|
2283
|
+
for (const [key, opt] of Object.entries(parsed.options)) {
|
|
2284
|
+
if (!opt || typeof opt !== "object") continue;
|
|
2285
|
+
optionNames.push(key);
|
|
2286
|
+
if (typeof opt.description === "string" && opt.description.length > 0) {
|
|
2287
|
+
optionDescriptions[key] = opt.description;
|
|
2288
|
+
}
|
|
2289
|
+
if (opt.type === "boolean") {
|
|
2290
|
+
optionTypes[key] = "boolean";
|
|
2291
|
+
} else if (opt.type === "string") {
|
|
2292
|
+
optionTypes[key] = "string";
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
}
|
|
2296
|
+
const name = typeof parsed.name === "string" ? parsed.name : "";
|
|
2297
|
+
const description = typeof parsed.description === "string" ? parsed.description : "";
|
|
2298
|
+
const rawUrl = typeof parsed.documentationURL === "string" ? parsed.documentationURL.trim() : "";
|
|
2299
|
+
const documentationURL = rawUrl.length > 0 && rawUrl.toLowerCase() !== "tbd" ? rawUrl : void 0;
|
|
2300
|
+
return {
|
|
2301
|
+
name,
|
|
2302
|
+
description,
|
|
2303
|
+
documentationURL,
|
|
2304
|
+
optionHints,
|
|
2305
|
+
optionDescriptions,
|
|
2306
|
+
optionNames,
|
|
2307
|
+
optionTypes,
|
|
2308
|
+
usageNotes
|
|
2309
|
+
};
|
|
2310
|
+
} catch {
|
|
2311
|
+
return void 0;
|
|
2312
|
+
}
|
|
2313
|
+
}
|
|
2314
|
+
|
|
2315
|
+
// src/init/feature-doc.ts
|
|
2316
|
+
function buildFeatureHeaderLines(summary, width) {
|
|
2317
|
+
const paragraphs = buildHeaderParagraphs(summary);
|
|
2318
|
+
const wrapped = [];
|
|
2319
|
+
for (const para of paragraphs) {
|
|
2320
|
+
for (const line of wrapToComment(para, width)) {
|
|
2321
|
+
wrapped.push(line);
|
|
2322
|
+
}
|
|
2323
|
+
}
|
|
2324
|
+
return wrapped;
|
|
2325
|
+
}
|
|
2326
|
+
function buildFeatureHeaderCommentBefore(summary, width) {
|
|
2327
|
+
const lines = buildFeatureHeaderLines(summary, width);
|
|
2328
|
+
return lines.map((l) => ` ${l}`).join("\n");
|
|
2329
|
+
}
|
|
2330
|
+
function buildHeaderParagraphs(summary) {
|
|
2331
|
+
if (!summary) return [];
|
|
2332
|
+
const out = [];
|
|
2333
|
+
const tagline = summary.name?.trim();
|
|
2334
|
+
const description = summary.description?.trim();
|
|
2335
|
+
if (tagline && description) {
|
|
2336
|
+
out.push(`${tagline} \u2014 ${description}`);
|
|
2337
|
+
} else if (tagline) {
|
|
2338
|
+
out.push(tagline);
|
|
2339
|
+
} else if (description) {
|
|
2340
|
+
out.push(description);
|
|
2341
|
+
}
|
|
2342
|
+
for (const note of summary.usageNotes) {
|
|
2343
|
+
const trimmed = note.trim();
|
|
2344
|
+
if (trimmed.length > 0) out.push(trimmed);
|
|
2345
|
+
}
|
|
2346
|
+
if (summary.optionHints.length > 0) {
|
|
2347
|
+
const parts = summary.optionHints.map((key) => {
|
|
2348
|
+
const desc = summary.optionDescriptions[key];
|
|
2349
|
+
const short = desc ? shortenOptionDescription(desc) : void 0;
|
|
2350
|
+
return short ? `${key} (${short})` : key;
|
|
2351
|
+
});
|
|
2352
|
+
out.push(`Options: ${parts.join(", ")}.`);
|
|
2353
|
+
}
|
|
2354
|
+
if (summary.documentationURL) {
|
|
2355
|
+
out.push(`See ${summary.documentationURL} for further information.`);
|
|
2356
|
+
}
|
|
2357
|
+
return out;
|
|
2358
|
+
}
|
|
2359
|
+
function shortenOptionDescription(desc) {
|
|
2360
|
+
const firstSentence = desc.split(/(?<=[.!?])\s+/)[0]?.trim() ?? desc.trim();
|
|
2361
|
+
return firstSentence.replace(/[.!?]+$/, "").trim();
|
|
2362
|
+
}
|
|
2363
|
+
function wrapToComment(text, width) {
|
|
2364
|
+
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
2365
|
+
if (words.length === 0) return [""];
|
|
2366
|
+
const usable = Math.max(width, 20);
|
|
2367
|
+
const lines = [];
|
|
2368
|
+
let current = "";
|
|
2369
|
+
for (const w of words) {
|
|
2370
|
+
if (current.length === 0) {
|
|
2371
|
+
current = w;
|
|
2372
|
+
continue;
|
|
2373
|
+
}
|
|
2374
|
+
if (current.length + 1 + w.length <= usable) {
|
|
2375
|
+
current += " " + w;
|
|
2376
|
+
} else {
|
|
2377
|
+
lines.push(current);
|
|
2378
|
+
current = w;
|
|
2379
|
+
}
|
|
2380
|
+
}
|
|
2381
|
+
if (current.length > 0) lines.push(current);
|
|
2382
|
+
return lines;
|
|
2383
|
+
}
|
|
2384
|
+
var FEATURE_HEADER_WIDTH = 76 - 2;
|
|
2385
|
+
|
|
2386
|
+
// src/modify/yml.ts
|
|
2240
2387
|
function ensureSeq(doc, key) {
|
|
2241
2388
|
const existing = doc.get(key, true);
|
|
2242
2389
|
if (existing && isSeq(existing)) return existing;
|
|
@@ -2474,6 +2621,15 @@ function addFeatureToDoc(doc, ref, options = {}, displayName) {
|
|
|
2474
2621
|
if (Object.keys(options).length > 0) {
|
|
2475
2622
|
entry2.set("options", options);
|
|
2476
2623
|
}
|
|
2624
|
+
const summary = loadFeatureManifestSummary(ref);
|
|
2625
|
+
const headerBefore = buildFeatureHeaderCommentBefore(
|
|
2626
|
+
summary,
|
|
2627
|
+
FEATURE_HEADER_WIDTH
|
|
2628
|
+
);
|
|
2629
|
+
if (headerBefore.length > 0) {
|
|
2630
|
+
entry2.commentBefore = headerBefore;
|
|
2631
|
+
entry2.spaceBefore = true;
|
|
2632
|
+
}
|
|
2477
2633
|
seq.add(entry2);
|
|
2478
2634
|
return true;
|
|
2479
2635
|
}
|
|
@@ -2512,7 +2668,6 @@ function addRepoToDoc(doc, repo) {
|
|
|
2512
2668
|
} else {
|
|
2513
2669
|
item.delete("provider");
|
|
2514
2670
|
}
|
|
2515
|
-
relocateLeakedSectionComments(doc);
|
|
2516
2671
|
return true;
|
|
2517
2672
|
}
|
|
2518
2673
|
const entry2 = new YAMLMap2();
|
|
@@ -2545,7 +2700,6 @@ function addRepoToDoc(doc, repo) {
|
|
|
2545
2700
|
entry2.comment = hintLines.join("\n");
|
|
2546
2701
|
}
|
|
2547
2702
|
seq.add(entry2);
|
|
2548
|
-
relocateLeakedSectionComments(doc);
|
|
2549
2703
|
return true;
|
|
2550
2704
|
}
|
|
2551
2705
|
function removeLanguageFromDoc(doc, lang) {
|
|
@@ -2779,7 +2933,7 @@ async function tryCloneInRunningContainer(input, entry2) {
|
|
|
2779
2933
|
logger.info(
|
|
2780
2934
|
`Cloned ${entry2.url} into /workspaces/${containerName2}/${targetRel} inside the running container.`
|
|
2781
2935
|
);
|
|
2782
|
-
void
|
|
2936
|
+
void path8;
|
|
2783
2937
|
}
|
|
2784
2938
|
function shquote(value) {
|
|
2785
2939
|
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
@@ -2976,6 +3130,7 @@ async function mutate(opts, apply) {
|
|
|
2976
3130
|
logger.info("No changes \u2014 yml is already in the desired state.");
|
|
2977
3131
|
return { status: "no-change" };
|
|
2978
3132
|
}
|
|
3133
|
+
relocateLeakedSectionComments(parsed.doc);
|
|
2979
3134
|
const newText = stringifyConfig(parsed.doc);
|
|
2980
3135
|
parseConfig(newText, ymlPath);
|
|
2981
3136
|
const out = opts.output ?? ((line) => process.stdout.write(line + "\n"));
|
|
@@ -3457,12 +3612,12 @@ var addServiceCommand = defineCommand7({
|
|
|
3457
3612
|
import { defineCommand as defineCommand8 } from "citty";
|
|
3458
3613
|
|
|
3459
3614
|
// src/apply/index.ts
|
|
3460
|
-
import { existsSync as
|
|
3615
|
+
import { existsSync as existsSync6, promises as fs11 } from "fs";
|
|
3461
3616
|
import { consola as consola11 } from "consola";
|
|
3462
3617
|
|
|
3463
3618
|
// src/config/state.ts
|
|
3464
3619
|
import { promises as fs9 } from "fs";
|
|
3465
|
-
import
|
|
3620
|
+
import path9 from "path";
|
|
3466
3621
|
function buildStateFile(opts) {
|
|
3467
3622
|
return {
|
|
3468
3623
|
schemaVersion: CONFIG_SCHEMA_VERSION,
|
|
@@ -3472,7 +3627,7 @@ function buildStateFile(opts) {
|
|
|
3472
3627
|
};
|
|
3473
3628
|
}
|
|
3474
3629
|
function stateFilePath(targetDir) {
|
|
3475
|
-
return
|
|
3630
|
+
return path9.join(targetDir, ".monoceros", "state.json");
|
|
3476
3631
|
}
|
|
3477
3632
|
async function readStateFile(targetDir) {
|
|
3478
3633
|
try {
|
|
@@ -3483,7 +3638,7 @@ async function readStateFile(targetDir) {
|
|
|
3483
3638
|
}
|
|
3484
3639
|
}
|
|
3485
3640
|
async function writeStateFile(targetDir, state) {
|
|
3486
|
-
const monocerosDir =
|
|
3641
|
+
const monocerosDir = path9.join(targetDir, ".monoceros");
|
|
3487
3642
|
await fs9.mkdir(monocerosDir, { recursive: true });
|
|
3488
3643
|
await fs9.writeFile(
|
|
3489
3644
|
stateFilePath(targetDir),
|
|
@@ -3555,8 +3710,8 @@ function solutionConfigToCreateOptions(config, featureDefaults = {}) {
|
|
|
3555
3710
|
|
|
3556
3711
|
// src/devcontainer/compose.ts
|
|
3557
3712
|
import { spawn as spawn5 } from "child_process";
|
|
3558
|
-
import { existsSync as
|
|
3559
|
-
import
|
|
3713
|
+
import { existsSync as existsSync5 } from "fs";
|
|
3714
|
+
import path11 from "path";
|
|
3560
3715
|
import { consola as consola9 } from "consola";
|
|
3561
3716
|
|
|
3562
3717
|
// src/util/mask-secrets.ts
|
|
@@ -3617,20 +3772,20 @@ function createSecretMaskStream() {
|
|
|
3617
3772
|
|
|
3618
3773
|
// src/devcontainer/cli.ts
|
|
3619
3774
|
import { spawn as spawn4 } from "child_process";
|
|
3620
|
-
import { readFileSync as
|
|
3775
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
3621
3776
|
import { createRequire } from "module";
|
|
3622
|
-
import
|
|
3777
|
+
import path10 from "path";
|
|
3623
3778
|
var require_ = createRequire(import.meta.url);
|
|
3624
3779
|
var cachedBinaryPath = null;
|
|
3625
3780
|
function devcontainerCliPath() {
|
|
3626
3781
|
if (cachedBinaryPath) return cachedBinaryPath;
|
|
3627
3782
|
const pkgJsonPath = require_.resolve("@devcontainers/cli/package.json");
|
|
3628
|
-
const pkg = JSON.parse(
|
|
3783
|
+
const pkg = JSON.parse(readFileSync3(pkgJsonPath, "utf8"));
|
|
3629
3784
|
const binEntry = typeof pkg.bin === "string" ? pkg.bin : pkg.bin?.devcontainer ?? "";
|
|
3630
3785
|
if (!binEntry) {
|
|
3631
3786
|
throw new Error("Could not resolve @devcontainers/cli bin entry.");
|
|
3632
3787
|
}
|
|
3633
|
-
cachedBinaryPath =
|
|
3788
|
+
cachedBinaryPath = path10.resolve(path10.dirname(pkgJsonPath), binEntry);
|
|
3634
3789
|
return cachedBinaryPath;
|
|
3635
3790
|
}
|
|
3636
3791
|
var spawnDevcontainer = (args, cwd, options = {}) => {
|
|
@@ -3702,16 +3857,16 @@ var spawnBash = (args, cwd) => {
|
|
|
3702
3857
|
});
|
|
3703
3858
|
};
|
|
3704
3859
|
function composeProjectName(root) {
|
|
3705
|
-
return `${
|
|
3860
|
+
return `${path11.basename(root)}_devcontainer`;
|
|
3706
3861
|
}
|
|
3707
3862
|
function resolveCompose(root) {
|
|
3708
|
-
if (!
|
|
3863
|
+
if (!existsSync5(path11.join(root, ".devcontainer"))) {
|
|
3709
3864
|
throw new Error(
|
|
3710
3865
|
`No .devcontainer/ at ${root}. Run \`monoceros apply <name>\` first.`
|
|
3711
3866
|
);
|
|
3712
3867
|
}
|
|
3713
|
-
const composeFile =
|
|
3714
|
-
if (!
|
|
3868
|
+
const composeFile = path11.join(root, ".devcontainer", "compose.yaml");
|
|
3869
|
+
if (!existsSync5(composeFile)) {
|
|
3715
3870
|
throw new Error(
|
|
3716
3871
|
`No compose.yaml at ${composeFile}. \`start\` / \`stop\` / \`status\` / \`logs\` require services configured via \`monoceros add-service <name> <svc>\`. Use \`monoceros shell <name>\` to enter the container directly.`
|
|
3717
3872
|
);
|
|
@@ -4006,7 +4161,7 @@ function formatRootlessNotSupportedError() {
|
|
|
4006
4161
|
// src/devcontainer/identity.ts
|
|
4007
4162
|
import { spawn as spawn8 } from "child_process";
|
|
4008
4163
|
import { promises as fs10 } from "fs";
|
|
4009
|
-
import
|
|
4164
|
+
import path12 from "path";
|
|
4010
4165
|
import { consola as consola10 } from "consola";
|
|
4011
4166
|
var realGitConfigGet = (key) => {
|
|
4012
4167
|
return new Promise((resolve, reject) => {
|
|
@@ -4120,8 +4275,8 @@ async function resolveIdentityWithPrompt(options = {}) {
|
|
|
4120
4275
|
};
|
|
4121
4276
|
}
|
|
4122
4277
|
async function collectGitIdentity(devContainerRoot, options = {}) {
|
|
4123
|
-
const gitconfigDir =
|
|
4124
|
-
const gitconfigPath =
|
|
4278
|
+
const gitconfigDir = path12.join(devContainerRoot, ".monoceros");
|
|
4279
|
+
const gitconfigPath = path12.join(gitconfigDir, "gitconfig");
|
|
4125
4280
|
const logger = options.logger ?? { info: () => {
|
|
4126
4281
|
}, warn: () => {
|
|
4127
4282
|
} };
|
|
@@ -4211,7 +4366,7 @@ ${sectionLine(label)}
|
|
|
4211
4366
|
);
|
|
4212
4367
|
}
|
|
4213
4368
|
const ymlPath = containerConfigPath(opts.name, home);
|
|
4214
|
-
if (!
|
|
4369
|
+
if (!existsSync6(ymlPath)) {
|
|
4215
4370
|
throw new Error(
|
|
4216
4371
|
`No such config: ${ymlPath}. Run \`monoceros init <template> ${opts.name}\` first.`
|
|
4217
4372
|
);
|
|
@@ -4340,7 +4495,7 @@ ${sectionLine(label)}
|
|
|
4340
4495
|
return { targetDir, configPath: ymlPath, containerExitCode: exitCode };
|
|
4341
4496
|
}
|
|
4342
4497
|
async function assertSafeTargetDir(targetDir, expectedOrigin) {
|
|
4343
|
-
if (!
|
|
4498
|
+
if (!existsSync6(targetDir)) return;
|
|
4344
4499
|
const entries = await fs11.readdir(targetDir);
|
|
4345
4500
|
if (entries.length === 0) return;
|
|
4346
4501
|
const state = await readStateFile(targetDir);
|
|
@@ -4433,7 +4588,7 @@ async function persistPromptedIdentity(prompted, ymlPath, home, logger) {
|
|
|
4433
4588
|
}
|
|
4434
4589
|
|
|
4435
4590
|
// src/version.ts
|
|
4436
|
-
var CLI_VERSION = true ? "1.9.
|
|
4591
|
+
var CLI_VERSION = true ? "1.9.6" : "dev";
|
|
4437
4592
|
|
|
4438
4593
|
// src/commands/_dispatch.ts
|
|
4439
4594
|
import { consola as consola12 } from "consola";
|
|
@@ -4595,82 +4750,6 @@ import { defineCommand as defineCommand10 } from "citty";
|
|
|
4595
4750
|
// src/completion/resolve.ts
|
|
4596
4751
|
import { existsSync as existsSync7, promises as fs12 } from "fs";
|
|
4597
4752
|
import path13 from "path";
|
|
4598
|
-
|
|
4599
|
-
// src/init/manifest.ts
|
|
4600
|
-
import { existsSync as existsSync6, readFileSync as readFileSync3 } from "fs";
|
|
4601
|
-
import path12 from "path";
|
|
4602
|
-
function resolveManifestPath(name, checkoutRoot) {
|
|
4603
|
-
if (checkoutRoot) {
|
|
4604
|
-
const checkoutPath = path12.join(
|
|
4605
|
-
checkoutRoot,
|
|
4606
|
-
"images",
|
|
4607
|
-
"features",
|
|
4608
|
-
name,
|
|
4609
|
-
"devcontainer-feature.json"
|
|
4610
|
-
);
|
|
4611
|
-
if (existsSync6(checkoutPath)) return checkoutPath;
|
|
4612
|
-
}
|
|
4613
|
-
const bundlePath = path12.join(
|
|
4614
|
-
bundledFeaturesDir(),
|
|
4615
|
-
name,
|
|
4616
|
-
"devcontainer-feature.json"
|
|
4617
|
-
);
|
|
4618
|
-
if (existsSync6(bundlePath)) return bundlePath;
|
|
4619
|
-
return null;
|
|
4620
|
-
}
|
|
4621
|
-
function loadFeatureManifestSummary(ref, checkoutRoot = workbenchCheckoutRoot()) {
|
|
4622
|
-
const match = matchMonocerosFeature(ref);
|
|
4623
|
-
if (!match) return void 0;
|
|
4624
|
-
const manifestPath = resolveManifestPath(match.name, checkoutRoot);
|
|
4625
|
-
if (!manifestPath) return void 0;
|
|
4626
|
-
try {
|
|
4627
|
-
const text = readFileSync3(manifestPath, "utf8");
|
|
4628
|
-
const parsed = JSON.parse(text);
|
|
4629
|
-
const rawHints = parsed["x-monoceros"]?.optionHints;
|
|
4630
|
-
const optionHints = Array.isArray(rawHints) ? rawHints.filter(
|
|
4631
|
-
(x) => typeof x === "string" && x.length > 0
|
|
4632
|
-
) : [];
|
|
4633
|
-
const rawNotes = parsed["x-monoceros"]?.usageNotes;
|
|
4634
|
-
const usageNotes = Array.isArray(rawNotes) ? rawNotes.filter(
|
|
4635
|
-
(x) => typeof x === "string" && x.length > 0
|
|
4636
|
-
) : [];
|
|
4637
|
-
const optionDescriptions = {};
|
|
4638
|
-
const optionTypes = {};
|
|
4639
|
-
const optionNames = [];
|
|
4640
|
-
if (parsed.options) {
|
|
4641
|
-
for (const [key, opt] of Object.entries(parsed.options)) {
|
|
4642
|
-
if (!opt || typeof opt !== "object") continue;
|
|
4643
|
-
optionNames.push(key);
|
|
4644
|
-
if (typeof opt.description === "string" && opt.description.length > 0) {
|
|
4645
|
-
optionDescriptions[key] = opt.description;
|
|
4646
|
-
}
|
|
4647
|
-
if (opt.type === "boolean") {
|
|
4648
|
-
optionTypes[key] = "boolean";
|
|
4649
|
-
} else if (opt.type === "string") {
|
|
4650
|
-
optionTypes[key] = "string";
|
|
4651
|
-
}
|
|
4652
|
-
}
|
|
4653
|
-
}
|
|
4654
|
-
const name = typeof parsed.name === "string" ? parsed.name : "";
|
|
4655
|
-
const description = typeof parsed.description === "string" ? parsed.description : "";
|
|
4656
|
-
const rawUrl = typeof parsed.documentationURL === "string" ? parsed.documentationURL.trim() : "";
|
|
4657
|
-
const documentationURL = rawUrl.length > 0 && rawUrl.toLowerCase() !== "tbd" ? rawUrl : void 0;
|
|
4658
|
-
return {
|
|
4659
|
-
name,
|
|
4660
|
-
description,
|
|
4661
|
-
documentationURL,
|
|
4662
|
-
optionHints,
|
|
4663
|
-
optionDescriptions,
|
|
4664
|
-
optionNames,
|
|
4665
|
-
optionTypes,
|
|
4666
|
-
usageNotes
|
|
4667
|
-
};
|
|
4668
|
-
} catch {
|
|
4669
|
-
return void 0;
|
|
4670
|
-
}
|
|
4671
|
-
}
|
|
4672
|
-
|
|
4673
|
-
// src/completion/resolve.ts
|
|
4674
4753
|
async function resolveCompletions(line, point, opts = {}) {
|
|
4675
4754
|
const { prev, current } = parseCompletionLine(line, point);
|
|
4676
4755
|
const ctx = { prev, current, opts };
|
|
@@ -5306,12 +5385,8 @@ function routingHeader(name) {
|
|
|
5306
5385
|
}
|
|
5307
5386
|
function renderFeatureBlock(out, feature, summary, commented) {
|
|
5308
5387
|
const yamlPrefix = commented ? "# " : "";
|
|
5309
|
-
const
|
|
5310
|
-
|
|
5311
|
-
const wrapped = wrapToComment(line, COMMENT_WIDTH - 2);
|
|
5312
|
-
for (const wl of wrapped) {
|
|
5313
|
-
out.push(`# ${wl}`.trimEnd());
|
|
5314
|
-
}
|
|
5388
|
+
for (const wl of buildFeatureHeaderLines(summary, COMMENT_WIDTH - 2)) {
|
|
5389
|
+
out.push(`# ${wl}`.trimEnd());
|
|
5315
5390
|
}
|
|
5316
5391
|
out.push(`${yamlPrefix} - ref: ${feature.ref}`);
|
|
5317
5392
|
const options = feature.options ?? {};
|
|
@@ -5341,41 +5416,6 @@ function renderFeatureBlock(out, feature, summary, commented) {
|
|
|
5341
5416
|
}
|
|
5342
5417
|
}
|
|
5343
5418
|
}
|
|
5344
|
-
function buildHeaderLines(summary) {
|
|
5345
|
-
const out = [];
|
|
5346
|
-
if (!summary) {
|
|
5347
|
-
return out;
|
|
5348
|
-
}
|
|
5349
|
-
const tagline = summary.name?.trim();
|
|
5350
|
-
const description = summary.description?.trim();
|
|
5351
|
-
if (tagline && description) {
|
|
5352
|
-
out.push(`${tagline} \u2014 ${description}`);
|
|
5353
|
-
} else if (tagline) {
|
|
5354
|
-
out.push(tagline);
|
|
5355
|
-
} else if (description) {
|
|
5356
|
-
out.push(description);
|
|
5357
|
-
}
|
|
5358
|
-
for (const note of summary.usageNotes) {
|
|
5359
|
-
const trimmed = note.trim();
|
|
5360
|
-
if (trimmed.length > 0) out.push(trimmed);
|
|
5361
|
-
}
|
|
5362
|
-
if (summary.optionHints.length > 0) {
|
|
5363
|
-
const parts = summary.optionHints.map((key) => {
|
|
5364
|
-
const desc = summary.optionDescriptions[key];
|
|
5365
|
-
const short = desc ? shortenOptionDescription(desc) : void 0;
|
|
5366
|
-
return short ? `${key} (${short})` : key;
|
|
5367
|
-
});
|
|
5368
|
-
out.push(`Options: ${parts.join(", ")}.`);
|
|
5369
|
-
}
|
|
5370
|
-
if (summary.documentationURL) {
|
|
5371
|
-
out.push(`See ${summary.documentationURL} for further information.`);
|
|
5372
|
-
}
|
|
5373
|
-
return out;
|
|
5374
|
-
}
|
|
5375
|
-
function shortenOptionDescription(desc) {
|
|
5376
|
-
const firstSentence = desc.split(/(?<=[.!?])\s+/)[0]?.trim() ?? desc.trim();
|
|
5377
|
-
return firstSentence.replace(/[.!?]+$/, "").trim();
|
|
5378
|
-
}
|
|
5379
5419
|
function pushHeader(out, header, name) {
|
|
5380
5420
|
for (const line of header.replace(/<name>/g, name).split("\n")) {
|
|
5381
5421
|
out.push(line);
|
|
@@ -5388,27 +5428,6 @@ function pushSectionHeader(out, text, _commented) {
|
|
|
5388
5428
|
out.push(`# ${wl}`.trimEnd());
|
|
5389
5429
|
}
|
|
5390
5430
|
}
|
|
5391
|
-
function wrapToComment(text, width) {
|
|
5392
|
-
const words = text.split(/\s+/).filter((w) => w.length > 0);
|
|
5393
|
-
if (words.length === 0) return [""];
|
|
5394
|
-
const usable = Math.max(width, 20);
|
|
5395
|
-
const lines = [];
|
|
5396
|
-
let current = "";
|
|
5397
|
-
for (const w of words) {
|
|
5398
|
-
if (current.length === 0) {
|
|
5399
|
-
current = w;
|
|
5400
|
-
continue;
|
|
5401
|
-
}
|
|
5402
|
-
if (current.length + 1 + w.length <= usable) {
|
|
5403
|
-
current += " " + w;
|
|
5404
|
-
} else {
|
|
5405
|
-
lines.push(current);
|
|
5406
|
-
current = w;
|
|
5407
|
-
}
|
|
5408
|
-
}
|
|
5409
|
-
if (current.length > 0) lines.push(current);
|
|
5410
|
-
return lines;
|
|
5411
|
-
}
|
|
5412
5431
|
function renderScalarValue(value) {
|
|
5413
5432
|
if (typeof value === "string") {
|
|
5414
5433
|
return /^[A-Za-z_][A-Za-z0-9._-]*$/.test(value) ? value : JSON.stringify(value);
|