clispark 1.14.0 → 1.15.0
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/cli.js +255 -41
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
- package/templates/dotnet/ARCHITECTURE.md +77 -0
- package/templates/dotnet/Cli.slnx +8 -0
- package/templates/dotnet/README.md +45 -0
- package/templates/dotnet/gitignore +4 -0
- package/templates/dotnet/src/Cli.csproj +24 -0
- package/templates/dotnet/src/CliUserException.cs +4 -0
- package/templates/dotnet/src/CommandDiscovery.cs +48 -0
- package/templates/dotnet/src/CommandPathAttribute.cs +12 -0
- package/templates/dotnet/src/Commands/HelloCommand.cs +28 -0
- package/templates/dotnet/src/Commands/TaskCommand.cs +28 -0
- package/templates/dotnet/src/Commands/TaskCompleteCommand.cs +30 -0
- package/templates/dotnet/src/Commands/TaskListCommand.cs +34 -0
- package/templates/dotnet/src/ICliCommand.cs +8 -0
- package/templates/dotnet/src/Logging/CliLoggerFactory.cs +70 -0
- package/templates/dotnet/src/Logging/SensitivePropertyEnricher.cs +19 -0
- package/templates/dotnet/src/Program.cs +35 -0
- package/templates/dotnet/tests/Cli.Tests.csproj +25 -0
- package/templates/dotnet/tests/HelloCommandTests.cs +28 -0
- package/templates/dotnet/tests/TaskCompleteCommandTests.cs +34 -0
package/dist/cli.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
|
-
import
|
|
4
|
+
import path12 from "path";
|
|
5
5
|
import { Command } from "commander";
|
|
6
6
|
|
|
7
7
|
// src/wizard.ts
|
|
@@ -212,9 +212,14 @@ async function applyPrivateIntent(targetDir) {
|
|
|
212
212
|
pkg.private = true;
|
|
213
213
|
await writeFile2(packageJsonPath, JSON.stringify(pkg, null, 2) + "\n");
|
|
214
214
|
}
|
|
215
|
+
async function applyRegistryUrl(targetDir, registryUrl) {
|
|
216
|
+
await writeFile2(path3.join(targetDir, ".npmrc"), `registry=${registryUrl}
|
|
217
|
+
`);
|
|
218
|
+
}
|
|
215
219
|
var npmRegistryChecker = {
|
|
216
220
|
checkNameAvailability,
|
|
217
|
-
applyPrivateIntent
|
|
221
|
+
applyPrivateIntent,
|
|
222
|
+
applyRegistryUrl
|
|
218
223
|
};
|
|
219
224
|
|
|
220
225
|
// src/languages/packs/node-oclif.ts
|
|
@@ -239,13 +244,223 @@ var nodeOclifPack = {
|
|
|
239
244
|
defaultUrl: NPM_DEFAULT_REGISTRY_URL,
|
|
240
245
|
promptLabel: "Custom npm registry URL (leave empty for npmjs.org)",
|
|
241
246
|
checkNameAvailability: npmRegistryChecker.checkNameAvailability,
|
|
242
|
-
applyPrivateIntent: npmRegistryChecker.applyPrivateIntent
|
|
247
|
+
applyPrivateIntent: npmRegistryChecker.applyPrivateIntent,
|
|
248
|
+
applyRegistryUrl: npmRegistryChecker.applyRegistryUrl
|
|
249
|
+
}
|
|
250
|
+
};
|
|
251
|
+
|
|
252
|
+
// src/languages/packs/dotnet.ts
|
|
253
|
+
import path7 from "path";
|
|
254
|
+
|
|
255
|
+
// src/update/adapters/dotnet.ts
|
|
256
|
+
import { readFile as readFile3, writeFile as writeFile3 } from "fs/promises";
|
|
257
|
+
import path5 from "path";
|
|
258
|
+
var CORE_FILE_PATHS2 = [
|
|
259
|
+
"Cli.slnx",
|
|
260
|
+
"src/Program.cs",
|
|
261
|
+
"src/ICliCommand.cs",
|
|
262
|
+
"src/CommandPathAttribute.cs",
|
|
263
|
+
"src/CommandDiscovery.cs",
|
|
264
|
+
"src/CliUserException.cs",
|
|
265
|
+
"src/Logging/CliLoggerFactory.cs",
|
|
266
|
+
"src/Logging/SensitivePropertyEnricher.cs",
|
|
267
|
+
"tests/Cli.Tests.csproj",
|
|
268
|
+
"ARCHITECTURE.md",
|
|
269
|
+
".gitignore"
|
|
270
|
+
];
|
|
271
|
+
function escapeRegExp(value) {
|
|
272
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
273
|
+
}
|
|
274
|
+
function extractTag(content, tag) {
|
|
275
|
+
const match = content.match(new RegExp(`<${tag}>([^<]*)</${tag}>`));
|
|
276
|
+
if (!match) throw new Error(`.csproj is missing a <${tag}> tag`);
|
|
277
|
+
return match[1];
|
|
278
|
+
}
|
|
279
|
+
function extractPackageReferences(content) {
|
|
280
|
+
const refs = {};
|
|
281
|
+
const re = /<PackageReference\s+Include="([^"]+)"\s+Version="([^"]+)"\s*\/>/g;
|
|
282
|
+
let m;
|
|
283
|
+
while (m = re.exec(content)) {
|
|
284
|
+
refs[m[1]] = m[2];
|
|
285
|
+
}
|
|
286
|
+
return refs;
|
|
287
|
+
}
|
|
288
|
+
function setTag(content, tag, value) {
|
|
289
|
+
const escapedTag = escapeRegExp(tag);
|
|
290
|
+
return content.replace(new RegExp(`(<${escapedTag}>)[^<]*(</${escapedTag}>)`), `$1${value}$2`);
|
|
291
|
+
}
|
|
292
|
+
function setPackageReferenceVersion(content, name, version) {
|
|
293
|
+
const re = new RegExp(`(<PackageReference\\s+Include="${escapeRegExp(name)}"\\s+Version=")[^"]+(")`);
|
|
294
|
+
return content.replace(re, `$1${version}$2`);
|
|
295
|
+
}
|
|
296
|
+
function addPackageReference(content, name, version) {
|
|
297
|
+
const re = /^([ \t]*)<PackageReference[^\n]*\/>\n(?=[ \t]*<\/ItemGroup>)/m;
|
|
298
|
+
return content.replace(re, (match, indent) => `${match}${indent}<PackageReference Include="${name}" Version="${version}" />
|
|
299
|
+
`);
|
|
300
|
+
}
|
|
301
|
+
function parseManifestFile(rawContent) {
|
|
302
|
+
return {
|
|
303
|
+
raw: rawContent,
|
|
304
|
+
version: extractTag(rawContent, "Version"),
|
|
305
|
+
targetFramework: extractTag(rawContent, "TargetFramework"),
|
|
306
|
+
packageId: extractTag(rawContent, "PackageId"),
|
|
307
|
+
toolCommandName: extractTag(rawContent, "ToolCommandName"),
|
|
308
|
+
packageReferences: extractPackageReferences(rawContent)
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
function extractCoreFields2(manifestFile) {
|
|
312
|
+
return {
|
|
313
|
+
coreDependencies: manifestFile.packageReferences,
|
|
314
|
+
coreScripts: {},
|
|
315
|
+
coreFields: { TargetFramework: manifestFile.targetFramework }
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
function mergeManifestFile(current, oldManifest, newTemplate) {
|
|
319
|
+
let raw = current.raw;
|
|
320
|
+
let changed = false;
|
|
321
|
+
const dependencies = [];
|
|
322
|
+
const coreDependencies = {};
|
|
323
|
+
for (const name of Object.keys(newTemplate.packageReferences)) {
|
|
324
|
+
const newValue = newTemplate.packageReferences[name];
|
|
325
|
+
const currentValue = current.packageReferences[name];
|
|
326
|
+
const oldValue = oldManifest.coreDependencies[name];
|
|
327
|
+
const result = reconcileEntry(currentValue, oldValue, newValue, stringEquals);
|
|
328
|
+
dependencies.push({ key: name, outcome: result.outcome });
|
|
329
|
+
coreDependencies[name] = result.value;
|
|
330
|
+
if (result.outcome === "added") {
|
|
331
|
+
changed = true;
|
|
332
|
+
raw = addPackageReference(raw, name, result.value);
|
|
333
|
+
} else if (result.outcome !== "skipped" && result.value !== currentValue) {
|
|
334
|
+
changed = true;
|
|
335
|
+
raw = setPackageReferenceVersion(raw, name, result.value);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
const oldCoreFields = oldManifest.coreFields;
|
|
339
|
+
const fields = [];
|
|
340
|
+
const targetFrameworkResult = reconcileEntry(
|
|
341
|
+
current.targetFramework,
|
|
342
|
+
oldCoreFields.TargetFramework,
|
|
343
|
+
newTemplate.targetFramework,
|
|
344
|
+
stringEquals
|
|
345
|
+
);
|
|
346
|
+
fields.push({ key: "TargetFramework", outcome: targetFrameworkResult.outcome });
|
|
347
|
+
if (targetFrameworkResult.outcome !== "skipped" && targetFrameworkResult.value !== current.targetFramework) {
|
|
348
|
+
changed = true;
|
|
349
|
+
raw = setTag(raw, "TargetFramework", targetFrameworkResult.value);
|
|
350
|
+
}
|
|
351
|
+
return {
|
|
352
|
+
updatedFile: { ...current, raw },
|
|
353
|
+
changed,
|
|
354
|
+
dependencies,
|
|
355
|
+
scripts: [],
|
|
356
|
+
fields,
|
|
357
|
+
coreDependencies,
|
|
358
|
+
coreScripts: {},
|
|
359
|
+
coreFields: { TargetFramework: targetFrameworkResult.value }
|
|
360
|
+
};
|
|
361
|
+
}
|
|
362
|
+
var dotnetAdapter = {
|
|
363
|
+
coreFilePaths: CORE_FILE_PATHS2,
|
|
364
|
+
templateSourcePath(relativePath) {
|
|
365
|
+
return relativePath === ".gitignore" ? "gitignore" : relativePath;
|
|
366
|
+
},
|
|
367
|
+
manifestFileName: "src/Cli.csproj",
|
|
368
|
+
async readManifestFile(dir) {
|
|
369
|
+
const content = await readFile3(path5.join(dir, "src", "Cli.csproj"), "utf8");
|
|
370
|
+
return parseManifestFile(content);
|
|
371
|
+
},
|
|
372
|
+
async writeManifestFile(dir, content) {
|
|
373
|
+
await writeFile3(path5.join(dir, "src", "Cli.csproj"), content.raw);
|
|
374
|
+
},
|
|
375
|
+
parseManifestFile,
|
|
376
|
+
readProjectName(manifestFile) {
|
|
377
|
+
return manifestFile.packageId;
|
|
378
|
+
},
|
|
379
|
+
extractCoreFields(manifestFile) {
|
|
380
|
+
return extractCoreFields2(manifestFile);
|
|
381
|
+
},
|
|
382
|
+
mergeManifestFile(current, oldManifest, newTemplate) {
|
|
383
|
+
return mergeManifestFile(current, oldManifest, newTemplate);
|
|
384
|
+
}
|
|
385
|
+
};
|
|
386
|
+
|
|
387
|
+
// src/languages/registry-checkers/nuget.ts
|
|
388
|
+
import { mkdir, readFile as readFile4, writeFile as writeFile4 } from "fs/promises";
|
|
389
|
+
import path6 from "path";
|
|
390
|
+
var NUGET_DEFAULT_REGISTRY_URL = "https://api.nuget.org/v3/index.json";
|
|
391
|
+
var NUGET_FLATCONTAINER_BASE = "https://api.nuget.org/v3-flatcontainer";
|
|
392
|
+
var FETCH_TIMEOUT_MS2 = 5e3;
|
|
393
|
+
async function checkNameAvailability2(name) {
|
|
394
|
+
const url = `${NUGET_FLATCONTAINER_BASE}/${encodeURIComponent(name.toLowerCase())}/index.json`;
|
|
395
|
+
try {
|
|
396
|
+
const response = await fetch(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS2) });
|
|
397
|
+
if (response.status === 404) return "available";
|
|
398
|
+
if (response.status === 200) return "taken";
|
|
399
|
+
return "unverified";
|
|
400
|
+
} catch {
|
|
401
|
+
return "unverified";
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
async function applyPrivateIntent2(targetDir) {
|
|
405
|
+
const csprojPath = path6.join(targetDir, "src", "Cli.csproj");
|
|
406
|
+
const content = await readFile4(csprojPath, "utf8");
|
|
407
|
+
const updated = content.replace(
|
|
408
|
+
/(<PropertyGroup>\s*\n)/,
|
|
409
|
+
"$1 <IsPackable>false</IsPackable>\n"
|
|
410
|
+
);
|
|
411
|
+
await writeFile4(csprojPath, updated);
|
|
412
|
+
}
|
|
413
|
+
async function applyRegistryUrl2(targetDir, registryUrl) {
|
|
414
|
+
const config = [
|
|
415
|
+
'<?xml version="1.0" encoding="utf-8"?>',
|
|
416
|
+
"<configuration>",
|
|
417
|
+
" <packageSources>",
|
|
418
|
+
" <clear />",
|
|
419
|
+
` <add key="custom" value="${registryUrl}" />`,
|
|
420
|
+
" </packageSources>",
|
|
421
|
+
"</configuration>",
|
|
422
|
+
""
|
|
423
|
+
].join("\n");
|
|
424
|
+
await mkdir(targetDir, { recursive: true });
|
|
425
|
+
await writeFile4(path6.join(targetDir, "NuGet.config"), config);
|
|
426
|
+
}
|
|
427
|
+
var nugetRegistryChecker = {
|
|
428
|
+
checkNameAvailability: checkNameAvailability2,
|
|
429
|
+
applyPrivateIntent: applyPrivateIntent2,
|
|
430
|
+
applyRegistryUrl: applyRegistryUrl2
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
// src/languages/packs/dotnet.ts
|
|
434
|
+
function validateProjectName2(value) {
|
|
435
|
+
if (!value || value.trim().length === 0) return "Project name is required.";
|
|
436
|
+
if (!/^[A-Z][A-Za-z0-9]*$/.test(value)) {
|
|
437
|
+
return "Use PascalCase, starting with an uppercase letter (e.g. MyTool).";
|
|
438
|
+
}
|
|
439
|
+
return void 0;
|
|
440
|
+
}
|
|
441
|
+
var dotnetPack = {
|
|
442
|
+
id: "dotnet",
|
|
443
|
+
displayName: ".NET / C# (System.CommandLine)",
|
|
444
|
+
templateDir: path7.join(findPackageRoot(), "templates", "dotnet"),
|
|
445
|
+
scaffoldCommands: [
|
|
446
|
+
{ command: "dotnet", args: ["restore"] },
|
|
447
|
+
{ command: "dotnet", args: ["build"] }
|
|
448
|
+
],
|
|
449
|
+
validateProjectName: validateProjectName2,
|
|
450
|
+
updateAdapter: dotnetAdapter,
|
|
451
|
+
registry: {
|
|
452
|
+
defaultUrl: NUGET_DEFAULT_REGISTRY_URL,
|
|
453
|
+
promptLabel: "Custom NuGet feed URL (leave empty for nuget.org)",
|
|
454
|
+
checkNameAvailability: nugetRegistryChecker.checkNameAvailability,
|
|
455
|
+
applyPrivateIntent: nugetRegistryChecker.applyPrivateIntent,
|
|
456
|
+
applyRegistryUrl: nugetRegistryChecker.applyRegistryUrl
|
|
243
457
|
}
|
|
244
458
|
};
|
|
245
459
|
|
|
246
460
|
// src/languages/index.ts
|
|
247
461
|
var LANGUAGE_PACKS = {
|
|
248
|
-
[nodeOclifPack.id]: nodeOclifPack
|
|
462
|
+
[nodeOclifPack.id]: nodeOclifPack,
|
|
463
|
+
[dotnetPack.id]: dotnetPack
|
|
249
464
|
};
|
|
250
465
|
|
|
251
466
|
// src/wizard.ts
|
|
@@ -324,15 +539,15 @@ async function runWizard(deps = defaultDeps) {
|
|
|
324
539
|
}
|
|
325
540
|
|
|
326
541
|
// src/scaffold.ts
|
|
327
|
-
import { cp, readdir, readFile as
|
|
328
|
-
import
|
|
542
|
+
import { cp, readdir, readFile as readFile6, rename, writeFile as writeFile6 } from "fs/promises";
|
|
543
|
+
import path9 from "path";
|
|
329
544
|
import spawn from "cross-spawn";
|
|
330
545
|
|
|
331
546
|
// src/update/manifest.ts
|
|
332
547
|
import { createHash } from "crypto";
|
|
333
548
|
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
334
|
-
import { mkdir, readFile as
|
|
335
|
-
import
|
|
549
|
+
import { mkdir as mkdir2, readFile as readFile5, writeFile as writeFile5 } from "fs/promises";
|
|
550
|
+
import path8 from "path";
|
|
336
551
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
337
552
|
|
|
338
553
|
// src/errors.ts
|
|
@@ -350,7 +565,7 @@ function hashContent(content) {
|
|
|
350
565
|
async function hashCoreFiles(dir, adapter) {
|
|
351
566
|
const entries = await Promise.all(
|
|
352
567
|
adapter.coreFilePaths.map(async (relativePath) => {
|
|
353
|
-
const content = await
|
|
568
|
+
const content = await readFile5(path8.join(dir, relativePath), "utf8");
|
|
354
569
|
return [relativePath, hashContent(content)];
|
|
355
570
|
})
|
|
356
571
|
);
|
|
@@ -362,15 +577,15 @@ async function buildManifest(targetDir, generatorVersion, language, adapter) {
|
|
|
362
577
|
const { coreDependencies, coreScripts, coreFields } = adapter.extractCoreFields(manifestFile);
|
|
363
578
|
return { generatorVersion, language, coreFiles, coreDependencies, coreScripts, coreFields };
|
|
364
579
|
}
|
|
365
|
-
var MANIFEST_RELATIVE_PATH =
|
|
580
|
+
var MANIFEST_RELATIVE_PATH = path8.join(".clispark", "manifest.json");
|
|
366
581
|
async function writeManifest(targetDir, manifest) {
|
|
367
|
-
const manifestPath =
|
|
368
|
-
await
|
|
369
|
-
await
|
|
582
|
+
const manifestPath = path8.join(targetDir, MANIFEST_RELATIVE_PATH);
|
|
583
|
+
await mkdir2(path8.dirname(manifestPath), { recursive: true });
|
|
584
|
+
await writeFile5(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
|
|
370
585
|
}
|
|
371
586
|
async function readManifest(targetDir) {
|
|
372
587
|
try {
|
|
373
|
-
const content = await
|
|
588
|
+
const content = await readFile5(path8.join(targetDir, MANIFEST_RELATIVE_PATH), "utf8");
|
|
374
589
|
return JSON.parse(content);
|
|
375
590
|
} catch {
|
|
376
591
|
return void 0;
|
|
@@ -386,14 +601,14 @@ async function requireManifest(targetDir) {
|
|
|
386
601
|
return manifest;
|
|
387
602
|
}
|
|
388
603
|
function getGeneratorVersion() {
|
|
389
|
-
let dir =
|
|
604
|
+
let dir = path8.dirname(fileURLToPath2(import.meta.url));
|
|
390
605
|
while (true) {
|
|
391
|
-
const pkgPath =
|
|
606
|
+
const pkgPath = path8.join(dir, "package.json");
|
|
392
607
|
if (existsSync2(pkgPath)) {
|
|
393
608
|
const pkg = JSON.parse(readFileSync2(pkgPath, "utf8"));
|
|
394
609
|
if (pkg.name === "clispark") return pkg.version;
|
|
395
610
|
}
|
|
396
|
-
const parentDir =
|
|
611
|
+
const parentDir = path8.dirname(dir);
|
|
397
612
|
if (parentDir === dir) {
|
|
398
613
|
throw new Error("Could not locate clispark's own package.json.");
|
|
399
614
|
}
|
|
@@ -420,7 +635,7 @@ async function collectFiles(dir) {
|
|
|
420
635
|
const entries = await readdir(dir, { withFileTypes: true });
|
|
421
636
|
const files = await Promise.all(
|
|
422
637
|
entries.map((entry) => {
|
|
423
|
-
const fullPath =
|
|
638
|
+
const fullPath = path9.join(dir, entry.name);
|
|
424
639
|
return entry.isDirectory() ? collectFiles(fullPath) : Promise.resolve([fullPath]);
|
|
425
640
|
})
|
|
426
641
|
);
|
|
@@ -430,9 +645,9 @@ async function replacePlaceholdersInTree(targetDir, projectName) {
|
|
|
430
645
|
const files = await collectFiles(targetDir);
|
|
431
646
|
await Promise.all(
|
|
432
647
|
files.map(async (filePath) => {
|
|
433
|
-
const content = await
|
|
648
|
+
const content = await readFile6(filePath, "utf8");
|
|
434
649
|
if (content.includes("{{projectName}}")) {
|
|
435
|
-
await
|
|
650
|
+
await writeFile6(filePath, applyPlaceholders(content, projectName));
|
|
436
651
|
}
|
|
437
652
|
})
|
|
438
653
|
);
|
|
@@ -441,14 +656,13 @@ async function copyTemplate(options, pack) {
|
|
|
441
656
|
const { projectName, targetDir, registryUrl, publishIntent } = options;
|
|
442
657
|
await assertTargetDirIsUsable(targetDir);
|
|
443
658
|
await cp(pack.templateDir, targetDir, { recursive: true });
|
|
444
|
-
await rename(
|
|
659
|
+
await rename(path9.join(targetDir, "gitignore"), path9.join(targetDir, ".gitignore"));
|
|
445
660
|
await replacePlaceholdersInTree(targetDir, projectName);
|
|
446
661
|
if (publishIntent === false) {
|
|
447
662
|
await pack.registry.applyPrivateIntent(targetDir);
|
|
448
663
|
}
|
|
449
664
|
if (registryUrl && registryUrl !== pack.registry.defaultUrl) {
|
|
450
|
-
await
|
|
451
|
-
`);
|
|
665
|
+
await pack.registry.applyRegistryUrl(targetDir, registryUrl);
|
|
452
666
|
}
|
|
453
667
|
}
|
|
454
668
|
async function defaultRunCommand(command, args, cwd) {
|
|
@@ -481,7 +695,7 @@ async function scaffoldProject(options, pack, deps = defaultScaffoldDeps) {
|
|
|
481
695
|
// src/logger.ts
|
|
482
696
|
import { randomBytes } from "crypto";
|
|
483
697
|
import { mkdirSync, readdirSync, statSync, unlinkSync, writeFileSync } from "fs";
|
|
484
|
-
import
|
|
698
|
+
import path10 from "path";
|
|
485
699
|
import envPaths from "env-paths";
|
|
486
700
|
import pino from "pino";
|
|
487
701
|
var paths = envPaths("clispark", { suffix: "" });
|
|
@@ -517,7 +731,7 @@ var SWEEP_MARKER_FILE = ".last-sweep";
|
|
|
517
731
|
var SWEEP_THROTTLE_MS = 24 * 60 * 60 * 1e3;
|
|
518
732
|
function sweepOldLogs(logDir) {
|
|
519
733
|
safely(() => {
|
|
520
|
-
const markerPath =
|
|
734
|
+
const markerPath = path10.join(logDir, SWEEP_MARKER_FILE);
|
|
521
735
|
let shouldSweep = true;
|
|
522
736
|
try {
|
|
523
737
|
shouldSweep = Date.now() - statSync(markerPath).mtimeMs >= SWEEP_THROTTLE_MS;
|
|
@@ -527,7 +741,7 @@ function sweepOldLogs(logDir) {
|
|
|
527
741
|
const cutoffMs = Date.now() - getRetentionDays() * 24 * 60 * 60 * 1e3;
|
|
528
742
|
for (const file of readdirSync(logDir)) {
|
|
529
743
|
if (file === SWEEP_MARKER_FILE) continue;
|
|
530
|
-
const filePath =
|
|
744
|
+
const filePath = path10.join(logDir, file);
|
|
531
745
|
if (statSync(filePath).mtimeMs < cutoffMs) {
|
|
532
746
|
unlinkSync(filePath);
|
|
533
747
|
}
|
|
@@ -538,7 +752,7 @@ function sweepOldLogs(logDir) {
|
|
|
538
752
|
function createLogger(commandName, logDir = paths.log) {
|
|
539
753
|
mkdirSync(logDir, { recursive: true });
|
|
540
754
|
sweepOldLogs(logDir);
|
|
541
|
-
const logFilePath =
|
|
755
|
+
const logFilePath = path10.join(logDir, buildLogFileName(commandName));
|
|
542
756
|
const fileDestination = pino.destination({ dest: logFilePath, sync: true, mode: 384 });
|
|
543
757
|
const destination = process.env.DEBUG ? pino.multistream([{ stream: fileDestination }, { stream: process.stdout }]) : fileDestination;
|
|
544
758
|
const logger = pino({ redact: buildRedactPaths([...SENSITIVE_LOG_KEYS, "registryUrl"]) }, destination);
|
|
@@ -576,8 +790,8 @@ function withLogging(commandName, action, logDir = paths.log, loggerFactory = cr
|
|
|
576
790
|
}
|
|
577
791
|
|
|
578
792
|
// src/update/update.ts
|
|
579
|
-
import { mkdir as
|
|
580
|
-
import
|
|
793
|
+
import { mkdir as mkdir3, readFile as readFile7, writeFile as writeFile7 } from "fs/promises";
|
|
794
|
+
import path11 from "path";
|
|
581
795
|
import spawn2 from "cross-spawn";
|
|
582
796
|
|
|
583
797
|
// src/update/releasenotes.ts
|
|
@@ -595,7 +809,7 @@ function compareVersions(a, b) {
|
|
|
595
809
|
return 0;
|
|
596
810
|
}
|
|
597
811
|
var RELEASES_URL = "https://api.github.com/repos/martinwichner/clispark/releases";
|
|
598
|
-
var
|
|
812
|
+
var FETCH_TIMEOUT_MS3 = 5e3;
|
|
599
813
|
async function fetchReleaseNotes(targetDir, fetchFn = fetch) {
|
|
600
814
|
const manifest = await requireManifest(targetDir);
|
|
601
815
|
const fromVersion = manifest.generatorVersion;
|
|
@@ -603,7 +817,7 @@ async function fetchReleaseNotes(targetDir, fetchFn = fetch) {
|
|
|
603
817
|
if (compareVersions(fromVersion, toVersion) >= 0) {
|
|
604
818
|
return { status: "up-to-date", fromVersion, toVersion, releases: [] };
|
|
605
819
|
}
|
|
606
|
-
const response = await fetchFn(RELEASES_URL, { signal: AbortSignal.timeout(
|
|
820
|
+
const response = await fetchFn(RELEASES_URL, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS3) });
|
|
607
821
|
if (!response.ok) {
|
|
608
822
|
throw new Error(`Failed to fetch release notes: GitHub API responded with ${response.status}`);
|
|
609
823
|
}
|
|
@@ -663,7 +877,7 @@ async function updateProject(targetDir, adapter, templateDir, language, deps = d
|
|
|
663
877
|
const currentManifestFile = await adapter.readManifestFile(targetDir);
|
|
664
878
|
const projectName = adapter.readProjectName(currentManifestFile);
|
|
665
879
|
const newTemplateRaw = applyPlaceholders(
|
|
666
|
-
await
|
|
880
|
+
await readFile7(path11.join(templateDir, adapter.manifestFileName), "utf8"),
|
|
667
881
|
projectName
|
|
668
882
|
);
|
|
669
883
|
const newTemplateManifestFile = adapter.parseManifestFile(newTemplateRaw);
|
|
@@ -673,13 +887,13 @@ async function updateProject(targetDir, adapter, templateDir, language, deps = d
|
|
|
673
887
|
const perFileResults = await Promise.all(
|
|
674
888
|
adapter.coreFilePaths.map(async (relativePath) => {
|
|
675
889
|
const newContent = applyPlaceholders(
|
|
676
|
-
await
|
|
890
|
+
await readFile7(path11.join(templateDir, adapter.templateSourcePath(relativePath)), "utf8"),
|
|
677
891
|
projectName
|
|
678
892
|
);
|
|
679
893
|
const newHash = hashContent(newContent);
|
|
680
894
|
let currentHash;
|
|
681
895
|
try {
|
|
682
|
-
currentHash = hashContent(await
|
|
896
|
+
currentHash = hashContent(await readFile7(path11.join(targetDir, relativePath), "utf8"));
|
|
683
897
|
} catch {
|
|
684
898
|
currentHash = void 0;
|
|
685
899
|
}
|
|
@@ -691,13 +905,13 @@ async function updateProject(targetDir, adapter, templateDir, language, deps = d
|
|
|
691
905
|
files.push({ path: relativePath, outcome: result.outcome });
|
|
692
906
|
newCoreFiles[relativePath] = result.value;
|
|
693
907
|
if (result.outcome === "added" || result.outcome === "replaced") {
|
|
694
|
-
fileWrites.push({ targetPath:
|
|
908
|
+
fileWrites.push({ targetPath: path11.join(targetDir, relativePath), content: newContent });
|
|
695
909
|
}
|
|
696
910
|
}
|
|
697
911
|
for (const relativePath of Object.keys(oldManifest.coreFiles)) {
|
|
698
912
|
if (adapter.coreFilePaths.includes(relativePath)) continue;
|
|
699
913
|
try {
|
|
700
|
-
await
|
|
914
|
+
await readFile7(path11.join(targetDir, relativePath), "utf8");
|
|
701
915
|
files.push({ path: relativePath, outcome: "no-longer-core" });
|
|
702
916
|
} catch {
|
|
703
917
|
}
|
|
@@ -719,8 +933,8 @@ async function updateProject(targetDir, adapter, templateDir, language, deps = d
|
|
|
719
933
|
};
|
|
720
934
|
}
|
|
721
935
|
for (const write of fileWrites) {
|
|
722
|
-
await
|
|
723
|
-
await
|
|
936
|
+
await mkdir3(path11.dirname(write.targetPath), { recursive: true });
|
|
937
|
+
await writeFile7(write.targetPath, write.content);
|
|
724
938
|
}
|
|
725
939
|
if (fileMerge.changed) {
|
|
726
940
|
await adapter.writeManifestFile(targetDir, fileMerge.updatedFile);
|
|
@@ -785,7 +999,7 @@ function formatUpdateSummary(result) {
|
|
|
785
999
|
// src/whoami.ts
|
|
786
1000
|
import os from "os";
|
|
787
1001
|
var JOKE_API_URL = "https://v2.jokeapi.dev/joke/Programming,Miscellaneous";
|
|
788
|
-
var
|
|
1002
|
+
var FETCH_TIMEOUT_MS4 = 3e3;
|
|
789
1003
|
var SUPPORTED_JOKE_LANGUAGES = ["cs", "de", "en", "es", "fr", "pt"];
|
|
790
1004
|
var LOGO = String.raw`
|
|
791
1005
|
⚡ clispark
|
|
@@ -843,7 +1057,7 @@ function getRandomFunFact(osFacts = defaultOsFacts, randomFn = Math.random) {
|
|
|
843
1057
|
async function fetchJoke(language, fetchFn) {
|
|
844
1058
|
try {
|
|
845
1059
|
const url = `${JOKE_API_URL}?lang=${language}&safe-mode`;
|
|
846
|
-
const response = await fetchFn(url, { signal: AbortSignal.timeout(
|
|
1060
|
+
const response = await fetchFn(url, { signal: AbortSignal.timeout(FETCH_TIMEOUT_MS4) });
|
|
847
1061
|
if (!response.ok) return void 0;
|
|
848
1062
|
const data = await response.json();
|
|
849
1063
|
if (data.error) return void 0;
|
|
@@ -896,7 +1110,7 @@ function resolvePack(language) {
|
|
|
896
1110
|
program.action(
|
|
897
1111
|
(options) => withLogging("scaffold", async (logger) => {
|
|
898
1112
|
const answers = await runWizard();
|
|
899
|
-
const targetDir =
|
|
1113
|
+
const targetDir = path12.join(process.cwd(), answers.projectName);
|
|
900
1114
|
const pack = resolvePack(answers.language);
|
|
901
1115
|
logger.info({ projectName: answers.projectName, targetDir, language: pack.id }, "scaffold started");
|
|
902
1116
|
await scaffoldProject(
|