alex-c-line 2.8.0 → 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 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 checkLockfileVersionDiscrepancy(program) {
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 gitPostMergeCleanup(program) {
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 outdatedDependencies(program) {
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
- checkLockfileVersionDiscrepancy,
439
- gitPostMergeCleanup,
658
+ internalCheckLockfileVersionDiscrepancy,
659
+ internalDependencyAudit,
660
+ internalGitPostMergeCleanup,
440
661
  internalMedia,
441
- outdatedDependencies
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.8.0";
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 checkLockfileVersionDiscrepancy(program) {
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 gitPostMergeCleanup(program) {
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 outdatedDependencies(program) {
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
- checkLockfileVersionDiscrepancy,
408
- gitPostMergeCleanup,
627
+ internalCheckLockfileVersionDiscrepancy,
628
+ internalDependencyAudit,
629
+ internalGitPostMergeCleanup,
409
630
  internalMedia,
410
- outdatedDependencies
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.8.0";
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.8.0",
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.0",
38
- "@inquirer/prompts": "8.4.3",
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.15.0",
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.0",
69
+ "tsdown": "0.22.1",
70
70
  "typescript": "6.0.3",
71
- "typescript-eslint": "8.59.4",
71
+ "typescript-eslint": "8.60.0",
72
72
  "vite": "8.0.14",
73
73
  "vitest": "4.1.7"
74
74
  },
@@ -4,6 +4,8 @@
4
4
  <th scope="col">Name</th>
5
5
  <th scope="col">Current Version</th>
6
6
  <th scope="col">Latest Version</th>
7
+ <th scope="col">Deprecated</th>
8
+ <th scope="col">Dependency Group</th>
7
9
  </tr>
8
10
  </thead>
9
11
  <tbody>
@@ -2,4 +2,6 @@
2
2
  <th scope="row">{{packageName}}</th>
3
3
  <td>{{currentVersion}}</td>
4
4
  <td>{{latestVersion}}</td>
5
+ <td>{{isDeprecated}}</td>
6
+ <td>{{dependencyGroup}}</td>
5
7
  </tr>
@@ -0,0 +1,13 @@
1
+ <table>
2
+ <thead>
3
+ <tr>
4
+ <th scope="col">Unmet Peer</th>
5
+ <th scope="col">Installed</th>
6
+ <th scope="col">Version Range Wanted</th>
7
+ <th scope="col">Range Wanted By</th>
8
+ </tr>
9
+ </thead>
10
+ <tbody>
11
+ {{tableRows}}
12
+ </tbody>
13
+ </table>
@@ -0,0 +1,6 @@
1
+ <tr>
2
+ <th scope="row">{{packageName}}</th>
3
+ <td>{{currentVersion}}</td>
4
+ <td>{{wantedRange}}</td>
5
+ <td>{{parentDependencies}}</td>
6
+ </tr>
@@ -0,0 +1,7 @@
1
+ <ul>
2
+ <li>Info: {{info}}</li>
3
+ <li>Low: {{low}}</li>
4
+ <li>Moderate: {{moderate}}</li>
5
+ <li>High: {{high}}</li>
6
+ <li>Critical: {{critical}}</li>
7
+ </ul>
@@ -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>
@@ -0,0 +1,10 @@
1
+ <tr>
2
+ <td>
3
+ <a href="{{url}}">{{advisoryId}}</a>
4
+ </td>
5
+ <th scope="row">{{severity}}</th>
6
+ <td>{{title}}</td>
7
+ <td>{{packageName}}</td>
8
+ <td>{{affected}}</td>
9
+ <td>{{patched}}</td>
10
+ </tr>