@effected/github-actions 0.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.
@@ -0,0 +1,100 @@
1
+ //#region src/WorkflowCommand.ts
2
+ /**
3
+ * Escape a command's message.
4
+ *
5
+ * @remarks
6
+ * The percent sign is replaced **first**, and the order is load-bearing: doing
7
+ * it last would re-escape the `%` of an escape sequence this function just
8
+ * produced, turning `%0A` into `%250A`.
9
+ */
10
+ const escapeMessage = (value) => value.replaceAll("%", "%25").replaceAll("\r", "%0D").replaceAll("\n", "%0A");
11
+ /**
12
+ * Escape a property value.
13
+ *
14
+ * @remarks
15
+ * Everything a message escapes, plus `:` and `,` — the two characters that
16
+ * delimit the property list and terminate it. An unescaped one truncates the
17
+ * command or lets a value be read as a new property.
18
+ */
19
+ const escapeProperty = (value) => escapeMessage(value).replaceAll(":", "%3A").replaceAll(",", "%2C");
20
+ /**
21
+ * The GitHub Actions workflow-command wire protocol: `::name key=value::message`.
22
+ *
23
+ * @remarks
24
+ * **Pure.** This module renders strings and nothing else — it performs no IO
25
+ * and holds no service — which is what makes the escaping rules testable
26
+ * without a runner, and what lets a non-Actions consumer reuse the protocol.
27
+ * Writing a rendered command to stdout is {@link ActionOutputs}'s job.
28
+ *
29
+ * The escaping is the whole point of the module. A message carrying a raw
30
+ * newline does not merely render oddly: the runner reads the text after it as
31
+ * a **new command**, so an unescaped log line is a command-injection vector.
32
+ *
33
+ * @example
34
+ * ```ts
35
+ * import { WorkflowCommand } from "@effected/github-actions";
36
+ *
37
+ * WorkflowCommand.error("build failed", { file: "src/main.ts", startLine: 12 });
38
+ * // "::error file=src/main.ts,line=12::build failed"
39
+ * ```
40
+ *
41
+ * @public
42
+ */
43
+ var WorkflowCommand = class WorkflowCommand {
44
+ constructor() {}
45
+ /**
46
+ * Render an arbitrary command. The primitive every other member uses.
47
+ *
48
+ * @remarks
49
+ * The property type is written out structurally rather than as the module's
50
+ * `CommandProperties` alias: an internal named type on a `@public` signature
51
+ * fails the API Extractor gate, and neither an `@internal` tag nor a second
52
+ * alias helps — only inlining does.
53
+ */
54
+ static render(name, properties, message) {
55
+ const rendered = Object.entries(properties).filter((entry) => entry[1] !== void 0).map(([key, value]) => `${key}=${escapeProperty(String(value))}`).join(",");
56
+ return `${rendered === "" ? `::${name}::` : `::${name} ${rendered}::`}${escapeMessage(message)}`;
57
+ }
58
+ /** `::debug::` — shown only when `ACTIONS_STEP_DEBUG` is enabled. */
59
+ static debug(message) {
60
+ return WorkflowCommand.render("debug", {}, message);
61
+ }
62
+ /** `::notice::` with optional source annotation. */
63
+ static notice(message, properties = {}) {
64
+ return WorkflowCommand.render("notice", WorkflowCommand.annotation(properties), message);
65
+ }
66
+ /** `::warning::` with optional source annotation. */
67
+ static warning(message, properties = {}) {
68
+ return WorkflowCommand.render("warning", WorkflowCommand.annotation(properties), message);
69
+ }
70
+ /** `::error::` with optional source annotation. */
71
+ static error(message, properties = {}) {
72
+ return WorkflowCommand.render("error", WorkflowCommand.annotation(properties), message);
73
+ }
74
+ /** `::group::` — opens a collapsible section in the runner log. */
75
+ static group(name) {
76
+ return WorkflowCommand.render("group", {}, name);
77
+ }
78
+ /** `::endgroup::` — closes the innermost open group. */
79
+ static endGroup() {
80
+ return WorkflowCommand.render("endgroup", {}, "");
81
+ }
82
+ /** `::add-mask::` — registers a value for redaction in the runner log. */
83
+ static addMask(value) {
84
+ return WorkflowCommand.render("add-mask", {}, value);
85
+ }
86
+ /** Map readable annotation fields onto GitHub's abbreviated wire names. */
87
+ static annotation(properties) {
88
+ return {
89
+ title: properties.title,
90
+ file: properties.file,
91
+ line: properties.startLine,
92
+ endLine: properties.endLine,
93
+ col: properties.startColumn,
94
+ endColumn: properties.endColumn
95
+ };
96
+ }
97
+ };
98
+
99
+ //#endregion
100
+ export { WorkflowCommand };