@optique/core 0.1.0-dev.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.
@@ -0,0 +1,194 @@
1
+ //#region src/message.ts
2
+ /**
3
+ * Creates a structured message with template strings and values.
4
+ *
5
+ * This function allows creating messages where specific values can be
6
+ * highlighted or styled differently when displayed to the user.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const error = message`Expected number between ${min} and ${max}, got ${value}`;
11
+ * const concat = message`${optionName("--age")}: ${error}`;
12
+ * ```
13
+ *
14
+ * @param message Template strings array (from template literal).
15
+ * @param values Values to be interpolated into the template.
16
+ * @returns A structured Message object.
17
+ */
18
+ function message(message$1, ...values$1) {
19
+ const messageTerms = [];
20
+ for (let i = 0; i < message$1.length; i++) {
21
+ if (message$1[i] !== "") messageTerms.push({
22
+ type: "text",
23
+ text: message$1[i]
24
+ });
25
+ if (i >= values$1.length) continue;
26
+ const value$1 = values$1[i];
27
+ if (typeof value$1 === "string") messageTerms.push({
28
+ type: "value",
29
+ value: value$1
30
+ });
31
+ else if (Array.isArray(value$1)) messageTerms.push(...value$1);
32
+ else if (typeof value$1 === "object" && value$1 != null && "type" in value$1) messageTerms.push(value$1);
33
+ else throw new TypeError(`Invalid value type in message: ${typeof value$1}.`);
34
+ }
35
+ return messageTerms;
36
+ }
37
+ /**
38
+ * Creates a {@link MessageTerm} for plain text. Usually used for
39
+ * dynamically generated messages.
40
+ * @param text The plain text to be included in the message.
41
+ * @returns A {@link MessageTerm} representing the plain text.
42
+ */
43
+ function text(text$1) {
44
+ return {
45
+ type: "text",
46
+ text: text$1
47
+ };
48
+ }
49
+ /**
50
+ * Creates a {@link MessageTerm} for an option name.
51
+ * @param name The name of the option, which can be a short or long option name.
52
+ * For example, `"-f"` or `"--foo"`.
53
+ * @returns A {@link MessageTerm} representing the option name.
54
+ */
55
+ function optionName(name) {
56
+ return {
57
+ type: "optionName",
58
+ optionName: name
59
+ };
60
+ }
61
+ /**
62
+ * Creates a {@link MessageTerm} for a list of option names.
63
+ * @param names The list of option names, which can include both short and long
64
+ * option names. For example, `["--foo", "--bar"]`.
65
+ * @returns A {@link MessageTerm} representing the list of option names.
66
+ */
67
+ function optionNames(names) {
68
+ return {
69
+ type: "optionNames",
70
+ optionNames: names
71
+ };
72
+ }
73
+ /**
74
+ * Creates a {@link MessageTerm} for a metavariable.
75
+ * @param metavar The metavariable name, which is a string that represents
76
+ * a variable in the message. For example, `"VALUE"` or
77
+ * `"ARG"`.
78
+ * @returns A {@link MessageTerm} representing the metavariable.
79
+ */
80
+ function metavar(metavar$1) {
81
+ return {
82
+ type: "metavar",
83
+ metavar: metavar$1
84
+ };
85
+ }
86
+ /**
87
+ * Creates a {@link MessageTerm} for a single value. However, you usually
88
+ * don't need to use this function directly, as {@link message} string template
89
+ * will automatically create a {@link MessageTerm} for a value when
90
+ * you use a string in a template literal.
91
+ * @param value The value, which can be any string representation of a value.
92
+ * For example, `"42"` or `"hello"`.
93
+ * @returns A {@link MessageTerm} representing the value.
94
+ */
95
+ function value(value$1) {
96
+ return {
97
+ type: "value",
98
+ value: value$1
99
+ };
100
+ }
101
+ /**
102
+ * Creates a {@link MessageTerm} for a list of consecutive values.
103
+ * @param values The list of consecutive values, which can include multiple
104
+ * string representations of consecutive values.
105
+ * For example, `["42", "hello"]`.
106
+ * @returns A {@link MessageTerm} representing the list of values.
107
+ */
108
+ function values(values$1) {
109
+ return {
110
+ type: "values",
111
+ values: values$1
112
+ };
113
+ }
114
+ /**
115
+ * Formats a {@link Message} into a human-readable string for
116
+ * the terminal.
117
+ * @param msg The message to format, which is an array of
118
+ * {@link MessageTerm} objects.
119
+ * @param options Optional formatting options to customize the output.
120
+ * @returns A formatted string representation of the message.
121
+ */
122
+ function formatMessage(msg, options = {}) {
123
+ const useColors = options.colors ?? false;
124
+ const useQuotes = options.quotes ?? true;
125
+ function* stream() {
126
+ const wordPattern = /\s*\S+\s*/g;
127
+ for (const term of msg) if (term.type === "text") while (true) {
128
+ const match = wordPattern.exec(term.text);
129
+ if (match == null) break;
130
+ yield {
131
+ text: match[0],
132
+ width: match[0].length
133
+ };
134
+ }
135
+ else if (term.type === "optionName") {
136
+ const name = useQuotes ? `\`${term.optionName}\`` : term.optionName;
137
+ yield {
138
+ text: useColors ? `\x1b[3m${name}\x1b[0m` : name,
139
+ width: name.length
140
+ };
141
+ } else if (term.type === "optionNames") {
142
+ const names = term.optionNames.map((name) => useQuotes ? `\`${name}\`` : name);
143
+ let i = 0;
144
+ for (const name of names) {
145
+ if (i > 0) yield {
146
+ text: "/",
147
+ width: 1
148
+ };
149
+ yield {
150
+ text: useColors ? `\x1b[3m${name}\x1b[0m` : name,
151
+ width: name.length
152
+ };
153
+ i++;
154
+ }
155
+ } else if (term.type === "metavar") {
156
+ const metavar$1 = useQuotes ? `\`${term.metavar}\`` : term.metavar;
157
+ yield {
158
+ text: useColors ? `\x1b[1m${metavar$1}\x1b[0m` : metavar$1,
159
+ width: metavar$1.length
160
+ };
161
+ } else if (term.type === "value") {
162
+ const value$1 = useQuotes ? `${JSON.stringify(term.value)}` : term.value;
163
+ yield {
164
+ text: useColors ? `\x1b[32m${value$1}\x1b[0m` : value$1,
165
+ width: value$1.length
166
+ };
167
+ } else if (term.type === "values") for (let i = 0; i < term.values.length; i++) {
168
+ if (i > 0) yield {
169
+ text: " ",
170
+ width: 1
171
+ };
172
+ const value$1 = useQuotes ? JSON.stringify(term.values[i]) : term.values[i];
173
+ yield {
174
+ text: useColors ? i <= 0 ? `\x1b[32m${value$1}` : i + 1 >= term.values.length ? `${value$1}\x1b[0m` : value$1 : value$1,
175
+ width: value$1.length
176
+ };
177
+ }
178
+ else throw new TypeError(`Invalid MessageTerm type: ${term["type"]}.`);
179
+ }
180
+ let output = "";
181
+ let totalWidth = 0;
182
+ for (const { text: text$1, width } of stream()) {
183
+ if (options.maxWidth != null && totalWidth + width > options.maxWidth) {
184
+ output += "\n";
185
+ totalWidth = 0;
186
+ }
187
+ output += text$1;
188
+ totalWidth += width;
189
+ }
190
+ return output;
191
+ }
192
+
193
+ //#endregion
194
+ export { formatMessage, message, metavar, optionName, optionNames, text, value, values };