alex-c-line 2.0.2 → 2.1.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
@@ -21,8 +21,8 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
21
21
  enumerable: true
22
22
  }) : target, mod));
23
23
  //#endregion
24
- let _alextheman_utility = require("@alextheman/utility");
25
24
  let commander = require("commander");
25
+ let _alextheman_utility = require("@alextheman/utility");
26
26
  let chalk = require("chalk");
27
27
  chalk = __toESM(chalk);
28
28
  let boxen = require("boxen");
@@ -46,6 +46,8 @@ let node_module = require("node:module");
46
46
  let gray_matter = require("gray-matter");
47
47
  gray_matter = __toESM(gray_matter);
48
48
  let _alextheman_utility_node = require("@alextheman/utility/node");
49
+ let axios = require("axios");
50
+ axios = __toESM(axios);
49
51
  let supports_color = require("supports-color");
50
52
  supports_color = __toESM(supports_color);
51
53
  let node_crypto = require("node:crypto");
@@ -826,7 +828,7 @@ function root(program) {
826
828
  });
827
829
  }
828
830
  //#endregion
829
- //#region src/utility/markdownTemplates/pullRequest/getPullRequestTemplatesFromMarkdown.ts
831
+ //#region src/utility/markdownTemplates/pullRequest/createPullRequestTemplatesFromTemplates.ts
830
832
  const __filename$2 = (0, node_url.fileURLToPath)(require("url").pathToFileURL(__filename).href);
831
833
  function getTemplateVariables$1(config) {
832
834
  if (config.category === "general") return {
@@ -839,7 +841,7 @@ function getTemplateVariables$1(config) {
839
841
  requireConfirmationFrom: config.requireConfirmationFrom
840
842
  };
841
843
  }
842
- async function getPullRequestTemplatesFromMarkdown(config) {
844
+ async function createPullRequestTemplatesFromTemplates(config) {
843
845
  const templateVariables = getTemplateVariables$1(config);
844
846
  const { category } = config;
845
847
  const templatesPath = node_path.default.join(await findPackageRoot(node_path.default.dirname(__filename$2), "alex-c-line"), "templates", "pullRequest");
@@ -883,7 +885,7 @@ function templatePullRequestCreate(program) {
883
885
  }));
884
886
  const gitHubPath = node_path.default.join(process.cwd(), ".github");
885
887
  const pullRequestTemplatePath = node_path.default.join(gitHubPath, "PULL_REQUEST_TEMPLATE");
886
- const allTemplates = await getPullRequestTemplatesFromMarkdown({
888
+ const allTemplates = await createPullRequestTemplatesFromTemplates({
887
889
  ...parsedOptions,
888
890
  projectName
889
891
  });
@@ -924,17 +926,6 @@ function parseReleaseStatus(data) {
924
926
  return ReleaseStatus[normalisedStringifiedData];
925
927
  }
926
928
  //#endregion
927
- //#region src/utility/markdownTemplates/createMarkdownComment.ts
928
- function createMarkdownComment(comment) {
929
- if (comment.startsWith("<!--") && comment.endsWith("-->")) return comment;
930
- return `<!-- ${comment} -->`;
931
- }
932
- //#endregion
933
- //#region src/utility/markdownTemplates/createMarkdownCommentPair.ts
934
- function createMarkdownCommentPair(comment) {
935
- return [createMarkdownComment(`${comment}-start`), createMarkdownComment(`${comment}-end`)];
936
- }
937
- //#endregion
938
929
  //#region src/utility/markdownTemplates/getMarkdownBlock.ts
939
930
  function getMarkdownBlock(content, startMarker, endMarker) {
940
931
  const startIndex = content.indexOf(startMarker);
@@ -943,6 +934,17 @@ function getMarkdownBlock(content, startMarker, endMarker) {
943
934
  return content.slice(startIndex + startMarker.length, endIndex).trim();
944
935
  }
945
936
  //#endregion
937
+ //#region src/utility/markdownTemplates/getMarkdownComment.ts
938
+ function createMarkdownComment(comment) {
939
+ if (comment.startsWith("<!--") && comment.endsWith("-->")) return comment;
940
+ return `<!-- ${comment} -->`;
941
+ }
942
+ //#endregion
943
+ //#region src/utility/markdownTemplates/getMarkdownCommentPair.ts
944
+ function getMarkdownCommentPair(comment) {
945
+ return [createMarkdownComment(`${comment}-start`), createMarkdownComment(`${comment}-end`)];
946
+ }
947
+ //#endregion
946
948
  //#region src/utility/markdownTemplates/normaliseMarkdown.ts
947
949
  function normaliseMarkdown(markdownString) {
948
950
  return markdownString.replace(/\r\n/g, "\n").split("\n").map((line) => {
@@ -952,7 +954,7 @@ function normaliseMarkdown(markdownString) {
952
954
  //#endregion
953
955
  //#region src/utility/markdownTemplates/releaseNote/getReleaseStatus.ts
954
956
  function getReleaseStatus(content) {
955
- const releaseStatus = getMarkdownBlock(content, ...createMarkdownCommentPair("alex-c-line-release-status"));
957
+ const releaseStatus = getMarkdownBlock(content, ...getMarkdownCommentPair("alex-c-line-release-status"));
956
958
  if (releaseStatus === null) throw new _alextheman_utility.DataError({ releaseStatus }, "RELEASE_STATUS_NOT_FOUND", "Could not find release status in document.");
957
959
  return (0, _alextheman_utility.parseZodSchema)(zod.default.enum(ReleaseStatus), normaliseMarkdown(releaseStatus.split(":")[1]));
958
960
  }
@@ -975,7 +977,7 @@ async function validateReleaseDocument(projectName, version, content, allowedRel
975
977
  Expected: ${allowedReleaseStatuses.length === 1 ? `"${allowedReleaseStatus}"` : `one of: ${allowedReleaseStatuses.map((status) => {
976
978
  return `"${status}"`;
977
979
  }).join(", ")}`}`);
978
- const releaseSummaryHeaders = createMarkdownCommentPair("alex-c-line-release-summary");
980
+ const releaseSummaryHeaders = getMarkdownCommentPair("alex-c-line-release-summary");
979
981
  const summary = getMarkdownBlock(content, ...releaseSummaryHeaders);
980
982
  const templateContent = await (0, node_fs_promises.readFile)(node_path.default.join(await findPackageRoot(node_path.default.dirname(__filename$1), "alex-c-line"), "templates", "releases", `${version.type}.md`), "utf-8");
981
983
  const templateSummary = getMarkdownBlock(templateContent, ...releaseSummaryHeaders)?.replaceAll(`{{projectName}}`, projectName);
@@ -1014,11 +1016,6 @@ function templateReleaseNoteCheck(program) {
1014
1016
  });
1015
1017
  }
1016
1018
  //#endregion
1017
- //#region src/utility/markdownTemplates/releaseNote/getReleaseNotePath.ts
1018
- function getReleaseNotePath(versionNumber) {
1019
- return node_path.default.join("docs", "releases", versionNumber.format({ omitMinor: true }), versionNumber.format({ omitPatch: true }), `${versionNumber}.md`);
1020
- }
1021
- //#endregion
1022
1019
  //#region src/utility/markdownTemplates/getReleaseNoteTemplatesPath.ts
1023
1020
  async function getReleaseNoteTemplatesPath() {
1024
1021
  return node_path.default.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "releases");
@@ -1042,7 +1039,7 @@ function replaceMarkdownPlaceholders(rawContent, templateVariables) {
1042
1039
  return finalContent;
1043
1040
  }
1044
1041
  //#endregion
1045
- //#region src/utility/markdownTemplates/releaseNote/getReleaseNoteTemplateFromMarkdown.ts
1042
+ //#region src/utility/markdownTemplates/releaseNote/createReleaseNoteFromTemplates.ts
1046
1043
  async function getTemplateVariables(projectName, version, templateVariables) {
1047
1044
  if ("editableSection" in templateVariables && templateVariables.editableSection) {
1048
1045
  const { status = "In progress", editableSection } = templateVariables;
@@ -1066,12 +1063,17 @@ async function getTemplateVariables(projectName, version, templateVariables) {
1066
1063
  editableSection
1067
1064
  };
1068
1065
  }
1069
- async function getReleaseNoteTemplateFromMarkdown(projectName, version, metadata) {
1066
+ async function createReleaseNoteFromTemplates(projectName, version, metadata) {
1070
1067
  const templateVariables = await getTemplateVariables(projectName, version, metadata);
1071
1068
  const templatesPath = node_path.default.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "releases");
1072
1069
  return replaceMarkdownPlaceholders(await (0, node_fs_promises.readFile)(node_path.default.join(templatesPath, `${version.type}.md`), "utf-8"), templateVariables);
1073
1070
  }
1074
1071
  //#endregion
1072
+ //#region src/utility/markdownTemplates/releaseNote/getReleaseNotePath.ts
1073
+ function getReleaseNotePath(versionNumber) {
1074
+ return node_path.default.join("docs", "releases", versionNumber.format({ omitMinor: true }), versionNumber.format({ omitPatch: true }), `${versionNumber}.md`);
1075
+ }
1076
+ //#endregion
1075
1077
  //#region src/cli/commands/template/releaseNote/create.ts
1076
1078
  function templateReleaseNoteCreate(program) {
1077
1079
  program.command("create").argument("[createFor]", _alextheman_utility.normaliseIndents`
@@ -1093,7 +1095,7 @@ function templateReleaseNoteCreate(program) {
1093
1095
  }), packageInfo);
1094
1096
  const versionNumber = target instanceof _alextheman_utility.VersionNumber ? target : target ? new _alextheman_utility.VersionNumber(packageVersion).increment(target) : new _alextheman_utility.VersionNumber(packageVersion);
1095
1097
  const releaseNotePath = getReleaseNotePath(versionNumber);
1096
- const releaseNoteTemplate = await getReleaseNoteTemplateFromMarkdown(name, versionNumber, { status: "In progress" });
1098
+ const releaseNoteTemplate = await createReleaseNoteFromTemplates(name, versionNumber, { status: "In progress" });
1097
1099
  try {
1098
1100
  await (0, node_fs_promises.mkdir)(node_path.default.dirname(releaseNotePath), { recursive: true });
1099
1101
  await (0, node_fs_promises.writeFile)(releaseNotePath, releaseNoteTemplate, { flag: "wx" });
@@ -1108,61 +1110,6 @@ function templateReleaseNoteCreate(program) {
1108
1110
  });
1109
1111
  }
1110
1112
  //#endregion
1111
- //#region src/cli/commands/template/releaseNote/migrate.ts
1112
- function templateReleaseNoteMigrate(program) {
1113
- program.command("migrate").description(_alextheman_utility.normaliseIndents`
1114
- Migrate the docs/releases folder generated from \`create-release-note\` to be more compatible with v2.
1115
- The release documents will now be structured as docs/releases/vX/vX.Y/vX.Y.Z.md, rather than docs/releases/<major|minor|patch>/vX.Y.Z`).option("--dry-run", "Perform a dry run of the migration without changing any files.").action(async ({ dryRun }) => {
1116
- if (dryRun) {
1117
- console.info("Running migration in dry-run mode. Existing files will not be altered.");
1118
- console.info();
1119
- }
1120
- const oldReleasesPath = node_path.default.join(process.cwd(), "docs", "releases");
1121
- const oldReleasesDirectory = await (0, node_fs_promises.readdir)(oldReleasesPath);
1122
- const versionTypes = Object.values(_alextheman_utility.VersionType).filter((value) => {
1123
- return oldReleasesDirectory.includes(value);
1124
- });
1125
- let filesMovedCount = 0;
1126
- for (const versionType of versionTypes) {
1127
- const versionPath = node_path.default.join(oldReleasesPath, versionType);
1128
- const versionNumbers = (await (0, node_fs_promises.readdir)(versionPath)).filter((fileName) => {
1129
- return fileName.endsWith(".md");
1130
- }).map((fileName) => {
1131
- const fileNameNoExtension = fileName.slice(0, -3);
1132
- try {
1133
- return new _alextheman_utility.VersionNumber(fileNameNoExtension);
1134
- } catch {}
1135
- }).filter((item) => {
1136
- return item !== void 0;
1137
- });
1138
- for (const versionNumber of versionNumbers) {
1139
- const oldFilePath = node_path.default.join(versionPath, `${versionNumber}.md`);
1140
- const newFilePath = node_path.default.join(oldReleasesPath, `v${versionNumber.major}`, `v${versionNumber.major}.${versionNumber.minor}`, `${versionNumber}.md`);
1141
- const relativeOldFilePath = node_path.default.relative(process.cwd(), oldFilePath);
1142
- const relativeNewFilePath = node_path.default.relative(process.cwd(), newFilePath);
1143
- if (dryRun) console.info(`Would move \`${relativeOldFilePath}\` to \`${relativeNewFilePath}\``);
1144
- else {
1145
- await (0, node_fs_promises.mkdir)(node_path.default.dirname(newFilePath), { recursive: true });
1146
- await (0, node_fs_promises.rename)(oldFilePath, newFilePath);
1147
- console.info(`Moved \`${relativeOldFilePath}\` to \`${relativeNewFilePath}\``);
1148
- }
1149
- filesMovedCount++;
1150
- }
1151
- }
1152
- console.info();
1153
- if (!dryRun) for (const oldFolderName of versionTypes) {
1154
- const oldFolderPath = node_path.default.join(oldReleasesPath, oldFolderName);
1155
- const relativeOldFolderPath = node_path.default.relative(process.cwd(), oldFolderPath);
1156
- if ((await (0, node_fs_promises.readdir)(oldFolderPath)).length === 0) {
1157
- await (0, node_fs_promises.rmdir)(oldFolderPath);
1158
- console.info(`All files from \`${relativeOldFolderPath}\` removed. Deleting \`${relativeOldFolderPath}\`.`);
1159
- }
1160
- }
1161
- console.info();
1162
- console.info(dryRun ? `Dry run complete! ${filesMovedCount} files would be moved.` : `Migration complete! ${filesMovedCount} files moved.`);
1163
- });
1164
- }
1165
- //#endregion
1166
1113
  //#region src/cli/commands/template/releaseNote/path.ts
1167
1114
  function templateReleaseNotePath(program) {
1168
1115
  program.command("path").description("Get the path to the release note for a given version.").argument("[version]", "The version number to get the release note path for (leave blank to default to the current directory's package.json version)", (rawVersion) => {
@@ -1189,13 +1136,13 @@ function templateReleaseNoteSetStatus(program) {
1189
1136
  const fullDocumentPath = node_path.default.join(process.cwd(), documentPath);
1190
1137
  const initialDocument = await (0, node_fs_promises.readFile)(fullDocumentPath, "utf-8");
1191
1138
  await validateReleaseDocument(name, versionNumber, initialDocument);
1192
- const [userEditableSectionStart, userEditableSectionEnd] = createMarkdownCommentPair("user-editable-section");
1139
+ const [userEditableSectionStart, userEditableSectionEnd] = getMarkdownCommentPair("user-editable-section");
1193
1140
  const editableSection = getMarkdownBlock(initialDocument, userEditableSectionStart, userEditableSectionEnd);
1194
1141
  if (editableSection === null) throw new _alextheman_utility.DataError({
1195
1142
  startMarker: userEditableSectionStart,
1196
1143
  endMarker: userEditableSectionEnd
1197
1144
  }, "EDITABLE_SECTION_NOT_FOUND", "Could not find editable section in the provided document.");
1198
- await (0, node_fs_promises.writeFile)(fullDocumentPath, await getReleaseNoteTemplateFromMarkdown(name, versionNumber, {
1145
+ await (0, node_fs_promises.writeFile)(fullDocumentPath, await createReleaseNoteFromTemplates(name, versionNumber, {
1199
1146
  status,
1200
1147
  editableSection
1201
1148
  }));
@@ -1208,7 +1155,6 @@ function templateReleaseNote(program) {
1208
1155
  loadCommands(program.command("release-note").description("Manage the release notes"), {
1209
1156
  templateReleaseNoteCheck,
1210
1157
  templateReleaseNoteCreate,
1211
- templateReleaseNoteMigrate,
1212
1158
  templateReleaseNotePath,
1213
1159
  templateReleaseNoteSetStatus
1214
1160
  });
@@ -1224,14 +1170,14 @@ function template(program) {
1224
1170
  //#endregion
1225
1171
  //#region package.json
1226
1172
  var name = "alex-c-line";
1227
- var version$1 = "2.0.2";
1173
+ var version$1 = "2.1.0";
1228
1174
  var description = "Command-line tool with commands to streamline the developer workflow.";
1229
1175
  //#endregion
1230
1176
  //#region src/utility/updates/checkUpdate.ts
1231
1177
  async function checkUpdate(options) {
1232
1178
  const currentVersion = new _alextheman_utility.VersionNumber(version$1);
1233
- const { stdout: npmViewResult } = await execa.execa`npm view alex-c-line version`;
1234
- const latestVersion = new _alextheman_utility.VersionNumber(npmViewResult.trim());
1179
+ const { data } = await axios.default.get("https://registry.npmjs.org/alex-c-line/latest", { timeout: 5e3 });
1180
+ const latestVersion = new _alextheman_utility.VersionNumber(data.version);
1235
1181
  if (!_alextheman_utility.VersionNumber.isEqual(currentVersion, latestVersion)) {
1236
1182
  const message = _alextheman_utility.normaliseIndents`
1237
1183
  A new update of \`alex-c-line\` is available!
@@ -1254,7 +1200,10 @@ async function checkUpdate(options) {
1254
1200
  exitCode: 2,
1255
1201
  code: "OUTDATED_VERSION"
1256
1202
  });
1257
- } else console.info(messageWithArtwork);
1203
+ } else {
1204
+ const { updateLogger = console.info } = options ?? {};
1205
+ updateLogger(messageWithArtwork);
1206
+ }
1258
1207
  } else if (options?.logNoUpdates) console.info(`alex-c-line is up to date (${currentVersion}).`);
1259
1208
  }
1260
1209
  //#endregion
@@ -1465,6 +1414,25 @@ function formatError(error) {
1465
1414
  throw error;
1466
1415
  }
1467
1416
  //#endregion
1417
+ //#region src/utility/updates/pendingUpdateMessage.ts
1418
+ let pendingUpdateMessage = null;
1419
+ let registered = false;
1420
+ function setPendingUpdateMessage(message) {
1421
+ pendingUpdateMessage = message;
1422
+ }
1423
+ function registerUpdateMessagePrinter() {
1424
+ if (registered) return;
1425
+ registered = true;
1426
+ function print() {
1427
+ if (pendingUpdateMessage) {
1428
+ console.info(`\n${pendingUpdateMessage}`);
1429
+ pendingUpdateMessage = null;
1430
+ }
1431
+ }
1432
+ process.once("beforeExit", print);
1433
+ process.once("exit", print);
1434
+ }
1435
+ //#endregion
1468
1436
  //#region src/cache/global/createAlexCLineGlobalCache.ts
1469
1437
  async function createAlexCLineGlobalCache(cacheData) {
1470
1438
  await (0, node_fs_promises.mkdir)(ALEX_C_LINE_GLOBAL_CACHE_DIRECTORY, { recursive: true });
@@ -1496,7 +1464,10 @@ async function runAutomatedUpdateCheck() {
1496
1464
  const lastChecked = cacheData?.updateChecks?.[version$1] ? new Date(cacheData?.updateChecks?.[version$1]) : void 0;
1497
1465
  const currentDate = /* @__PURE__ */ new Date();
1498
1466
  if (lastChecked === void 0 || currentDate.getTime() - lastChecked.getTime() >= _alextheman_utility.ONE_DAY_IN_MILLISECONDS) {
1499
- await checkUpdate({ logNoUpdates: false });
1467
+ await checkUpdate({
1468
+ logNoUpdates: false,
1469
+ updateLogger: setPendingUpdateMessage
1470
+ });
1500
1471
  await createAlexCLineGlobalCache({
1501
1472
  ...cacheData ?? {},
1502
1473
  updateChecks: {
@@ -1508,12 +1479,18 @@ async function runAutomatedUpdateCheck() {
1508
1479
  } catch {}
1509
1480
  }
1510
1481
  //#endregion
1482
+ //#region src/utility/updates/shouldRunAutomatedUpdateCheck.ts
1483
+ const shouldRunAutomatedUpdateCheck = !(process.env.NODE_ENV === "test" || (0, _alextheman_utility.parseBoolean)(process.env.RUN_END_TO_END ?? "false") || (0, _alextheman_utility.parseBoolean)(process.env.CI ?? "false"));
1484
+ //#endregion
1511
1485
  //#region src/cli/index.ts
1512
1486
  (async () => {
1513
1487
  try {
1514
1488
  const program = new commander.Command();
1515
1489
  program.name(name).description(description).version(version$1);
1516
- if (!(process.env.NODE_ENV === "test" || (0, _alextheman_utility.parseBoolean)(process.env.RUN_END_TO_END ?? "false") || (0, _alextheman_utility.parseBoolean)(process.env.CI ?? "false"))) await runAutomatedUpdateCheck();
1490
+ registerUpdateMessagePrinter();
1491
+ if (shouldRunAutomatedUpdateCheck) setTimeout(() => {
1492
+ runAutomatedUpdateCheck();
1493
+ }, 0);
1517
1494
  createCommands(program);
1518
1495
  await program.parseAsync(process.argv);
1519
1496
  } catch (error) {
package/dist/index.js CHANGED
@@ -1,13 +1,13 @@
1
1
  #!/usr/bin/env node
2
2
  import { createRequire } from "node:module";
3
- import { DataError, ONE_DAY_IN_MILLISECONDS, VersionNumber, VersionType, encryptWithKey, fillArray, getStringsAndInterpolations, interpolate, isTemplateStringsArray, kebabToCamel, normaliseIndents, omitProperties, parseBoolean, parseVersionType, parseZodSchema, parseZodSchemaAsync, removeDuplicates, removeUndefinedFromObject, stringifyDotenv } from "@alextheman/utility";
4
3
  import { Command } from "commander";
4
+ import { DataError, ONE_DAY_IN_MILLISECONDS, VersionNumber, encryptWithKey, fillArray, getStringsAndInterpolations, interpolate, isTemplateStringsArray, kebabToCamel, normaliseIndents, omitProperties, parseBoolean, parseVersionType, parseZodSchema, parseZodSchemaAsync, removeDuplicates, removeUndefinedFromObject, stringifyDotenv } from "@alextheman/utility";
5
5
  import chalk from "chalk";
6
6
  import boxen from "boxen";
7
7
  import figlet from "figlet";
8
8
  import path from "node:path";
9
9
  import { createCanvas } from "canvas";
10
- import { access, mkdir, readFile, readdir, rename, rm, rmdir, writeFile } from "node:fs/promises";
10
+ import { access, mkdir, readFile, readdir, rm, writeFile } from "node:fs/promises";
11
11
  import envPaths from "env-paths";
12
12
  import { confirm, input, password, select } from "@inquirer/prompts";
13
13
  import { parse } from "dotenv";
@@ -17,6 +17,7 @@ import { DependencyGroup, PackageManager, getDependenciesFromGroup, getExpectedT
17
17
  import z from "zod";
18
18
  import matter from "gray-matter";
19
19
  import { parseFilePath } from "@alextheman/utility/node";
20
+ import axios from "axios";
20
21
  import supportsColor from "supports-color";
21
22
  import { randomUUID } from "node:crypto";
22
23
  import { minVersion, prerelease } from "semver";
@@ -796,7 +797,7 @@ function root(program) {
796
797
  });
797
798
  }
798
799
  //#endregion
799
- //#region src/utility/markdownTemplates/pullRequest/getPullRequestTemplatesFromMarkdown.ts
800
+ //#region src/utility/markdownTemplates/pullRequest/createPullRequestTemplatesFromTemplates.ts
800
801
  const __filename$1 = fileURLToPath(import.meta.url);
801
802
  function getTemplateVariables$1(config) {
802
803
  if (config.category === "general") return {
@@ -809,7 +810,7 @@ function getTemplateVariables$1(config) {
809
810
  requireConfirmationFrom: config.requireConfirmationFrom
810
811
  };
811
812
  }
812
- async function getPullRequestTemplatesFromMarkdown(config) {
813
+ async function createPullRequestTemplatesFromTemplates(config) {
813
814
  const templateVariables = getTemplateVariables$1(config);
814
815
  const { category } = config;
815
816
  const templatesPath = path.join(await findPackageRoot(path.dirname(__filename$1), "alex-c-line"), "templates", "pullRequest");
@@ -853,7 +854,7 @@ function templatePullRequestCreate(program) {
853
854
  }));
854
855
  const gitHubPath = path.join(process.cwd(), ".github");
855
856
  const pullRequestTemplatePath = path.join(gitHubPath, "PULL_REQUEST_TEMPLATE");
856
- const allTemplates = await getPullRequestTemplatesFromMarkdown({
857
+ const allTemplates = await createPullRequestTemplatesFromTemplates({
857
858
  ...parsedOptions,
858
859
  projectName
859
860
  });
@@ -894,17 +895,6 @@ function parseReleaseStatus(data) {
894
895
  return ReleaseStatus[normalisedStringifiedData];
895
896
  }
896
897
  //#endregion
897
- //#region src/utility/markdownTemplates/createMarkdownComment.ts
898
- function createMarkdownComment(comment) {
899
- if (comment.startsWith("<!--") && comment.endsWith("-->")) return comment;
900
- return `<!-- ${comment} -->`;
901
- }
902
- //#endregion
903
- //#region src/utility/markdownTemplates/createMarkdownCommentPair.ts
904
- function createMarkdownCommentPair(comment) {
905
- return [createMarkdownComment(`${comment}-start`), createMarkdownComment(`${comment}-end`)];
906
- }
907
- //#endregion
908
898
  //#region src/utility/markdownTemplates/getMarkdownBlock.ts
909
899
  function getMarkdownBlock(content, startMarker, endMarker) {
910
900
  const startIndex = content.indexOf(startMarker);
@@ -913,6 +903,17 @@ function getMarkdownBlock(content, startMarker, endMarker) {
913
903
  return content.slice(startIndex + startMarker.length, endIndex).trim();
914
904
  }
915
905
  //#endregion
906
+ //#region src/utility/markdownTemplates/getMarkdownComment.ts
907
+ function createMarkdownComment(comment) {
908
+ if (comment.startsWith("<!--") && comment.endsWith("-->")) return comment;
909
+ return `<!-- ${comment} -->`;
910
+ }
911
+ //#endregion
912
+ //#region src/utility/markdownTemplates/getMarkdownCommentPair.ts
913
+ function getMarkdownCommentPair(comment) {
914
+ return [createMarkdownComment(`${comment}-start`), createMarkdownComment(`${comment}-end`)];
915
+ }
916
+ //#endregion
916
917
  //#region src/utility/markdownTemplates/normaliseMarkdown.ts
917
918
  function normaliseMarkdown(markdownString) {
918
919
  return markdownString.replace(/\r\n/g, "\n").split("\n").map((line) => {
@@ -922,7 +923,7 @@ function normaliseMarkdown(markdownString) {
922
923
  //#endregion
923
924
  //#region src/utility/markdownTemplates/releaseNote/getReleaseStatus.ts
924
925
  function getReleaseStatus(content) {
925
- const releaseStatus = getMarkdownBlock(content, ...createMarkdownCommentPair("alex-c-line-release-status"));
926
+ const releaseStatus = getMarkdownBlock(content, ...getMarkdownCommentPair("alex-c-line-release-status"));
926
927
  if (releaseStatus === null) throw new DataError({ releaseStatus }, "RELEASE_STATUS_NOT_FOUND", "Could not find release status in document.");
927
928
  return parseZodSchema(z.enum(ReleaseStatus), normaliseMarkdown(releaseStatus.split(":")[1]));
928
929
  }
@@ -945,7 +946,7 @@ async function validateReleaseDocument(projectName, version, content, allowedRel
945
946
  Expected: ${allowedReleaseStatuses.length === 1 ? `"${allowedReleaseStatus}"` : `one of: ${allowedReleaseStatuses.map((status) => {
946
947
  return `"${status}"`;
947
948
  }).join(", ")}`}`);
948
- const releaseSummaryHeaders = createMarkdownCommentPair("alex-c-line-release-summary");
949
+ const releaseSummaryHeaders = getMarkdownCommentPair("alex-c-line-release-summary");
949
950
  const summary = getMarkdownBlock(content, ...releaseSummaryHeaders);
950
951
  const templateContent = await readFile(path.join(await findPackageRoot(path.dirname(__filename), "alex-c-line"), "templates", "releases", `${version.type}.md`), "utf-8");
951
952
  const templateSummary = getMarkdownBlock(templateContent, ...releaseSummaryHeaders)?.replaceAll(`{{projectName}}`, projectName);
@@ -984,11 +985,6 @@ function templateReleaseNoteCheck(program) {
984
985
  });
985
986
  }
986
987
  //#endregion
987
- //#region src/utility/markdownTemplates/releaseNote/getReleaseNotePath.ts
988
- function getReleaseNotePath(versionNumber) {
989
- return path.join("docs", "releases", versionNumber.format({ omitMinor: true }), versionNumber.format({ omitPatch: true }), `${versionNumber}.md`);
990
- }
991
- //#endregion
992
988
  //#region src/utility/markdownTemplates/getReleaseNoteTemplatesPath.ts
993
989
  async function getReleaseNoteTemplatesPath() {
994
990
  return path.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "releases");
@@ -1012,7 +1008,7 @@ function replaceMarkdownPlaceholders(rawContent, templateVariables) {
1012
1008
  return finalContent;
1013
1009
  }
1014
1010
  //#endregion
1015
- //#region src/utility/markdownTemplates/releaseNote/getReleaseNoteTemplateFromMarkdown.ts
1011
+ //#region src/utility/markdownTemplates/releaseNote/createReleaseNoteFromTemplates.ts
1016
1012
  async function getTemplateVariables(projectName, version, templateVariables) {
1017
1013
  if ("editableSection" in templateVariables && templateVariables.editableSection) {
1018
1014
  const { status = "In progress", editableSection } = templateVariables;
@@ -1036,12 +1032,17 @@ async function getTemplateVariables(projectName, version, templateVariables) {
1036
1032
  editableSection
1037
1033
  };
1038
1034
  }
1039
- async function getReleaseNoteTemplateFromMarkdown(projectName, version, metadata) {
1035
+ async function createReleaseNoteFromTemplates(projectName, version, metadata) {
1040
1036
  const templateVariables = await getTemplateVariables(projectName, version, metadata);
1041
1037
  const templatesPath = path.join(await ALEX_C_LINE_PACKAGE_ROOT, "templates", "releases");
1042
1038
  return replaceMarkdownPlaceholders(await readFile(path.join(templatesPath, `${version.type}.md`), "utf-8"), templateVariables);
1043
1039
  }
1044
1040
  //#endregion
1041
+ //#region src/utility/markdownTemplates/releaseNote/getReleaseNotePath.ts
1042
+ function getReleaseNotePath(versionNumber) {
1043
+ return path.join("docs", "releases", versionNumber.format({ omitMinor: true }), versionNumber.format({ omitPatch: true }), `${versionNumber}.md`);
1044
+ }
1045
+ //#endregion
1045
1046
  //#region src/cli/commands/template/releaseNote/create.ts
1046
1047
  function templateReleaseNoteCreate(program) {
1047
1048
  program.command("create").argument("[createFor]", normaliseIndents`
@@ -1063,7 +1064,7 @@ function templateReleaseNoteCreate(program) {
1063
1064
  }), packageInfo);
1064
1065
  const versionNumber = target instanceof VersionNumber ? target : target ? new VersionNumber(packageVersion).increment(target) : new VersionNumber(packageVersion);
1065
1066
  const releaseNotePath = getReleaseNotePath(versionNumber);
1066
- const releaseNoteTemplate = await getReleaseNoteTemplateFromMarkdown(name, versionNumber, { status: "In progress" });
1067
+ const releaseNoteTemplate = await createReleaseNoteFromTemplates(name, versionNumber, { status: "In progress" });
1067
1068
  try {
1068
1069
  await mkdir(path.dirname(releaseNotePath), { recursive: true });
1069
1070
  await writeFile(releaseNotePath, releaseNoteTemplate, { flag: "wx" });
@@ -1078,61 +1079,6 @@ function templateReleaseNoteCreate(program) {
1078
1079
  });
1079
1080
  }
1080
1081
  //#endregion
1081
- //#region src/cli/commands/template/releaseNote/migrate.ts
1082
- function templateReleaseNoteMigrate(program) {
1083
- program.command("migrate").description(normaliseIndents`
1084
- Migrate the docs/releases folder generated from \`create-release-note\` to be more compatible with v2.
1085
- The release documents will now be structured as docs/releases/vX/vX.Y/vX.Y.Z.md, rather than docs/releases/<major|minor|patch>/vX.Y.Z`).option("--dry-run", "Perform a dry run of the migration without changing any files.").action(async ({ dryRun }) => {
1086
- if (dryRun) {
1087
- console.info("Running migration in dry-run mode. Existing files will not be altered.");
1088
- console.info();
1089
- }
1090
- const oldReleasesPath = path.join(process.cwd(), "docs", "releases");
1091
- const oldReleasesDirectory = await readdir(oldReleasesPath);
1092
- const versionTypes = Object.values(VersionType).filter((value) => {
1093
- return oldReleasesDirectory.includes(value);
1094
- });
1095
- let filesMovedCount = 0;
1096
- for (const versionType of versionTypes) {
1097
- const versionPath = path.join(oldReleasesPath, versionType);
1098
- const versionNumbers = (await readdir(versionPath)).filter((fileName) => {
1099
- return fileName.endsWith(".md");
1100
- }).map((fileName) => {
1101
- const fileNameNoExtension = fileName.slice(0, -3);
1102
- try {
1103
- return new VersionNumber(fileNameNoExtension);
1104
- } catch {}
1105
- }).filter((item) => {
1106
- return item !== void 0;
1107
- });
1108
- for (const versionNumber of versionNumbers) {
1109
- const oldFilePath = path.join(versionPath, `${versionNumber}.md`);
1110
- const newFilePath = path.join(oldReleasesPath, `v${versionNumber.major}`, `v${versionNumber.major}.${versionNumber.minor}`, `${versionNumber}.md`);
1111
- const relativeOldFilePath = path.relative(process.cwd(), oldFilePath);
1112
- const relativeNewFilePath = path.relative(process.cwd(), newFilePath);
1113
- if (dryRun) console.info(`Would move \`${relativeOldFilePath}\` to \`${relativeNewFilePath}\``);
1114
- else {
1115
- await mkdir(path.dirname(newFilePath), { recursive: true });
1116
- await rename(oldFilePath, newFilePath);
1117
- console.info(`Moved \`${relativeOldFilePath}\` to \`${relativeNewFilePath}\``);
1118
- }
1119
- filesMovedCount++;
1120
- }
1121
- }
1122
- console.info();
1123
- if (!dryRun) for (const oldFolderName of versionTypes) {
1124
- const oldFolderPath = path.join(oldReleasesPath, oldFolderName);
1125
- const relativeOldFolderPath = path.relative(process.cwd(), oldFolderPath);
1126
- if ((await readdir(oldFolderPath)).length === 0) {
1127
- await rmdir(oldFolderPath);
1128
- console.info(`All files from \`${relativeOldFolderPath}\` removed. Deleting \`${relativeOldFolderPath}\`.`);
1129
- }
1130
- }
1131
- console.info();
1132
- console.info(dryRun ? `Dry run complete! ${filesMovedCount} files would be moved.` : `Migration complete! ${filesMovedCount} files moved.`);
1133
- });
1134
- }
1135
- //#endregion
1136
1082
  //#region src/cli/commands/template/releaseNote/path.ts
1137
1083
  function templateReleaseNotePath(program) {
1138
1084
  program.command("path").description("Get the path to the release note for a given version.").argument("[version]", "The version number to get the release note path for (leave blank to default to the current directory's package.json version)", (rawVersion) => {
@@ -1159,13 +1105,13 @@ function templateReleaseNoteSetStatus(program) {
1159
1105
  const fullDocumentPath = path.join(process.cwd(), documentPath);
1160
1106
  const initialDocument = await readFile(fullDocumentPath, "utf-8");
1161
1107
  await validateReleaseDocument(name, versionNumber, initialDocument);
1162
- const [userEditableSectionStart, userEditableSectionEnd] = createMarkdownCommentPair("user-editable-section");
1108
+ const [userEditableSectionStart, userEditableSectionEnd] = getMarkdownCommentPair("user-editable-section");
1163
1109
  const editableSection = getMarkdownBlock(initialDocument, userEditableSectionStart, userEditableSectionEnd);
1164
1110
  if (editableSection === null) throw new DataError({
1165
1111
  startMarker: userEditableSectionStart,
1166
1112
  endMarker: userEditableSectionEnd
1167
1113
  }, "EDITABLE_SECTION_NOT_FOUND", "Could not find editable section in the provided document.");
1168
- await writeFile(fullDocumentPath, await getReleaseNoteTemplateFromMarkdown(name, versionNumber, {
1114
+ await writeFile(fullDocumentPath, await createReleaseNoteFromTemplates(name, versionNumber, {
1169
1115
  status,
1170
1116
  editableSection
1171
1117
  }));
@@ -1178,7 +1124,6 @@ function templateReleaseNote(program) {
1178
1124
  loadCommands(program.command("release-note").description("Manage the release notes"), {
1179
1125
  templateReleaseNoteCheck,
1180
1126
  templateReleaseNoteCreate,
1181
- templateReleaseNoteMigrate,
1182
1127
  templateReleaseNotePath,
1183
1128
  templateReleaseNoteSetStatus
1184
1129
  });
@@ -1194,14 +1139,14 @@ function template(program) {
1194
1139
  //#endregion
1195
1140
  //#region package.json
1196
1141
  var name = "alex-c-line";
1197
- var version$1 = "2.0.2";
1142
+ var version$1 = "2.1.0";
1198
1143
  var description = "Command-line tool with commands to streamline the developer workflow.";
1199
1144
  //#endregion
1200
1145
  //#region src/utility/updates/checkUpdate.ts
1201
1146
  async function checkUpdate(options) {
1202
1147
  const currentVersion = new VersionNumber(version$1);
1203
- const { stdout: npmViewResult } = await execa`npm view alex-c-line version`;
1204
- const latestVersion = new VersionNumber(npmViewResult.trim());
1148
+ const { data } = await axios.get("https://registry.npmjs.org/alex-c-line/latest", { timeout: 5e3 });
1149
+ const latestVersion = new VersionNumber(data.version);
1205
1150
  if (!VersionNumber.isEqual(currentVersion, latestVersion)) {
1206
1151
  const message = normaliseIndents`
1207
1152
  A new update of \`alex-c-line\` is available!
@@ -1224,7 +1169,10 @@ async function checkUpdate(options) {
1224
1169
  exitCode: 2,
1225
1170
  code: "OUTDATED_VERSION"
1226
1171
  });
1227
- } else console.info(messageWithArtwork);
1172
+ } else {
1173
+ const { updateLogger = console.info } = options ?? {};
1174
+ updateLogger(messageWithArtwork);
1175
+ }
1228
1176
  } else if (options?.logNoUpdates) console.info(`alex-c-line is up to date (${currentVersion}).`);
1229
1177
  }
1230
1178
  //#endregion
@@ -1435,6 +1383,25 @@ function formatError(error) {
1435
1383
  throw error;
1436
1384
  }
1437
1385
  //#endregion
1386
+ //#region src/utility/updates/pendingUpdateMessage.ts
1387
+ let pendingUpdateMessage = null;
1388
+ let registered = false;
1389
+ function setPendingUpdateMessage(message) {
1390
+ pendingUpdateMessage = message;
1391
+ }
1392
+ function registerUpdateMessagePrinter() {
1393
+ if (registered) return;
1394
+ registered = true;
1395
+ function print() {
1396
+ if (pendingUpdateMessage) {
1397
+ console.info(`\n${pendingUpdateMessage}`);
1398
+ pendingUpdateMessage = null;
1399
+ }
1400
+ }
1401
+ process.once("beforeExit", print);
1402
+ process.once("exit", print);
1403
+ }
1404
+ //#endregion
1438
1405
  //#region src/cache/global/createAlexCLineGlobalCache.ts
1439
1406
  async function createAlexCLineGlobalCache(cacheData) {
1440
1407
  await mkdir(ALEX_C_LINE_GLOBAL_CACHE_DIRECTORY, { recursive: true });
@@ -1466,7 +1433,10 @@ async function runAutomatedUpdateCheck() {
1466
1433
  const lastChecked = cacheData?.updateChecks?.[version$1] ? new Date(cacheData?.updateChecks?.[version$1]) : void 0;
1467
1434
  const currentDate = /* @__PURE__ */ new Date();
1468
1435
  if (lastChecked === void 0 || currentDate.getTime() - lastChecked.getTime() >= ONE_DAY_IN_MILLISECONDS) {
1469
- await checkUpdate({ logNoUpdates: false });
1436
+ await checkUpdate({
1437
+ logNoUpdates: false,
1438
+ updateLogger: setPendingUpdateMessage
1439
+ });
1470
1440
  await createAlexCLineGlobalCache({
1471
1441
  ...cacheData ?? {},
1472
1442
  updateChecks: {
@@ -1478,12 +1448,18 @@ async function runAutomatedUpdateCheck() {
1478
1448
  } catch {}
1479
1449
  }
1480
1450
  //#endregion
1451
+ //#region src/utility/updates/shouldRunAutomatedUpdateCheck.ts
1452
+ const shouldRunAutomatedUpdateCheck = !(process.env.NODE_ENV === "test" || parseBoolean(process.env.RUN_END_TO_END ?? "false") || parseBoolean(process.env.CI ?? "false"));
1453
+ //#endregion
1481
1454
  //#region src/cli/index.ts
1482
1455
  (async () => {
1483
1456
  try {
1484
1457
  const program = new Command();
1485
1458
  program.name(name).description(description).version(version$1);
1486
- if (!(process.env.NODE_ENV === "test" || parseBoolean(process.env.RUN_END_TO_END ?? "false") || parseBoolean(process.env.CI ?? "false"))) await runAutomatedUpdateCheck();
1459
+ registerUpdateMessagePrinter();
1460
+ if (shouldRunAutomatedUpdateCheck) setTimeout(() => {
1461
+ runAutomatedUpdateCheck();
1462
+ }, 0);
1487
1463
  createCommands(program);
1488
1464
  await program.parseAsync(process.argv);
1489
1465
  } catch (error) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "alex-c-line",
3
- "version": "2.0.2",
3
+ "version": "2.1.0",
4
4
  "description": "Command-line tool with commands to streamline the developer workflow.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,8 +34,9 @@
34
34
  "templates"
35
35
  ],
36
36
  "dependencies": {
37
- "@alextheman/utility": "^5.6.1",
37
+ "@alextheman/utility": "^5.6.2",
38
38
  "@inquirer/prompts": "^8.3.0",
39
+ "axios": "^1.13.6",
39
40
  "boxen": "^8.0.1",
40
41
  "canvas": "^3.2.1",
41
42
  "chalk": "^5.6.2",
@@ -5,8 +5,6 @@ placeholders:
5
5
  - projectName
6
6
  - infrastructureProvider
7
7
  ---
8
-
9
-
10
8
  # Select a Template
11
9
 
12
10
  Please select the option that best describes your changes to `{{projectName}}`:
@@ -4,7 +4,6 @@ category: infrastructure
4
4
  placeholders:
5
5
  - projectName
6
6
  ---
7
-
8
7
  # Bug Fix
9
8
 
10
9
  This is a bug fix for `{{projectName}}`. It fixes an unintended side-effect of the configuration or deployment.
@@ -4,7 +4,6 @@ category: infrastructure
4
4
  placeholders:
5
5
  - projectName
6
6
  ---
7
-
8
7
  # Documentation Change
9
8
 
10
9
  This is a change to the documentation of `{{projectName}}`. It changes the way that information about the repository is presented to users.
@@ -5,7 +5,6 @@ placeholders:
5
5
  - projectName
6
6
  - infrastructureProvider
7
7
  ---
8
-
9
8
  # Irreversible Destruction
10
9
 
11
10
  This is a change to `{{projectName}}` that irreversibly destroys a managed {{infrastructureProvider}} resource. This change can **NOT** be fixed by simply reverting back the changes as it will try recreating the resource entirely and there is no guarantee that it will be restored back to the same state it was previously in.
@@ -6,7 +6,6 @@ placeholders:
6
6
  - infrastructureProvider
7
7
  - requireConfirmationFrom
8
8
  ---
9
-
10
9
  # Manual Change
11
10
 
12
11
  This is a change to `{{projectName}}` that requires manual changes to the managed {{infrastructureProvider}} resources. {{requireConfirmationFrom}} **MUST** confirm by approval (or authorship of pull request) that these changes have been made before this can be merged in.
@@ -4,7 +4,6 @@ category: infrastructure
4
4
  placeholders:
5
5
  - projectName
6
6
  ---
7
-
8
7
  # Miscellaneous
9
8
 
10
9
  This is a general change to `{{projectName}}` that does not fit in any of the other provided categories.
@@ -5,7 +5,6 @@ placeholders:
5
5
  - projectName
6
6
  - infrastructureProvider
7
7
  ---
8
-
9
8
  # New Feature
10
9
 
11
10
  This is a new feature for `{{projectName}}` that adds a new {{infrastructureProvider}}-managed resource.
@@ -4,7 +4,6 @@ category: infrastructure
4
4
  placeholders:
5
5
  - projectName
6
6
  ---
7
-
8
7
  # Refactor
9
8
 
10
9
  This is a change to the code layout of `{{projectName}}`. It changes how the code is presented in terms of quality and structure without changing the overall plan.
@@ -5,7 +5,6 @@ placeholders:
5
5
  - projectName
6
6
  - infrastructureProvider
7
7
  ---
8
-
9
8
  # Resource Update
10
9
 
11
10
  This is a change to an existing resource in `{{projectName}}` in the {{infrastructureProvider}} plan. It changes the currently managed state without removing or adding anything else to the plan.
@@ -4,7 +4,6 @@ category: infrastructure
4
4
  placeholders:
5
5
  - projectName
6
6
  ---
7
-
8
7
  # Tooling Change
9
8
 
10
9
  This is a change to the tooling of `{{projectName}}`. It changes the internal workings of the repository and should have no noticeable effect on the plan.