@meltemi/diagrams-cli 0.0.0-stage → 1.9.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 (163) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +58 -2
  3. package/dist/assets-command.d.ts +16 -0
  4. package/dist/assets-command.d.ts.map +1 -0
  5. package/dist/assets-command.js +145 -0
  6. package/dist/assets-command.js.map +1 -0
  7. package/dist/assist-command.d.ts +19 -0
  8. package/dist/assist-command.d.ts.map +1 -0
  9. package/dist/assist-command.js +268 -0
  10. package/dist/assist-command.js.map +1 -0
  11. package/dist/auth-command.d.ts +14 -0
  12. package/dist/auth-command.d.ts.map +1 -0
  13. package/dist/auth-command.js +233 -0
  14. package/dist/auth-command.js.map +1 -0
  15. package/dist/bin.d.ts +3 -0
  16. package/dist/bin.d.ts.map +1 -0
  17. package/dist/bin.js +60 -0
  18. package/dist/bin.js.map +1 -0
  19. package/dist/build-command.d.ts +23 -0
  20. package/dist/build-command.d.ts.map +1 -0
  21. package/dist/build-command.js +123 -0
  22. package/dist/build-command.js.map +1 -0
  23. package/dist/cli.d.ts +46 -0
  24. package/dist/cli.d.ts.map +1 -0
  25. package/dist/cli.js +823 -0
  26. package/dist/cli.js.map +1 -0
  27. package/dist/cloud-client.d.ts +246 -0
  28. package/dist/cloud-client.d.ts.map +1 -0
  29. package/dist/cloud-client.js +591 -0
  30. package/dist/cloud-client.js.map +1 -0
  31. package/dist/cloud-command.d.ts +56 -0
  32. package/dist/cloud-command.d.ts.map +1 -0
  33. package/dist/cloud-command.js +81 -0
  34. package/dist/cloud-command.js.map +1 -0
  35. package/dist/cloud-context.d.ts +106 -0
  36. package/dist/cloud-context.d.ts.map +1 -0
  37. package/dist/cloud-context.js +185 -0
  38. package/dist/cloud-context.js.map +1 -0
  39. package/dist/cloud-errors.d.ts +37 -0
  40. package/dist/cloud-errors.d.ts.map +1 -0
  41. package/dist/cloud-errors.js +46 -0
  42. package/dist/cloud-errors.js.map +1 -0
  43. package/dist/cloud-host.d.ts +72 -0
  44. package/dist/cloud-host.d.ts.map +1 -0
  45. package/dist/cloud-host.js +129 -0
  46. package/dist/cloud-host.js.map +1 -0
  47. package/dist/cloud-manifest.d.ts +12 -0
  48. package/dist/cloud-manifest.d.ts.map +1 -0
  49. package/dist/cloud-manifest.js +21 -0
  50. package/dist/cloud-manifest.js.map +1 -0
  51. package/dist/cloud-paths.d.ts +48 -0
  52. package/dist/cloud-paths.d.ts.map +1 -0
  53. package/dist/cloud-paths.js +104 -0
  54. package/dist/cloud-paths.js.map +1 -0
  55. package/dist/credentials.d.ts +107 -0
  56. package/dist/credentials.d.ts.map +1 -0
  57. package/dist/credentials.js +243 -0
  58. package/dist/credentials.js.map +1 -0
  59. package/dist/export-command.d.ts +35 -0
  60. package/dist/export-command.d.ts.map +1 -0
  61. package/dist/export-command.js +524 -0
  62. package/dist/export-command.js.map +1 -0
  63. package/dist/import-command.d.ts +20 -0
  64. package/dist/import-command.d.ts.map +1 -0
  65. package/dist/import-command.js +254 -0
  66. package/dist/import-command.js.map +1 -0
  67. package/dist/index.d.ts +4 -0
  68. package/dist/index.d.ts.map +1 -0
  69. package/dist/index.js +4 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/init-command.d.ts +28 -0
  72. package/dist/init-command.d.ts.map +1 -0
  73. package/dist/init-command.js +199 -0
  74. package/dist/init-command.js.map +1 -0
  75. package/dist/login-listener.d.ts +58 -0
  76. package/dist/login-listener.d.ts.map +1 -0
  77. package/dist/login-listener.js +173 -0
  78. package/dist/login-listener.js.map +1 -0
  79. package/dist/messages/en.d.ts +533 -0
  80. package/dist/messages/en.d.ts.map +1 -0
  81. package/dist/messages/en.js +803 -0
  82. package/dist/messages/en.js.map +1 -0
  83. package/dist/messages/es.d.ts +3 -0
  84. package/dist/messages/es.d.ts.map +1 -0
  85. package/dist/messages/es.js +764 -0
  86. package/dist/messages/es.js.map +1 -0
  87. package/dist/messages/index.d.ts +442 -0
  88. package/dist/messages/index.d.ts.map +1 -0
  89. package/dist/messages/index.js +42 -0
  90. package/dist/messages/index.js.map +1 -0
  91. package/dist/messages/push-pull-en.d.ts +84 -0
  92. package/dist/messages/push-pull-en.d.ts.map +1 -0
  93. package/dist/messages/push-pull-en.js +146 -0
  94. package/dist/messages/push-pull-en.js.map +1 -0
  95. package/dist/messages/push-pull-es.d.ts +7 -0
  96. package/dist/messages/push-pull-es.d.ts.map +1 -0
  97. package/dist/messages/push-pull-es.js +144 -0
  98. package/dist/messages/push-pull-es.js.map +1 -0
  99. package/dist/open-url.d.ts +11 -0
  100. package/dist/open-url.d.ts.map +1 -0
  101. package/dist/open-url.js +36 -0
  102. package/dist/open-url.js.map +1 -0
  103. package/dist/plugins-command.d.ts +15 -0
  104. package/dist/plugins-command.d.ts.map +1 -0
  105. package/dist/plugins-command.js +106 -0
  106. package/dist/plugins-command.js.map +1 -0
  107. package/dist/preview.d.ts +54 -0
  108. package/dist/preview.d.ts.map +1 -0
  109. package/dist/preview.js +249 -0
  110. package/dist/preview.js.map +1 -0
  111. package/dist/project-errors.d.ts +17 -0
  112. package/dist/project-errors.d.ts.map +1 -0
  113. package/dist/project-errors.js +85 -0
  114. package/dist/project-errors.js.map +1 -0
  115. package/dist/projects-command.d.ts +13 -0
  116. package/dist/projects-command.d.ts.map +1 -0
  117. package/dist/projects-command.js +85 -0
  118. package/dist/projects-command.js.map +1 -0
  119. package/dist/publish-command.d.ts +41 -0
  120. package/dist/publish-command.d.ts.map +1 -0
  121. package/dist/publish-command.js +311 -0
  122. package/dist/publish-command.js.map +1 -0
  123. package/dist/pull-command.d.ts +21 -0
  124. package/dist/pull-command.d.ts.map +1 -0
  125. package/dist/pull-command.js +300 -0
  126. package/dist/pull-command.js.map +1 -0
  127. package/dist/push-command.d.ts +31 -0
  128. package/dist/push-command.d.ts.map +1 -0
  129. package/dist/push-command.js +391 -0
  130. package/dist/push-command.js.map +1 -0
  131. package/dist/push-review.d.ts +16 -0
  132. package/dist/push-review.d.ts.map +1 -0
  133. package/dist/push-review.js +72 -0
  134. package/dist/push-review.js.map +1 -0
  135. package/dist/push-set.d.ts +126 -0
  136. package/dist/push-set.d.ts.map +1 -0
  137. package/dist/push-set.js +289 -0
  138. package/dist/push-set.js.map +1 -0
  139. package/dist/push-validation.d.ts +20 -0
  140. package/dist/push-validation.d.ts.map +1 -0
  141. package/dist/push-validation.js +70 -0
  142. package/dist/push-validation.js.map +1 -0
  143. package/dist/redact.d.ts +9 -0
  144. package/dist/redact.d.ts.map +1 -0
  145. package/dist/redact.js +22 -0
  146. package/dist/redact.js.map +1 -0
  147. package/dist/review-command.d.ts +44 -0
  148. package/dist/review-command.d.ts.map +1 -0
  149. package/dist/review-command.js +348 -0
  150. package/dist/review-command.js.map +1 -0
  151. package/package.json +56 -3
  152. package/templates/c4/diagrams/views.meltemi +16 -0
  153. package/templates/c4/models/system.meltemi +23 -0
  154. package/templates/ci/github.yml +96 -0
  155. package/templates/ci/gitlab.yml +53 -0
  156. package/templates/flow/diagrams/overview.meltemi +15 -0
  157. package/templates/free/diagrams/slide.meltemi +39 -0
  158. package/templates/purchase/diagrams/architecture.meltemi +36 -0
  159. package/templates/purchase/diagrams/executive.meltemi +52 -0
  160. package/templates/purchase/diagrams/payment.meltemi +42 -0
  161. package/templates/purchase/models/commerce.meltemi +30 -0
  162. package/templates/purchase/stories/purchase.meltemi +38 -0
  163. package/templates/sequence/diagrams/sign-in.meltemi +36 -0
@@ -0,0 +1,126 @@
1
+ /**
2
+ * The push set and its comparison (`cli-cloud`, "Push"): what a folder offers the cloud project, and
3
+ * how it differs from what the cloud holds.
4
+ *
5
+ * The set is the folder's project as `validate` reads it, widened to every file the cloud keeps:
6
+ * `project.json`, the `.meltemi` sources, themes, and the other text files (`isTextPath`) travel by
7
+ * content; images and fonts travel by hash (`png`, `jpg`, `jpeg`, `gif`, `webp`, `woff2`, `ttf`,
8
+ * `otf`, at most 10 MiB each). Never part of it: dotfiles and dot folders (`.git`), `node_modules`,
9
+ * what the manifest's `exclude` names, the catalog's output (`catalog.out`), links (never followed)
10
+ * and files of a kind the cloud does not keep (listed as `ignored`).
11
+ *
12
+ * A file the folder has but cannot send (its path breaks the cloud's path rule, it is not UTF-8,
13
+ * it cannot be read) is reported in `notSent`, never sent, and never leads to the deletion of the
14
+ * cloud's file of that name. The same goes for anything the folder deliberately leaves out.
15
+ *
16
+ * `compareWithCloud` compares every path against the cloud's files, fetched once: text by content,
17
+ * binaries by hash, cloud paths absent from the folder as deletions.
18
+ */
19
+ import { type ProjectManifest } from "@meltemi/diagrams-project";
20
+ import { CloudError } from "./cloud-errors.js";
21
+ export type FileKind = "text" | "binary";
22
+ /** What the cloud keeps a path as: text, an image or a font, or nothing (undefined). */
23
+ export declare function kindOfPath(path: string): FileKind | undefined;
24
+ /** An image or a font of the folder: its hash, its size and where it is. */
25
+ export interface LocalBinary {
26
+ readonly hash: string;
27
+ readonly size: number;
28
+ /** The file, as a native absolute path, read again when it is uploaded. */
29
+ readonly file: string;
30
+ }
31
+ export type NotSentReason = "path" | "encoding" | "unreadable";
32
+ /** A file or folder of the project that is not sent, and why. */
33
+ export interface NotSent {
34
+ /** The project path; a folder ends with `/`. */
35
+ readonly path: string;
36
+ readonly reason: NotSentReason;
37
+ /** The system's reason, for `unreadable`. */
38
+ readonly detail?: string;
39
+ }
40
+ /** A file over a limit of the cloud: refused before anything is sent, with the service's code. */
41
+ export interface OverLimit {
42
+ readonly path: string;
43
+ readonly code: "doc.too-large" | "quota.binary";
44
+ }
45
+ export interface PushSet {
46
+ /** The folder, as a native absolute path. */
47
+ readonly folder: string;
48
+ /** Path to text, `project.json` included. */
49
+ readonly texts: Map<string, string>;
50
+ /** Path to the image or font. */
51
+ readonly binaries: Map<string, LocalBinary>;
52
+ readonly notSent: NotSent[];
53
+ /** Files of a kind the cloud does not keep, and links. */
54
+ readonly ignored: string[];
55
+ readonly overLimit: OverLimit[];
56
+ /** Whether the folder holds more files than the cloud keeps (the walk stopped reading). */
57
+ readonly truncated: boolean;
58
+ /** Whether a path is one the folder leaves out on purpose or could not send. */
59
+ holds(path: string): boolean;
60
+ }
61
+ /**
62
+ * Whether a project path is left out of the push set by rule: a hidden name, `node_modules`, a
63
+ * path the manifest excludes or the catalog's output.
64
+ */
65
+ export declare function leftOutRule(manifest: ProjectManifest | null): (path: string) => boolean;
66
+ /**
67
+ * Reads the push set of a folder. `manifest` is its `project.json` as read (null when there is
68
+ * none): its `exclude` and `catalog.out` shape the set. Never follows a link, never reads past what
69
+ * a limit refuses, and never throws for a file: each is either part of the set or listed.
70
+ */
71
+ export declare function readPushSet(folder: string, manifest: ProjectManifest | null): PushSet;
72
+ /**
73
+ * The refusal the limits of the cloud call for, before anything is sent, with the service's own
74
+ * code: a file over its limit (`doc.too-large`, `quota.binary`, naming the path), more than 2000
75
+ * files (`quota.files`), texts over the 16 MiB a project's document holds (`doc.too-large`).
76
+ */
77
+ export declare function limitError(set: PushSet): CloudError | undefined;
78
+ /** One path whose cloud state differs from the folder's. */
79
+ export interface Difference {
80
+ readonly path: string;
81
+ /** What the folder holds there; what the cloud holds for a deletion. */
82
+ readonly kind: FileKind;
83
+ /** `added`: not in the cloud yet. `changed`: both have it and it differs. `deleted`: only in the cloud. */
84
+ readonly change: "added" | "changed" | "deleted";
85
+ }
86
+ /** A cloud path the push leaves alone, and why. */
87
+ export interface LeftAlone {
88
+ readonly path: string;
89
+ readonly why: "collision" | "kept-out";
90
+ }
91
+ export interface Comparison {
92
+ /** Every path that differs, by path. */
93
+ readonly differences: readonly Difference[];
94
+ readonly left: readonly LeftAlone[];
95
+ }
96
+ /** The cloud's files as `GET …/files` answers them. */
97
+ export interface CloudState {
98
+ readonly files: Readonly<Record<string, string>>;
99
+ readonly binaries: Readonly<Record<string, string>>;
100
+ readonly collisions: readonly unknown[];
101
+ }
102
+ /**
103
+ * Compares every path of the push set with the cloud's: text files by content, binaries by hash and
104
+ * cloud paths the folder lacks as deletions. A cloud path left alone: the loser of a name collision
105
+ * (`<path>~<id>`, which the path rule refuses to send), and one the folder keeps out on purpose or
106
+ * could not send (excluded, unreadable, not UTF-8).
107
+ */
108
+ export declare function compareWithCloud(set: PushSet, cloud: CloudState): Comparison;
109
+ /** What a push sends, as `PUT …/files` takes it, and the binaries to put in the cloud first. */
110
+ export interface PushPlan {
111
+ /** Path to text, or `null` to delete the path. Only what differs. */
112
+ readonly texts: Record<string, string | null>;
113
+ /** Path to the hash of an image or font, or `null` to delete the path. Only what differs. */
114
+ readonly binaries: Record<string, string | null>;
115
+ /** The images and fonts that differ and so need their bytes in the cloud before the push. */
116
+ readonly uploads: readonly {
117
+ readonly path: string;
118
+ readonly binary: LocalBinary;
119
+ }[];
120
+ }
121
+ /**
122
+ * What it takes to make the cloud equal to the set, given the comparison: the texts that differ, the
123
+ * hashes that differ, the deletions, and a deletion of the other kind of a path whose kind changed.
124
+ */
125
+ export declare function planPush(set: PushSet, comparison: Comparison, cloud: CloudState): PushPlan;
126
+ //# sourceMappingURL=push-set.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-set.d.ts","sourceRoot":"","sources":["../src/push-set.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,OAAO,EAML,KAAK,eAAe,EACrB,MAAM,2BAA2B,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;AAczC,wFAAwF;AACxF,wBAAgB,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS,CAK7D;AAOD,4EAA4E;AAC5E,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,2EAA2E;IAC3E,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,MAAM,aAAa,GAAG,MAAM,GAAG,UAAU,GAAG,YAAY,CAAC;AAE/D,iEAAiE;AACjE,MAAM,WAAW,OAAO;IACtB,gDAAgD;IAChD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC;IAC/B,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,kGAAkG;AAClG,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,cAAc,CAAC;CACjD;AAED,MAAM,WAAW,OAAO;IACtB,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACpC,iCAAiC;IACjC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC5C,QAAQ,CAAC,OAAO,EAAE,OAAO,EAAE,CAAC;IAC5B,0DAA0D;IAC1D,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,SAAS,EAAE,CAAC;IAChC,2FAA2F;IAC3F,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,gFAAgF;IAChF,KAAK,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;CAC9B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI,GAAG,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CASvF;AAKD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,IAAI,GAAG,OAAO,CAgHrF;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,GAAG,UAAU,GAAG,SAAS,CA0B/D;AAID,4DAA4D;AAC5D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IACxB,2GAA2G;IAC3G,QAAQ,CAAC,MAAM,EAAE,OAAO,GAAG,SAAS,GAAG,SAAS,CAAC;CAClD;AAED,mDAAmD;AACnD,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,GAAG,EAAE,WAAW,GAAG,UAAU,CAAC;CACxC;AAED,MAAM,WAAW,UAAU;IACzB,wCAAwC;IACxC,QAAQ,CAAC,WAAW,EAAE,SAAS,UAAU,EAAE,CAAC;IAC5C,QAAQ,CAAC,IAAI,EAAE,SAAS,SAAS,EAAE,CAAC;CACrC;AAED,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACjD,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACpD,QAAQ,CAAC,UAAU,EAAE,SAAS,OAAO,EAAE,CAAC;CACzC;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,OAAO,EAAE,KAAK,EAAE,UAAU,GAAG,UAAU,CAuC5E;AAED,gGAAgG;AAChG,MAAM,WAAW,QAAQ;IACvB,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9C,6FAA6F;IAC7F,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IACjD,6FAA6F;IAC7F,QAAQ,CAAC,OAAO,EAAE,SAAS;QAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;KAAE,EAAE,CAAC;CACtF;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,GAAG,QAAQ,CAmB1F"}
@@ -0,0 +1,289 @@
1
+ /**
2
+ * The push set and its comparison (`cli-cloud`, "Push"): what a folder offers the cloud project, and
3
+ * how it differs from what the cloud holds.
4
+ *
5
+ * The set is the folder's project as `validate` reads it, widened to every file the cloud keeps:
6
+ * `project.json`, the `.meltemi` sources, themes, and the other text files (`isTextPath`) travel by
7
+ * content; images and fonts travel by hash (`png`, `jpg`, `jpeg`, `gif`, `webp`, `woff2`, `ttf`,
8
+ * `otf`, at most 10 MiB each). Never part of it: dotfiles and dot folders (`.git`), `node_modules`,
9
+ * what the manifest's `exclude` names, the catalog's output (`catalog.out`), links (never followed)
10
+ * and files of a kind the cloud does not keep (listed as `ignored`).
11
+ *
12
+ * A file the folder has but cannot send (its path breaks the cloud's path rule, it is not UTF-8,
13
+ * it cannot be read) is reported in `notSent`, never sent, and never leads to the deletion of the
14
+ * cloud's file of that name. The same goes for anything the folder deliberately leaves out.
15
+ *
16
+ * `compareWithCloud` compares every path against the cloud's files, fetched once: text by content,
17
+ * binaries by hash, cloud paths absent from the folder as deletions.
18
+ */
19
+ import { readFileSync, readdirSync, statSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ import { ALWAYS_EXCLUDED, CLOUD_LIMITS, DEFAULT_CATALOG, isCleanPath, isTextPath, } from "@meltemi/diagrams-project";
22
+ import { sha256Hex } from "./cloud-client.js";
23
+ import { CloudError } from "./cloud-errors.js";
24
+ import { collisionLosers } from "./cloud-paths.js";
25
+ /** Extensions of the images and fonts the cloud keeps by hash (SVG is a text file in a cloud project). */
26
+ const BINARY_EXTENSIONS = [
27
+ "png",
28
+ "jpg",
29
+ "jpeg",
30
+ "gif",
31
+ "webp",
32
+ "woff2",
33
+ "ttf",
34
+ "otf",
35
+ ];
36
+ /** What the cloud keeps a path as: text, an image or a font, or nothing (undefined). */
37
+ export function kindOfPath(path) {
38
+ if (isTextPath(path))
39
+ return "text";
40
+ const dot = path.lastIndexOf(".");
41
+ const extension = dot === -1 ? "" : path.slice(dot + 1).toLowerCase();
42
+ return BINARY_EXTENSIONS.includes(extension) ? "binary" : undefined;
43
+ }
44
+ /** A text of 2 Mi characters takes at most four bytes each: a file over this is too large unread. */
45
+ const MAX_TEXT_BYTES = CLOUD_LIMITS.textCharacters * 4;
46
+ const DECODER = new TextDecoder("utf-8", { fatal: true, ignoreBOM: true });
47
+ /**
48
+ * Whether a project path is left out of the push set by rule: a hidden name, `node_modules`, a
49
+ * path the manifest excludes or the catalog's output.
50
+ */
51
+ export function leftOutRule(manifest) {
52
+ const excluded = [...(manifest?.exclude ?? []), manifest?.catalog.out ?? DEFAULT_CATALOG.out];
53
+ return (path) => path
54
+ .split("/")
55
+ .some((name) => name.startsWith(".") || ALWAYS_EXCLUDED.includes(name)) ||
56
+ excluded.some((entry) => entry === "." || path === entry || path.startsWith(`${entry}/`));
57
+ }
58
+ const byName = (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0;
59
+ /**
60
+ * Reads the push set of a folder. `manifest` is its `project.json` as read (null when there is
61
+ * none): its `exclude` and `catalog.out` shape the set. Never follows a link, never reads past what
62
+ * a limit refuses, and never throws for a file: each is either part of the set or listed.
63
+ */
64
+ export function readPushSet(folder, manifest) {
65
+ const leftOut = leftOutRule(manifest);
66
+ const texts = new Map();
67
+ const binaries = new Map();
68
+ const notSent = [];
69
+ const ignored = [];
70
+ const overLimit = [];
71
+ let kept = 0;
72
+ let truncated = false;
73
+ const readFile = (path, kind, file) => {
74
+ let size;
75
+ try {
76
+ size = statSync(file).size;
77
+ }
78
+ catch (error) {
79
+ notSent.push({ path, reason: "unreadable", detail: error.message });
80
+ return;
81
+ }
82
+ if (kind === "binary" && size > CLOUD_LIMITS.binaryBytes) {
83
+ overLimit.push({ path, code: "quota.binary" });
84
+ return;
85
+ }
86
+ if (kind === "text" && size > MAX_TEXT_BYTES) {
87
+ overLimit.push({ path, code: "doc.too-large" });
88
+ return;
89
+ }
90
+ let raw;
91
+ try {
92
+ raw = readFileSync(file);
93
+ }
94
+ catch (error) {
95
+ notSent.push({ path, reason: "unreadable", detail: error.message });
96
+ return;
97
+ }
98
+ if (kind === "binary") {
99
+ binaries.set(path, { hash: sha256Hex(raw), size: raw.byteLength, file });
100
+ return;
101
+ }
102
+ let text;
103
+ try {
104
+ text = DECODER.decode(raw);
105
+ }
106
+ catch {
107
+ notSent.push({ path, reason: "encoding" });
108
+ return;
109
+ }
110
+ if (text.length > CLOUD_LIMITS.textCharacters)
111
+ overLimit.push({ path, code: "doc.too-large" });
112
+ else
113
+ texts.set(path, text);
114
+ };
115
+ const visit = (absolute, prefix) => {
116
+ let entries;
117
+ try {
118
+ entries = readdirSync(absolute, { withFileTypes: true });
119
+ }
120
+ catch (error) {
121
+ notSent.push({ path: `${prefix}/`, reason: "unreadable", detail: error.message });
122
+ return;
123
+ }
124
+ for (const entry of entries.sort(byName)) {
125
+ if (truncated)
126
+ return;
127
+ const name = entry.name;
128
+ if (name.startsWith("."))
129
+ continue;
130
+ const path = prefix === "" ? name : `${prefix}/${name}`;
131
+ if (leftOut(path))
132
+ continue;
133
+ if (entry.isSymbolicLink()) {
134
+ ignored.push(path);
135
+ continue;
136
+ }
137
+ if (entry.isDirectory()) {
138
+ if (isCleanPath(name))
139
+ visit(join(absolute, name), path);
140
+ else
141
+ notSent.push({ path: `${path}/`, reason: "path" });
142
+ continue;
143
+ }
144
+ if (!entry.isFile())
145
+ continue;
146
+ const kind = kindOfPath(path);
147
+ if (kind === undefined) {
148
+ ignored.push(path);
149
+ continue;
150
+ }
151
+ if (!isCleanPath(path)) {
152
+ notSent.push({ path, reason: "path" });
153
+ continue;
154
+ }
155
+ // One file past the limit is enough to refuse the push; there is no point in reading the rest.
156
+ if (kept > CLOUD_LIMITS.files) {
157
+ truncated = true;
158
+ return;
159
+ }
160
+ kept++;
161
+ readFile(path, kind, join(absolute, name));
162
+ }
163
+ };
164
+ visit(folder, "");
165
+ const set = {
166
+ folder,
167
+ texts,
168
+ binaries,
169
+ notSent,
170
+ ignored,
171
+ overLimit,
172
+ truncated,
173
+ holds: (path) => leftOut(path) ||
174
+ notSent.some((item) => item.path === path || (item.path.endsWith("/") && path.startsWith(item.path))) ||
175
+ // A link to a folder holds everything under it: the folder is left out, never deleted.
176
+ ignored.some((link) => link === path || path.startsWith(`${link}/`)) ||
177
+ // A root that could not be read holds the whole folder.
178
+ notSent.some((item) => item.path === "/") ||
179
+ overLimit.some((item) => item.path === path),
180
+ };
181
+ return set;
182
+ }
183
+ /**
184
+ * The refusal the limits of the cloud call for, before anything is sent, with the service's own
185
+ * code: a file over its limit (`doc.too-large`, `quota.binary`, naming the path), more than 2000
186
+ * files (`quota.files`), texts over the 16 MiB a project's document holds (`doc.too-large`).
187
+ */
188
+ export function limitError(set) {
189
+ const first = set.overLimit[0];
190
+ if (first) {
191
+ return new CloudError(first.code, first.code === "quota.binary"
192
+ ? `${first.path} is larger than the 10 MiB an image or font may be.`
193
+ : `${first.path} is larger than the 2 Mi characters a text file may have.`, { details: { path: first.path } });
194
+ }
195
+ if (set.truncated || set.texts.size + set.binaries.size > CLOUD_LIMITS.files) {
196
+ return new CloudError("quota.files", `The folder holds more than the ${CLOUD_LIMITS.files} files a project may.`);
197
+ }
198
+ let bytes = 0;
199
+ for (const text of set.texts.values())
200
+ bytes += Buffer.byteLength(text);
201
+ if (bytes > CLOUD_LIMITS.documentBytes) {
202
+ return new CloudError("doc.too-large", "The texts of the folder are larger than a project's 16 MiB.");
203
+ }
204
+ return undefined;
205
+ }
206
+ /**
207
+ * Compares every path of the push set with the cloud's: text files by content, binaries by hash and
208
+ * cloud paths the folder lacks as deletions. A cloud path left alone: the loser of a name collision
209
+ * (`<path>~<id>`, which the path rule refuses to send), and one the folder keeps out on purpose or
210
+ * could not send (excluded, unreadable, not UTF-8).
211
+ */
212
+ export function compareWithCloud(set, cloud) {
213
+ const differences = [];
214
+ const left = [];
215
+ const cloudTexts = new Map(Object.entries(cloud.files));
216
+ const cloudBinaries = new Map(Object.entries(cloud.binaries));
217
+ const losers = collisionLosers([...cloudTexts.keys(), ...cloudBinaries.keys()], cloud.collisions);
218
+ for (const [path, text] of set.texts) {
219
+ const held = cloudTexts.get(path);
220
+ if (held === undefined) {
221
+ differences.push({
222
+ path,
223
+ kind: "text",
224
+ change: cloudBinaries.has(path) ? "changed" : "added",
225
+ });
226
+ }
227
+ else if (held !== text)
228
+ differences.push({ path, kind: "text", change: "changed" });
229
+ }
230
+ for (const [path, binary] of set.binaries) {
231
+ const held = cloudBinaries.get(path);
232
+ if (held === undefined) {
233
+ differences.push({
234
+ path,
235
+ kind: "binary",
236
+ change: cloudTexts.has(path) ? "changed" : "added",
237
+ });
238
+ }
239
+ else if (held !== binary.hash)
240
+ differences.push({ path, kind: "binary", change: "changed" });
241
+ }
242
+ const cloudOnly = (path, kind) => {
243
+ if (set.texts.has(path) || set.binaries.has(path))
244
+ return;
245
+ if (losers.has(path))
246
+ left.push({ path, why: "collision" });
247
+ else if (!isCleanPath(path) || set.holds(path))
248
+ left.push({ path, why: "kept-out" });
249
+ else
250
+ differences.push({ path, kind, change: "deleted" });
251
+ };
252
+ for (const path of cloudTexts.keys())
253
+ cloudOnly(path, "text");
254
+ for (const path of cloudBinaries.keys())
255
+ cloudOnly(path, "binary");
256
+ const byPath = (a, b) => a.path < b.path ? -1 : a.path > b.path ? 1 : 0;
257
+ return { differences: differences.sort(byPath), left: left.sort(byPath) };
258
+ }
259
+ /**
260
+ * What it takes to make the cloud equal to the set, given the comparison: the texts that differ, the
261
+ * hashes that differ, the deletions, and a deletion of the other kind of a path whose kind changed.
262
+ */
263
+ export function planPush(set, comparison, cloud) {
264
+ const texts = {};
265
+ const binaries = {};
266
+ const uploads = [];
267
+ for (const { path, kind, change } of comparison.differences) {
268
+ if (change === "deleted") {
269
+ if (kind === "text")
270
+ texts[path] = null;
271
+ else
272
+ binaries[path] = null;
273
+ }
274
+ else if (kind === "text") {
275
+ texts[path] = set.texts.get(path);
276
+ if (Object.hasOwn(cloud.binaries, path))
277
+ binaries[path] = null;
278
+ }
279
+ else {
280
+ const binary = set.binaries.get(path);
281
+ binaries[path] = binary.hash;
282
+ uploads.push({ path, binary });
283
+ if (Object.hasOwn(cloud.files, path))
284
+ texts[path] = null;
285
+ }
286
+ }
287
+ return { texts, binaries, uploads };
288
+ }
289
+ //# sourceMappingURL=push-set.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-set.js","sourceRoot":"","sources":["../src/push-set.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * The validation a push prints (`cli-cloud`, "Push"): the diagnostics of the folder's project as
3
+ * `validate <folder>` prints them (the manifest, the limits, plugins, assets, every source with its
4
+ * composition), in the same line format. They do not stop a push (the page shows them too) unless
5
+ * `--strict` asks for it.
6
+ */
7
+ export interface ValidationResult {
8
+ /** Files with diagnostics are listed; this is how many files were checked (sources and manifest). */
9
+ readonly files: number;
10
+ readonly errors: number;
11
+ readonly warnings: number;
12
+ /** The printed lines, in the order `validate` prints them. */
13
+ readonly lines: readonly string[];
14
+ }
15
+ /** Validates the project of a folder as `validate` does and returns what it would print. */
16
+ export declare function validateFolder(folder: string, options: {
17
+ readonly toolVersion: string;
18
+ readonly display: (path: string) => string;
19
+ }): ValidationResult;
20
+ //# sourceMappingURL=push-validation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-validation.d.ts","sourceRoot":"","sources":["../src/push-validation.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAQH,MAAM,WAAW,gBAAgB;IAC/B,qGAAqG;IACrG,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAiBD,4FAA4F;AAC5F,wBAAgB,cAAc,CAC5B,MAAM,EAAE,MAAM,EACd,OAAO,EAAE;IAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAA;CAAE,GACpF,gBAAgB,CAwClB"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * The validation a push prints (`cli-cloud`, "Push"): the diagnostics of the folder's project as
3
+ * `validate <folder>` prints them (the manifest, the limits, plugins, assets, every source with its
4
+ * composition), in the same line format. They do not stop a push (the page shows them too) unless
5
+ * `--strict` asks for it.
6
+ */
7
+ import { ProjectSessions } from "@meltemi/diagrams-editor/node";
8
+ import { sortDiagnostics } from "@meltemi/diagrams-language";
9
+ import { toProjectPath } from "@meltemi/diagrams-project";
10
+ import { createNodeHost } from "@meltemi/diagrams-project/node";
11
+ import { messages } from "./messages/index.js";
12
+ /** Diagnostics of `project.json`, of the project's plugins and of its assets, by file. */
13
+ function projectDiagnostics(workspace) {
14
+ const manifest = workspace.manifest();
15
+ const byPath = new Map();
16
+ if (manifest.diagnostics.length > 0)
17
+ byPath.set(manifest.path, [...manifest.diagnostics]);
18
+ for (const [path, list] of [
19
+ ...workspace.limits(),
20
+ ...workspace.plugins().diagnostics,
21
+ ...workspace.assets().diagnostics,
22
+ ]) {
23
+ byPath.set(path, [...(byPath.get(path) ?? []), ...list]);
24
+ }
25
+ return new Map([...byPath].map(([path, list]) => [path, sortDiagnostics(list)]));
26
+ }
27
+ /** Validates the project of a folder as `validate` does and returns what it would print. */
28
+ export function validateFolder(folder, options) {
29
+ const root = toProjectPath(folder);
30
+ const projects = new ProjectSessions({
31
+ toolVersion: options.toolVersion,
32
+ host: createNodeHost(),
33
+ });
34
+ const workspace = projects.forFolder(root);
35
+ const results = new Map(projectDiagnostics(workspace));
36
+ /** A file's diagnostics with the composition of its diagrams, as the editor shows them. */
37
+ const withComposition = (diagnostics, file) => {
38
+ const layout = projects.analyze(file).diagnostics.filter((d) => d.code.startsWith("layout."));
39
+ const seen = new Set(diagnostics.map((d) => `${d.code}@${d.range.start.offset}|${d.message}`));
40
+ return sortDiagnostics([
41
+ ...diagnostics,
42
+ ...layout.filter((d) => !seen.has(`${d.code}@${d.range.start.offset}|${d.message}`)),
43
+ ]);
44
+ };
45
+ const program = workspace.compileProject();
46
+ let files = results.size;
47
+ for (const [file, compiled] of program.files) {
48
+ if (file !== root && !file.startsWith(`${root}/`))
49
+ continue;
50
+ if (!results.has(file))
51
+ files++;
52
+ results.set(file, withComposition(compiled.diagnostics, file));
53
+ }
54
+ const lines = [];
55
+ let errors = 0;
56
+ let warnings = 0;
57
+ for (const [path, diagnostics] of results) {
58
+ for (const d of diagnostics) {
59
+ if (d.severity === "error")
60
+ errors++;
61
+ else if (d.severity === "warning")
62
+ warnings++;
63
+ lines.push(`${options.display(path)}:${d.range.start.line}:${d.range.start.column}: ${d.severity} ${d.code} ${d.message}`);
64
+ for (const hint of d.hints ?? [])
65
+ lines.push(` ${messages().common.hint}: ${hint}`);
66
+ }
67
+ }
68
+ return { files, errors, warnings, lines };
69
+ }
70
+ //# sourceMappingURL=push-validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"push-validation.js","sourceRoot":"","sources":["../src/push-validation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ /** What a token is shown as. */
2
+ export declare const REDACTED_TOKEN = "mdg_\u2026";
3
+ /**
4
+ * A message with API tokens (`mdg_…`) and the values of secret-looking environment variables
5
+ * (names with KEY, TOKEN, SECRET, PASSWORD or CREDENTIAL) removed, so that an unexpected error never
6
+ * prints a key or a token (decision 0030).
7
+ */
8
+ export declare function redactSecrets(message: string, env: Readonly<Record<string, string | undefined>>): string;
9
+ //# sourceMappingURL=redact.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.d.ts","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAMA,gCAAgC;AAChC,eAAO,MAAM,cAAc,eAAU,CAAC;AAEtC;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GAChD,MAAM,CAOR"}
package/dist/redact.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * An API token of the cloud service: `mdg_` followed by base64url characters (`cli-cloud`,
3
+ * "Tokens never shown"). `mdg_` alone, and words such as `mdg push`, are not tokens.
4
+ */
5
+ const API_TOKEN = /mdg_[A-Za-z0-9_-]+/g;
6
+ /** What a token is shown as. */
7
+ export const REDACTED_TOKEN = "mdg_…";
8
+ /**
9
+ * A message with API tokens (`mdg_…`) and the values of secret-looking environment variables
10
+ * (names with KEY, TOKEN, SECRET, PASSWORD or CREDENTIAL) removed, so that an unexpected error never
11
+ * prints a key or a token (decision 0030).
12
+ */
13
+ export function redactSecrets(message, env) {
14
+ let result = message.replace(API_TOKEN, REDACTED_TOKEN);
15
+ for (const [name, value] of Object.entries(env)) {
16
+ if (!value || value.length < 8 || !/KEY|TOKEN|SECRET|PASSWORD|CREDENTIAL/i.test(name))
17
+ continue;
18
+ result = result.split(value).join("[redacted]");
19
+ }
20
+ return result;
21
+ }
22
+ //# sourceMappingURL=redact.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redact.js","sourceRoot":"","sources":["../src/redact.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,SAAS,GAAG,qBAAqB,CAAC;AAExC,gCAAgC;AAChC,MAAM,CAAC,MAAM,cAAc,GAAG,OAAO,CAAC;AAEtC;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,OAAe,EACf,GAAiD;IAEjD,IAAI,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,cAAc,CAAC,CAAC;IACxD,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;QAChD,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,uCAAuC,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,SAAS;QAChG,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,44 @@
1
+ import { type Locale } from "@meltemi/diagrams-i18n";
2
+ import { type Review } from "@meltemi/diagrams-editor/node";
3
+ import { type ModelChange } from "@meltemi/diagrams-model";
4
+ import { type CloudContext } from "./cloud-context.js";
5
+ /** What the review command needs from the CLI. */
6
+ export interface ReviewContext {
7
+ readonly name: string;
8
+ readonly stdout: (text: string) => void;
9
+ readonly stderr: (text: string) => void;
10
+ readonly cwd: string;
11
+ /** A path as printed: relative to the working folder. */
12
+ readonly display: (path: string) => string;
13
+ readonly toolVersion: string;
14
+ /** The language of what the command writes: `--lang`, when given. */
15
+ readonly locale?: Locale;
16
+ /**
17
+ * The connection to the cloud service, for `--base cloud[:<n>]` (`cloudContext("review", …)` of
18
+ * `cloud-command.ts`). Everything the command prints or writes goes through its `redactSecrets`,
19
+ * so no token reaches a line, the JSON or the review page.
20
+ */
21
+ readonly cloud?: CloudContext;
22
+ }
23
+ /**
24
+ * What `--base` names when it is the cloud: `cloud` (the project's current files) or `cloud:<n>`
25
+ * (version `n`); `invalid` for `cloud:` and `cloud:x`; undefined for a Git revision.
26
+ */
27
+ export declare function parseCloudBase(base: string | undefined): {
28
+ readonly version: number | undefined;
29
+ } | "invalid" | undefined;
30
+ /** Counts of changes by kind, over every file. */
31
+ export declare function reviewSummary(review: Review): Record<ModelChange["kind"], number> & {
32
+ files: number;
33
+ };
34
+ /**
35
+ * The review page: the changes of every file and the pictures of its changed diagrams, with its
36
+ * words in `locale`, the language of the files the command writes (never the machine's).
37
+ */
38
+ export declare function reviewPage(review: Review, title: string, compared: string, pictures: ReadonlyMap<string, {
39
+ before: string | null;
40
+ after: string | null;
41
+ }>, locale?: Locale): string;
42
+ /** `meltemi-diagrams review`; asynchronous, because `--base cloud` reads the cloud project first. */
43
+ export declare function reviewCommand(args: readonly string[], context: ReviewContext): Promise<number>;
44
+ //# sourceMappingURL=review-command.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-command.d.ts","sourceRoot":"","sources":["../src/review-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,KAAK,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAIhE,OAAO,EAKL,KAAK,MAAM,EAGZ,MAAM,+BAA+B,CAAC;AACvC,OAAO,EAAkB,KAAK,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAK3E,OAAO,EAA+B,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAKpF,kDAAkD;AAClD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,QAAQ,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,MAAM,CAAC;IAC3C,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,qEAAqE;IACrE,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB;;;;OAIG;IACH,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC;CAC/B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,IAAI,EAAE,MAAM,GAAG,SAAS,GACvB;IAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,GAAG,SAAS,GAAG,SAAS,CAIlE;AAqBD,kDAAkD;AAClD,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,WAAW,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAIzD;AAuCD;;;GAGG;AACH,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE;IAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;CAAE,CAAC,EAC9E,MAAM,GAAE,MAAa,GACpB,MAAM,CAqER;AAED,qGAAqG;AACrG,wBAAsB,aAAa,CACjC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC,MAAM,CAAC,CAoMjB"}