@floh-solutions/pharos-cli 0.22.0 → 0.24.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,455 @@
1
+ import { normalizeRepo } from "@floh-solutions/gh-core";
2
+ import { FALLBACK_TERMINAL_STATES } from "./wiql-build.js";
3
+ /**
4
+ * The join behind `pharos issue drift` and `pharos issue backfill`, with no I/O
5
+ * in it.
6
+ *
7
+ * **Separate from the command for the same reason `wiql-build.ts` is** — this is
8
+ * where the bugs are. Every interesting question here is a comparison between
9
+ * two records that came from two different systems, and comparisons are exactly
10
+ * what can be proved without a network: which spelling of a repository counts as
11
+ * the same repository, what "still open" means on a board that renamed its
12
+ * states, whether one piece of evidence on each of two layers is one link or
13
+ * two. The command file around this reads, calls, and prints.
14
+ *
15
+ * ## The one idea both verbs are built on
16
+ *
17
+ * **The Azure DevOps side is the enumerable one, and that is what makes a
18
+ * 400-issue repository affordable.**
19
+ *
20
+ * GitHub cannot answer "which of my issues has Pharos adopted" — the answer
21
+ * lives in a comment on each issue, so asking costs one request per issue and a
22
+ * backfill would spend four hundred requests deciding what to do before doing
23
+ * anything. Azure DevOps *can*: a work item carries its `Hyperlink` relations on
24
+ * its own row, so one WIQL plus one `workitemsbatch` returns every link on the
25
+ * board at once.
26
+ *
27
+ * That index is correct as an answer to "what is already adopted" because
28
+ * `adopt` writes the Azure DevOps end **first** (`issue.ts` ▸ the write order).
29
+ * The half-state it can leave is a hyperlink with no comment, never a comment
30
+ * with no hyperlink — so an issue missing from this index was either never
31
+ * adopted, or adopted by something that died before its first write. Both mean
32
+ * the same thing to a backfill.
33
+ *
34
+ * The mirror-image state is still possible if somebody deletes the relation by
35
+ * hand, and it is why {@link backfillCandidates} produces *candidates* rather
36
+ * than a work list: the per-issue marker read that would catch it happens at
37
+ * adoption time, on the handful being written, instead of on all four hundred.
38
+ *
39
+ * ## Two traps peers already paid for
40
+ *
41
+ * 1. **Repositories are compared on {@link normalizeRepo}, never with `===`.**
42
+ * GitHub resolves a repository case-insensitively and echoes back whatever
43
+ * spelling it was created with, so `Contoso/Widgets` and `contoso/widgets`
44
+ * are one repository and two strings. The app track reported a perfectly good
45
+ * link as half-written over exactly this (#787).
46
+ * 2. **Evidence is counted nowhere.** `["marker","mention"]` is two pieces of
47
+ * evidence and one side — both are GitHub's — so a link with no `Hyperlink`
48
+ * at all passes a length check (#782 found this in its own code). Whether
49
+ * both platforms carry a link is `gh-core`'s `isTwoSided`, and whether the
50
+ * GitHub half was even *looked at* is {@link IssueSide.markers} being present
51
+ * rather than empty.
52
+ */
53
+ // MARK: - which work items to look at
54
+ /**
55
+ * The statement `drift` runs when nobody passed `--wiql`.
56
+ *
57
+ * **BOTH `System.HyperLinkCount` AND `System.ExternalLinkCount`, and the reason
58
+ * this reads as belt-and-braces is that it once was neither.**
59
+ *
60
+ * This narrowed on `ExternalLinkCount` alone, on the stated grounds that it was
61
+ * the *broader* filter and that a false negative here is far worse than a false
62
+ * positive. The asymmetry argument is right. The premise was wrong, and it made
63
+ * the command silently useless: **the two counters are disjoint, not nested.**
64
+ * Azure DevOps counts each relation kind separately —
65
+ * `RelatedLinkCount` (work item ↔ work item), `HyperLinkCount` (a plain
66
+ * `Hyperlink`), `ExternalLinkCount` (an `ArtifactLink`: a commit, PR or build),
67
+ * `AttachedFileCount`.
68
+ *
69
+ * `adopt` writes a **`Hyperlink`** — it must, because minting the native
70
+ * `vstfs:///GitHub/Issue/…` artifact URI needs a connection id that is behind a
71
+ * 401 on our scopes (§2). So every pair this tool creates increments
72
+ * `HyperLinkCount` and leaves `ExternalLinkCount` at zero, and the old default
73
+ * could **never** see a link Pharos had made. It answered "no drift" forever,
74
+ * exit 0, which is the failure mode a drift detector must not have.
75
+ *
76
+ * Measured on the live board (#801, re-verified): an adopted pair read
77
+ * `HyperLinkCount 1, ExternalLinkCount 0`, and the two work items that DID
78
+ * match `ExternalLinkCount > 0` each carried an `ArtifactLink` and no
79
+ * `Hyperlink`.
80
+ *
81
+ * Both are kept rather than swapping one for the other, because a client whose
82
+ * org *does* have the Azure Boards GitHub connection gets a native artifact
83
+ * link in addition to ours (§2) — narrowing to hyperlinks alone would then miss
84
+ * exactly the boards that are best integrated.
85
+ *
86
+ * There is no way to ask WIQL about the *contents* of a relation — it queries
87
+ * fields, and a `Hyperlink`'s URL is not one. So this narrows to work items that
88
+ * have external links at all and the URLs are parsed afterwards, in
89
+ * {@link linksOnWorkItems}.
90
+ *
91
+ * `[System.TeamProject] = @project` is not redundant with the project in the
92
+ * URL: WIQL happily returns items from every project the token can read, and a
93
+ * drift report that reached across an organisation would be answering a question
94
+ * nobody asked. Same argument `buildWiql` already makes.
95
+ */
96
+ export function driftWiql() {
97
+ return ("SELECT [System.Id] FROM WorkItems"
98
+ + " WHERE [System.TeamProject] = @project"
99
+ + " AND ([System.HyperLinkCount] > 0 OR [System.ExternalLinkCount] > 0)"
100
+ + " ORDER BY [System.ChangedDate] DESC");
101
+ }
102
+ /**
103
+ * The statement `adopt` runs **before creating anything**, to find a work item
104
+ * that already links the issue in front of it.
105
+ *
106
+ * ## Why this is not `driftWiql`
107
+ *
108
+ * Two narrower choices, and both are the point.
109
+ *
110
+ * **`HyperLinkCount` alone.** `drift` asks "is any link here broken", so it
111
+ * takes both counters — a client whose organisation *does* have the Azure
112
+ * Boards connection gets a native `ArtifactLink` in addition to ours, and
113
+ * missing those would miss the best-integrated boards. This asks a different
114
+ * question: *did Pharos already adopt this issue*, and Pharos writes a
115
+ * `Hyperlink`, always, because the connection id an artifact link needs is
116
+ * behind a 401 on our scopes (§2). So `ExternalLinkCount` here would add every
117
+ * work item that ever had a commit, a PR or a build attached — which on a real
118
+ * board is most of them — to a query that runs on the way to a single
119
+ * adoption. Measured on the live board (#801): the adopted pair answered
120
+ * `HyperLinkCount 1, ExternalLinkCount 0`, and `[System.HyperLinkCount] > 0`
121
+ * returned it while `[System.ExternalLinkCount] > 0` returned two other items
122
+ * and not it.
123
+ *
124
+ * **Capped, newest first.** `drift` is a deliberate sweep and reads the whole
125
+ * board; this is a guard on a one-issue verb and must not turn it into one. The
126
+ * state it exists to catch is a work item written minutes ago, so ordering by
127
+ * `ChangedDate` descending and stopping at {@link ADOPT_GUARD_LIMIT} keeps the
128
+ * cost flat while looking exactly where the answer is. A board with more
129
+ * hyperlinked work items than that is not a wrong answer — it is a partial one,
130
+ * and `adopt` says so rather than reporting a clean check.
131
+ *
132
+ * There is still no way to ask WIQL about the *contents* of a relation, so the
133
+ * URLs are matched afterwards, client-side, by {@link claimsOn}. That is the
134
+ * same narrow-then-filter shape `drift` uses and the same reason.
135
+ */
136
+ export function adoptGuardWiql() {
137
+ return ("SELECT [System.Id] FROM WorkItems"
138
+ + " WHERE [System.TeamProject] = @project"
139
+ + " AND [System.HyperLinkCount] > 0"
140
+ + " ORDER BY [System.ChangedDate] DESC");
141
+ }
142
+ /**
143
+ * How many hyperlinked work items `adopt`'s guard looks at. Two
144
+ * `workitemsbatch` calls at the 200-per-request chunk, on top of the WIQL.
145
+ */
146
+ export const ADOPT_GUARD_LIMIT = 400;
147
+ /**
148
+ * Every GitHub issue link on a batch of work items, flattened.
149
+ *
150
+ * `hyperlinks` is a function rather than a field because reading relations off a
151
+ * `WorkItem` is the command's business — this file is not allowed to care what
152
+ * shape Azure DevOps returns.
153
+ */
154
+ export function linksOnWorkItems(items, describe, hyperlinks) {
155
+ const out = [];
156
+ for (const item of items) {
157
+ const workItem = describe(item);
158
+ for (const link of hyperlinks(item)) {
159
+ out.push({
160
+ workItem,
161
+ repo: normalizeRepo(link.repo),
162
+ spelling: link.repo,
163
+ issueNumber: link.issueNumber,
164
+ });
165
+ }
166
+ }
167
+ return out;
168
+ }
169
+ /**
170
+ * The links that name one particular issue — "who on this board already claims
171
+ * it".
172
+ *
173
+ * Compared on {@link normalizeRepo}, never with `===`: GitHub resolves a
174
+ * repository case-insensitively and echoes back whichever spelling it was
175
+ * created with, so a `Hyperlink` written as `Contoso/Widgets` and a coordinate
176
+ * typed as `contoso/widgets` are one issue and two strings. #787 reported a
177
+ * perfectly good link as half-written over exactly this, and here the same slip
178
+ * would be worse: it would report *no* claim, and a second work item is what
179
+ * follows from that.
180
+ */
181
+ export function claimsOn(links, coordinate) {
182
+ const repo = normalizeRepo(coordinate.repo);
183
+ return links.filter((link) => link.repo === repo && link.issueNumber === coordinate.number);
184
+ }
185
+ /** The repositories a set of links touches, lower-cased and de-duplicated. */
186
+ export function reposOf(links) {
187
+ return [...new Set(links.map((link) => link.repo))].sort();
188
+ }
189
+ /** The catalogue as this file needs it, or the stock names with a warning attached. */
190
+ export function finishedStates(catalog, failure) {
191
+ if (catalog === undefined) {
192
+ return {
193
+ source: "fallback",
194
+ terminal: FALLBACK_TERMINAL_STATES,
195
+ byType: new Map(),
196
+ ambiguous: [],
197
+ note: "COULD NOT read this project's state categories"
198
+ + (failure === undefined ? "" : ` (${failure})`)
199
+ + ", so these are Azure DevOps' stock names. A project that renames its states will have "
200
+ + "work items misclassified here — treat a state drift row as a question rather than a "
201
+ + "finding until this reads.",
202
+ };
203
+ }
204
+ return {
205
+ source: "categories",
206
+ terminal: catalog.terminal,
207
+ byType: new Map([...catalog.byType].map(([type, states]) => [type, states.terminal])),
208
+ ambiguous: catalog.ambiguous,
209
+ note: "Read from this project's own state categories, so it is right whatever the process "
210
+ + "template calls things."
211
+ + (catalog.ambiguous.length === 0
212
+ ? ""
213
+ : ` ${catalog.ambiguous.join(", ")} mean different things on different work item types, `
214
+ + "so each work item was judged against its own."),
215
+ };
216
+ }
217
+ /**
218
+ * Is this work item finished?
219
+ *
220
+ * **Its own type's list first**, because that is the whole reason `StateCatalog`
221
+ * carries `byType`: `Resolved` can be terminal on a Bug and open on a User
222
+ * Story, and one flat list gets one of them wrong. The flat list is the fallback
223
+ * for a type the catalogue does not know — a work item type added since, or a
224
+ * batch that came back with no `System.WorkItemType` at all.
225
+ *
226
+ * **An unknown state counts as open**, matching `stateCatalog`'s own rule and
227
+ * for its reason: the two mistakes are not equal. Calling a finished work item
228
+ * open puts a row in front of somebody who can dismiss it; calling an open one
229
+ * finished hides drift, which is the one thing this command exists to surface.
230
+ */
231
+ export function isFinished(states, type, state) {
232
+ if (state === null || state === "")
233
+ return false;
234
+ const perType = type === null ? undefined : states.byType.get(type);
235
+ if (perType !== undefined)
236
+ return perType.includes(state);
237
+ return states.terminal.includes(state);
238
+ }
239
+ export function terminalStateFor(states, type) {
240
+ // The catalogue could not be read at all. `drift` degrades to the stock names
241
+ // because a misclassified ROW is a question somebody can dismiss; here the
242
+ // same guess would be a WRITE, so it refuses instead.
243
+ if (states.source === "fallback")
244
+ return { kind: "unknown" };
245
+ const perType = type === null ? undefined : states.byType.get(type);
246
+ const candidates = perType ?? states.terminal;
247
+ if (candidates.length === 0)
248
+ return { kind: "none" };
249
+ if (candidates.length === 1)
250
+ return { kind: "one", state: candidates[0] };
251
+ return { kind: "several", states: [...candidates].sort() };
252
+ }
253
+ /**
254
+ * Judge one link.
255
+ *
256
+ * **Order matters, and it is worst-first.** A pair whose issue cannot be read
257
+ * has no state to compare and no marker to look for, so reporting it as three
258
+ * problems would be reporting one problem three times — and the three rows would
259
+ * not even agree, because two of them would be inferred from an absence. Each
260
+ * link produces at most one row.
261
+ */
262
+ export function judgeLink(link, side, states) {
263
+ const coordinate = `${link.spelling}#${link.issueNumber}`;
264
+ const base = { workItem: link.workItem, coordinate, issue: null };
265
+ if (side.missing === true) {
266
+ return {
267
+ healthy: false,
268
+ drift: {
269
+ ...base,
270
+ kind: "missing-issue",
271
+ evidence: ["hyperlink"],
272
+ detail: `Work item #${link.workItem.id} links ${coordinate}, and GitHub says there is no such `
273
+ + "issue. It was deleted, transferred to another repository, or the link was written "
274
+ + "with the wrong number.",
275
+ ...(side.problem === undefined ? {} : { problem: side.problem }),
276
+ },
277
+ };
278
+ }
279
+ if (side.issue === undefined) {
280
+ return {
281
+ healthy: false,
282
+ drift: {
283
+ ...base,
284
+ kind: "unreadable",
285
+ evidence: ["hyperlink"],
286
+ problem: side.problem ?? "the issue could not be read",
287
+ detail: `Work item #${link.workItem.id} links ${coordinate} and that repository could not be `
288
+ + "read from this machine, so nothing about this pair was checked. This is usually a "
289
+ + "repository nobody here is bound to — somebody else adopted it, configured "
290
+ + "differently — which is information rather than a fault.",
291
+ },
292
+ };
293
+ }
294
+ const issue = { ...side.issue, coordinate };
295
+ const evidence = ["hyperlink"];
296
+ let marked = false;
297
+ if (side.markers !== undefined) {
298
+ // Only markers naming THIS work item count. An issue carrying a marker for
299
+ // some other work item is not this link's other half, and taking it as one
300
+ // would report a genuinely broken pair as complete.
301
+ for (const found of side.markers) {
302
+ if (found.workItemId !== link.workItem.id)
303
+ continue;
304
+ for (const piece of found.evidence) {
305
+ if (piece === "hyperlink")
306
+ continue;
307
+ if (!evidence.includes(piece))
308
+ evidence.push(piece);
309
+ marked = true;
310
+ }
311
+ }
312
+ }
313
+ evidence.sort();
314
+ // Checked before the state comparison because a half-written link is a fact
315
+ // about the LINK, and the state comparison is a fact about the work — a pair
316
+ // that is both gets reported as the one somebody has to fix first.
317
+ if (side.markers !== undefined && !marked) {
318
+ return {
319
+ healthy: false,
320
+ drift: {
321
+ ...base,
322
+ kind: "one-sided",
323
+ missing: "marker",
324
+ issue,
325
+ evidence,
326
+ detail: `Work item #${link.workItem.id} links ${coordinate} and nothing on the issue says so. `
327
+ + "The reporter cannot see that anybody picked this up, and no sweep starting from "
328
+ + "GitHub will find the work item. This is what a failed `adopt` leaves behind.",
329
+ recover: `pharos issue link ${coordinate} ${link.workItem.id}`,
330
+ },
331
+ };
332
+ }
333
+ const finished = isFinished(states, link.workItem.type, link.workItem.state);
334
+ const closed = side.issue.state === "closed";
335
+ if (closed && !finished) {
336
+ return {
337
+ healthy: false,
338
+ drift: {
339
+ ...base,
340
+ kind: "state",
341
+ direction: "issue-closed",
342
+ issue,
343
+ evidence,
344
+ detail: `${coordinate} is closed${side.issue.stateReason === null ? "" : ` (${side.issue.stateReason})`}`
345
+ + ` and work item #${link.workItem.id} is ${describeState(link.workItem.state)}. Either `
346
+ + "the board has not caught up, or it was closed on GitHub without the work being done.",
347
+ },
348
+ };
349
+ }
350
+ if (!closed && finished) {
351
+ return {
352
+ healthy: false,
353
+ drift: {
354
+ ...base,
355
+ kind: "state",
356
+ direction: "work-item-finished",
357
+ issue,
358
+ evidence,
359
+ detail: `Work item #${link.workItem.id} is ${describeState(link.workItem.state)} and `
360
+ + `${coordinate} is still open. The reporter has not been told it is done — this is the `
361
+ + "one that is rude on a public repository.",
362
+ },
363
+ };
364
+ }
365
+ return { healthy: true };
366
+ }
367
+ function describeState(state) {
368
+ return state === null || state === "" ? "in an unnamed state" : `in "${state}"`;
369
+ }
370
+ /** The counts a drift report leads with, so nobody has to tally the rows. */
371
+ export function tallyDrift(rows) {
372
+ const counts = {
373
+ state: 0,
374
+ "missing-issue": 0,
375
+ "one-sided": 0,
376
+ unreadable: 0,
377
+ };
378
+ for (const row of rows)
379
+ counts[row.kind] += 1;
380
+ return counts;
381
+ }
382
+ /**
383
+ * Which issues in a repository the board has never heard of.
384
+ *
385
+ * `linked` is the set of issue numbers already reached by a `Hyperlink` — the
386
+ * index this file's header argues for, and the reason this costs two Azure
387
+ * DevOps calls instead of one GitHub call per issue.
388
+ *
389
+ * **Ordered by issue number ascending**, which is a decision rather than an
390
+ * accident. The sweep arrives in `updated_at` order, so taking the first `n` of
391
+ * *that* would adopt a different set every run as issues get touched — and a
392
+ * `--limit` that means something different each time is a `--limit` nobody can
393
+ * resume against. Oldest issue first is stable, obvious, and makes a second run
394
+ * carry on where the first stopped.
395
+ */
396
+ export function backfillCandidates(issues, linked) {
397
+ return issues
398
+ .filter((issue) => !linked.has(issue.number))
399
+ .sort((left, right) => left.number - right.number);
400
+ }
401
+ /** The issue numbers already linked from the board, for one repository. */
402
+ export function linkedNumbersIn(links, repo) {
403
+ const wanted = normalizeRepo(repo);
404
+ return new Set(links.filter((link) => link.repo === wanted).map((link) => link.issueNumber));
405
+ }
406
+ /** How many writes adopting `count` issues costs. One create, one comment, each. */
407
+ export const WRITES_PER_ADOPTION = 2;
408
+ // MARK: - running the reads
409
+ /**
410
+ * Run `work` over `items`, at most `limit` at a time, keeping the input order.
411
+ *
412
+ * `drift` reads two endpoints per link and a board with four hundred of them is
413
+ * the case this milestone exists for, so doing them one at a time is minutes of
414
+ * waiting. `Promise.all` over all of them is the other extreme and it is worse:
415
+ * GitHub's secondary rate limit is explicitly about concurrency rather than
416
+ * volume, and tripping it turns a diagnostic into an hour's ban on a token
417
+ * somebody else is also using.
418
+ *
419
+ * Rejections are **not** caught here. A caller that wants a failed read to
420
+ * become a row rather than an exception says so in `work` — which `drift` does,
421
+ * because one unreadable repository must not kill a sweep (#782).
422
+ */
423
+ export async function inBatches(items, limit, work) {
424
+ const results = new Array(items.length);
425
+ let next = 0;
426
+ const runner = async () => {
427
+ for (;;) {
428
+ const index = next++;
429
+ if (index >= items.length)
430
+ return;
431
+ results[index] = await work(items[index], index);
432
+ }
433
+ };
434
+ await Promise.all(Array.from({ length: Math.max(1, Math.min(limit, items.length)) }, runner));
435
+ return results;
436
+ }
437
+ /** How many issue reads `drift` has in flight at once. */
438
+ export const READ_CONCURRENCY = 6;
439
+ /**
440
+ * A WIQL failure that names the field this file introduced.
441
+ *
442
+ * `System.ExternalLinkCount` is queryable on every process template Azure DevOps
443
+ * ships, and this has not been run against a customised one. If a project
444
+ * somehow does not expose it the statement fails to parse, which reads as "drift
445
+ * is broken" — so the error says which clause is suspect and hands over the
446
+ * escape hatch `pharos query` already established.
447
+ */
448
+ export function looksLikeWiqlRejection(message) {
449
+ const text = message.toLowerCase();
450
+ return (text.includes("externallinkcount")
451
+ || text.includes("wiql")
452
+ || text.includes("does not exist")
453
+ || text.includes("is not recognized"));
454
+ }
455
+ //# sourceMappingURL=issue-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"issue-scan.js","sourceRoot":"","sources":["../src/issue-scan.ts"],"names":[],"mappings":"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"}
package/dist/output.d.ts CHANGED
@@ -27,7 +27,9 @@ export declare const EXIT_FAILED = 1;
27
27
  export declare const EXIT_USAGE = 2;
28
28
  export declare const EXIT_REFUSED = 3;
29
29
  export type ExitCode = 0 | 1 | 2 | 3;
30
- export type ErrorKind = "usage" | "config" | "auth" | "refused" | "conflict" | "notFound" | "rateLimit" | "network" | "ado" | "internal";
30
+ export type ErrorKind = "usage" | "config" | "auth" | "refused" | "conflict" | "notFound" | "rateLimit" | "network" | "ado"
31
+ /** GitHub said no, and none of the kinds above describe it more usefully. */
32
+ | "github" | "internal";
31
33
  export interface Io {
32
34
  stdout: (line: string) => void;
33
35
  stderr: (line: string) => void;
@@ -84,4 +86,19 @@ export declare function emitText(io: Io, text: string): ExitCode;
84
86
  * repeating the identical call is correct.
85
87
  */
86
88
  export declare function reportError(io: Io, error: unknown): ExitCode;
89
+ /**
90
+ * The same classification `reportError` uses, without emitting anything.
91
+ *
92
+ * For the one shape that needs it: a verb that has **already written one half of
93
+ * something** when the second half fails. `pharos issue adopt` creates the work
94
+ * item and then comments on the issue, so a failure at the second step must
95
+ * report the first step's result rather than only the error — otherwise the work
96
+ * item exists and nothing anywhere names it. Re-classifying by hand there would
97
+ * be a second, drifting copy of this table.
98
+ */
99
+ export declare function failureOf(error: unknown): {
100
+ kind: ErrorKind;
101
+ code: ExitCode;
102
+ body: Record<string, unknown>;
103
+ };
87
104
  //# sourceMappingURL=output.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,IAAI,CAAC;AACzB,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAErC,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,QAAQ,GACR,MAAM,GACN,SAAS,GACT,UAAU,GACV,UAAU,GACV,WAAW,GACX,SAAS,GACT,KAAK,GACL,UAAU,CAAC;AAEf,MAAM,WAAW,EAAE;IACjB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEzC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,QAAQ;gBAGtB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,QAAQ,EAClB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;CAQvC;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,QAAQ,CAE1F;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,QAAQ,CAEvF;AAED,iFAAiF;AACjF,wBAAgB,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAGrD;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAGvD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAI5D"}
1
+ {"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AA0BA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,IAAI,CAAC;AACzB,eAAO,MAAM,WAAW,IAAI,CAAC;AAC7B,eAAO,MAAM,UAAU,IAAI,CAAC;AAC5B,eAAO,MAAM,YAAY,IAAI,CAAC;AAE9B,MAAM,MAAM,QAAQ,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAErC,MAAM,MAAM,SAAS,GACjB,OAAO,GACP,QAAQ,GACR,MAAM,GACN,SAAS,GACT,UAAU,GACV,UAAU,GACV,WAAW,GACX,SAAS,GACT,KAAK;AACP,6EAA6E;GAC3E,QAAQ,GACR,UAAU,CAAC;AAEf,MAAM,WAAW,EAAE;IACjB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CAChC;AAED;;;;;;GAMG;AACH,qBAAa,QAAS,SAAQ,KAAK;IACjC,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAEzC;;;;;;OAMG;IACH,QAAQ,CAAC,OAAO,QAAQ;gBAGtB,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,EACf,QAAQ,EAAE,QAAQ,EAClB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;CAQvC;AAED,2EAA2E;AAC3E,wBAAgB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,QAAQ,CAE1F;AAED;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,GAAG,QAAQ,CAEvF;AAED,iFAAiF;AACjF,wBAAgB,IAAI,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAGrD;AAED,sDAAsD;AACtD,wBAAgB,QAAQ,CAAC,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,QAAQ,CAGvD;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,OAAO,GAAG,QAAQ,CAI5D;AAED;;;;;;;;;GASG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,GAAG;IACzC,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,QAAQ,CAAC;IACf,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAC/B,CAGA"}