alex-c-line 2.8.1 → 2.9.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/index.cjs +249 -100
- package/dist/index.js +249 -100
- package/package.json +6 -6
- package/templates/{outdated → dependencyAudit/outdated}/table.html +2 -0
- package/templates/{outdated → dependencyAudit/outdated}/tableRow.html +2 -0
- package/templates/dependencyAudit/peerCheck/table.html +13 -0
- package/templates/dependencyAudit/peerCheck/tableRow.html +6 -0
- package/templates/dependencyAudit/securityAudit/summary.html +7 -0
- package/templates/dependencyAudit/securityAudit/table.html +15 -0
- package/templates/dependencyAudit/securityAudit/tableRow.html +10 -0
package/dist/index.cjs
CHANGED
|
@@ -38,10 +38,10 @@ let _inquirer_prompts = require("@inquirer/prompts");
|
|
|
38
38
|
let node_fs_promises = require("node:fs/promises");
|
|
39
39
|
let dotenv = require("dotenv");
|
|
40
40
|
let execa = require("execa");
|
|
41
|
-
let node_url = require("node:url");
|
|
42
|
-
let _alextheman_utility_internal = require("@alextheman/utility/internal");
|
|
43
41
|
let zod = require("zod");
|
|
44
42
|
zod = __toESM(zod, 1);
|
|
43
|
+
let _alextheman_utility_internal = require("@alextheman/utility/internal");
|
|
44
|
+
let node_url = require("node:url");
|
|
45
45
|
let node_module = require("node:module");
|
|
46
46
|
let toml = require("toml");
|
|
47
47
|
let gray_matter = require("gray-matter");
|
|
@@ -270,7 +270,7 @@ function envFile(program) {
|
|
|
270
270
|
}
|
|
271
271
|
//#endregion
|
|
272
272
|
//#region src/cli/commands/internal/check-lockfile-version-discrepancy.ts
|
|
273
|
-
function
|
|
273
|
+
function internalCheckLockfileVersionDiscrepancy(program) {
|
|
274
274
|
program.command("check-lockfile-version-discrepancy").description("Check that version numbers in package.json and package-lock.json match").action(async () => {
|
|
275
275
|
console.info("Checking for package.json and package-lock.json discrepancies...");
|
|
276
276
|
const { version: packageVersion } = JSON.parse(await (0, node_fs_promises.readFile)(node_path.default.resolve(process.cwd(), "package.json"), "utf-8"));
|
|
@@ -284,8 +284,247 @@ function checkLockfileVersionDiscrepancy(program) {
|
|
|
284
284
|
});
|
|
285
285
|
}
|
|
286
286
|
//#endregion
|
|
287
|
+
//#region src/configs/helpers/preCommit/definePreCommitConfig.ts
|
|
288
|
+
const preCommitStepOptionsSchema = zod.default.strictObject({ arguments: zod.default.array(zod.default.string()).optional() });
|
|
289
|
+
const preCommitConfigSchema = zod.default.strictObject({
|
|
290
|
+
packageManager: zod.default.enum(_alextheman_utility_internal.PackageManager).optional(),
|
|
291
|
+
allowNoStagedChanges: zod.default.boolean().optional(),
|
|
292
|
+
steps: zod.default.array(zod.default.union([
|
|
293
|
+
zod.default.function({
|
|
294
|
+
input: [zod.default.function()],
|
|
295
|
+
output: zod.default.any()
|
|
296
|
+
}),
|
|
297
|
+
zod.default.string(),
|
|
298
|
+
zod.default.tuple([zod.default.string(), preCommitStepOptionsSchema])
|
|
299
|
+
])),
|
|
300
|
+
updateIndex: zod.default.boolean().optional()
|
|
301
|
+
});
|
|
302
|
+
//#endregion
|
|
303
|
+
//#region src/configs/helpers/template/pullRequest/defineTemplatePullRequestSchema.ts
|
|
304
|
+
const templatePullRequestBaseSchema = zod.default.strictObject({ projectName: zod.default.string().optional() });
|
|
305
|
+
const templatePullRequestSchema = zod.default.discriminatedUnion("category", [templatePullRequestBaseSchema.extend({
|
|
306
|
+
category: zod.default.literal("general"),
|
|
307
|
+
projectType: zod.default.string()
|
|
308
|
+
}), templatePullRequestBaseSchema.extend({
|
|
309
|
+
category: zod.default.literal("infrastructure"),
|
|
310
|
+
infrastructureProvider: zod.default.string(),
|
|
311
|
+
requireConfirmationFrom: zod.default.string()
|
|
312
|
+
})]);
|
|
313
|
+
function parseTemplatePullRequestConfig(input) {
|
|
314
|
+
return _alextheman_utility.az.with(templatePullRequestSchema).parse(input);
|
|
315
|
+
}
|
|
316
|
+
//#endregion
|
|
317
|
+
//#region src/configs/helpers/defineAlexCLineConfig.ts
|
|
318
|
+
const alexCLineConfigSchema = zod.default.strictObject({
|
|
319
|
+
preCommit: preCommitConfigSchema,
|
|
320
|
+
template: zod.default.object({ pullRequest: templatePullRequestSchema })
|
|
321
|
+
}).partial();
|
|
322
|
+
async function parseAlexCLineConfig(input) {
|
|
323
|
+
return await _alextheman_utility.az.with(alexCLineConfigSchema).parseAsync(input);
|
|
324
|
+
}
|
|
325
|
+
//#endregion
|
|
326
|
+
//#region src/configs/types/ConfigFileName.ts
|
|
327
|
+
const ConfigFileName = {
|
|
328
|
+
STANDARD_JAVASCRIPT: "alex-c-line.config.js",
|
|
329
|
+
ES_MODULES_JAVASCRIPT: "alex-c-line.config.mjs",
|
|
330
|
+
COMMON_JS_JAVASCRIPT: "alex-c-line.config.cjs"
|
|
331
|
+
};
|
|
332
|
+
const PrivateConfigFileName = {
|
|
333
|
+
STANDARD_JAVASCRIPT: ".alex-c-line.private.config.js",
|
|
334
|
+
ES_MODULES_JAVASCRIPT: ".alex-c-line.private.config.mjs",
|
|
335
|
+
COMMON_JS_JAVASCRIPT: ".alex-c-line.private.config.cjs"
|
|
336
|
+
};
|
|
337
|
+
//#endregion
|
|
338
|
+
//#region src/configs/types/template/pullRequest/PullRequestTemplateCategory.ts
|
|
339
|
+
const PullRequestTemplateCategory = {
|
|
340
|
+
GENERAL: "general",
|
|
341
|
+
INFRASTRUCTURE: "infrastructure"
|
|
342
|
+
};
|
|
343
|
+
//#endregion
|
|
344
|
+
//#region src/configs/helpers/defineAlexCLinePrivateConfig.ts
|
|
345
|
+
const alexCLinePrivateConfigSchema = zod.default.object({ localPackage: zod.default.strictObject({
|
|
346
|
+
enableCache: zod.default.boolean().optional(),
|
|
347
|
+
localPackages: zod.default.record(zod.default.string(), zod.default.strictObject({
|
|
348
|
+
packageManager: zod.default.enum(_alextheman_utility_internal.PackageManager),
|
|
349
|
+
path: zod.default.string(),
|
|
350
|
+
prepareScript: zod.default.string().optional(),
|
|
351
|
+
dependencyGroup: zod.default.enum(_alextheman_utility_internal.DependencyGroup).optional(),
|
|
352
|
+
keepOldTarballs: zod.default.boolean().optional()
|
|
353
|
+
}))
|
|
354
|
+
}) });
|
|
355
|
+
function parseAlexCLinePrivateConfig(data) {
|
|
356
|
+
return _alextheman_utility.az.with(alexCLinePrivateConfigSchema).parse(data);
|
|
357
|
+
}
|
|
358
|
+
//#endregion
|
|
359
|
+
//#region src/utility/fileSystem/findPackageRoot.ts
|
|
360
|
+
async function findPackageRoot(startDirectory, packageName) {
|
|
361
|
+
let directory = startDirectory;
|
|
362
|
+
while (true) {
|
|
363
|
+
const packagePath = node_path.default.join(directory, "package.json");
|
|
364
|
+
try {
|
|
365
|
+
if (JSON.parse(await (0, node_fs_promises.readFile)(packagePath, "utf-8"))?.name === packageName) return directory;
|
|
366
|
+
} catch {}
|
|
367
|
+
const parent = node_path.default.dirname(directory);
|
|
368
|
+
if (parent === directory) break;
|
|
369
|
+
directory = parent;
|
|
370
|
+
}
|
|
371
|
+
throw new _alextheman_utility_v6.DataError({ packageName }, "PACKAGE_ROOT_NOT_FOUND", `Could not find package root for ${packageName}`);
|
|
372
|
+
}
|
|
373
|
+
//#endregion
|
|
374
|
+
//#region src/utility/constants/ALEX_C_LINE_PACKAGE_ROOT.ts
|
|
375
|
+
const __filename$3 = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
|
|
376
|
+
const ALEX_C_LINE_PACKAGE_ROOT = findPackageRoot(node_path.default.dirname(__filename$3), "alex-c-line");
|
|
377
|
+
//#endregion
|
|
378
|
+
//#region src/cli/commands/internal/dependency-audit/helpers/getOutdatedDependencies.ts
|
|
379
|
+
const pnpmOutdatedSchema = zod.default.record(zod.default.string(), zod.default.object({
|
|
380
|
+
current: _alextheman_utility.az.versionNumber(),
|
|
381
|
+
latest: _alextheman_utility.az.versionNumber(),
|
|
382
|
+
isDeprecated: zod.default.boolean(),
|
|
383
|
+
dependencyType: zod.default.enum(_alextheman_utility_internal.DependencyGroup)
|
|
384
|
+
}));
|
|
385
|
+
function parseOutdated(input) {
|
|
386
|
+
return _alextheman_utility.az.with(pnpmOutdatedSchema).parse(input);
|
|
387
|
+
}
|
|
388
|
+
async function getOutdatedDependencies(program) {
|
|
389
|
+
const { exitCode, stdout, stderr } = await (0, execa.execa)({ reject: false })`pnpm outdated --json`;
|
|
390
|
+
if (![0, 1].includes(exitCode)) program.error(stderr ?? stdout, {
|
|
391
|
+
exitCode,
|
|
392
|
+
code: "OUTDATED_DEPENDENCIES_ERROR"
|
|
393
|
+
});
|
|
394
|
+
const outdatedDependencies = parseOutdated(JSON.parse(stdout.trim()));
|
|
395
|
+
if (Object.keys(outdatedDependencies).length === 0) return "No outdated dependencies found.";
|
|
396
|
+
const outdatedTemplatesPath = node_path.default.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "dependencyAudit", "outdated");
|
|
397
|
+
const tableTemplate = await (0, node_fs_promises.readFile)(node_path.default.join(outdatedTemplatesPath, "table.html"), "utf-8");
|
|
398
|
+
const tableRowTemplate = await (0, node_fs_promises.readFile)(node_path.default.join(outdatedTemplatesPath, "tableRow.html"), "utf-8");
|
|
399
|
+
return tableTemplate.replace("{{tableRows}}", Object.entries(outdatedDependencies).map(([packageName, data]) => {
|
|
400
|
+
return tableRowTemplate.replace("{{packageName}}", packageName).replace("{{currentVersion}}", data.current.toString()).replace("{{latestVersion}}", data.latest.toString()).replace("{{isDeprecated}}", data.isDeprecated ? "Yes" : "No").replace("{{dependencyGroup}}", data.dependencyType);
|
|
401
|
+
}).join("\n"));
|
|
402
|
+
}
|
|
403
|
+
//#endregion
|
|
404
|
+
//#region src/cli/commands/internal/dependency-audit/helpers/getPeerCheck.ts
|
|
405
|
+
const pnpmPeerCheckSchema = zod.default.object({ ".": zod.default.object({ bad: zod.default.record(zod.default.string(), zod.default.array(zod.default.object({
|
|
406
|
+
parents: zod.default.array(zod.default.object({
|
|
407
|
+
name: zod.default.string(),
|
|
408
|
+
version: _alextheman_utility.az.versionNumber()
|
|
409
|
+
})),
|
|
410
|
+
optional: zod.default.boolean(),
|
|
411
|
+
wantedRange: zod.default.string(),
|
|
412
|
+
foundVersion: _alextheman_utility.az.versionNumber()
|
|
413
|
+
}))) }) });
|
|
414
|
+
function parsePeerCheck(input) {
|
|
415
|
+
return _alextheman_utility.az.with(pnpmPeerCheckSchema).parse(input);
|
|
416
|
+
}
|
|
417
|
+
async function getPeerCheck(program) {
|
|
418
|
+
const { stdout, stderr, exitCode } = await (0, execa.execa)({ reject: false })`pnpm peers check --json`;
|
|
419
|
+
if (![0, 1].includes(exitCode)) program.error(stderr ?? stdout, {
|
|
420
|
+
exitCode,
|
|
421
|
+
code: "PEERS_CHECK_ERROR"
|
|
422
|
+
});
|
|
423
|
+
const peerCheck = parsePeerCheck(JSON.parse(stdout));
|
|
424
|
+
const auditTemplatesPath = node_path.default.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "dependencyAudit", "peerCheck");
|
|
425
|
+
const peerCheckTableTemplate = await (0, node_fs_promises.readFile)(node_path.default.join(auditTemplatesPath, "table.html"), "utf-8");
|
|
426
|
+
const peerCheckTableRowTemplate = await (0, node_fs_promises.readFile)(node_path.default.join(auditTemplatesPath, "tableRow.html"), "utf-8");
|
|
427
|
+
if (Object.keys(peerCheck["."].bad).length === 0) return "No peer dependency issues found";
|
|
428
|
+
return peerCheckTableTemplate.replace("{{tableRows}}", Object.entries(peerCheck["."].bad).flatMap(([packageName, data]) => {
|
|
429
|
+
return data.map((item) => {
|
|
430
|
+
return peerCheckTableRowTemplate.replace("{{packageName}}", packageName).replace("{{currentVersion}}", item.foundVersion.toString()).replace("{{wantedRange}}", item.wantedRange).replace("{{parentDependencies}}", item.parents.map((parent) => {
|
|
431
|
+
return `${parent.name}@${parent.version}`;
|
|
432
|
+
}).join(", "));
|
|
433
|
+
});
|
|
434
|
+
}).join("\n"));
|
|
435
|
+
}
|
|
436
|
+
//#endregion
|
|
437
|
+
//#region src/cli/commands/internal/dependency-audit/helpers/getSecurityAudit.ts
|
|
438
|
+
const auditSchema = zod.default.object({
|
|
439
|
+
advisories: zod.default.record(zod.default.string(), zod.default.object({
|
|
440
|
+
title: zod.default.string(),
|
|
441
|
+
module_name: zod.default.string(),
|
|
442
|
+
vulnerable_versions: zod.default.string(),
|
|
443
|
+
patched_versions: zod.default.string(),
|
|
444
|
+
severity: zod.default.enum({
|
|
445
|
+
INFO: "info",
|
|
446
|
+
LOW: "low",
|
|
447
|
+
MODERATE: "moderate",
|
|
448
|
+
HIGH: "high",
|
|
449
|
+
CRITICAL: "critical"
|
|
450
|
+
}),
|
|
451
|
+
url: zod.default.url()
|
|
452
|
+
})),
|
|
453
|
+
metadata: zod.default.object({ vulnerabilities: zod.default.object({
|
|
454
|
+
info: zod.default.number(),
|
|
455
|
+
low: zod.default.number(),
|
|
456
|
+
moderate: zod.default.number(),
|
|
457
|
+
high: zod.default.number(),
|
|
458
|
+
critical: zod.default.number()
|
|
459
|
+
}) })
|
|
460
|
+
});
|
|
461
|
+
function parseSecurityAudit(input) {
|
|
462
|
+
return _alextheman_utility.az.with(auditSchema).parse(input);
|
|
463
|
+
}
|
|
464
|
+
async function getSecurityAudit(program) {
|
|
465
|
+
const { stdout, stderr, exitCode } = await (0, execa.execa)({ reject: false })`pnpm audit --json`;
|
|
466
|
+
if (![0, 1].includes(exitCode)) program.error(stderr ?? stdout, {
|
|
467
|
+
exitCode,
|
|
468
|
+
code: "SECURITY_AUDIT_ERROR"
|
|
469
|
+
});
|
|
470
|
+
const securityAudit = parseSecurityAudit(JSON.parse(stdout));
|
|
471
|
+
const auditTemplatesPath = node_path.default.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "dependencyAudit", "securityAudit");
|
|
472
|
+
const tableTemplate = await (0, node_fs_promises.readFile)(node_path.default.join(auditTemplatesPath, "table.html"), "utf-8");
|
|
473
|
+
const tableRowTemplate = await (0, node_fs_promises.readFile)(node_path.default.join(auditTemplatesPath, "tableRow.html"), "utf-8");
|
|
474
|
+
if (Object.keys(securityAudit.advisories).length === 0) return "No security issues found";
|
|
475
|
+
const severityOrder = {
|
|
476
|
+
critical: 5,
|
|
477
|
+
high: 4,
|
|
478
|
+
moderate: 3,
|
|
479
|
+
low: 2,
|
|
480
|
+
info: 1
|
|
481
|
+
};
|
|
482
|
+
const auditTable = tableTemplate.replace("{{tableRows}}", Object.entries(securityAudit.advisories).toSorted(([_, first], [__, second]) => {
|
|
483
|
+
return severityOrder[second.severity] - severityOrder[first.severity];
|
|
484
|
+
}).map(([id, data]) => {
|
|
485
|
+
return tableRowTemplate.replace("{{advisoryId}}", id).replace("{{severity}}", data.severity).replace("{{packageName}}", data.module_name).replace("{{title}}", data.title).replace("{{affected}}", data.vulnerable_versions).replace("{{patched}}", data.patched_versions).replace("{{url}}", data.url);
|
|
486
|
+
}).join("\n"));
|
|
487
|
+
return _alextheman_utility.normaliseIndents`
|
|
488
|
+
### Summary
|
|
489
|
+
|
|
490
|
+
${(await (0, node_fs_promises.readFile)(node_path.default.join(auditTemplatesPath, "summary.html"), "utf-8")).replace("{{info}}", securityAudit.metadata.vulnerabilities.info.toString()).replace("{{low}}", securityAudit.metadata.vulnerabilities.low.toString()).replace("{{moderate}}", securityAudit.metadata.vulnerabilities.moderate.toString()).replace("{{high}}", securityAudit.metadata.vulnerabilities.high.toString()).replace("{{critical}}", securityAudit.metadata.vulnerabilities.critical.toString())}
|
|
491
|
+
|
|
492
|
+
### Audit Results
|
|
493
|
+
|
|
494
|
+
${auditTable}
|
|
495
|
+
`;
|
|
496
|
+
}
|
|
497
|
+
//#endregion
|
|
498
|
+
//#region src/cli/commands/internal/dependency-audit/index.ts
|
|
499
|
+
function internalDependencyAudit(program) {
|
|
500
|
+
program.command("dependency-audit").description("Run an audit of the PNPM dependencies").option("-o, --output <path>", "Save the output to markdown file.").action(async ({ output }) => {
|
|
501
|
+
const content = _alextheman_utility.normaliseIndents`
|
|
502
|
+
# JavaScript Dependency Audit
|
|
503
|
+
|
|
504
|
+
## Security Audit
|
|
505
|
+
|
|
506
|
+
${await getSecurityAudit(program)}
|
|
507
|
+
|
|
508
|
+
## Peer Dependency Check
|
|
509
|
+
|
|
510
|
+
${await getPeerCheck(program)}
|
|
511
|
+
|
|
512
|
+
## Outdated Dependencies
|
|
513
|
+
|
|
514
|
+
${await getOutdatedDependencies(program)}
|
|
515
|
+
`;
|
|
516
|
+
console.info(content);
|
|
517
|
+
if (output) {
|
|
518
|
+
const fullSavePath = node_path.default.join(process.cwd(), output);
|
|
519
|
+
if (node_path.default.extname(output) !== ".md") throw new _alextheman_utility_v6.DataError({ output }, "INVALID_FILE_EXTENSION", "The file extension must be `.md`");
|
|
520
|
+
await (0, node_fs_promises.writeFile)(fullSavePath, content);
|
|
521
|
+
console.info(`Audit results saved to ${fullSavePath}`);
|
|
522
|
+
}
|
|
523
|
+
});
|
|
524
|
+
}
|
|
525
|
+
//#endregion
|
|
287
526
|
//#region src/cli/commands/internal/git-post-merge-cleanup.ts
|
|
288
|
-
function
|
|
527
|
+
function internalGitPostMergeCleanup(program) {
|
|
289
528
|
program.command("git-post-merge-cleanup").alias("git-cleanup").description("Run after merging into a given branch to quickly clean up").argument("[branch]", "The branch you want to merge into", "main").option("--rebase", "Enable if your repository mainly rebases into main", true).action(async (branch, { rebase }) => {
|
|
290
529
|
console.info(`Running git-post-merge-cleanup in ${rebase ? "rebase" : "merge"} mode...`);
|
|
291
530
|
const { stdout: currentBranch } = await execa.execa`git branch --show-current`;
|
|
@@ -391,27 +630,8 @@ function internalMedia(program) {
|
|
|
391
630
|
loadCommands(program.command("media"), { internalMediaGenerate });
|
|
392
631
|
}
|
|
393
632
|
//#endregion
|
|
394
|
-
//#region src/utility/fileSystem/findPackageRoot.ts
|
|
395
|
-
async function findPackageRoot(startDirectory, packageName) {
|
|
396
|
-
let directory = startDirectory;
|
|
397
|
-
while (true) {
|
|
398
|
-
const packagePath = node_path.default.join(directory, "package.json");
|
|
399
|
-
try {
|
|
400
|
-
if (JSON.parse(await (0, node_fs_promises.readFile)(packagePath, "utf-8"))?.name === packageName) return directory;
|
|
401
|
-
} catch {}
|
|
402
|
-
const parent = node_path.default.dirname(directory);
|
|
403
|
-
if (parent === directory) break;
|
|
404
|
-
directory = parent;
|
|
405
|
-
}
|
|
406
|
-
throw new _alextheman_utility_v6.DataError({ packageName }, "PACKAGE_ROOT_NOT_FOUND", `Could not find package root for ${packageName}`);
|
|
407
|
-
}
|
|
408
|
-
//#endregion
|
|
409
|
-
//#region src/utility/constants/ALEX_C_LINE_PACKAGE_ROOT.ts
|
|
410
|
-
const __filename$3 = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
|
|
411
|
-
const ALEX_C_LINE_PACKAGE_ROOT = findPackageRoot(node_path.default.dirname(__filename$3), "alex-c-line");
|
|
412
|
-
//#endregion
|
|
413
633
|
//#region src/cli/commands/internal/outdated-dependencies.ts
|
|
414
|
-
function
|
|
634
|
+
function internalOutdatedDependencies(program) {
|
|
415
635
|
program.command("outdated-dependencies").action(async () => {
|
|
416
636
|
const { exitCode, stdout, stderr } = await (0, execa.execa)({ reject: false })`pnpm outdated --json`;
|
|
417
637
|
if (![0, 1].includes(exitCode)) program.error(stderr ?? stdout, {
|
|
@@ -435,10 +655,11 @@ function outdatedDependencies(program) {
|
|
|
435
655
|
//#region src/cli/commands/internal/index.ts
|
|
436
656
|
function internal(program) {
|
|
437
657
|
loadCommands(program.command("internal").description("Commands meant more for internal use by me and is not recommended for production usage."), {
|
|
438
|
-
|
|
439
|
-
|
|
658
|
+
internalCheckLockfileVersionDiscrepancy,
|
|
659
|
+
internalDependencyAudit,
|
|
660
|
+
internalGitPostMergeCleanup,
|
|
440
661
|
internalMedia,
|
|
441
|
-
|
|
662
|
+
internalOutdatedDependencies
|
|
442
663
|
});
|
|
443
664
|
}
|
|
444
665
|
//#endregion
|
|
@@ -449,78 +670,6 @@ async function createAlexCLineProjectCache(cacheContents) {
|
|
|
449
670
|
await (0, node_fs_promises.writeFile)(cacheFilePath, JSON.stringify(cacheContents, void 0, 2));
|
|
450
671
|
}
|
|
451
672
|
//#endregion
|
|
452
|
-
//#region src/configs/helpers/preCommit/definePreCommitConfig.ts
|
|
453
|
-
const preCommitStepOptionsSchema = zod.default.strictObject({ arguments: zod.default.array(zod.default.string()).optional() });
|
|
454
|
-
const preCommitConfigSchema = zod.default.strictObject({
|
|
455
|
-
packageManager: zod.default.enum(_alextheman_utility_internal.PackageManager).optional(),
|
|
456
|
-
allowNoStagedChanges: zod.default.boolean().optional(),
|
|
457
|
-
steps: zod.default.array(zod.default.union([
|
|
458
|
-
zod.default.function({
|
|
459
|
-
input: [zod.default.function()],
|
|
460
|
-
output: zod.default.any()
|
|
461
|
-
}),
|
|
462
|
-
zod.default.string(),
|
|
463
|
-
zod.default.tuple([zod.default.string(), preCommitStepOptionsSchema])
|
|
464
|
-
])),
|
|
465
|
-
updateIndex: zod.default.boolean().optional()
|
|
466
|
-
});
|
|
467
|
-
//#endregion
|
|
468
|
-
//#region src/configs/helpers/template/pullRequest/defineTemplatePullRequestSchema.ts
|
|
469
|
-
const templatePullRequestBaseSchema = zod.default.strictObject({ projectName: zod.default.string().optional() });
|
|
470
|
-
const templatePullRequestSchema = zod.default.discriminatedUnion("category", [templatePullRequestBaseSchema.extend({
|
|
471
|
-
category: zod.default.literal("general"),
|
|
472
|
-
projectType: zod.default.string()
|
|
473
|
-
}), templatePullRequestBaseSchema.extend({
|
|
474
|
-
category: zod.default.literal("infrastructure"),
|
|
475
|
-
infrastructureProvider: zod.default.string(),
|
|
476
|
-
requireConfirmationFrom: zod.default.string()
|
|
477
|
-
})]);
|
|
478
|
-
function parseTemplatePullRequestConfig(input) {
|
|
479
|
-
return _alextheman_utility.az.with(templatePullRequestSchema).parse(input);
|
|
480
|
-
}
|
|
481
|
-
//#endregion
|
|
482
|
-
//#region src/configs/helpers/defineAlexCLineConfig.ts
|
|
483
|
-
const alexCLineConfigSchema = zod.default.strictObject({
|
|
484
|
-
preCommit: preCommitConfigSchema,
|
|
485
|
-
template: zod.default.object({ pullRequest: templatePullRequestSchema })
|
|
486
|
-
}).partial();
|
|
487
|
-
async function parseAlexCLineConfig(input) {
|
|
488
|
-
return await _alextheman_utility.az.with(alexCLineConfigSchema).parseAsync(input);
|
|
489
|
-
}
|
|
490
|
-
//#endregion
|
|
491
|
-
//#region src/configs/types/ConfigFileName.ts
|
|
492
|
-
const ConfigFileName = {
|
|
493
|
-
STANDARD_JAVASCRIPT: "alex-c-line.config.js",
|
|
494
|
-
ES_MODULES_JAVASCRIPT: "alex-c-line.config.mjs",
|
|
495
|
-
COMMON_JS_JAVASCRIPT: "alex-c-line.config.cjs"
|
|
496
|
-
};
|
|
497
|
-
const PrivateConfigFileName = {
|
|
498
|
-
STANDARD_JAVASCRIPT: ".alex-c-line.private.config.js",
|
|
499
|
-
ES_MODULES_JAVASCRIPT: ".alex-c-line.private.config.mjs",
|
|
500
|
-
COMMON_JS_JAVASCRIPT: ".alex-c-line.private.config.cjs"
|
|
501
|
-
};
|
|
502
|
-
//#endregion
|
|
503
|
-
//#region src/configs/types/template/pullRequest/PullRequestTemplateCategory.ts
|
|
504
|
-
const PullRequestTemplateCategory = {
|
|
505
|
-
GENERAL: "general",
|
|
506
|
-
INFRASTRUCTURE: "infrastructure"
|
|
507
|
-
};
|
|
508
|
-
//#endregion
|
|
509
|
-
//#region src/configs/helpers/defineAlexCLinePrivateConfig.ts
|
|
510
|
-
const alexCLinePrivateConfigSchema = zod.default.object({ localPackage: zod.default.strictObject({
|
|
511
|
-
enableCache: zod.default.boolean().optional(),
|
|
512
|
-
localPackages: zod.default.record(zod.default.string(), zod.default.strictObject({
|
|
513
|
-
packageManager: zod.default.enum(_alextheman_utility_internal.PackageManager),
|
|
514
|
-
path: zod.default.string(),
|
|
515
|
-
prepareScript: zod.default.string().optional(),
|
|
516
|
-
dependencyGroup: zod.default.enum(_alextheman_utility_internal.DependencyGroup).optional(),
|
|
517
|
-
keepOldTarballs: zod.default.boolean().optional()
|
|
518
|
-
}))
|
|
519
|
-
}) });
|
|
520
|
-
function parseAlexCLinePrivateConfig(data) {
|
|
521
|
-
return _alextheman_utility.az.with(alexCLinePrivateConfigSchema).parse(data);
|
|
522
|
-
}
|
|
523
|
-
//#endregion
|
|
524
673
|
//#region src/cache/project/types/AlexCLineProjectCache.ts
|
|
525
674
|
const alexCLineProjectCacheSchema = zod.default.object({ useLocalPackage: zod.default.object({ dependencies: zod.default.record(zod.default.string(), zod.default.object({
|
|
526
675
|
currentVersion: zod.default.string(),
|
|
@@ -1207,7 +1356,7 @@ function template(program) {
|
|
|
1207
1356
|
//#endregion
|
|
1208
1357
|
//#region package.json
|
|
1209
1358
|
var name = "alex-c-line";
|
|
1210
|
-
var version$1 = "2.
|
|
1359
|
+
var version$1 = "2.9.0";
|
|
1211
1360
|
var description = "Command-line tool with commands to streamline the developer workflow.";
|
|
1212
1361
|
//#endregion
|
|
1213
1362
|
//#region src/utility/updates/checkUpdate.ts
|
package/dist/index.js
CHANGED
|
@@ -12,9 +12,9 @@ import { confirm, input, password, select } from "@inquirer/prompts";
|
|
|
12
12
|
import { access, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
|
|
13
13
|
import { parse } from "dotenv";
|
|
14
14
|
import { ExecaError, execa } from "execa";
|
|
15
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
16
|
-
import { DependencyGroup, PackageManager, getDependenciesFromGroup, getExpectedTgzName, getPackageJsonContents, packageJsonNotFoundError } from "@alextheman/utility/internal";
|
|
17
15
|
import z from "zod";
|
|
16
|
+
import { DependencyGroup, PackageManager, getDependenciesFromGroup, getExpectedTgzName, getPackageJsonContents, packageJsonNotFoundError } from "@alextheman/utility/internal";
|
|
17
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
18
18
|
import { parse as parse$1 } from "toml";
|
|
19
19
|
import matter from "gray-matter";
|
|
20
20
|
import { parseFilePath } from "@alextheman/utility/node";
|
|
@@ -239,7 +239,7 @@ function envFile(program) {
|
|
|
239
239
|
}
|
|
240
240
|
//#endregion
|
|
241
241
|
//#region src/cli/commands/internal/check-lockfile-version-discrepancy.ts
|
|
242
|
-
function
|
|
242
|
+
function internalCheckLockfileVersionDiscrepancy(program) {
|
|
243
243
|
program.command("check-lockfile-version-discrepancy").description("Check that version numbers in package.json and package-lock.json match").action(async () => {
|
|
244
244
|
console.info("Checking for package.json and package-lock.json discrepancies...");
|
|
245
245
|
const { version: packageVersion } = JSON.parse(await readFile(path.resolve(process.cwd(), "package.json"), "utf-8"));
|
|
@@ -253,8 +253,247 @@ function checkLockfileVersionDiscrepancy(program) {
|
|
|
253
253
|
});
|
|
254
254
|
}
|
|
255
255
|
//#endregion
|
|
256
|
+
//#region src/configs/helpers/preCommit/definePreCommitConfig.ts
|
|
257
|
+
const preCommitStepOptionsSchema = z.strictObject({ arguments: z.array(z.string()).optional() });
|
|
258
|
+
const preCommitConfigSchema = z.strictObject({
|
|
259
|
+
packageManager: z.enum(PackageManager).optional(),
|
|
260
|
+
allowNoStagedChanges: z.boolean().optional(),
|
|
261
|
+
steps: z.array(z.union([
|
|
262
|
+
z.function({
|
|
263
|
+
input: [z.function()],
|
|
264
|
+
output: z.any()
|
|
265
|
+
}),
|
|
266
|
+
z.string(),
|
|
267
|
+
z.tuple([z.string(), preCommitStepOptionsSchema])
|
|
268
|
+
])),
|
|
269
|
+
updateIndex: z.boolean().optional()
|
|
270
|
+
});
|
|
271
|
+
//#endregion
|
|
272
|
+
//#region src/configs/helpers/template/pullRequest/defineTemplatePullRequestSchema.ts
|
|
273
|
+
const templatePullRequestBaseSchema = z.strictObject({ projectName: z.string().optional() });
|
|
274
|
+
const templatePullRequestSchema = z.discriminatedUnion("category", [templatePullRequestBaseSchema.extend({
|
|
275
|
+
category: z.literal("general"),
|
|
276
|
+
projectType: z.string()
|
|
277
|
+
}), templatePullRequestBaseSchema.extend({
|
|
278
|
+
category: z.literal("infrastructure"),
|
|
279
|
+
infrastructureProvider: z.string(),
|
|
280
|
+
requireConfirmationFrom: z.string()
|
|
281
|
+
})]);
|
|
282
|
+
function parseTemplatePullRequestConfig(input) {
|
|
283
|
+
return az.with(templatePullRequestSchema).parse(input);
|
|
284
|
+
}
|
|
285
|
+
//#endregion
|
|
286
|
+
//#region src/configs/helpers/defineAlexCLineConfig.ts
|
|
287
|
+
const alexCLineConfigSchema = z.strictObject({
|
|
288
|
+
preCommit: preCommitConfigSchema,
|
|
289
|
+
template: z.object({ pullRequest: templatePullRequestSchema })
|
|
290
|
+
}).partial();
|
|
291
|
+
async function parseAlexCLineConfig(input) {
|
|
292
|
+
return await az.with(alexCLineConfigSchema).parseAsync(input);
|
|
293
|
+
}
|
|
294
|
+
//#endregion
|
|
295
|
+
//#region src/configs/types/ConfigFileName.ts
|
|
296
|
+
const ConfigFileName = {
|
|
297
|
+
STANDARD_JAVASCRIPT: "alex-c-line.config.js",
|
|
298
|
+
ES_MODULES_JAVASCRIPT: "alex-c-line.config.mjs",
|
|
299
|
+
COMMON_JS_JAVASCRIPT: "alex-c-line.config.cjs"
|
|
300
|
+
};
|
|
301
|
+
const PrivateConfigFileName = {
|
|
302
|
+
STANDARD_JAVASCRIPT: ".alex-c-line.private.config.js",
|
|
303
|
+
ES_MODULES_JAVASCRIPT: ".alex-c-line.private.config.mjs",
|
|
304
|
+
COMMON_JS_JAVASCRIPT: ".alex-c-line.private.config.cjs"
|
|
305
|
+
};
|
|
306
|
+
//#endregion
|
|
307
|
+
//#region src/configs/types/template/pullRequest/PullRequestTemplateCategory.ts
|
|
308
|
+
const PullRequestTemplateCategory = {
|
|
309
|
+
GENERAL: "general",
|
|
310
|
+
INFRASTRUCTURE: "infrastructure"
|
|
311
|
+
};
|
|
312
|
+
//#endregion
|
|
313
|
+
//#region src/configs/helpers/defineAlexCLinePrivateConfig.ts
|
|
314
|
+
const alexCLinePrivateConfigSchema = z.object({ localPackage: z.strictObject({
|
|
315
|
+
enableCache: z.boolean().optional(),
|
|
316
|
+
localPackages: z.record(z.string(), z.strictObject({
|
|
317
|
+
packageManager: z.enum(PackageManager),
|
|
318
|
+
path: z.string(),
|
|
319
|
+
prepareScript: z.string().optional(),
|
|
320
|
+
dependencyGroup: z.enum(DependencyGroup).optional(),
|
|
321
|
+
keepOldTarballs: z.boolean().optional()
|
|
322
|
+
}))
|
|
323
|
+
}) });
|
|
324
|
+
function parseAlexCLinePrivateConfig(data) {
|
|
325
|
+
return az.with(alexCLinePrivateConfigSchema).parse(data);
|
|
326
|
+
}
|
|
327
|
+
//#endregion
|
|
328
|
+
//#region src/utility/fileSystem/findPackageRoot.ts
|
|
329
|
+
async function findPackageRoot(startDirectory, packageName) {
|
|
330
|
+
let directory = startDirectory;
|
|
331
|
+
while (true) {
|
|
332
|
+
const packagePath = path.join(directory, "package.json");
|
|
333
|
+
try {
|
|
334
|
+
if (JSON.parse(await readFile(packagePath, "utf-8"))?.name === packageName) return directory;
|
|
335
|
+
} catch {}
|
|
336
|
+
const parent = path.dirname(directory);
|
|
337
|
+
if (parent === directory) break;
|
|
338
|
+
directory = parent;
|
|
339
|
+
}
|
|
340
|
+
throw new DataError({ packageName }, "PACKAGE_ROOT_NOT_FOUND", `Could not find package root for ${packageName}`);
|
|
341
|
+
}
|
|
342
|
+
//#endregion
|
|
343
|
+
//#region src/utility/constants/ALEX_C_LINE_PACKAGE_ROOT.ts
|
|
344
|
+
const __filename$2 = fileURLToPath(import.meta.url);
|
|
345
|
+
const ALEX_C_LINE_PACKAGE_ROOT = findPackageRoot(path.dirname(__filename$2), "alex-c-line");
|
|
346
|
+
//#endregion
|
|
347
|
+
//#region src/cli/commands/internal/dependency-audit/helpers/getOutdatedDependencies.ts
|
|
348
|
+
const pnpmOutdatedSchema = z.record(z.string(), z.object({
|
|
349
|
+
current: az.versionNumber(),
|
|
350
|
+
latest: az.versionNumber(),
|
|
351
|
+
isDeprecated: z.boolean(),
|
|
352
|
+
dependencyType: z.enum(DependencyGroup)
|
|
353
|
+
}));
|
|
354
|
+
function parseOutdated(input) {
|
|
355
|
+
return az.with(pnpmOutdatedSchema).parse(input);
|
|
356
|
+
}
|
|
357
|
+
async function getOutdatedDependencies(program) {
|
|
358
|
+
const { exitCode, stdout, stderr } = await execa({ reject: false })`pnpm outdated --json`;
|
|
359
|
+
if (![0, 1].includes(exitCode)) program.error(stderr ?? stdout, {
|
|
360
|
+
exitCode,
|
|
361
|
+
code: "OUTDATED_DEPENDENCIES_ERROR"
|
|
362
|
+
});
|
|
363
|
+
const outdatedDependencies = parseOutdated(JSON.parse(stdout.trim()));
|
|
364
|
+
if (Object.keys(outdatedDependencies).length === 0) return "No outdated dependencies found.";
|
|
365
|
+
const outdatedTemplatesPath = path.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "dependencyAudit", "outdated");
|
|
366
|
+
const tableTemplate = await readFile(path.join(outdatedTemplatesPath, "table.html"), "utf-8");
|
|
367
|
+
const tableRowTemplate = await readFile(path.join(outdatedTemplatesPath, "tableRow.html"), "utf-8");
|
|
368
|
+
return tableTemplate.replace("{{tableRows}}", Object.entries(outdatedDependencies).map(([packageName, data]) => {
|
|
369
|
+
return tableRowTemplate.replace("{{packageName}}", packageName).replace("{{currentVersion}}", data.current.toString()).replace("{{latestVersion}}", data.latest.toString()).replace("{{isDeprecated}}", data.isDeprecated ? "Yes" : "No").replace("{{dependencyGroup}}", data.dependencyType);
|
|
370
|
+
}).join("\n"));
|
|
371
|
+
}
|
|
372
|
+
//#endregion
|
|
373
|
+
//#region src/cli/commands/internal/dependency-audit/helpers/getPeerCheck.ts
|
|
374
|
+
const pnpmPeerCheckSchema = z.object({ ".": z.object({ bad: z.record(z.string(), z.array(z.object({
|
|
375
|
+
parents: z.array(z.object({
|
|
376
|
+
name: z.string(),
|
|
377
|
+
version: az.versionNumber()
|
|
378
|
+
})),
|
|
379
|
+
optional: z.boolean(),
|
|
380
|
+
wantedRange: z.string(),
|
|
381
|
+
foundVersion: az.versionNumber()
|
|
382
|
+
}))) }) });
|
|
383
|
+
function parsePeerCheck(input) {
|
|
384
|
+
return az.with(pnpmPeerCheckSchema).parse(input);
|
|
385
|
+
}
|
|
386
|
+
async function getPeerCheck(program) {
|
|
387
|
+
const { stdout, stderr, exitCode } = await execa({ reject: false })`pnpm peers check --json`;
|
|
388
|
+
if (![0, 1].includes(exitCode)) program.error(stderr ?? stdout, {
|
|
389
|
+
exitCode,
|
|
390
|
+
code: "PEERS_CHECK_ERROR"
|
|
391
|
+
});
|
|
392
|
+
const peerCheck = parsePeerCheck(JSON.parse(stdout));
|
|
393
|
+
const auditTemplatesPath = path.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "dependencyAudit", "peerCheck");
|
|
394
|
+
const peerCheckTableTemplate = await readFile(path.join(auditTemplatesPath, "table.html"), "utf-8");
|
|
395
|
+
const peerCheckTableRowTemplate = await readFile(path.join(auditTemplatesPath, "tableRow.html"), "utf-8");
|
|
396
|
+
if (Object.keys(peerCheck["."].bad).length === 0) return "No peer dependency issues found";
|
|
397
|
+
return peerCheckTableTemplate.replace("{{tableRows}}", Object.entries(peerCheck["."].bad).flatMap(([packageName, data]) => {
|
|
398
|
+
return data.map((item) => {
|
|
399
|
+
return peerCheckTableRowTemplate.replace("{{packageName}}", packageName).replace("{{currentVersion}}", item.foundVersion.toString()).replace("{{wantedRange}}", item.wantedRange).replace("{{parentDependencies}}", item.parents.map((parent) => {
|
|
400
|
+
return `${parent.name}@${parent.version}`;
|
|
401
|
+
}).join(", "));
|
|
402
|
+
});
|
|
403
|
+
}).join("\n"));
|
|
404
|
+
}
|
|
405
|
+
//#endregion
|
|
406
|
+
//#region src/cli/commands/internal/dependency-audit/helpers/getSecurityAudit.ts
|
|
407
|
+
const auditSchema = z.object({
|
|
408
|
+
advisories: z.record(z.string(), z.object({
|
|
409
|
+
title: z.string(),
|
|
410
|
+
module_name: z.string(),
|
|
411
|
+
vulnerable_versions: z.string(),
|
|
412
|
+
patched_versions: z.string(),
|
|
413
|
+
severity: z.enum({
|
|
414
|
+
INFO: "info",
|
|
415
|
+
LOW: "low",
|
|
416
|
+
MODERATE: "moderate",
|
|
417
|
+
HIGH: "high",
|
|
418
|
+
CRITICAL: "critical"
|
|
419
|
+
}),
|
|
420
|
+
url: z.url()
|
|
421
|
+
})),
|
|
422
|
+
metadata: z.object({ vulnerabilities: z.object({
|
|
423
|
+
info: z.number(),
|
|
424
|
+
low: z.number(),
|
|
425
|
+
moderate: z.number(),
|
|
426
|
+
high: z.number(),
|
|
427
|
+
critical: z.number()
|
|
428
|
+
}) })
|
|
429
|
+
});
|
|
430
|
+
function parseSecurityAudit(input) {
|
|
431
|
+
return az.with(auditSchema).parse(input);
|
|
432
|
+
}
|
|
433
|
+
async function getSecurityAudit(program) {
|
|
434
|
+
const { stdout, stderr, exitCode } = await execa({ reject: false })`pnpm audit --json`;
|
|
435
|
+
if (![0, 1].includes(exitCode)) program.error(stderr ?? stdout, {
|
|
436
|
+
exitCode,
|
|
437
|
+
code: "SECURITY_AUDIT_ERROR"
|
|
438
|
+
});
|
|
439
|
+
const securityAudit = parseSecurityAudit(JSON.parse(stdout));
|
|
440
|
+
const auditTemplatesPath = path.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "dependencyAudit", "securityAudit");
|
|
441
|
+
const tableTemplate = await readFile(path.join(auditTemplatesPath, "table.html"), "utf-8");
|
|
442
|
+
const tableRowTemplate = await readFile(path.join(auditTemplatesPath, "tableRow.html"), "utf-8");
|
|
443
|
+
if (Object.keys(securityAudit.advisories).length === 0) return "No security issues found";
|
|
444
|
+
const severityOrder = {
|
|
445
|
+
critical: 5,
|
|
446
|
+
high: 4,
|
|
447
|
+
moderate: 3,
|
|
448
|
+
low: 2,
|
|
449
|
+
info: 1
|
|
450
|
+
};
|
|
451
|
+
const auditTable = tableTemplate.replace("{{tableRows}}", Object.entries(securityAudit.advisories).toSorted(([_, first], [__, second]) => {
|
|
452
|
+
return severityOrder[second.severity] - severityOrder[first.severity];
|
|
453
|
+
}).map(([id, data]) => {
|
|
454
|
+
return tableRowTemplate.replace("{{advisoryId}}", id).replace("{{severity}}", data.severity).replace("{{packageName}}", data.module_name).replace("{{title}}", data.title).replace("{{affected}}", data.vulnerable_versions).replace("{{patched}}", data.patched_versions).replace("{{url}}", data.url);
|
|
455
|
+
}).join("\n"));
|
|
456
|
+
return normaliseIndents`
|
|
457
|
+
### Summary
|
|
458
|
+
|
|
459
|
+
${(await readFile(path.join(auditTemplatesPath, "summary.html"), "utf-8")).replace("{{info}}", securityAudit.metadata.vulnerabilities.info.toString()).replace("{{low}}", securityAudit.metadata.vulnerabilities.low.toString()).replace("{{moderate}}", securityAudit.metadata.vulnerabilities.moderate.toString()).replace("{{high}}", securityAudit.metadata.vulnerabilities.high.toString()).replace("{{critical}}", securityAudit.metadata.vulnerabilities.critical.toString())}
|
|
460
|
+
|
|
461
|
+
### Audit Results
|
|
462
|
+
|
|
463
|
+
${auditTable}
|
|
464
|
+
`;
|
|
465
|
+
}
|
|
466
|
+
//#endregion
|
|
467
|
+
//#region src/cli/commands/internal/dependency-audit/index.ts
|
|
468
|
+
function internalDependencyAudit(program) {
|
|
469
|
+
program.command("dependency-audit").description("Run an audit of the PNPM dependencies").option("-o, --output <path>", "Save the output to markdown file.").action(async ({ output }) => {
|
|
470
|
+
const content = normaliseIndents`
|
|
471
|
+
# JavaScript Dependency Audit
|
|
472
|
+
|
|
473
|
+
## Security Audit
|
|
474
|
+
|
|
475
|
+
${await getSecurityAudit(program)}
|
|
476
|
+
|
|
477
|
+
## Peer Dependency Check
|
|
478
|
+
|
|
479
|
+
${await getPeerCheck(program)}
|
|
480
|
+
|
|
481
|
+
## Outdated Dependencies
|
|
482
|
+
|
|
483
|
+
${await getOutdatedDependencies(program)}
|
|
484
|
+
`;
|
|
485
|
+
console.info(content);
|
|
486
|
+
if (output) {
|
|
487
|
+
const fullSavePath = path.join(process.cwd(), output);
|
|
488
|
+
if (path.extname(output) !== ".md") throw new DataError({ output }, "INVALID_FILE_EXTENSION", "The file extension must be `.md`");
|
|
489
|
+
await writeFile(fullSavePath, content);
|
|
490
|
+
console.info(`Audit results saved to ${fullSavePath}`);
|
|
491
|
+
}
|
|
492
|
+
});
|
|
493
|
+
}
|
|
494
|
+
//#endregion
|
|
256
495
|
//#region src/cli/commands/internal/git-post-merge-cleanup.ts
|
|
257
|
-
function
|
|
496
|
+
function internalGitPostMergeCleanup(program) {
|
|
258
497
|
program.command("git-post-merge-cleanup").alias("git-cleanup").description("Run after merging into a given branch to quickly clean up").argument("[branch]", "The branch you want to merge into", "main").option("--rebase", "Enable if your repository mainly rebases into main", true).action(async (branch, { rebase }) => {
|
|
259
498
|
console.info(`Running git-post-merge-cleanup in ${rebase ? "rebase" : "merge"} mode...`);
|
|
260
499
|
const { stdout: currentBranch } = await execa`git branch --show-current`;
|
|
@@ -360,27 +599,8 @@ function internalMedia(program) {
|
|
|
360
599
|
loadCommands(program.command("media"), { internalMediaGenerate });
|
|
361
600
|
}
|
|
362
601
|
//#endregion
|
|
363
|
-
//#region src/utility/fileSystem/findPackageRoot.ts
|
|
364
|
-
async function findPackageRoot(startDirectory, packageName) {
|
|
365
|
-
let directory = startDirectory;
|
|
366
|
-
while (true) {
|
|
367
|
-
const packagePath = path.join(directory, "package.json");
|
|
368
|
-
try {
|
|
369
|
-
if (JSON.parse(await readFile(packagePath, "utf-8"))?.name === packageName) return directory;
|
|
370
|
-
} catch {}
|
|
371
|
-
const parent = path.dirname(directory);
|
|
372
|
-
if (parent === directory) break;
|
|
373
|
-
directory = parent;
|
|
374
|
-
}
|
|
375
|
-
throw new DataError({ packageName }, "PACKAGE_ROOT_NOT_FOUND", `Could not find package root for ${packageName}`);
|
|
376
|
-
}
|
|
377
|
-
//#endregion
|
|
378
|
-
//#region src/utility/constants/ALEX_C_LINE_PACKAGE_ROOT.ts
|
|
379
|
-
const __filename$2 = fileURLToPath(import.meta.url);
|
|
380
|
-
const ALEX_C_LINE_PACKAGE_ROOT = findPackageRoot(path.dirname(__filename$2), "alex-c-line");
|
|
381
|
-
//#endregion
|
|
382
602
|
//#region src/cli/commands/internal/outdated-dependencies.ts
|
|
383
|
-
function
|
|
603
|
+
function internalOutdatedDependencies(program) {
|
|
384
604
|
program.command("outdated-dependencies").action(async () => {
|
|
385
605
|
const { exitCode, stdout, stderr } = await execa({ reject: false })`pnpm outdated --json`;
|
|
386
606
|
if (![0, 1].includes(exitCode)) program.error(stderr ?? stdout, {
|
|
@@ -404,10 +624,11 @@ function outdatedDependencies(program) {
|
|
|
404
624
|
//#region src/cli/commands/internal/index.ts
|
|
405
625
|
function internal(program) {
|
|
406
626
|
loadCommands(program.command("internal").description("Commands meant more for internal use by me and is not recommended for production usage."), {
|
|
407
|
-
|
|
408
|
-
|
|
627
|
+
internalCheckLockfileVersionDiscrepancy,
|
|
628
|
+
internalDependencyAudit,
|
|
629
|
+
internalGitPostMergeCleanup,
|
|
409
630
|
internalMedia,
|
|
410
|
-
|
|
631
|
+
internalOutdatedDependencies
|
|
411
632
|
});
|
|
412
633
|
}
|
|
413
634
|
//#endregion
|
|
@@ -418,78 +639,6 @@ async function createAlexCLineProjectCache(cacheContents) {
|
|
|
418
639
|
await writeFile(cacheFilePath, JSON.stringify(cacheContents, void 0, 2));
|
|
419
640
|
}
|
|
420
641
|
//#endregion
|
|
421
|
-
//#region src/configs/helpers/preCommit/definePreCommitConfig.ts
|
|
422
|
-
const preCommitStepOptionsSchema = z.strictObject({ arguments: z.array(z.string()).optional() });
|
|
423
|
-
const preCommitConfigSchema = z.strictObject({
|
|
424
|
-
packageManager: z.enum(PackageManager).optional(),
|
|
425
|
-
allowNoStagedChanges: z.boolean().optional(),
|
|
426
|
-
steps: z.array(z.union([
|
|
427
|
-
z.function({
|
|
428
|
-
input: [z.function()],
|
|
429
|
-
output: z.any()
|
|
430
|
-
}),
|
|
431
|
-
z.string(),
|
|
432
|
-
z.tuple([z.string(), preCommitStepOptionsSchema])
|
|
433
|
-
])),
|
|
434
|
-
updateIndex: z.boolean().optional()
|
|
435
|
-
});
|
|
436
|
-
//#endregion
|
|
437
|
-
//#region src/configs/helpers/template/pullRequest/defineTemplatePullRequestSchema.ts
|
|
438
|
-
const templatePullRequestBaseSchema = z.strictObject({ projectName: z.string().optional() });
|
|
439
|
-
const templatePullRequestSchema = z.discriminatedUnion("category", [templatePullRequestBaseSchema.extend({
|
|
440
|
-
category: z.literal("general"),
|
|
441
|
-
projectType: z.string()
|
|
442
|
-
}), templatePullRequestBaseSchema.extend({
|
|
443
|
-
category: z.literal("infrastructure"),
|
|
444
|
-
infrastructureProvider: z.string(),
|
|
445
|
-
requireConfirmationFrom: z.string()
|
|
446
|
-
})]);
|
|
447
|
-
function parseTemplatePullRequestConfig(input) {
|
|
448
|
-
return az.with(templatePullRequestSchema).parse(input);
|
|
449
|
-
}
|
|
450
|
-
//#endregion
|
|
451
|
-
//#region src/configs/helpers/defineAlexCLineConfig.ts
|
|
452
|
-
const alexCLineConfigSchema = z.strictObject({
|
|
453
|
-
preCommit: preCommitConfigSchema,
|
|
454
|
-
template: z.object({ pullRequest: templatePullRequestSchema })
|
|
455
|
-
}).partial();
|
|
456
|
-
async function parseAlexCLineConfig(input) {
|
|
457
|
-
return await az.with(alexCLineConfigSchema).parseAsync(input);
|
|
458
|
-
}
|
|
459
|
-
//#endregion
|
|
460
|
-
//#region src/configs/types/ConfigFileName.ts
|
|
461
|
-
const ConfigFileName = {
|
|
462
|
-
STANDARD_JAVASCRIPT: "alex-c-line.config.js",
|
|
463
|
-
ES_MODULES_JAVASCRIPT: "alex-c-line.config.mjs",
|
|
464
|
-
COMMON_JS_JAVASCRIPT: "alex-c-line.config.cjs"
|
|
465
|
-
};
|
|
466
|
-
const PrivateConfigFileName = {
|
|
467
|
-
STANDARD_JAVASCRIPT: ".alex-c-line.private.config.js",
|
|
468
|
-
ES_MODULES_JAVASCRIPT: ".alex-c-line.private.config.mjs",
|
|
469
|
-
COMMON_JS_JAVASCRIPT: ".alex-c-line.private.config.cjs"
|
|
470
|
-
};
|
|
471
|
-
//#endregion
|
|
472
|
-
//#region src/configs/types/template/pullRequest/PullRequestTemplateCategory.ts
|
|
473
|
-
const PullRequestTemplateCategory = {
|
|
474
|
-
GENERAL: "general",
|
|
475
|
-
INFRASTRUCTURE: "infrastructure"
|
|
476
|
-
};
|
|
477
|
-
//#endregion
|
|
478
|
-
//#region src/configs/helpers/defineAlexCLinePrivateConfig.ts
|
|
479
|
-
const alexCLinePrivateConfigSchema = z.object({ localPackage: z.strictObject({
|
|
480
|
-
enableCache: z.boolean().optional(),
|
|
481
|
-
localPackages: z.record(z.string(), z.strictObject({
|
|
482
|
-
packageManager: z.enum(PackageManager),
|
|
483
|
-
path: z.string(),
|
|
484
|
-
prepareScript: z.string().optional(),
|
|
485
|
-
dependencyGroup: z.enum(DependencyGroup).optional(),
|
|
486
|
-
keepOldTarballs: z.boolean().optional()
|
|
487
|
-
}))
|
|
488
|
-
}) });
|
|
489
|
-
function parseAlexCLinePrivateConfig(data) {
|
|
490
|
-
return az.with(alexCLinePrivateConfigSchema).parse(data);
|
|
491
|
-
}
|
|
492
|
-
//#endregion
|
|
493
642
|
//#region src/cache/project/types/AlexCLineProjectCache.ts
|
|
494
643
|
const alexCLineProjectCacheSchema = z.object({ useLocalPackage: z.object({ dependencies: z.record(z.string(), z.object({
|
|
495
644
|
currentVersion: z.string(),
|
|
@@ -1176,7 +1325,7 @@ function template(program) {
|
|
|
1176
1325
|
//#endregion
|
|
1177
1326
|
//#region package.json
|
|
1178
1327
|
var name = "alex-c-line";
|
|
1179
|
-
var version$1 = "2.
|
|
1328
|
+
var version$1 = "2.9.0";
|
|
1180
1329
|
var description = "Command-line tool with commands to streamline the developer workflow.";
|
|
1181
1330
|
//#endregion
|
|
1182
1331
|
//#region src/utility/updates/checkUpdate.ts
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alex-c-line",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.9.0",
|
|
4
4
|
"description": "Command-line tool with commands to streamline the developer workflow.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"templates"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@alextheman/utility": "5.19.
|
|
38
|
-
"@inquirer/prompts": "8.
|
|
37
|
+
"@alextheman/utility": "5.19.1",
|
|
38
|
+
"@inquirer/prompts": "8.5.0",
|
|
39
39
|
"axios": "1.16.1",
|
|
40
40
|
"boxen": "8.0.1",
|
|
41
41
|
"chalk": "5.6.2",
|
|
@@ -52,7 +52,7 @@
|
|
|
52
52
|
"zod": "4.4.3"
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"@alextheman/eslint-plugin": "5.
|
|
55
|
+
"@alextheman/eslint-plugin": "5.16.1",
|
|
56
56
|
"@commander-js/extra-typings": "14.0.0",
|
|
57
57
|
"@types/eslint": "9.6.1",
|
|
58
58
|
"@types/node": "25.9.1",
|
|
@@ -66,9 +66,9 @@
|
|
|
66
66
|
"prettier": "3.8.3",
|
|
67
67
|
"tempy": "3.2.0",
|
|
68
68
|
"ts-node": "10.9.2",
|
|
69
|
-
"tsdown": "0.22.
|
|
69
|
+
"tsdown": "0.22.1",
|
|
70
70
|
"typescript": "6.0.3",
|
|
71
|
-
"typescript-eslint": "8.
|
|
71
|
+
"typescript-eslint": "8.60.0",
|
|
72
72
|
"vite": "8.0.14",
|
|
73
73
|
"vitest": "4.1.7"
|
|
74
74
|
},
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<table>
|
|
2
|
+
<thead>
|
|
3
|
+
<tr>
|
|
4
|
+
<th scope="col">ID</th>
|
|
5
|
+
<th scope="col">Severity</th>
|
|
6
|
+
<th scope="col">Title</th>
|
|
7
|
+
<th scope="col">Package</th>
|
|
8
|
+
<th scope="col">Affected</th>
|
|
9
|
+
<th scope="col">Patched</th>
|
|
10
|
+
</tr>
|
|
11
|
+
</thead>
|
|
12
|
+
<tbody>
|
|
13
|
+
{{tableRows}}
|
|
14
|
+
</tbody>
|
|
15
|
+
</table>
|