actions-up 1.3.1 → 1.4.1

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.
Files changed (46) hide show
  1. package/dist/cli/index.js +41 -41
  2. package/dist/core/api/check-updates.js +135 -179
  3. package/dist/core/api/create-github-client.js +28 -29
  4. package/dist/core/api/get-all-releases.js +20 -27
  5. package/dist/core/api/get-all-tags.js +5 -7
  6. package/dist/core/api/get-latest-release.js +16 -19
  7. package/dist/core/api/get-reference-type.js +6 -12
  8. package/dist/core/api/get-tag-info.js +47 -76
  9. package/dist/core/api/get-tag-sha.js +12 -22
  10. package/dist/core/api/internal-rate-limit-error.js +3 -4
  11. package/dist/core/api/make-request.js +18 -21
  12. package/dist/core/api/resolve-github-token-sync.js +20 -26
  13. package/dist/core/api/update-rate-limit-info.js +7 -7
  14. package/dist/core/ast/guards/has-range.js +2 -2
  15. package/dist/core/ast/guards/is-node.js +2 -2
  16. package/dist/core/ast/guards/is-pair.js +2 -2
  17. package/dist/core/ast/guards/is-scalar.js +2 -2
  18. package/dist/core/ast/guards/is-yaml-map.js +2 -2
  19. package/dist/core/ast/guards/is-yaml-sequence.js +2 -2
  20. package/dist/core/ast/scanners/scan-composite-action-ast.js +9 -11
  21. package/dist/core/ast/scanners/scan-workflow-ast.js +12 -14
  22. package/dist/core/ast/update/apply-updates.js +24 -27
  23. package/dist/core/ast/utils/extract-uses-from-steps.js +12 -14
  24. package/dist/core/ast/utils/find-map-pair.js +2 -5
  25. package/dist/core/ast/utils/get-line-number.js +4 -4
  26. package/dist/core/constants.js +1 -3
  27. package/dist/core/filters/parse-exclude-patterns.d.ts +17 -0
  28. package/dist/core/filters/parse-exclude-patterns.js +23 -0
  29. package/dist/core/fs/is-yaml-file.js +2 -2
  30. package/dist/core/fs/read-yaml-document.js +4 -5
  31. package/dist/core/ignore/should-ignore.d.ts +23 -0
  32. package/dist/core/ignore/should-ignore.js +14 -0
  33. package/dist/core/interactive/format-version.js +16 -30
  34. package/dist/core/interactive/pad-string.js +5 -6
  35. package/dist/core/interactive/prompt-update-selection.js +106 -163
  36. package/dist/core/interactive/strip-ansi.js +10 -17
  37. package/dist/core/parsing/parse-action-reference.js +23 -23
  38. package/dist/core/scan-action-file.js +3 -3
  39. package/dist/core/scan-github-actions.js +87 -136
  40. package/dist/core/scan-workflow-file.js +3 -3
  41. package/dist/core/schema/composite/is-composite-action-runs.js +2 -4
  42. package/dist/core/schema/composite/is-composite-action-structure.js +4 -4
  43. package/dist/core/schema/workflow/is-workflow-structure.js +4 -4
  44. package/dist/package.js +1 -1
  45. package/package.json +1 -1
  46. package/readme.md +55 -8
@@ -5,20 +5,18 @@ import { isYAMLMap } from "../guards/is-yaml-map.js";
5
5
  import { isScalar } from "../guards/is-scalar.js";
6
6
  import { isNode } from "../guards/is-node.js";
7
7
  import { isPair } from "../guards/is-pair.js";
8
- function extractUsesFromSteps(stepsNode, filePath, content) {
9
- if (!isYAMLSequence(stepsNode)) return [];
10
- let actions = [];
11
- for (let stepNode of stepsNode.items) {
12
- if (!isYAMLMap(stepNode) || !isNode(stepNode)) continue;
13
- let step = stepNode.toJSON();
14
- if (step === null || typeof step !== "object" || Array.isArray(step)) continue;
15
- let stepObject = step;
16
- if (typeof stepObject["uses"] !== "string") continue;
17
- let usesPair = stepNode.items.find((item) => isPair(item) && isScalar(item.key) && item.key.value === "uses");
18
- let lineNumber = usesPair?.key ? getLineNumberForKey(content, usesPair.key) : 0;
19
- let action = parseActionReference(stepObject["uses"], filePath, lineNumber);
20
- if (action) actions.push(action);
8
+ function extractUsesFromSteps(s, c, l) {
9
+ if (!isYAMLSequence(s)) return [];
10
+ let u = [];
11
+ for (let o of s.items) {
12
+ if (!isYAMLMap(o) || !isNode(o)) continue;
13
+ let s = o.toJSON();
14
+ if (typeof s != "object" || !s || Array.isArray(s)) continue;
15
+ let d = s;
16
+ if (typeof d.uses != "string") continue;
17
+ let f = o.items.find((e) => isPair(e) && isScalar(e.key) && e.key.value === "uses"), p = f?.key ? getLineNumberForKey(l, f.key) : 0, m = parseActionReference(d.uses, c, p);
18
+ m && u.push(m);
21
19
  }
22
- return actions;
20
+ return u;
23
21
  }
24
22
  export { extractUsesFromSteps };
@@ -1,10 +1,7 @@
1
1
  import { isYAMLMap } from "../guards/is-yaml-map.js";
2
2
  import { isScalar } from "../guards/is-scalar.js";
3
3
  import { isPair } from "../guards/is-pair.js";
4
- function findMapPair(map, key) {
5
- if (!isYAMLMap(map) || !Array.isArray(map.items)) return null;
6
- let yamlMap = map;
7
- let pair = yamlMap.items.find((item) => isPair(item) && isScalar(item.key) && item.key.value === key);
8
- return pair ?? null;
4
+ function findMapPair(r, i) {
5
+ return !isYAMLMap(r) || !Array.isArray(r.items) ? null : r.items.find((e) => isPair(e) && isScalar(e.key) && e.key.value === i) ?? null;
9
6
  }
10
7
  export { findMapPair };
@@ -1,8 +1,8 @@
1
1
  import { hasRange } from "../guards/has-range.js";
2
- function getLineNumberForKey(content, keyNode) {
3
- if (hasRange(keyNode) && keyNode.range) {
4
- let [offset] = keyNode.range;
5
- if (typeof offset === "number" && Number.isFinite(offset)) return content.slice(0, Math.max(0, offset)).split("\n").length;
2
+ function getLineNumberForKey(t, n) {
3
+ if (hasRange(n) && n.range) {
4
+ let [e] = n.range;
5
+ if (typeof e == "number" && Number.isFinite(e)) return t.slice(0, Math.max(0, e)).split("\n").length;
6
6
  }
7
7
  return 0;
8
8
  }
@@ -1,4 +1,2 @@
1
- const GITHUB_DIRECTORY = ".github";
2
- const WORKFLOWS_DIRECTORY = "workflows";
3
- const ACTIONS_DIRECTORY = "actions";
1
+ const GITHUB_DIRECTORY = ".github", WORKFLOWS_DIRECTORY = "workflows", ACTIONS_DIRECTORY = "actions";
4
2
  export { ACTIONS_DIRECTORY, GITHUB_DIRECTORY, WORKFLOWS_DIRECTORY };
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Parse CLI --exclude patterns into regular expressions.
3
+ *
4
+ * Supports two forms:
5
+ *
6
+ * - Raw regex literal with optional flags: `/pattern/i`
7
+ * - Plain pattern string compiled as case-insensitive regex: `pattern`.
8
+ *
9
+ * Commas should be split at the CLI level; this function assumes patterns are
10
+ * already individual entries.
11
+ *
12
+ * Invalid patterns are skipped with a console warning.
13
+ *
14
+ * @param patterns - List of pattern strings provided via CLI.
15
+ * @returns Array of RegExp objects.
16
+ */
17
+ export declare function parseExcludePatterns(patterns: string[]): RegExp[];
@@ -0,0 +1,23 @@
1
+ function parseExcludePatterns(e) {
2
+ let t = [];
3
+ for (let n of e) {
4
+ let e = n.trim();
5
+ if (!e) continue;
6
+ let r;
7
+ if (e.startsWith("/") && e.lastIndexOf("/") > 0) {
8
+ let t = e.lastIndexOf("/"), i = e.slice(1, t), a = e.slice(t + 1);
9
+ try {
10
+ r = new RegExp(i, a || "i");
11
+ } catch (e) {
12
+ console.warn(`Invalid regex exclude: ${n}`, e), r = null;
13
+ }
14
+ } else try {
15
+ r = new RegExp(e, "i");
16
+ } catch (e) {
17
+ console.warn(`Invalid regex exclude: ${n}`, e), r = null;
18
+ }
19
+ r && t.push(r);
20
+ }
21
+ return t;
22
+ }
23
+ export { parseExcludePatterns };
@@ -1,4 +1,4 @@
1
- function isYamlFile(filePath) {
2
- return filePath.endsWith(".yml") || filePath.endsWith(".yaml");
1
+ function isYamlFile(e) {
2
+ return e.endsWith(".yml") || e.endsWith(".yaml");
3
3
  }
4
4
  export { isYamlFile };
@@ -1,11 +1,10 @@
1
1
  import { readFile } from "node:fs/promises";
2
2
  import { parseDocument } from "yaml";
3
- async function readYamlDocument(filePath) {
4
- let content = await readFile(filePath, "utf8");
5
- let document = parseDocument(content);
3
+ async function readYamlDocument(n) {
4
+ let r = await readFile(n, "utf8");
6
5
  return {
7
- document,
8
- content
6
+ document: parseDocument(r),
7
+ content: r
9
8
  };
10
9
  }
11
10
  export { readYamlDocument };
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Determine whether a given file/line should be ignored based on inline comment
3
+ * directives present in the file content.
4
+ *
5
+ * Supported directives (lowercase, exact match):
6
+ *
7
+ * - `actions-up-ignore-file`
8
+ * - `actions-up-ignore-start` … `actions-up-ignore-end`
9
+ * - `actions-up-ignore-next-line`
10
+ * - `actions-up-ignore` (inline on the same line).
11
+ *
12
+ * Notes:
13
+ *
14
+ * - "next-line" applies strictly to the immediate next physical line.
15
+ * - Block directives behave as a simple toggle; nested blocks are not supported.
16
+ * - Optional text after a colon is ignored.
17
+ * - If line is missing or <= 0, only file-level ignore applies.
18
+ *
19
+ * @param filePath - Path to the YAML file being processed.
20
+ * @param line - One-based line number to check.
21
+ * @returns Promise that resolves to true when the target should be ignored.
22
+ */
23
+ export declare function shouldIgnore(filePath: undefined | string, line: undefined | number): Promise<boolean>;
@@ -0,0 +1,14 @@
1
+ import { readFile } from "node:fs/promises";
2
+ async function shouldIgnore(t, n) {
3
+ if (!t) return !1;
4
+ let r = (await readFile(t, "utf8")).split("\n");
5
+ for (let e of r) if (e.includes("actions-up-ignore-file")) return !0;
6
+ if (!n || n <= 0) return !1;
7
+ let i = /* @__PURE__ */ new Set(), a = !1;
8
+ for (let [e, t] of r.entries()) {
9
+ let n = t, r = e + 1;
10
+ n.includes("actions-up-ignore-start") && (a = !0), a && i.add(r), n.includes("actions-up-ignore-end") && (i.add(r), a = !1), n.includes("actions-up-ignore-next-line") && i.add(r + 1), n.includes("actions-up-ignore") && !n.includes("actions-up-ignore-next-line") && !n.includes("actions-up-ignore-start") && !n.includes("actions-up-ignore-end") && !n.includes("actions-up-ignore-file") && i.add(r);
11
+ }
12
+ return i.has(n);
13
+ }
14
+ export { shouldIgnore };
@@ -1,36 +1,22 @@
1
1
  import pc from "picocolors";
2
2
  import semver from "semver";
3
- function formatVersion(latestVersion, currentVersion) {
4
- if (!latestVersion) return pc.gray("unknown");
5
- let latest = semver.parse(latestVersion);
6
- let current = currentVersion ? semver.parse(normalizeVersion(currentVersion)) : null;
7
- if (!current || !latest) return latestVersion;
8
- let change = semver.diff(normalizeVersion(currentVersion), latestVersion);
9
- let unstable = current.major === 0;
10
- let changeColor = unstable ? pc.yellowBright : pc.gray;
11
- let parts = [
12
- latest.major,
13
- latest.minor,
14
- latest.patch
15
- ];
16
- let colors = parts.map((_, i) => {
17
- if (change === "major") return pc.redBright;
18
- if (change === "minor" && i >= 1) return changeColor;
19
- if (change === "patch" && i === 2) return changeColor;
20
- return identity;
21
- });
22
- let result = colors[0](String(parts[0]));
23
- if (parts[1] !== void 0) result += colors[0](".") + colors[1](String(parts[1]));
24
- if (parts[2] !== void 0) result += colors[1](".") + colors[2](String(parts[2]));
25
- return result;
3
+ function formatVersion(i, a) {
4
+ if (!i) return pc.gray("unknown");
5
+ let o = semver.parse(i), s = a ? semver.parse(normalizeVersion(a)) : null;
6
+ if (!s || !o) return i;
7
+ let c = semver.diff(normalizeVersion(a), i), l = s.major === 0 ? pc.yellowBright : pc.gray, u = [
8
+ o.major,
9
+ o.minor,
10
+ o.patch
11
+ ], d = u.map((r, i) => c === "major" ? pc.redBright : c === "minor" && i >= 1 || c === "patch" && i === 2 ? l : identity), f = d[0](String(u[0]));
12
+ return u[1] !== void 0 && (f += d[0](".") + d[1](String(u[1]))), u[2] !== void 0 && (f += d[1](".") + d[2](String(u[2]))), f;
26
13
  }
27
- function normalizeVersion(version) {
28
- let cleaned = version.replace(/^v/u, "");
29
- let parts = cleaned.split(".");
30
- while (parts.length < 3) parts.push("0");
31
- return parts.slice(0, 3).join(".");
14
+ function normalizeVersion(e) {
15
+ let r = e.replace(/^v/u, "").split(".");
16
+ for (; r.length < 3;) r.push("0");
17
+ return r.slice(0, 3).join(".");
32
18
  }
33
- function identity(string) {
34
- return string;
19
+ function identity(e) {
20
+ return e;
35
21
  }
36
22
  export { formatVersion };
@@ -1,9 +1,8 @@
1
1
  import { stripAnsi } from "./strip-ansi.js";
2
- function padString(string, length) {
3
- let stripped = stripAnsi(string);
4
- let diff = length - stripped.length;
5
- if (diff <= 0) return string;
6
- let padding = " ".repeat(diff);
7
- return string + padding;
2
+ function padString(t, n) {
3
+ let r = stripAnsi(t), i = n - r.length;
4
+ if (i <= 0) return t;
5
+ let a = " ".repeat(i);
6
+ return t + a;
8
7
  }
9
8
  export { padString };
@@ -7,154 +7,115 @@ import pc from "picocolors";
7
7
  import { readFile } from "node:fs/promises";
8
8
  import enquirer from "enquirer";
9
9
  import path from "node:path";
10
- const MIN_ACTION_WIDTH = 56;
11
- const MIN_CURRENT_WIDTH = 16;
12
- async function promptUpdateSelection(updates) {
13
- if (updates.length === 0) return null;
14
- let outdated = updates.filter((update) => update.hasUpdate);
15
- if (outdated.length === 0) {
16
- console.info(pc.green(" All actions are up to date!"));
17
- return null;
10
+ async function promptUpdateSelection(a) {
11
+ if (a.length === 0) return null;
12
+ let s = a.filter((e) => e.hasUpdate);
13
+ if (s.length === 0) return console.info(pc.green("✓ All actions are up to date!")), null;
14
+ let u = /* @__PURE__ */ new Map();
15
+ for (let [e, i] of s.entries()) {
16
+ let a = i.action.file ?? "unknown file", o = path.relative(path.join(process.cwd(), GITHUB_DIRECTORY), a);
17
+ o === "" && (o = a);
18
+ let s = u.get(o) ?? [];
19
+ s.push({
20
+ update: i,
21
+ index: e
22
+ }), u.set(o, s);
18
23
  }
19
- let groups = /* @__PURE__ */ new Map();
20
- for (let [index, update] of outdated.entries()) {
21
- let originalFile = update.action.file ?? "unknown file";
22
- let file = path.relative(path.join(process.cwd(), GITHUB_DIRECTORY), originalFile);
23
- if (file === "") file = originalFile;
24
- let group = groups.get(file) ?? [];
25
- group.push({
26
- update,
27
- index
28
- });
29
- groups.set(file, group);
30
- }
31
- let currentComputedByIndex = await Promise.all(outdated.map(async (update) => {
32
- let display = formatVersionOrSha(update.currentVersion);
33
- let effectiveForDiff = update.currentVersion ?? void 0;
34
- if (!update.currentVersion || !isSha(update.currentVersion)) return {
35
- effectiveForDiff,
36
- display
24
+ let p = await Promise.all(s.map(async (e) => {
25
+ let r = formatVersionOrSha(e.currentVersion), i = e.currentVersion ?? void 0;
26
+ if (!e.currentVersion || !isSha(e.currentVersion)) return {
27
+ effectiveForDiff: i,
28
+ display: r
37
29
  };
38
- let versionFromComment = await tryReadInlineVersionComment(update.action.file, update.action.line);
39
- if (versionFromComment) {
40
- let shortSha = update.currentVersion.slice(0, 7);
41
- let version = formatVersionOrSha(versionFromComment);
42
- display = `${version} ${pc.gray(`(${shortSha})`)}`;
43
- effectiveForDiff = versionFromComment;
30
+ let a = await tryReadInlineVersionComment(e.action.file, e.action.line);
31
+ if (a) {
32
+ let s = e.currentVersion.slice(0, 7);
33
+ r = `${formatVersionOrSha(a)} ${pc.gray(`(${s})`)}`, i = a;
44
34
  }
45
35
  return {
46
- effectiveForDiff,
47
- display
36
+ effectiveForDiff: i,
37
+ display: r
48
38
  };
49
- }));
50
- let choices = [];
51
- let maxActionLength = stripAnsi("Action").length;
52
- let maxCurrentLength = stripAnsi("Current").length;
53
- for (let [index, update] of outdated.entries()) {
54
- let actionNameRaw = update.action.name;
55
- let currentRaw = currentComputedByIndex[index].display;
56
- maxActionLength = Math.max(maxActionLength, actionNameRaw.length);
57
- maxCurrentLength = Math.max(maxCurrentLength, stripAnsi(currentRaw).length);
39
+ })), m = [], h = stripAnsi("Action").length, g = stripAnsi("Current").length;
40
+ for (let [e, r] of s.entries()) {
41
+ let a = r.action.name, o = p[e].display;
42
+ h = Math.max(h, a.length), g = Math.max(g, stripAnsi(o).length);
58
43
  }
59
- let globalActionWidth = Math.max(maxActionLength, MIN_ACTION_WIDTH);
60
- let globalCurrentWidth = Math.max(maxCurrentLength, MIN_CURRENT_WIDTH);
61
- let sortedFiles = [...groups.keys()].toSorted();
62
- for (let [fileIndex, file] of sortedFiles.entries()) {
63
- let fileGroup = groups.get(file);
64
- if (!fileGroup) {
65
- console.warn(`Unexpected missing group for file: ${file}`);
44
+ let _ = Math.max(h, 56), v = Math.max(g, 16), y = [...u.keys()].toSorted();
45
+ for (let [r, i] of y.entries()) {
46
+ let a = u.get(i);
47
+ if (!a) {
48
+ console.warn(`Unexpected missing group for file: ${i}`);
66
49
  continue;
67
50
  }
68
- let tableRows = [];
69
- let groupOrder = fileGroup;
70
- tableRows.push({
51
+ let s = [], c = a;
52
+ s.push({
71
53
  current: "Current",
72
54
  action: "Action",
73
55
  target: "Target",
74
56
  arrow: "❯"
75
57
  });
76
- for (let { update, index } of groupOrder) {
77
- let hasSha = Boolean(update.latestSha);
78
- let current = currentComputedByIndex[index].display;
79
- let effectiveCurrentForDiff = currentComputedByIndex[index]?.effectiveForDiff ?? update.currentVersion;
80
- let latest = formatVersion(update.latestVersion, effectiveCurrentForDiff);
81
- let actionName = update.action.name;
82
- if (update.latestSha) {
83
- let shortSha = update.latestSha.slice(0, 7);
84
- latest = `${latest} ${pc.gray(`(${shortSha})`)}`;
58
+ for (let { update: r, index: i } of c) {
59
+ let a = !!r.latestSha, c = p[i].display, l = p[i]?.effectiveForDiff ?? r.currentVersion, u = formatVersion(r.latestVersion, l), d = r.action.name;
60
+ if (r.latestSha) {
61
+ let e = r.latestSha.slice(0, 7);
62
+ u = `${u} ${pc.gray(`(${e})`)}`;
85
63
  }
86
- if (!hasSha) {
87
- latest = pc.gray(latest);
88
- current = pc.gray(current);
89
- actionName = pc.gray(actionName);
90
- }
91
- tableRows.push({
92
- action: actionName,
93
- target: latest,
64
+ a || (u = pc.gray(u), c = pc.gray(c), d = pc.gray(d)), s.push({
65
+ action: d,
66
+ target: u,
94
67
  arrow: "❯",
95
- current
68
+ current: c
96
69
  });
97
70
  }
98
- let maxActionWidth = Math.max(globalActionWidth, MIN_ACTION_WIDTH);
99
- let maxCurrentWidth = Math.max(globalCurrentWidth, MIN_CURRENT_WIDTH);
100
- let groupChildren = [];
101
- for (let [i, row] of tableRows.entries()) {
102
- let isHeader = i === 0;
103
- let formattedRow = formatTableRow(row, maxActionWidth, maxCurrentWidth);
104
- if (isHeader) groupChildren.push({
105
- message: pc.gray(` ○ ${formattedRow}`),
71
+ let l = Math.max(_, 56), d = Math.max(v, 16), f = [];
72
+ for (let [e, r] of s.entries()) {
73
+ let i = e === 0, a = formatTableRow(r, l, d);
74
+ if (i) f.push({
75
+ message: pc.gray(` ${a}`),
106
76
  role: "separator",
107
77
  indent: "",
108
78
  name: ""
109
79
  });
110
80
  else {
111
- let entry = groupOrder[i - 1];
112
- if (!entry) continue;
113
- let { update, index } = entry;
114
- let hasSha = Boolean(update.latestSha);
115
- let enabled = hasSha && !update.isBreaking;
116
- groupChildren.push({
117
- message: formattedRow,
118
- value: String(index),
119
- name: String(index),
120
- disabled: !hasSha,
81
+ let r = c[e - 1];
82
+ if (!r) continue;
83
+ let { update: i, index: o } = r, s = !!i.latestSha, l = s && !i.isBreaking;
84
+ f.push({
85
+ message: a,
86
+ value: String(o),
87
+ name: String(o),
88
+ disabled: !s,
121
89
  indent: "",
122
- enabled
90
+ enabled: l
123
91
  });
124
92
  }
125
93
  }
126
- choices.push({
127
- message: pc.gray(file),
128
- value: `label|${file}`,
129
- choices: groupChildren,
130
- name: `label|${file}`,
131
- isGroupLabel: true,
132
- enabled: false
133
- });
134
- if (fileIndex < sortedFiles.length - 1) choices.push({
94
+ m.push({
95
+ message: pc.gray(i),
96
+ value: `label|${i}`,
97
+ choices: f,
98
+ name: `label|${i}`,
99
+ isGroupLabel: !0,
100
+ enabled: !1
101
+ }), r < y.length - 1 && m.push({
135
102
  role: "separator",
136
103
  message: " ",
137
104
  name: ""
138
105
  });
139
106
  }
140
107
  try {
141
- let promptOptions = {
142
- indicator(_state, choice) {
143
- let isLabel = Boolean(choice.isGroupLabel);
144
- if (isLabel) {
145
- let allChildren = choice.choices ?? [];
146
- let rows = allChildren.filter((child) => !("role" in child));
147
- let total = rows.length;
148
- let selectedCount = rows.filter((row) => Boolean(row.enabled)).length;
149
- let mark = selectedCount === total ? "●" : "○";
150
- return ` ${pc.gray(mark)}`;
108
+ let e = {
109
+ indicator(e, r) {
110
+ if (r.isGroupLabel) {
111
+ let e = (r.choices ?? []).filter((e) => !("role" in e)), i = e.length, a = e.filter((e) => !!e.enabled).length === i ? "●" : "○";
112
+ return ` ${pc.gray(a)}`;
151
113
  }
152
- return ` ${choice.enabled ? "●" : "○"}`;
114
+ return ` ${r.enabled ? "●" : "○"}`;
153
115
  },
154
116
  message: `Choose which actions to update (Press ${pc.cyan("<space>")} to select, ${pc.cyan("<a>")} to toggle all, ${pc.cyan("<i>")} to invert selection)`,
155
117
  cancel() {
156
- console.info(pc.yellow("\nSelection cancelled"));
157
- return null;
118
+ return console.info(pc.yellow("\nSelection cancelled")), null;
158
119
  },
159
120
  styles: {
160
121
  success: pc.reset,
@@ -171,67 +132,49 @@ async function promptUpdateSelection(updates) {
171
132
  type: "multiselect",
172
133
  name: "selected",
173
134
  pointer: "❯",
174
- choices
175
- };
176
- let { selected } = await enquirer.prompt(promptOptions);
177
- let selectedIndexes = /* @__PURE__ */ new Set();
178
- for (let valueString of selected) {
179
- if (valueString.startsWith("label|")) {
180
- let fileKey = valueString.slice(6);
181
- let groupItems = groups.get(fileKey) ?? [];
182
- for (let { update: upd, index: index$1 } of groupItems) if (upd.latestSha) selectedIndexes.add(index$1);
135
+ choices: m
136
+ }, { selected: r } = await enquirer.prompt(e), i = /* @__PURE__ */ new Set();
137
+ for (let e of r) {
138
+ if (e.startsWith("label|")) {
139
+ let r = e.slice(6), a = u.get(r) ?? [];
140
+ for (let { update: e, index: r } of a) e.latestSha && i.add(r);
183
141
  continue;
184
142
  }
185
- let index = Number.parseInt(valueString, 10);
186
- if (Number.isFinite(index)) selectedIndexes.add(index);
187
- }
188
- let result = [];
189
- for (let [index, outdatedUpdate] of outdated.entries()) if (selectedIndexes.has(index) && outdatedUpdate.latestSha) result.push(outdatedUpdate);
190
- if (result.length === 0) {
191
- console.info(pc.yellow("\nNo actions selected"));
192
- return null;
193
- }
194
- return result;
195
- } catch (error) {
196
- if (error instanceof Error && (error.message.includes("cancelled") || error.message.includes("ESC") || error.name === "ExitPromptError")) {
197
- console.info(pc.yellow("\nSelection cancelled"));
198
- return null;
143
+ let r = Number.parseInt(e, 10);
144
+ Number.isFinite(r) && i.add(r);
199
145
  }
200
- console.error(pc.red("Unexpected error during selection:"), error);
201
- throw error;
146
+ let a = [];
147
+ for (let [e, r] of s.entries()) i.has(e) && r.latestSha && a.push(r);
148
+ return a.length === 0 ? (console.info(pc.yellow("\nNo actions selected")), null) : a;
149
+ } catch (e) {
150
+ if (e instanceof Error && (e.message.includes("cancelled") || e.message.includes("ESC") || e.name === "ExitPromptError")) return console.info(pc.yellow("\nSelection cancelled")), null;
151
+ throw console.error(pc.red("Unexpected error during selection:"), e), e;
202
152
  }
203
153
  }
204
- async function tryReadInlineVersionComment(filePath, lineNumber) {
154
+ async function tryReadInlineVersionComment(e, r) {
205
155
  try {
206
- if (!filePath || !lineNumber || lineNumber <= 0) return null;
207
- let content = await readFile(filePath, "utf8");
208
- let lines = content.split("\n");
209
- let index = lineNumber - 1;
210
- if (index < 0 || index >= lines.length) return null;
211
- let line = lines[index];
212
- let match = line.match(/#\s*(?<version>[Vv]?\d+(?:\.\d+){0,2}(?:[+-][\w\-.]+)?)/u);
213
- if (match?.groups?.["version"]) return match.groups["version"];
156
+ if (!e || !r || r <= 0) return null;
157
+ let i = (await readFile(e, "utf8")).split("\n"), a = r - 1;
158
+ if (a < 0 || a >= i.length) return null;
159
+ let o = i[a].match(/#\s*(?<version>[Vv]?\d+(?:\.\d+){0,2}(?:[+-][\w\-.]+)?)/u);
160
+ if (o?.groups?.version) return o.groups.version;
214
161
  } catch {}
215
162
  return null;
216
163
  }
217
- function formatTableRow(row, actionWidth, currentWidth) {
218
- let parts = [
219
- padString(row.action, actionWidth),
220
- padString(row.current, currentWidth),
221
- row.arrow,
222
- row.target
223
- ];
224
- let line = parts.join(" ");
225
- return line.replace(/\s+$/u, "");
164
+ function formatTableRow(e, r, i) {
165
+ return [
166
+ padString(e.action, r),
167
+ padString(e.current, i),
168
+ e.arrow,
169
+ e.target
170
+ ].join(" ").replace(/\s+$/u, "");
226
171
  }
227
- function isSha(value) {
228
- if (!value) return false;
229
- let normalized = value.replace(/^v/u, "");
230
- return /^[0-9a-f]{7,40}$/iu.test(normalized);
172
+ function isSha(e) {
173
+ if (!e) return !1;
174
+ let r = e.replace(/^v/u, "");
175
+ return /^[0-9a-f]{7,40}$/iu.test(r);
231
176
  }
232
- function formatVersionOrSha(version) {
233
- if (!version) return pc.gray("unknown");
234
- if (isSha(version)) return version.slice(0, 7);
235
- return version.replace(/^v/u, "");
177
+ function formatVersionOrSha(e) {
178
+ return e ? isSha(e) ? e.slice(0, 7) : e.replace(/^v/u, "") : pc.gray("unknown");
236
179
  }
237
180
  export { promptUpdateSelection };
@@ -1,21 +1,14 @@
1
- function stripAnsi(string) {
2
- let result = "";
3
- let i = 0;
4
- while (i < string.length) if (string.charCodeAt(i) === 27 && i + 1 < string.length && string[i + 1] === "[") {
5
- i += 2;
6
- while (i < string.length) {
7
- let char = string[i];
8
- i++;
9
- if (char === "m") break;
10
- if (!/[\d;]/u.test(char)) {
11
- result += `${String.fromCharCode(27)}[${string.slice(i - 1, i)}`;
12
- break;
13
- }
1
+ function stripAnsi(e) {
2
+ let t = "", n = 0;
3
+ for (; n < e.length;) if (e.charCodeAt(n) === 27 && n + 1 < e.length && e[n + 1] === "[") for (n += 2; n < e.length;) {
4
+ let r = e[n];
5
+ if (n++, r === "m") break;
6
+ if (!/[\d;]/u.test(r)) {
7
+ t += `[${e.slice(n - 1, n)}`;
8
+ break;
14
9
  }
15
- } else {
16
- result += string[i];
17
- i++;
18
10
  }
19
- return result;
11
+ else t += e[n], n++;
12
+ return t;
20
13
  }
21
14
  export { stripAnsi };