@aruzone/aze-forge 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.
Files changed (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +408 -0
  3. package/dist/acceptance.d.ts +48 -0
  4. package/dist/acceptance.js +180 -0
  5. package/dist/acceptance.js.map +1 -0
  6. package/dist/assets.d.ts +19 -0
  7. package/dist/assets.js +509 -0
  8. package/dist/assets.js.map +1 -0
  9. package/dist/atomic-write.d.ts +1 -0
  10. package/dist/atomic-write.js +23 -0
  11. package/dist/atomic-write.js.map +1 -0
  12. package/dist/callout.d.ts +27 -0
  13. package/dist/callout.js +78 -0
  14. package/dist/callout.js.map +1 -0
  15. package/dist/capabilities-json.d.ts +4 -0
  16. package/dist/capabilities-json.js +225 -0
  17. package/dist/capabilities-json.js.map +1 -0
  18. package/dist/capabilities.d.ts +110 -0
  19. package/dist/capabilities.js +270 -0
  20. package/dist/capabilities.js.map +1 -0
  21. package/dist/cli.d.ts +2 -0
  22. package/dist/cli.js +1096 -0
  23. package/dist/cli.js.map +1 -0
  24. package/dist/compiler.d.ts +3 -0
  25. package/dist/compiler.js +1034 -0
  26. package/dist/compiler.js.map +1 -0
  27. package/dist/configuration-error.d.ts +4 -0
  28. package/dist/configuration-error.js +9 -0
  29. package/dist/configuration-error.js.map +1 -0
  30. package/dist/diagnostics-json.d.ts +23 -0
  31. package/dist/diagnostics-json.js +143 -0
  32. package/dist/diagnostics-json.js.map +1 -0
  33. package/dist/diagnostics.d.ts +16 -0
  34. package/dist/diagnostics.js +154 -0
  35. package/dist/diagnostics.js.map +1 -0
  36. package/dist/equation.d.ts +74 -0
  37. package/dist/equation.js +485 -0
  38. package/dist/equation.js.map +1 -0
  39. package/dist/font.d.ts +19 -0
  40. package/dist/font.js +75 -0
  41. package/dist/font.js.map +1 -0
  42. package/dist/format.d.ts +2 -0
  43. package/dist/format.js +308 -0
  44. package/dist/format.js.map +1 -0
  45. package/dist/hash.d.ts +5 -0
  46. package/dist/hash.js +189 -0
  47. package/dist/hash.js.map +1 -0
  48. package/dist/help.d.ts +9 -0
  49. package/dist/help.js +102 -0
  50. package/dist/help.js.map +1 -0
  51. package/dist/html-fragment.d.ts +7 -0
  52. package/dist/html-fragment.js +70 -0
  53. package/dist/html-fragment.js.map +1 -0
  54. package/dist/index.d.ts +39 -0
  55. package/dist/index.js +32 -0
  56. package/dist/index.js.map +1 -0
  57. package/dist/markdown.d.ts +14 -0
  58. package/dist/markdown.js +425 -0
  59. package/dist/markdown.js.map +1 -0
  60. package/dist/mermaid-browser.d.ts +43 -0
  61. package/dist/mermaid-browser.js +358 -0
  62. package/dist/mermaid-browser.js.map +1 -0
  63. package/dist/mermaid.d.ts +84 -0
  64. package/dist/mermaid.js +740 -0
  65. package/dist/mermaid.js.map +1 -0
  66. package/dist/model.d.ts +406 -0
  67. package/dist/model.js +2 -0
  68. package/dist/model.js.map +1 -0
  69. package/dist/parse.d.ts +3 -0
  70. package/dist/parse.js +1374 -0
  71. package/dist/parse.js.map +1 -0
  72. package/dist/preview-server.d.ts +39 -0
  73. package/dist/preview-server.js +156 -0
  74. package/dist/preview-server.js.map +1 -0
  75. package/dist/preview-shell.d.ts +29 -0
  76. package/dist/preview-shell.js +102 -0
  77. package/dist/preview-shell.js.map +1 -0
  78. package/dist/reference-validation.d.ts +7 -0
  79. package/dist/reference-validation.js +42 -0
  80. package/dist/reference-validation.js.map +1 -0
  81. package/dist/registry.d.ts +29 -0
  82. package/dist/registry.js +384 -0
  83. package/dist/registry.js.map +1 -0
  84. package/dist/render-html.d.ts +24 -0
  85. package/dist/render-html.js +149 -0
  86. package/dist/render-html.js.map +1 -0
  87. package/dist/render-pdf.d.ts +64 -0
  88. package/dist/render-pdf.js +503 -0
  89. package/dist/render-pdf.js.map +1 -0
  90. package/dist/render-png.d.ts +32 -0
  91. package/dist/render-png.js +427 -0
  92. package/dist/render-png.js.map +1 -0
  93. package/dist/render-svg.d.ts +23 -0
  94. package/dist/render-svg.js +243 -0
  95. package/dist/render-svg.js.map +1 -0
  96. package/dist/runtime-support.d.ts +26 -0
  97. package/dist/runtime-support.js +62 -0
  98. package/dist/runtime-support.js.map +1 -0
  99. package/dist/source-map.d.ts +12 -0
  100. package/dist/source-map.js +75 -0
  101. package/dist/source-map.js.map +1 -0
  102. package/dist/table.d.ts +22 -0
  103. package/dist/table.js +90 -0
  104. package/dist/table.js.map +1 -0
  105. package/dist/theme.d.ts +6 -0
  106. package/dist/theme.js +89 -0
  107. package/dist/theme.js.map +1 -0
  108. package/dist/tool-version.d.ts +3 -0
  109. package/dist/tool-version.js +3 -0
  110. package/dist/tool-version.js.map +1 -0
  111. package/dist/type-guards.d.ts +1 -0
  112. package/dist/type-guards.js +4 -0
  113. package/dist/type-guards.js.map +1 -0
  114. package/dist/validate-document.d.ts +2 -0
  115. package/dist/validate-document.js +248 -0
  116. package/dist/validate-document.js.map +1 -0
  117. package/dist/version.d.ts +37 -0
  118. package/dist/version.js +111 -0
  119. package/dist/version.js.map +1 -0
  120. package/dist/watch-dependencies.d.ts +15 -0
  121. package/dist/watch-dependencies.js +93 -0
  122. package/dist/watch-dependencies.js.map +1 -0
  123. package/dist/watch-events.d.ts +51 -0
  124. package/dist/watch-events.js +27 -0
  125. package/dist/watch-events.js.map +1 -0
  126. package/dist/watch-loop.d.ts +39 -0
  127. package/dist/watch-loop.js +117 -0
  128. package/dist/watch-loop.js.map +1 -0
  129. package/package.json +70 -0
  130. package/schemas/acceptance.json +104 -0
  131. package/schemas/capabilities.json +491 -0
  132. package/schemas/diagnostics.json +219 -0
  133. package/schemas/version.json +167 -0
package/dist/cli.js ADDED
@@ -0,0 +1,1096 @@
1
+ #!/usr/bin/env node
2
+ import { readFile, realpath } from "node:fs/promises";
3
+ import { basename, dirname, extname, join, resolve } from "node:path";
4
+ import { commitArtifact } from "./atomic-write.js";
5
+ import { buildCapabilities, serializeCapabilities } from "./capabilities.js";
6
+ import { createCompiler } from "./compiler.js";
7
+ import { createDiagnostic } from "./diagnostics.js";
8
+ import { createDiagnosticsReport } from "./diagnostics-json.js";
9
+ import { HELP_COMMANDS, commandHelp, globalHelp, humanCapabilitiesReport, humanVersionReport, versionLine, } from "./help.js";
10
+ import { createVersionReport } from "./version.js";
11
+ import { extractServedAssets, renderDiagnosticsPage, renderStartingPage, wrapPreviewShell, } from "./preview-shell.js";
12
+ import { PreviewServer } from "./preview-server.js";
13
+ import { collectImageSources, resolveWatchPaths } from "./watch-dependencies.js";
14
+ import { createResultEvent, createStartedEvent, createStoppedEvent, serializeEvent, } from "./watch-events.js";
15
+ import { WatchDriver } from "./watch-loop.js";
16
+ const FORMAT_BY_EXTENSION = {
17
+ ".html": "html",
18
+ ".svg": "svg",
19
+ ".png": "png",
20
+ ".pdf": "pdf",
21
+ };
22
+ class CliUsageError extends Error {
23
+ }
24
+ class ArtifactCommitError extends Error {
25
+ }
26
+ class InvalidUtf8Error extends Error {
27
+ sourcePath;
28
+ constructor(sourcePath) {
29
+ super(`Source "${sourcePath}" is not valid UTF-8.`);
30
+ this.name = "InvalidUtf8Error";
31
+ this.sourcePath = sourcePath;
32
+ }
33
+ }
34
+ function requestedDiagnosticsMode(arguments_) {
35
+ return arguments_.some((argument, index) => argument === "--diagnostics" && arguments_[index + 1] === "json")
36
+ ? "json"
37
+ : "human";
38
+ }
39
+ function claimAllowRawLatex(current) {
40
+ if (current) {
41
+ throw new CliUsageError('Option "--allow-raw-latex" was provided more than once.');
42
+ }
43
+ return true;
44
+ }
45
+ function claimFormatFlag(name, current) {
46
+ if (current) {
47
+ throw new CliUsageError(`Option "${name}" was provided more than once.`);
48
+ }
49
+ return true;
50
+ }
51
+ function claimJsonFlag(current) {
52
+ if (current) {
53
+ throw new CliUsageError('Option "--json" was provided more than once.');
54
+ }
55
+ return true;
56
+ }
57
+ function claimProbeFlag(current) {
58
+ if (current) {
59
+ throw new CliUsageError('Option "--probe" was provided more than once.');
60
+ }
61
+ return true;
62
+ }
63
+ function machineFromJsonFlags(json, diagnosticsMode) {
64
+ if (json && diagnosticsMode === "json") {
65
+ throw new CliUsageError('Options "--json" and "--diagnostics" cannot be combined.');
66
+ }
67
+ return json || diagnosticsMode === "json";
68
+ }
69
+ function parseCapabilitiesArguments(rest, diagnosticsMode) {
70
+ let probe = false;
71
+ let json = false;
72
+ for (const option of rest) {
73
+ if (option === "--probe") {
74
+ probe = claimProbeFlag(probe);
75
+ }
76
+ else if (option === "--json") {
77
+ json = claimJsonFlag(json);
78
+ }
79
+ else if (option.startsWith("-")) {
80
+ throw new CliUsageError(`Unknown option "${option}".`);
81
+ }
82
+ else {
83
+ throw new CliUsageError("Capabilities accepts no Source path.");
84
+ }
85
+ }
86
+ return {
87
+ command: "capabilities",
88
+ probe,
89
+ machine: machineFromJsonFlags(json, diagnosticsMode),
90
+ diagnosticsMode,
91
+ };
92
+ }
93
+ function parseVersionArguments(rest, diagnosticsMode) {
94
+ let json = false;
95
+ for (const option of rest) {
96
+ if (option === "--json") {
97
+ json = claimJsonFlag(json);
98
+ }
99
+ else if (option.startsWith("-")) {
100
+ throw new CliUsageError(`Unknown option "${option}".`);
101
+ }
102
+ else {
103
+ throw new CliUsageError("Version accepts no Source path.");
104
+ }
105
+ }
106
+ return {
107
+ command: "version",
108
+ machine: machineFromJsonFlags(json, diagnosticsMode),
109
+ diagnosticsMode,
110
+ };
111
+ }
112
+ function parseHelpArguments(topic, rest, diagnosticsMode) {
113
+ if (rest.length > 0) {
114
+ throw new CliUsageError("Usage: azeforge help [command]");
115
+ }
116
+ if (topic === undefined) {
117
+ return { command: "help", diagnosticsMode };
118
+ }
119
+ if (!HELP_COMMANDS.includes(topic)) {
120
+ throw new CliUsageError(`Unknown command "${topic}".`);
121
+ }
122
+ return { command: "help", topic: topic, diagnosticsMode };
123
+ }
124
+ function parseFormatArguments(first, rest, diagnosticsMode) {
125
+ const tokens = first === undefined ? [...rest] : [first, ...rest];
126
+ let stdin = false;
127
+ let write = false;
128
+ let check = false;
129
+ let sourcePath;
130
+ for (const token of tokens) {
131
+ if (token === "--stdin") {
132
+ stdin = claimFormatFlag("--stdin", stdin);
133
+ }
134
+ else if (token === "--write") {
135
+ write = claimFormatFlag("--write", write);
136
+ }
137
+ else if (token === "--check") {
138
+ check = claimFormatFlag("--check", check);
139
+ }
140
+ else if (token.startsWith("-")) {
141
+ throw new CliUsageError(`Unknown option "${token}".`);
142
+ }
143
+ else if (sourcePath !== undefined) {
144
+ throw new CliUsageError("Format accepts one Source path.");
145
+ }
146
+ else {
147
+ sourcePath = token;
148
+ }
149
+ }
150
+ if (sourcePath === undefined && !stdin) {
151
+ throw new CliUsageError("Usage: azeforge format <source> [--write | --check] | azeforge format --stdin [--check]");
152
+ }
153
+ if (sourcePath !== undefined && stdin) {
154
+ throw new CliUsageError("Format accepts either a Source path or --stdin, not both.");
155
+ }
156
+ if (write && check) {
157
+ throw new CliUsageError('Options "--write" and "--check" cannot be combined.');
158
+ }
159
+ if (write && stdin) {
160
+ throw new CliUsageError('Option "--write" rejects stdin Source.');
161
+ }
162
+ if (!write && !check && diagnosticsMode === "json") {
163
+ throw new CliUsageError("JSON diagnostics cannot be combined with formatted Source stdout.");
164
+ }
165
+ return {
166
+ command: "format",
167
+ ...(sourcePath === undefined ? {} : { sourcePath }),
168
+ stdin,
169
+ write,
170
+ check,
171
+ diagnosticsMode,
172
+ };
173
+ }
174
+ function parseArguments(rawArguments, diagnosticsMode) {
175
+ const arguments_ = [];
176
+ let diagnosticsSeen = false;
177
+ for (let index = 0; index < rawArguments.length; index += 1) {
178
+ const argument = rawArguments[index];
179
+ if (argument !== "--diagnostics") {
180
+ arguments_.push(argument ?? "");
181
+ continue;
182
+ }
183
+ const value = rawArguments[index + 1];
184
+ if (value !== "json") {
185
+ throw new CliUsageError('Option "--diagnostics" requires the value "json".');
186
+ }
187
+ if (diagnosticsSeen) {
188
+ throw new CliUsageError('Option "--diagnostics" was provided more than once.');
189
+ }
190
+ diagnosticsSeen = true;
191
+ index += 1;
192
+ }
193
+ if (arguments_.length === 0) {
194
+ return { command: "help", diagnosticsMode };
195
+ }
196
+ if (arguments_.includes("--help") ||
197
+ arguments_.includes("-h") ||
198
+ arguments_[0] === "help") {
199
+ if (arguments_[0] === "help") {
200
+ return parseHelpArguments(arguments_[1], arguments_.slice(2), diagnosticsMode);
201
+ }
202
+ const withoutHelp = arguments_.filter((token) => token !== "--help" && token !== "-h");
203
+ if (withoutHelp.length === 0) {
204
+ return { command: "help", diagnosticsMode };
205
+ }
206
+ if (withoutHelp.length === 1 &&
207
+ HELP_COMMANDS.includes(withoutHelp[0] ?? "")) {
208
+ return {
209
+ command: "help",
210
+ topic: withoutHelp[0],
211
+ diagnosticsMode,
212
+ };
213
+ }
214
+ throw new CliUsageError('Option "--help" cannot be combined with other options.');
215
+ }
216
+ if (arguments_[0] === "--version") {
217
+ if (arguments_.length > 1) {
218
+ throw new CliUsageError('Option "--version" accepts no additional arguments.');
219
+ }
220
+ return { command: "version-line", diagnosticsMode };
221
+ }
222
+ if (arguments_[0] === "capabilities") {
223
+ return parseCapabilitiesArguments(arguments_.slice(1), diagnosticsMode);
224
+ }
225
+ if (arguments_[0] === "version") {
226
+ return parseVersionArguments(arguments_.slice(1), diagnosticsMode);
227
+ }
228
+ const [command, sourcePath, ...rest] = arguments_;
229
+ if (command === "format") {
230
+ return parseFormatArguments(sourcePath, rest, diagnosticsMode);
231
+ }
232
+ if (command === "watch") {
233
+ if (sourcePath === undefined || sourcePath.startsWith("-")) {
234
+ throw new CliUsageError("Usage: azeforge watch <source> --output <artifact.html>");
235
+ }
236
+ return parseWatchArguments(sourcePath, rest, diagnosticsMode);
237
+ }
238
+ if (command === "serve") {
239
+ if (sourcePath === undefined || sourcePath.startsWith("-")) {
240
+ throw new CliUsageError("Usage: azeforge serve <source> [--port <port>]");
241
+ }
242
+ return parseServeArguments(sourcePath, rest, diagnosticsMode);
243
+ }
244
+ if ((command !== "validate" && command !== "render") ||
245
+ sourcePath === undefined ||
246
+ sourcePath.startsWith("-")) {
247
+ throw new CliUsageError("Usage: azeforge render <source> --output <artifact> | azeforge validate <source> | azeforge format <source> [--write | --check] | azeforge watch <source> --output <artifact> | azeforge serve <source> [--port <port>] | azeforge capabilities [--probe] [--json] | azeforge version [--json]");
248
+ }
249
+ if (command === "validate") {
250
+ let allowRawLatex = false;
251
+ for (const option of rest) {
252
+ if (option !== "--allow-raw-latex") {
253
+ throw new CliUsageError("Validate accepts one Source path.");
254
+ }
255
+ allowRawLatex = claimAllowRawLatex(allowRawLatex);
256
+ }
257
+ return { command, sourcePath, diagnosticsMode, allowRawLatex };
258
+ }
259
+ let artifactPath;
260
+ let stdout = false;
261
+ let allowRawLatex = false;
262
+ let format;
263
+ let theme;
264
+ for (let index = 0; index < rest.length; index += 1) {
265
+ const option = rest[index];
266
+ if (option === "--stdout") {
267
+ if (stdout)
268
+ throw new CliUsageError('Option "--stdout" was provided more than once.');
269
+ stdout = true;
270
+ continue;
271
+ }
272
+ if (option === "--allow-raw-latex") {
273
+ allowRawLatex = claimAllowRawLatex(allowRawLatex);
274
+ continue;
275
+ }
276
+ const value = rest[index + 1];
277
+ if (value === undefined || value.startsWith("--")) {
278
+ throw new CliUsageError(`Option "${option}" needs a value.`);
279
+ }
280
+ index += 1;
281
+ if (option === "--output") {
282
+ if (artifactPath !== undefined) {
283
+ throw new CliUsageError('Option "--output" was provided more than once.');
284
+ }
285
+ artifactPath = value;
286
+ }
287
+ else if (option === "--format") {
288
+ if (format !== undefined) {
289
+ throw new CliUsageError('Option "--format" was provided more than once.');
290
+ }
291
+ format = value;
292
+ }
293
+ else if (option === "--theme") {
294
+ if (theme !== undefined) {
295
+ throw new CliUsageError('Option "--theme" was provided more than once.');
296
+ }
297
+ theme = value;
298
+ }
299
+ else {
300
+ throw new CliUsageError(`Unknown option "${option}".`);
301
+ }
302
+ }
303
+ if ((artifactPath === undefined && !stdout) ||
304
+ (artifactPath !== undefined && stdout)) {
305
+ throw new CliUsageError("Render requires exactly one of --output or --stdout.");
306
+ }
307
+ if (stdout && diagnosticsMode === "json") {
308
+ throw new CliUsageError("JSON diagnostics cannot be combined with Artifact stdout.");
309
+ }
310
+ if (stdout && format === undefined) {
311
+ throw new CliUsageError("Render --stdout requires an explicit --format.");
312
+ }
313
+ const selectedFormat = selectArtifactFormat(format, artifactPath);
314
+ return {
315
+ command,
316
+ sourcePath,
317
+ diagnosticsMode,
318
+ ...(artifactPath === undefined ? {} : { artifactPath }),
319
+ stdout,
320
+ format: selectedFormat,
321
+ allowRawLatex,
322
+ ...(theme === undefined ? {} : { theme }),
323
+ };
324
+ }
325
+ function selectArtifactFormat(format, artifactPath) {
326
+ const extension = artifactPath === undefined ? "" : extname(artifactPath).toLowerCase();
327
+ const inferredFormat = FORMAT_BY_EXTENSION[extension];
328
+ const selectedFormat = format ?? inferredFormat;
329
+ if ((selectedFormat !== "html" && selectedFormat !== "svg" && selectedFormat !== "png" && selectedFormat !== "pdf") ||
330
+ (format !== undefined && inferredFormat !== undefined && format !== inferredFormat)) {
331
+ throw new CliUsageError("The Artifact format and destination extension disagree.");
332
+ }
333
+ return selectedFormat;
334
+ }
335
+ function parseWatchArguments(sourcePath, rest, diagnosticsMode) {
336
+ let artifactPath;
337
+ let allowRawLatex = false;
338
+ let format;
339
+ let theme;
340
+ for (let index = 0; index < rest.length; index += 1) {
341
+ const option = rest[index];
342
+ if (option === "--stdout") {
343
+ throw new CliUsageError("Watch requires --output and rejects --stdout.");
344
+ }
345
+ if (option === "--allow-raw-latex") {
346
+ allowRawLatex = claimAllowRawLatex(allowRawLatex);
347
+ continue;
348
+ }
349
+ const value = rest[index + 1];
350
+ if (value === undefined || value.startsWith("--")) {
351
+ throw new CliUsageError(`Option "${option}" needs a value.`);
352
+ }
353
+ index += 1;
354
+ if (option === "--output") {
355
+ if (artifactPath !== undefined) {
356
+ throw new CliUsageError('Option "--output" was provided more than once.');
357
+ }
358
+ artifactPath = value;
359
+ }
360
+ else if (option === "--format") {
361
+ if (format !== undefined) {
362
+ throw new CliUsageError('Option "--format" was provided more than once.');
363
+ }
364
+ format = value;
365
+ }
366
+ else if (option === "--theme") {
367
+ if (theme !== undefined) {
368
+ throw new CliUsageError('Option "--theme" was provided more than once.');
369
+ }
370
+ theme = value;
371
+ }
372
+ else {
373
+ throw new CliUsageError(`Unknown option "${option}".`);
374
+ }
375
+ }
376
+ if (artifactPath === undefined) {
377
+ throw new CliUsageError("Watch requires --output <artifact>.");
378
+ }
379
+ return {
380
+ command: "watch",
381
+ sourcePath,
382
+ diagnosticsMode,
383
+ allowRawLatex,
384
+ artifactPath,
385
+ format: selectArtifactFormat(format, artifactPath),
386
+ ...(theme === undefined ? {} : { theme }),
387
+ };
388
+ }
389
+ function parseServeArguments(sourcePath, rest, diagnosticsMode) {
390
+ let allowRawLatex = false;
391
+ let theme;
392
+ let port;
393
+ for (let index = 0; index < rest.length; index += 1) {
394
+ const option = rest[index];
395
+ if (option === "--output" ||
396
+ option === "--stdout" ||
397
+ option === "--format") {
398
+ throw new CliUsageError("Serve accepts no --format, --output, or --stdout.");
399
+ }
400
+ if (option === "--host") {
401
+ throw new CliUsageError("Serve binds only 127.0.0.1.");
402
+ }
403
+ if (option === "--allow-raw-latex") {
404
+ allowRawLatex = claimAllowRawLatex(allowRawLatex);
405
+ continue;
406
+ }
407
+ const value = rest[index + 1];
408
+ if (value === undefined || value.startsWith("--")) {
409
+ throw new CliUsageError(`Option "${option}" needs a value.`);
410
+ }
411
+ index += 1;
412
+ if (option === "--port") {
413
+ if (port !== undefined) {
414
+ throw new CliUsageError('Option "--port" was provided more than once.');
415
+ }
416
+ if (!/^\d+$/.test(value) || Number(value) > 65535) {
417
+ throw new CliUsageError('Option "--port" needs a value between 0 and 65535.');
418
+ }
419
+ port = Number(value);
420
+ }
421
+ else if (option === "--theme") {
422
+ if (theme !== undefined) {
423
+ throw new CliUsageError('Option "--theme" was provided more than once.');
424
+ }
425
+ theme = value;
426
+ }
427
+ else {
428
+ throw new CliUsageError(`Unknown option "${option}".`);
429
+ }
430
+ }
431
+ return {
432
+ command: "serve",
433
+ sourcePath,
434
+ diagnosticsMode,
435
+ allowRawLatex,
436
+ port: port ?? 0,
437
+ ...(theme === undefined ? {} : { theme }),
438
+ };
439
+ }
440
+ function formatDiagnostic(diagnostic, sourceText) {
441
+ const source = diagnostic.location?.source ?? "<source>";
442
+ const range = diagnostic.location?.range;
443
+ const location = range === undefined
444
+ ? source
445
+ : `${source}:${range.start.line}:${range.start.column}`;
446
+ const lines = [
447
+ `${location}: ${diagnostic.severity} [${diagnostic.code}]`,
448
+ diagnostic.message,
449
+ ];
450
+ if (sourceText !== undefined && range !== undefined) {
451
+ const sourceLine = sourceText.split(/\r\n|\n|\r/)[range.start.line - 1];
452
+ if (sourceLine !== undefined) {
453
+ const codePoints = [...sourceLine];
454
+ const boundedLine = codePoints.slice(0, 120).join("");
455
+ lines.push(` ${boundedLine}`);
456
+ if (codePoints.length <= 120 &&
457
+ /^[\x20-\x7e]*$/.test(sourceLine)) {
458
+ const caretStart = Math.max(0, range.start.column - 1);
459
+ const caretLength = Math.max(1, range.end.line === range.start.line
460
+ ? range.end.column - range.start.column
461
+ : 1);
462
+ lines.push(` ${" ".repeat(caretStart)}${"^".repeat(caretLength)}`);
463
+ }
464
+ }
465
+ }
466
+ if (diagnostic.suggestion !== undefined) {
467
+ lines.push(`Help: ${diagnostic.suggestion}`);
468
+ }
469
+ if (diagnostic.fix !== undefined) {
470
+ lines.push(`Fix: ${diagnostic.fix.title}`);
471
+ }
472
+ for (const related of diagnostic.relatedLocations) {
473
+ const relatedSource = related.source ?? source;
474
+ lines.push(`Related: ${relatedSource}:${related.range.start.line}:${related.range.start.column}: ${related.message}`);
475
+ }
476
+ return `${lines.join("\n")}\n`;
477
+ }
478
+ function decodeSource(bytes, sourceLabel) {
479
+ try {
480
+ return new TextDecoder("utf-8", { fatal: true, ignoreBOM: true }).decode(bytes);
481
+ }
482
+ catch {
483
+ throw new InvalidUtf8Error(sourceLabel);
484
+ }
485
+ }
486
+ async function readSource(path) {
487
+ return decodeSource(await readFile(path), path);
488
+ }
489
+ async function readStdin(sourceLabel) {
490
+ const chunks = [];
491
+ for await (const chunk of process.stdin) {
492
+ chunks.push(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk);
493
+ }
494
+ return decodeSource(Buffer.concat(chunks), sourceLabel);
495
+ }
496
+ async function canonicalDestinationPath(path) {
497
+ try {
498
+ return await realpath(path);
499
+ }
500
+ catch (error) {
501
+ if (!(error instanceof Error) ||
502
+ !("code" in error) ||
503
+ error.code !== "ENOENT") {
504
+ throw error;
505
+ }
506
+ const absolutePath = resolve(path);
507
+ return join(await realpath(dirname(absolutePath)), basename(absolutePath));
508
+ }
509
+ }
510
+ async function assertArtifactSeparate(sourcePath, artifactPath) {
511
+ const canonicalSourcePath = await realpath(sourcePath);
512
+ const canonicalArtifactPath = await canonicalDestinationPath(artifactPath);
513
+ if (canonicalSourcePath === canonicalArtifactPath) {
514
+ throw new CliUsageError("The Artifact destination cannot replace its Source.");
515
+ }
516
+ }
517
+ function emitDiagnostics(diagnosticsMode, command, success, diagnostics, sourceText, details = {}) {
518
+ if (diagnosticsMode === "json") {
519
+ process.stdout.write(`${JSON.stringify(createDiagnosticsReport(command, success, diagnostics, details))}\n`);
520
+ return;
521
+ }
522
+ for (const diagnostic of diagnostics) {
523
+ process.stderr.write(formatDiagnostic(diagnostic, sourceText));
524
+ }
525
+ }
526
+ function scanImageSourcesFromText(sourceText) {
527
+ const pattern = /!\[[^\]\n]*\]\(\s*<?([^)\s>]+)>?(?:\s+(?:"[^"]*"|'[^']*'))?\s*\)/g;
528
+ const sources = [];
529
+ for (let match = pattern.exec(sourceText); match !== null; match = pattern.exec(sourceText)) {
530
+ const src = match[1];
531
+ if (src !== undefined)
532
+ sources.push(src);
533
+ }
534
+ return sources;
535
+ }
536
+ async function compileWatchSource(options) {
537
+ let sourceText;
538
+ try {
539
+ sourceText = await readSource(options.sourcePath);
540
+ }
541
+ catch {
542
+ return {
543
+ diagnostics: [
544
+ createDiagnostic("azeforge.source#read-failed", "error", "The Source could not be read.", { location: { source: options.sourcePath } }),
545
+ ],
546
+ imageSources: [],
547
+ };
548
+ }
549
+ const compiler = createCompiler();
550
+ let result;
551
+ try {
552
+ result = await compiler.compile(sourceText, {
553
+ format: options.format,
554
+ sourceName: options.sourcePath,
555
+ projectRoot: options.projectRoot,
556
+ ...(options.theme === undefined ? {} : { theme: options.theme }),
557
+ ...(options.allowRawLatex ? { allowRawLatex: true } : {}),
558
+ });
559
+ }
560
+ catch {
561
+ return {
562
+ sourceText,
563
+ diagnostics: [
564
+ createDiagnostic("azeforge.cli#operation-failed", "error", "The accepted operation failed unexpectedly."),
565
+ ],
566
+ imageSources: scanImageSourcesFromText(sourceText),
567
+ };
568
+ }
569
+ return {
570
+ sourceText,
571
+ diagnostics: result.diagnostics,
572
+ ...(result.contentHash === undefined ? {} : { contentHash: result.contentHash }),
573
+ ...(result.artifact === undefined ? {} : { artifact: result.artifact }),
574
+ imageSources: result.document === undefined
575
+ ? scanImageSourcesFromText(sourceText)
576
+ : collectImageSources(result.document),
577
+ };
578
+ }
579
+ async function resolveSourcePath(path) {
580
+ try {
581
+ return await realpath(path);
582
+ }
583
+ catch {
584
+ return resolve(path);
585
+ }
586
+ }
587
+ function reportCycleHuman(sourceText, diagnostics) {
588
+ for (const diagnostic of diagnostics) {
589
+ process.stderr.write(formatDiagnostic(diagnostic, sourceText));
590
+ }
591
+ }
592
+ function closedStdoutErrorCode(error) {
593
+ if (typeof error !== "object" || error === null)
594
+ return undefined;
595
+ if (!("code" in error))
596
+ return undefined;
597
+ const code = error.code;
598
+ return typeof code === "string" ? code : undefined;
599
+ }
600
+ function installClosedStdoutGuard(onClosed) {
601
+ process.stdout.on("error", (error) => {
602
+ if (closedStdoutErrorCode(error) === "EPIPE")
603
+ onClosed();
604
+ });
605
+ }
606
+ async function runWatch(watchArguments) {
607
+ const machine = watchArguments.diagnosticsMode === "json";
608
+ let seq = 0;
609
+ const emit = (event) => {
610
+ if (machine)
611
+ process.stdout.write(`${serializeEvent(event)}\n`);
612
+ };
613
+ try {
614
+ const canonicalSourcePath = await realpath(watchArguments.sourcePath);
615
+ const canonicalArtifactPath = await canonicalDestinationPath(watchArguments.artifactPath);
616
+ if (canonicalSourcePath === canonicalArtifactPath) {
617
+ throw new CliUsageError("The Artifact destination cannot replace its Source.");
618
+ }
619
+ }
620
+ catch (error) {
621
+ if (error instanceof CliUsageError)
622
+ throw error;
623
+ }
624
+ const sourceRealPath = await resolveSourcePath(watchArguments.sourcePath);
625
+ const projectRoot = dirname(sourceRealPath);
626
+ let driver;
627
+ let settling = false;
628
+ let compiling = false;
629
+ let pending = false;
630
+ let inflight;
631
+ const shutdown = (code, reason) => {
632
+ if (settling)
633
+ return;
634
+ settling = true;
635
+ const done = async () => {
636
+ try {
637
+ await inflight;
638
+ }
639
+ catch {
640
+ // Settle: cleanup continues without a stack trace.
641
+ }
642
+ await driver?.close();
643
+ if (machine && reason !== undefined) {
644
+ try {
645
+ process.stdout.write(`${serializeEvent(createStoppedEvent("watch", seq, reason))}\n`);
646
+ }
647
+ catch {
648
+ // Best effort: consumers cannot require a final event.
649
+ }
650
+ }
651
+ process.exit(code);
652
+ };
653
+ void done();
654
+ };
655
+ process.once("SIGINT", () => shutdown(130, "signal"));
656
+ process.once("SIGTERM", () => shutdown(143, "signal"));
657
+ if (machine)
658
+ installClosedStdoutGuard(() => shutdown(0));
659
+ const compileOnce = async () => {
660
+ const outcome = await compileWatchSource({
661
+ sourcePath: watchArguments.sourcePath,
662
+ projectRoot,
663
+ format: watchArguments.format,
664
+ ...(watchArguments.theme === undefined ? {} : { theme: watchArguments.theme }),
665
+ allowRawLatex: watchArguments.allowRawLatex,
666
+ });
667
+ if (settling)
668
+ return;
669
+ let success = outcome.artifact !== undefined;
670
+ let diagnostics = outcome.diagnostics;
671
+ let contentHash = outcome.contentHash;
672
+ let artifact = outcome.artifact;
673
+ if (success && artifact !== undefined) {
674
+ try {
675
+ await assertArtifactSeparate(watchArguments.sourcePath, watchArguments.artifactPath);
676
+ await commitArtifact(watchArguments.artifactPath, artifact.bytes);
677
+ }
678
+ catch {
679
+ success = false;
680
+ diagnostics = [
681
+ createDiagnostic("azeforge.artifact#commit-failed", "error", "The Artifact could not be committed."),
682
+ ];
683
+ contentHash = undefined;
684
+ artifact = undefined;
685
+ }
686
+ }
687
+ if (machine) {
688
+ emit(createResultEvent("watch", seq, {
689
+ success,
690
+ diagnostics,
691
+ ...(success && contentHash !== undefined ? { contentHash } : {}),
692
+ ...(success && artifact !== undefined ? { artifact: artifact.metadata } : {}),
693
+ }));
694
+ seq += 1;
695
+ }
696
+ else {
697
+ reportCycleHuman(outcome.sourceText, diagnostics);
698
+ process.stderr.write(success
699
+ ? `watch: updated ${watchArguments.artifactPath}\n`
700
+ : `watch: failed; preserved ${watchArguments.artifactPath}\n`);
701
+ }
702
+ await driver?.rearm({ imageSources: outcome.imageSources });
703
+ };
704
+ const runLoop = async () => {
705
+ for (;;) {
706
+ compiling = true;
707
+ const iteration = compileOnce();
708
+ inflight = iteration;
709
+ try {
710
+ await iteration;
711
+ }
712
+ finally {
713
+ compiling = false;
714
+ if (inflight === iteration)
715
+ inflight = undefined;
716
+ }
717
+ if (settling || !pending)
718
+ break;
719
+ pending = false;
720
+ }
721
+ };
722
+ const onChange = () => {
723
+ if (settling)
724
+ return;
725
+ if (compiling) {
726
+ pending = true;
727
+ return;
728
+ }
729
+ void runLoop();
730
+ };
731
+ driver = await WatchDriver.start({
732
+ sourcePath: sourceRealPath,
733
+ projectRoot,
734
+ debounceMs: 60,
735
+ watchPathsFor: (outcome) => resolveWatchPaths(projectRoot, outcome?.imageSources ?? []),
736
+ onChange,
737
+ onWatcherFailed: () => shutdown(1, "watcher-failed"),
738
+ }, undefined);
739
+ emit(createStartedEvent("watch", seq, {
740
+ source: watchArguments.sourcePath,
741
+ artifact: watchArguments.artifactPath,
742
+ format: watchArguments.format,
743
+ }));
744
+ seq += 1;
745
+ if (!machine) {
746
+ process.stderr.write(`watch: watching ${watchArguments.sourcePath} → ${watchArguments.artifactPath}\n`);
747
+ }
748
+ await runLoop();
749
+ }
750
+ async function runServe(serveArguments) {
751
+ const machine = serveArguments.diagnosticsMode === "json";
752
+ let seq = 0;
753
+ const emit = (event) => {
754
+ if (machine)
755
+ process.stdout.write(`${serializeEvent(event)}\n`);
756
+ };
757
+ const sourceRealPath = await resolveSourcePath(serveArguments.sourcePath);
758
+ const projectRoot = dirname(sourceRealPath);
759
+ let preview;
760
+ try {
761
+ preview = await PreviewServer.listen({
762
+ port: serveArguments.port,
763
+ onError: () => shutdown(1, "listener-failed"),
764
+ });
765
+ }
766
+ catch {
767
+ emitDiagnostics(serveArguments.diagnosticsMode, "serve", false, [
768
+ createDiagnostic("azeforge.cli#operation-failed", "error", `The preview server could not listen on port ${serveArguments.port}.`, { suggestion: "Choose another --port." }),
769
+ ]);
770
+ process.exitCode = 1;
771
+ return;
772
+ }
773
+ preview.update(renderStartingPage(serveArguments.sourcePath), []);
774
+ let driver;
775
+ let settling = false;
776
+ let compiling = false;
777
+ let pending = false;
778
+ let inflight;
779
+ const shutdown = (code, reason) => {
780
+ if (settling)
781
+ return;
782
+ settling = true;
783
+ const done = async () => {
784
+ try {
785
+ await inflight;
786
+ }
787
+ catch {
788
+ // Settle: cleanup continues without a stack trace.
789
+ }
790
+ await driver?.close();
791
+ await preview.close();
792
+ if (machine && reason !== undefined) {
793
+ try {
794
+ process.stdout.write(`${serializeEvent(createStoppedEvent("serve", seq, reason))}\n`);
795
+ }
796
+ catch {
797
+ // Best effort: consumers cannot require a final event.
798
+ }
799
+ }
800
+ process.exit(code);
801
+ };
802
+ void done();
803
+ };
804
+ process.once("SIGINT", () => shutdown(130, "signal"));
805
+ process.once("SIGTERM", () => shutdown(143, "signal"));
806
+ if (machine)
807
+ installClosedStdoutGuard(() => shutdown(0));
808
+ const compileOnce = async () => {
809
+ const outcome = await compileWatchSource({
810
+ sourcePath: serveArguments.sourcePath,
811
+ projectRoot,
812
+ format: "html",
813
+ ...(serveArguments.theme === undefined ? {} : { theme: serveArguments.theme }),
814
+ allowRawLatex: serveArguments.allowRawLatex,
815
+ });
816
+ if (settling)
817
+ return;
818
+ const success = outcome.artifact !== undefined;
819
+ if (success && outcome.artifact !== undefined) {
820
+ const html = new TextDecoder().decode(outcome.artifact.bytes);
821
+ const assets = extractServedAssets(html);
822
+ preview.update(wrapPreviewShell(html), assets);
823
+ if (machine) {
824
+ emit(createResultEvent("serve", seq, {
825
+ success: true,
826
+ diagnostics: outcome.diagnostics,
827
+ ...(outcome.contentHash === undefined
828
+ ? {}
829
+ : { contentHash: outcome.contentHash }),
830
+ artifact: outcome.artifact.metadata,
831
+ url: preview.url,
832
+ assets: assets.map((asset) => ({
833
+ url: `${preview.url}assets/${asset.token}`,
834
+ mediaType: asset.mediaType,
835
+ byteLength: asset.bytes.byteLength,
836
+ })),
837
+ }));
838
+ seq += 1;
839
+ }
840
+ else {
841
+ reportCycleHuman(outcome.sourceText, outcome.diagnostics);
842
+ process.stderr.write("serve: updated preview\n");
843
+ }
844
+ }
845
+ else {
846
+ preview.update(renderDiagnosticsPage(outcome.diagnostics, serveArguments.sourcePath), []);
847
+ if (machine) {
848
+ emit(createResultEvent("serve", seq, {
849
+ success: false,
850
+ diagnostics: outcome.diagnostics,
851
+ url: preview.url,
852
+ assets: [],
853
+ }));
854
+ seq += 1;
855
+ }
856
+ else {
857
+ reportCycleHuman(outcome.sourceText, outcome.diagnostics);
858
+ process.stderr.write("serve: showing current diagnostics\n");
859
+ }
860
+ }
861
+ await driver?.rearm({ imageSources: outcome.imageSources });
862
+ };
863
+ const runLoop = async () => {
864
+ for (;;) {
865
+ compiling = true;
866
+ const iteration = compileOnce();
867
+ inflight = iteration;
868
+ try {
869
+ await iteration;
870
+ }
871
+ finally {
872
+ compiling = false;
873
+ if (inflight === iteration)
874
+ inflight = undefined;
875
+ }
876
+ if (settling || !pending)
877
+ break;
878
+ pending = false;
879
+ }
880
+ };
881
+ const onChange = () => {
882
+ if (settling)
883
+ return;
884
+ if (compiling) {
885
+ pending = true;
886
+ return;
887
+ }
888
+ void runLoop();
889
+ };
890
+ driver = await WatchDriver.start({
891
+ sourcePath: sourceRealPath,
892
+ projectRoot,
893
+ debounceMs: 60,
894
+ watchPathsFor: (outcome) => resolveWatchPaths(projectRoot, outcome?.imageSources ?? []),
895
+ onChange,
896
+ onWatcherFailed: () => shutdown(1, "watcher-failed"),
897
+ }, undefined);
898
+ emit(createStartedEvent("serve", seq, {
899
+ source: serveArguments.sourcePath,
900
+ url: preview.url,
901
+ }));
902
+ seq += 1;
903
+ if (!machine) {
904
+ process.stderr.write(`serve: listening on ${preview.url} for ${serveArguments.sourcePath}\n`);
905
+ }
906
+ await runLoop();
907
+ }
908
+ async function main() {
909
+ const rawArguments = process.argv.slice(2);
910
+ const diagnosticsMode = requestedDiagnosticsMode(rawArguments);
911
+ const commandName = rawArguments[0] ?? "unknown";
912
+ let arguments_;
913
+ try {
914
+ arguments_ = parseArguments(rawArguments, diagnosticsMode);
915
+ }
916
+ catch (error) {
917
+ const message = error instanceof Error ? error.message : "Invalid command line.";
918
+ emitDiagnostics(diagnosticsMode, commandName, false, [
919
+ createDiagnostic("azeforge.cli#invalid-operation", "error", message),
920
+ ]);
921
+ process.exitCode = 2;
922
+ return;
923
+ }
924
+ try {
925
+ if (arguments_.command === "help") {
926
+ process.stderr.write(arguments_.topic === undefined
927
+ ? globalHelp()
928
+ : commandHelp(arguments_.topic));
929
+ return;
930
+ }
931
+ if (arguments_.command === "version-line") {
932
+ process.stdout.write(versionLine());
933
+ return;
934
+ }
935
+ if (arguments_.command === "version") {
936
+ if (arguments_.machine) {
937
+ process.stdout.write(`${JSON.stringify(createVersionReport())}\n`);
938
+ return;
939
+ }
940
+ process.stderr.write(humanVersionReport(createVersionReport()));
941
+ return;
942
+ }
943
+ if (arguments_.command === "capabilities") {
944
+ let report;
945
+ try {
946
+ report = await buildCapabilities({
947
+ ...(arguments_.probe ? { probe: true } : {}),
948
+ });
949
+ }
950
+ catch {
951
+ emitDiagnostics(arguments_.diagnosticsMode, "capabilities", false, [
952
+ createDiagnostic("azeforge.cli#operation-failed", "error", "No trustworthy capabilities manifest could be produced."),
953
+ ]);
954
+ process.exitCode = 1;
955
+ return;
956
+ }
957
+ if (arguments_.machine) {
958
+ process.stdout.write(serializeCapabilities(report));
959
+ return;
960
+ }
961
+ process.stderr.write(humanCapabilitiesReport(report));
962
+ return;
963
+ }
964
+ if (arguments_.command === "watch") {
965
+ await runWatch(arguments_);
966
+ return;
967
+ }
968
+ if (arguments_.command === "serve") {
969
+ await runServe(arguments_);
970
+ return;
971
+ }
972
+ if (arguments_.command === "render" &&
973
+ arguments_.stdout &&
974
+ (arguments_.format === "png" || arguments_.format === "pdf") &&
975
+ process.stdout.isTTY === true) {
976
+ emitDiagnostics(diagnosticsMode, arguments_.command, false, [
977
+ createDiagnostic("azeforge.cli#invalid-operation", "error", "Binary Artifact stdout requires a redirected destination, not an interactive terminal."),
978
+ ]);
979
+ process.exitCode = 2;
980
+ return;
981
+ }
982
+ if (arguments_.command === "render" && arguments_.artifactPath !== undefined) {
983
+ const canonicalSourcePath = await realpath(arguments_.sourcePath);
984
+ let canonicalArtifactPath;
985
+ try {
986
+ canonicalArtifactPath = await canonicalDestinationPath(arguments_.artifactPath);
987
+ }
988
+ catch {
989
+ throw new ArtifactCommitError();
990
+ }
991
+ if (canonicalSourcePath === canonicalArtifactPath) {
992
+ throw new CliUsageError("The Artifact destination cannot replace its Source.");
993
+ }
994
+ }
995
+ if (arguments_.command === "format") {
996
+ const filePath = arguments_.sourcePath;
997
+ const sourceLabel = filePath ?? "<stdin>";
998
+ const formatSourceText = arguments_.stdin || filePath === undefined
999
+ ? await readStdin(sourceLabel)
1000
+ : await readSource(filePath);
1001
+ const compiler = createCompiler();
1002
+ const formatted = compiler.format(formatSourceText, {
1003
+ sourceName: sourceLabel,
1004
+ });
1005
+ if (formatted.source === undefined) {
1006
+ emitDiagnostics(arguments_.diagnosticsMode, arguments_.command, false, formatted.diagnostics, formatSourceText);
1007
+ process.exitCode = 1;
1008
+ return;
1009
+ }
1010
+ if (arguments_.check) {
1011
+ if (formatted.source === formatSourceText) {
1012
+ emitDiagnostics(arguments_.diagnosticsMode, arguments_.command, true, []);
1013
+ return;
1014
+ }
1015
+ emitDiagnostics(arguments_.diagnosticsMode, arguments_.command, false, [
1016
+ createDiagnostic("azeforge.format#format-required", "error", "Source requires formatting.", {
1017
+ location: { source: sourceLabel },
1018
+ suggestion: "Run `azeforge format` to apply formatting.",
1019
+ }),
1020
+ ], formatSourceText);
1021
+ process.exitCode = 1;
1022
+ return;
1023
+ }
1024
+ if (arguments_.write && filePath !== undefined) {
1025
+ if (formatted.source !== formatSourceText) {
1026
+ await commitArtifact(filePath, new TextEncoder().encode(formatted.source));
1027
+ }
1028
+ emitDiagnostics(arguments_.diagnosticsMode, arguments_.command, true, []);
1029
+ return;
1030
+ }
1031
+ process.stdout.write(formatted.source);
1032
+ return;
1033
+ }
1034
+ const source = await readSource(arguments_.sourcePath);
1035
+ const compiler = createCompiler();
1036
+ if (arguments_.command === "validate") {
1037
+ const result = compiler.validate(compiler.parse(source, {
1038
+ sourceName: arguments_.sourcePath,
1039
+ ...(arguments_.allowRawLatex ? { allowRawLatex: true } : {}),
1040
+ }));
1041
+ emitDiagnostics(arguments_.diagnosticsMode, arguments_.command, result.document !== undefined, result.diagnostics, source);
1042
+ if (result.document === undefined)
1043
+ process.exitCode = 1;
1044
+ return;
1045
+ }
1046
+ const result = await compiler.compile(source, {
1047
+ format: arguments_.format,
1048
+ sourceName: arguments_.sourcePath,
1049
+ projectRoot: dirname(await realpath(arguments_.sourcePath)),
1050
+ ...(arguments_.theme === undefined ? {} : { theme: arguments_.theme }),
1051
+ ...(arguments_.allowRawLatex ? { allowRawLatex: true } : {}),
1052
+ });
1053
+ if (result.artifact === undefined) {
1054
+ emitDiagnostics(arguments_.diagnosticsMode, arguments_.command, false, result.diagnostics, source);
1055
+ process.exitCode = 1;
1056
+ return;
1057
+ }
1058
+ if (arguments_.stdout) {
1059
+ process.stdout.write(result.artifact.bytes);
1060
+ }
1061
+ else if (arguments_.artifactPath !== undefined) {
1062
+ try {
1063
+ await assertArtifactSeparate(arguments_.sourcePath, arguments_.artifactPath);
1064
+ await commitArtifact(arguments_.artifactPath, result.artifact.bytes);
1065
+ }
1066
+ catch (error) {
1067
+ if (error instanceof CliUsageError)
1068
+ throw error;
1069
+ throw new ArtifactCommitError();
1070
+ }
1071
+ }
1072
+ emitDiagnostics(arguments_.diagnosticsMode, arguments_.command, true, result.diagnostics, source, {
1073
+ ...(result.contentHash === undefined
1074
+ ? {}
1075
+ : { contentHash: result.contentHash }),
1076
+ artifact: result.artifact.metadata,
1077
+ });
1078
+ }
1079
+ catch (error) {
1080
+ const failure = error instanceof InvalidUtf8Error
1081
+ ? createDiagnostic("azeforge.source#invalid-utf8", "error", "Source must contain valid UTF-8.", { location: { source: error.sourcePath } })
1082
+ : error instanceof CliUsageError
1083
+ ? createDiagnostic("azeforge.cli#invalid-operation", "error", error.message)
1084
+ : error instanceof ArtifactCommitError
1085
+ ? createDiagnostic("azeforge.artifact#commit-failed", "error", "The Artifact could not be committed.")
1086
+ : error instanceof Error &&
1087
+ "code" in error &&
1088
+ (error.code === "ENOENT" || error.code === "EACCES")
1089
+ ? createDiagnostic("azeforge.source#read-failed", "error", "The Source could not be read.", { location: { source: "sourcePath" in arguments_ ? (arguments_.sourcePath ?? "<stdin>") : "<stdin>" } })
1090
+ : createDiagnostic("azeforge.cli#operation-failed", "error", "The accepted operation failed unexpectedly.");
1091
+ emitDiagnostics(arguments_.diagnosticsMode, arguments_.command, false, [failure]);
1092
+ process.exitCode = error instanceof CliUsageError ? 2 : 1;
1093
+ }
1094
+ }
1095
+ await main();
1096
+ //# sourceMappingURL=cli.js.map