@popcorn245/cornfield-components 0.52.0 → 0.53.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.
- package/README.md +1 -1
- package/dist/chunks/around-BcnegEdS.js +99 -0
- package/dist/chunks/connection-KDiWvV19.js +23 -0
- package/dist/chunks/{engine-HIgX35hE.js → engine-xmHJvQY9.js} +1360 -1343
- package/dist/chunks/{layers-n1mJVJs8.js → layers-ho10a2y7.js} +68 -68
- package/dist/chunks/{map-CeP9M2_w.js → map-DbfPgQRe.js} +736 -705
- package/dist/chunks/node-panel-CC8UrSzJ.js +410 -0
- package/dist/chunks/panel-review-ih7RlfkH.js +884 -0
- package/dist/chunks/review-pieces-DtRxCDMr.js +2523 -0
- package/dist/chunks/{review-source-DWisOXyR.js → review-source-CmbwaPCM.js} +1 -1
- package/dist/chunks/scope-2m2VmJXn.js +185 -0
- package/dist/chunks/scope-proposal-T06ndbin.js +116 -0
- package/dist/chunks/sheets-BWANwtZP.js +209 -0
- package/dist/chunks/source-address-DXanAREm.js +57 -0
- package/dist/chunks/{status-CsFpnQxw.js → status-DM-iIEsg.js} +57 -56
- package/dist/corn-changes.js +43 -0
- package/dist/corn-decision.js +52 -0
- package/dist/corn-layers.js +275 -1
- package/dist/corn-map.js +125 -1
- package/dist/corn-node-panel.js +42 -1
- package/dist/corn-proposal.js +50 -0
- package/dist/corn-review.js +425 -1
- package/dist/corn-scope.js +33 -9
- package/dist/corn-search.js +484 -1
- package/dist/index.js +11 -8
- package/dist/manifest.json +95 -70
- package/dist/tokens.css +6 -0
- package/dist/types/components.d.ts +111 -5
- package/dist/types/corn-changes.d.ts +2 -0
- package/dist/types/corn-decision.d.ts +2 -0
- package/dist/types/corn-proposal.d.ts +2 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/version.json +1 -1
- package/package.json +17 -5
- package/dist/chunks/around-D7aqHejs.js +0 -78
- package/dist/chunks/corn-layers-g9AprK6G.js +0 -275
- package/dist/chunks/corn-map-DE-pg-A0.js +0 -125
- package/dist/chunks/corn-node-panel-CdtFb9IZ.js +0 -42
- package/dist/chunks/corn-review-9krtLSPK.js +0 -2900
- package/dist/chunks/corn-search-BY1Po63S.js +0 -484
- package/dist/chunks/node-panel-CY5xnuKC.js +0 -1291
- package/dist/chunks/scope-CUhp8mkf.js +0 -137
- package/dist/chunks/sheets-TFCL_dIn.js +0 -204
- package/dist/chunks/source-address-C70zNPIj.js +0 -79
|
@@ -0,0 +1,884 @@
|
|
|
1
|
+
import { J as e, Kt as t, Ot as n, X as r, _t as i, dt as a, ft as o, gt as s, kt as c, lt as l, mt as u, pt as d, ut as f, vt as p, xn as m, yn as h, yt as ee } from "./engine-xmHJvQY9.js";
|
|
2
|
+
// ../explorer/corn-state.js
|
|
3
|
+
var g = Object.freeze([
|
|
4
|
+
"open",
|
|
5
|
+
"merged",
|
|
6
|
+
"closed",
|
|
7
|
+
"draft",
|
|
8
|
+
"queued",
|
|
9
|
+
"running",
|
|
10
|
+
"requested",
|
|
11
|
+
"claimed",
|
|
12
|
+
"working",
|
|
13
|
+
"waiting",
|
|
14
|
+
"done",
|
|
15
|
+
"failed",
|
|
16
|
+
"stopped",
|
|
17
|
+
"success",
|
|
18
|
+
"failure",
|
|
19
|
+
"added",
|
|
20
|
+
"changed",
|
|
21
|
+
"removed",
|
|
22
|
+
"edit",
|
|
23
|
+
"sent-back"
|
|
24
|
+
]), _ = Object.freeze([
|
|
25
|
+
"added",
|
|
26
|
+
"changed",
|
|
27
|
+
"removed",
|
|
28
|
+
"edit"
|
|
29
|
+
]);
|
|
30
|
+
Object.freeze([
|
|
31
|
+
"requested",
|
|
32
|
+
"claimed",
|
|
33
|
+
"working",
|
|
34
|
+
"waiting",
|
|
35
|
+
"done",
|
|
36
|
+
"failed",
|
|
37
|
+
"stopped"
|
|
38
|
+
]);
|
|
39
|
+
var v = Object.freeze({
|
|
40
|
+
quiet: "waiting",
|
|
41
|
+
"stop-requested": "stopped",
|
|
42
|
+
neutral: "done",
|
|
43
|
+
skipped: "done",
|
|
44
|
+
cancelled: "stopped",
|
|
45
|
+
approved: "success",
|
|
46
|
+
unreviewed: "waiting",
|
|
47
|
+
changed: "waiting",
|
|
48
|
+
missing: "failure",
|
|
49
|
+
allowed: "success",
|
|
50
|
+
refused: "failure",
|
|
51
|
+
mismatch: "failure",
|
|
52
|
+
pending: "running",
|
|
53
|
+
ok: "success",
|
|
54
|
+
bad: "failure",
|
|
55
|
+
stale: "waiting",
|
|
56
|
+
off: "stopped",
|
|
57
|
+
error: "failure",
|
|
58
|
+
idle: "running"
|
|
59
|
+
});
|
|
60
|
+
function y(e) {
|
|
61
|
+
let t = String(e || "");
|
|
62
|
+
return v[t] || (g.includes(t) && !_.includes(t) ? t : "");
|
|
63
|
+
}
|
|
64
|
+
function b(e) {
|
|
65
|
+
let t = String(e || "");
|
|
66
|
+
return _.includes(t) ? t : "";
|
|
67
|
+
}
|
|
68
|
+
function x(e) {
|
|
69
|
+
let t = b(e);
|
|
70
|
+
return t ? ` data-corn-state="${t}"` : "";
|
|
71
|
+
}
|
|
72
|
+
function S(e) {
|
|
73
|
+
let t = y(e);
|
|
74
|
+
return t ? ` data-corn-state="${t}"` : "";
|
|
75
|
+
}
|
|
76
|
+
Object.freeze({
|
|
77
|
+
requested: "<circle cx=\"6\" cy=\"6\" r=\"4.2\" stroke-dasharray=\"2 1.8\"/>",
|
|
78
|
+
queued: "<circle cx=\"6\" cy=\"6\" r=\"4.2\" stroke-dasharray=\"2 1.8\"/>",
|
|
79
|
+
claimed: "<circle cx=\"6\" cy=\"6\" r=\"4.2\"/><circle cx=\"6\" cy=\"6\" r=\"1.4\" fill=\"currentColor\" stroke=\"none\"/>",
|
|
80
|
+
working: "<path class=\"hx-state-spin\" d=\"M6 1.8a4.2 4.2 0 1 1-4.2 4.2\"/>",
|
|
81
|
+
running: "<path class=\"hx-state-spin\" d=\"M6 1.8a4.2 4.2 0 1 1-4.2 4.2\"/>",
|
|
82
|
+
waiting: "<path d=\"M6 1.2L11 10.4H1Z\" stroke-linejoin=\"round\"/><path d=\"M6 4.6v2.7M6 8.6v.1\"/>",
|
|
83
|
+
done: "<path d=\"M2 6.4l2.6 2.6L10 3.4\"/>",
|
|
84
|
+
success: "<path d=\"M2 6.4l2.6 2.6L10 3.4\"/>",
|
|
85
|
+
failed: "<path d=\"M2.6 2.6l6.8 6.8M9.4 2.6L2.6 9.4\"/>",
|
|
86
|
+
failure: "<path d=\"M2.6 2.6l6.8 6.8M9.4 2.6L2.6 9.4\"/>",
|
|
87
|
+
stopped: "<rect x=\"2.4\" y=\"2.4\" width=\"7.2\" height=\"7.2\" rx=\"1\" fill=\"currentColor\"/>",
|
|
88
|
+
neutral: "<path d=\"M2.4 6h7.2\"/>",
|
|
89
|
+
skipped: "<path d=\"M2.4 6h7.2\"/>",
|
|
90
|
+
cancelled: "<circle cx=\"6\" cy=\"6\" r=\"4.2\"/><path d=\"M3 9L9 3\"/>",
|
|
91
|
+
"sent-back": "<path d=\"M4.6 2.2L2 4.8l2.6 2.6\"/><path d=\"M2.2 4.8H7a2.8 2.8 0 0 1 0 5.6H4.6\"/>"
|
|
92
|
+
}), Object.freeze([
|
|
93
|
+
["code", "Code: a branch and a pull request"],
|
|
94
|
+
["summary", "Summary of the conversation"],
|
|
95
|
+
["brief", "A brief for another run"],
|
|
96
|
+
["proposal", "A proposal drafted from the thread"]
|
|
97
|
+
]), Object.freeze({
|
|
98
|
+
merged: "done",
|
|
99
|
+
closed: "stopped",
|
|
100
|
+
quiet: "waiting",
|
|
101
|
+
"stop-requested": "stopped"
|
|
102
|
+
});
|
|
103
|
+
function C(e) {
|
|
104
|
+
let t = Math.max(0, Math.round(e / 1e3));
|
|
105
|
+
return t < 60 ? `${t} s` : t < 3600 ? `${Math.floor(t / 60)} min` : `${Math.floor(t / 3600)} h`;
|
|
106
|
+
}
|
|
107
|
+
Object.freeze([
|
|
108
|
+
"minutes",
|
|
109
|
+
"turns",
|
|
110
|
+
"cost",
|
|
111
|
+
"tokens"
|
|
112
|
+
]), Object.freeze([
|
|
113
|
+
{
|
|
114
|
+
key: "decide",
|
|
115
|
+
title: "toDecide"
|
|
116
|
+
},
|
|
117
|
+
{
|
|
118
|
+
key: "agent",
|
|
119
|
+
title: "withAgent"
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
key: "approved",
|
|
123
|
+
title: "approvedGroup"
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
key: "drafts",
|
|
127
|
+
title: "drafts"
|
|
128
|
+
}
|
|
129
|
+
]), Object.freeze([
|
|
130
|
+
{
|
|
131
|
+
key: "needs",
|
|
132
|
+
title: "needsYou"
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
key: "motion",
|
|
136
|
+
title: "inMotion"
|
|
137
|
+
},
|
|
138
|
+
{
|
|
139
|
+
key: "finished",
|
|
140
|
+
title: "finished"
|
|
141
|
+
}
|
|
142
|
+
]), Object.freeze([
|
|
143
|
+
"to-decide",
|
|
144
|
+
"changed",
|
|
145
|
+
"sent-back",
|
|
146
|
+
"approved",
|
|
147
|
+
"draft-pr",
|
|
148
|
+
"local",
|
|
149
|
+
"unknown"
|
|
150
|
+
]), Object.freeze({
|
|
151
|
+
"to-decide": "To decide",
|
|
152
|
+
changed: "Changed since approved",
|
|
153
|
+
"sent-back": "Sent back",
|
|
154
|
+
approved: "Approved",
|
|
155
|
+
"draft-pr": "Draft PR",
|
|
156
|
+
local: "Local",
|
|
157
|
+
unknown: "Review state unknown"
|
|
158
|
+
}), Object.freeze({
|
|
159
|
+
"to-decide": "waiting",
|
|
160
|
+
changed: "waiting",
|
|
161
|
+
"sent-back": "sent-back",
|
|
162
|
+
approved: "success",
|
|
163
|
+
"draft-pr": "draft",
|
|
164
|
+
local: "draft",
|
|
165
|
+
unknown: "failure"
|
|
166
|
+
});
|
|
167
|
+
function w(e) {
|
|
168
|
+
let t = e && e.report && typeof e.report.note == "string" ? e.report.note.replace(/\s+/g, " ").trim() : "", n = t.length > 90 ? `${t.slice(0, 89).trimEnd()}\u2026` : t;
|
|
169
|
+
return `A run is waiting on you${n ? `: ${n}` : ""}`;
|
|
170
|
+
}
|
|
171
|
+
// ../explorer/proposal-model.js
|
|
172
|
+
var te = [
|
|
173
|
+
"before",
|
|
174
|
+
"diff",
|
|
175
|
+
"after"
|
|
176
|
+
], T = [
|
|
177
|
+
"added",
|
|
178
|
+
"changed",
|
|
179
|
+
"removed"
|
|
180
|
+
];
|
|
181
|
+
function E(e) {
|
|
182
|
+
let t = D({
|
|
183
|
+
...e,
|
|
184
|
+
scenarios: 0
|
|
185
|
+
}).filter((e) => e.mark).map((e) => e.text.replace(/^\+/, ""));
|
|
186
|
+
return t.length ? t.join(" · ") : "No changes";
|
|
187
|
+
}
|
|
188
|
+
function D(e) {
|
|
189
|
+
let t = (t) => e?.[t] || 0, n = (e, t) => `${e} ${t}${e === 1 ? "" : "s"}`, r = (r) => {
|
|
190
|
+
let i = e?.nodes?.[r] || 0, a = e?.edges?.[r] || 0;
|
|
191
|
+
return !e?.nodes || i + a !== t(r) ? `${r === "added" ? "+" : ""}${t(r)} ${r}` : `${[i && n(i, "node"), a && n(a, "edge")].filter(Boolean).join(", ")} ${r}`;
|
|
192
|
+
}, i = T.filter((e) => t(e) > 0).map((e) => ({
|
|
193
|
+
mark: e,
|
|
194
|
+
text: r(e)
|
|
195
|
+
}));
|
|
196
|
+
return t("scenarios") > 0 && i.push({
|
|
197
|
+
mark: null,
|
|
198
|
+
text: `${t("scenarios")} ${t("scenarios") === 1 ? "scenario" : "scenarios"}`
|
|
199
|
+
}), i.length ? i : [{
|
|
200
|
+
mark: null,
|
|
201
|
+
text: "No changes"
|
|
202
|
+
}];
|
|
203
|
+
}
|
|
204
|
+
var O = (e) => `${e === "before" ? "Before" : e === "after" ? "After" : "Diff"} view`, k = (e, t) => `${t}, ${String(e).toLowerCase()}. The map is on it.`, A = /^[A-Za-z0-9][A-Za-z0-9._-]*$/, j = 200, M = (e) => typeof e == "string" && e.length <= j && A.test(e);
|
|
205
|
+
function N(e) {
|
|
206
|
+
let t = String(e ?? ""), n = t.length > 60 ? `${t.slice(0, 59)}\u2026` : t;
|
|
207
|
+
return n.trim() ? `\u201c${n}\u201d is not a proposal's name.` : "That is not a proposal's name.";
|
|
208
|
+
}
|
|
209
|
+
function P(e) {
|
|
210
|
+
return e == null ? "" : typeof e == "string" ? e : JSON.stringify(e);
|
|
211
|
+
}
|
|
212
|
+
var F = [
|
|
213
|
+
"mark",
|
|
214
|
+
"editOp",
|
|
215
|
+
"before",
|
|
216
|
+
"why",
|
|
217
|
+
"x",
|
|
218
|
+
"y",
|
|
219
|
+
"r",
|
|
220
|
+
"baseR",
|
|
221
|
+
"degree",
|
|
222
|
+
"scaleDelta",
|
|
223
|
+
"color",
|
|
224
|
+
"from",
|
|
225
|
+
"to"
|
|
226
|
+
];
|
|
227
|
+
function I(e) {
|
|
228
|
+
return c(e) === "added" ? Object.keys(e).filter((t) => !F.includes(t) && e[t] !== void 0).map((t) => ({
|
|
229
|
+
field: t,
|
|
230
|
+
before: "",
|
|
231
|
+
after: P(e[t])
|
|
232
|
+
})) : e.mark === "changed" && e.before ? Object.keys(e.before).map((t) => ({
|
|
233
|
+
field: t,
|
|
234
|
+
before: P(e.before[t]),
|
|
235
|
+
after: P(e[t])
|
|
236
|
+
})) : [];
|
|
237
|
+
}
|
|
238
|
+
var L = {
|
|
239
|
+
added: "Added",
|
|
240
|
+
changed: "Changed",
|
|
241
|
+
removed: "Removed",
|
|
242
|
+
edit: "Your edit"
|
|
243
|
+
};
|
|
244
|
+
function ne(e) {
|
|
245
|
+
if (!n(e)) return "";
|
|
246
|
+
let r = I(e).map((n) => e.mark === "changed" ? `<div class="hx-change" data-corn="field-change"><span class="hx-change-field">${t(n.field)}</span><span class="hx-change-before">${t(n.before) || "<em>nothing</em>"}</span><span class="hx-change-arrow" aria-hidden="true">→</span><span class="hx-change-after">${t(n.after) || "<em>nothing</em>"}</span></div>` : `<div class="hx-change" data-corn="field-change"><span class="hx-change-field">${t(n.field)}</span><span class="hx-change-after">${t(n.after)}</span></div>`).join("");
|
|
247
|
+
return `<div class="hx-sec hx-proposal-sec hx-proposal-sec--${t(e.mark)}" data-proposal-mark="${t(e.mark)}" data-corn="section">
|
|
248
|
+
<strong class="hx-strong"><span class="hx-mark-dot hx-mark-dot--${t(e.mark)}" data-corn="mark-dot"${x(e.mark)}></span>${t(e.mark === "edit" ? `${e.editOp === "removed" ? "Removed" : "Added"} by your edit` : `${L[e.mark] || e.mark} by this proposal`)}</strong>
|
|
249
|
+
${e.why ? `<div class="hx-why">${t(e.why)}</div>` : ""}
|
|
250
|
+
${r}
|
|
251
|
+
</div>`;
|
|
252
|
+
}
|
|
253
|
+
var R = (e, t) => `${e} ${t}${e === 1 ? "" : "s"}`;
|
|
254
|
+
function z(e) {
|
|
255
|
+
if (!Array.isArray(e) || e.length === 0) return "no checks";
|
|
256
|
+
let t = (t) => e.filter((e) => t.includes(e.state)).length, n = t(["failure"]), r = t(["cancelled"]), i = t(["running", "queued"]), a = [];
|
|
257
|
+
return n && a.push(`${R(n, "check")} failed`), r && a.push(`${R(r, "check")} cancelled`), i && a.push(`${R(i, "check")} running`), a.length ? a.join(", ") : e.length === 1 ? "1 check passed" : `all ${e.length} checks passed`;
|
|
258
|
+
}
|
|
259
|
+
function B(e) {
|
|
260
|
+
let t = typeof e == "string" ? /^pull\/([1-9]\d{0,8})$/.exec(e) : null;
|
|
261
|
+
return t ? Number(t[1]) : null;
|
|
262
|
+
}
|
|
263
|
+
function re(e) {
|
|
264
|
+
let t = B(e);
|
|
265
|
+
return t ? `PR #${t}` : !e || e === "checkout" ? "the checkout" : `worktree ${e}`;
|
|
266
|
+
}
|
|
267
|
+
function ie(e, t = null, n = null) {
|
|
268
|
+
let r = B(e);
|
|
269
|
+
if (!r) {
|
|
270
|
+
let t = !e || e === "checkout" ? "in the checkout" : `in worktree ${e}`;
|
|
271
|
+
return {
|
|
272
|
+
text: `Local draft \u00b7 ${t}`,
|
|
273
|
+
href: null,
|
|
274
|
+
state: "draft",
|
|
275
|
+
label: `This is a local draft, ${t}, not a pull request`
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
let i = [`PR #${r}`], a = t ? t.state === "merged" || t.state === "closed" ? t.state : typeof t.draft == "boolean" ? t.draft ? "draft" : "open" : "" : "";
|
|
279
|
+
return a && i.push(a), Array.isArray(n) && i.push(z(n)), {
|
|
280
|
+
text: i.join(" · "),
|
|
281
|
+
href: t && typeof t.url == "string" ? t.url : null,
|
|
282
|
+
state: a,
|
|
283
|
+
label: `Reviewing spec pull request: ${i.join(", ")}`
|
|
284
|
+
};
|
|
285
|
+
}
|
|
286
|
+
function ae(e, t, n = null) {
|
|
287
|
+
return t ? B(t) || t === "checkout" || n && n.has(t) && A.test(t) ? `There is no proposal called ${e} in ${re(t)}.` : `There is no proposal called ${e}. This link's source is not a PR, the checkout or a worktree.` : `There is no proposal called ${e}.`;
|
|
288
|
+
}
|
|
289
|
+
function oe(e) {
|
|
290
|
+
let t = new URLSearchParams(e || "");
|
|
291
|
+
if (!t.has("proposal")) return null;
|
|
292
|
+
let n = t.get("proposal") || "";
|
|
293
|
+
return A.test(n) ? null : n.trim() ? `This link does not name a proposal: ${N(n)}` : "This link does not name a proposal.";
|
|
294
|
+
}
|
|
295
|
+
function se(e, t, n) {
|
|
296
|
+
return Array.isArray(e) ? e.filter((e) => e && e.slug === t && e.source !== n && !e.error).sort((e, t) => +!!B(t.source) - !!B(e.source)).map((e) => ({
|
|
297
|
+
slug: e.slug,
|
|
298
|
+
source: e.source,
|
|
299
|
+
label: B(e.source) ? `Open the copy in PR #${B(e.source)}${e.pull && e.pull.draft ? " (draft)" : ""}` : `Open the copy ${e.source === "checkout" ? "in the checkout" : `in worktree ${e.source}`}`
|
|
300
|
+
})) : [];
|
|
301
|
+
}
|
|
302
|
+
function ce(e, t = !1) {
|
|
303
|
+
let n = Array.isArray(e) ? e : [];
|
|
304
|
+
if (!n.length) return "";
|
|
305
|
+
let r = (e) => n.filter((t) => t && e.includes(t.op)).length, i = (e, t) => `${e} ${t}${e === 1 ? "" : "s"}`, a = [];
|
|
306
|
+
r(["add-node"]) && a.push(`+${i(r(["add-node"]), "node")}`), r(["add-edge"]) && a.push(`+${i(r(["add-edge"]), "edge")}`), r(["remove-node"]) && a.push(`\u2212${i(r(["remove-node"]), "node")}`), r(["remove-edge"]) && a.push(`\u2212${i(r(["remove-edge"]), "edge")}`);
|
|
307
|
+
let o = r([
|
|
308
|
+
"add-step",
|
|
309
|
+
"reword-step",
|
|
310
|
+
"delete-step",
|
|
311
|
+
"move-step"
|
|
312
|
+
]);
|
|
313
|
+
o && a.push(`${i(o, "step")} changed`);
|
|
314
|
+
let s = n.length - r([
|
|
315
|
+
"add-node",
|
|
316
|
+
"add-edge",
|
|
317
|
+
"remove-node",
|
|
318
|
+
"remove-edge",
|
|
319
|
+
"add-step",
|
|
320
|
+
"reword-step",
|
|
321
|
+
"delete-step",
|
|
322
|
+
"move-step"
|
|
323
|
+
]);
|
|
324
|
+
return s > 0 && a.push(i(s, "other edit")), `yours: ${a.join(", ")}${t ? " (hidden)" : ""}`;
|
|
325
|
+
}
|
|
326
|
+
// ../core/proposal.js
|
|
327
|
+
var le = [
|
|
328
|
+
"version",
|
|
329
|
+
"spec",
|
|
330
|
+
"title",
|
|
331
|
+
"summary",
|
|
332
|
+
"nodes",
|
|
333
|
+
"edges",
|
|
334
|
+
"mockups",
|
|
335
|
+
"scenarios"
|
|
336
|
+
], ue = [
|
|
337
|
+
"node",
|
|
338
|
+
"path",
|
|
339
|
+
"title"
|
|
340
|
+
], de = [
|
|
341
|
+
"png",
|
|
342
|
+
"jpg",
|
|
343
|
+
"jpeg",
|
|
344
|
+
"webp",
|
|
345
|
+
"svg",
|
|
346
|
+
"html"
|
|
347
|
+
], fe = [
|
|
348
|
+
"id",
|
|
349
|
+
"title",
|
|
350
|
+
"steps",
|
|
351
|
+
"stepMs",
|
|
352
|
+
"linkNodes",
|
|
353
|
+
"actor",
|
|
354
|
+
"down"
|
|
355
|
+
], V = [
|
|
356
|
+
"node",
|
|
357
|
+
"edge",
|
|
358
|
+
"text",
|
|
359
|
+
"ms",
|
|
360
|
+
"actor",
|
|
361
|
+
"at",
|
|
362
|
+
"check",
|
|
363
|
+
"expect"
|
|
364
|
+
], pe = [
|
|
365
|
+
"GET",
|
|
366
|
+
"POST",
|
|
367
|
+
"PUT",
|
|
368
|
+
"PATCH",
|
|
369
|
+
"DELETE"
|
|
370
|
+
], me = [
|
|
371
|
+
"read",
|
|
372
|
+
"write",
|
|
373
|
+
"delete"
|
|
374
|
+
], he = [
|
|
375
|
+
"own",
|
|
376
|
+
"household",
|
|
377
|
+
"others",
|
|
378
|
+
"shared-read",
|
|
379
|
+
"shared-write"
|
|
380
|
+
], ge = ["allowed", "refused"], _e = /^[a-z0-9]+(?:-[a-z0-9]+)*$/, H = `live-room-<id>, live-floor-<id> or live-device-<kind>-<id> (kind one of ${l.join(", ")})`, ve = [
|
|
381
|
+
"add",
|
|
382
|
+
"change",
|
|
383
|
+
"remove"
|
|
384
|
+
], ye = ["mark", "before"], be = [
|
|
385
|
+
"mark",
|
|
386
|
+
"before",
|
|
387
|
+
"why"
|
|
388
|
+
], xe = [
|
|
389
|
+
"from",
|
|
390
|
+
"to",
|
|
391
|
+
"kind",
|
|
392
|
+
"flow"
|
|
393
|
+
], U = (e) => typeof e == "object" && !!e && !Array.isArray(e), W = (e) => typeof e == "string" && e.trim() !== "", G = (e) => e === void 0 ? e : JSON.parse(JSON.stringify(e)), K = (e) => Array.isArray(e) ? e : [], Se = (e) => typeof e == "number" && Number.isFinite(e) && e > 0;
|
|
394
|
+
function q(e, t) {
|
|
395
|
+
if (e === t) return !0;
|
|
396
|
+
if (!e || !t || typeof e != "object" || typeof t != "object" || Array.isArray(e) !== Array.isArray(t)) return !1;
|
|
397
|
+
let n = Object.keys(e);
|
|
398
|
+
return n.length === Object.keys(t).length && n.every((n) => q(e[n], t[n]));
|
|
399
|
+
}
|
|
400
|
+
function Ce(e) {
|
|
401
|
+
if (typeof e != "string" || e.trim() === "") return "\"path\" must be the file's path, relative to the proposals folder.";
|
|
402
|
+
if (e.length > 200) return "\"path\" is at most 200 characters.";
|
|
403
|
+
if (/[\\\u0000-\u001f:%?#]/.test(e)) return "\"path\" has a character a plain relative path does not (a backslash, a colon, a control character, %, ? or #).";
|
|
404
|
+
if (e.startsWith("/")) return "\"path\" is relative to the proposals folder; it does not start with a slash.";
|
|
405
|
+
let t = e.split("/");
|
|
406
|
+
if (t.some((e) => e === "" || e === "." || e === "..")) return "\"path\" stays inside the proposals folder: no \"..\", no \".\" and no empty parts.";
|
|
407
|
+
if (t.some((e) => e.startsWith("."))) return "\"path\" has a hidden part (one that starts with a dot).";
|
|
408
|
+
let n = t[t.length - 1].split(".").length > 1 ? t[t.length - 1].split(".").pop().toLowerCase() : "";
|
|
409
|
+
return de.includes(n) ? null : `A mockup is one of: ${de.join(", ")}.`;
|
|
410
|
+
}
|
|
411
|
+
function we(e) {
|
|
412
|
+
if (!U(e) || !Array.isArray(e.mockups)) return [];
|
|
413
|
+
let t = [];
|
|
414
|
+
return e.mockups.slice(0, 40).forEach((e, n) => {
|
|
415
|
+
U(e) && W(e.node) && W(e.title) && Ce(e.path) === null && t.push({
|
|
416
|
+
index: n,
|
|
417
|
+
node: e.node,
|
|
418
|
+
path: e.path,
|
|
419
|
+
title: e.title.trim()
|
|
420
|
+
});
|
|
421
|
+
}), t;
|
|
422
|
+
}
|
|
423
|
+
function J(e) {
|
|
424
|
+
return `${e.from}|${e.to}|${e.kind === "flow" ? `flow:${e.flow}` : e.kind || "own"}`;
|
|
425
|
+
}
|
|
426
|
+
var Te = (e) => ({
|
|
427
|
+
from: e.parent,
|
|
428
|
+
to: e.id
|
|
429
|
+
});
|
|
430
|
+
function Ee(e, t) {
|
|
431
|
+
let n = [], r = (e, t, r) => n.push(r ? {
|
|
432
|
+
path: e,
|
|
433
|
+
message: t,
|
|
434
|
+
state: r
|
|
435
|
+
} : {
|
|
436
|
+
path: e,
|
|
437
|
+
message: t
|
|
438
|
+
});
|
|
439
|
+
if (!U(t)) return r("", "A proposal is a JSON object."), n;
|
|
440
|
+
for (let e of Object.keys(t)) le.includes(e) || r(e, `Unknown key "${e}". A proposal has: ${le.join(", ")}.`);
|
|
441
|
+
t.version !== 1 && r("version", `"version" must be the number 1 (got ${JSON.stringify(t.version)}).`), W(t.title) || r("title", "\"title\" must be a non-empty string."), W(t.summary) || r("summary", "\"summary\" must be a non-empty string: the one sentence the maintainer reads first."), t.spec !== void 0 && !W(t.spec) && r("spec", "\"spec\" must be the spec number as a string, like \"0013\".");
|
|
442
|
+
let c = (e) => {
|
|
443
|
+
let n = t[e];
|
|
444
|
+
if (n === void 0) return {
|
|
445
|
+
add: [],
|
|
446
|
+
change: [],
|
|
447
|
+
remove: []
|
|
448
|
+
};
|
|
449
|
+
if (!U(n)) return r(e, `"${e}" must be an object with add, change and remove lists.`), {
|
|
450
|
+
add: [],
|
|
451
|
+
change: [],
|
|
452
|
+
remove: []
|
|
453
|
+
};
|
|
454
|
+
let i = {};
|
|
455
|
+
for (let t of Object.keys(n)) ve.includes(t) || r(`${e}.${t}`, `Unknown key "${t}" in "${e}". Use add, change or remove.`);
|
|
456
|
+
for (let t of ve) n[t] === void 0 ? i[t] = [] : Array.isArray(n[t]) ? i[t] = n[t] : (r(`${e}.${t}`, `"${e}.${t}" must be a list.`), i[t] = []);
|
|
457
|
+
return i;
|
|
458
|
+
}, m = c("nodes"), h = c("edges"), g = new Map(K(e?.nodes).map((e) => [e.id, e])), _ = new Set(K(e?.edges).map(J)), v = /* @__PURE__ */ new Map();
|
|
459
|
+
m.add.forEach((e, t) => {
|
|
460
|
+
U(e) && W(e.id) && !v.has(e.id) && v.set(e.id, t);
|
|
461
|
+
});
|
|
462
|
+
let y = new Set(m.remove.filter((e) => U(e) && W(e.id)).map((e) => e.id)), b = (e) => g.has(e) || v.has(e), x = /* @__PURE__ */ new Set(), S = /* @__PURE__ */ new Map();
|
|
463
|
+
m.add.forEach((e, t) => {
|
|
464
|
+
let n = `nodes.add[${t}]`;
|
|
465
|
+
if (!U(e)) return r(n, "An added node is an object with an id, a label and a type.");
|
|
466
|
+
W(e.id) ? g.has(e.id) ? r(`${n}.id`, `Node "${e.id}" already exists in the map. Use nodes.change to change it.`, "exists") : x.has(e.id) && r(`${n}.id`, `Node "${e.id}" is added twice.`) : r(`${n}.id`, "An added node needs an \"id\"."), W(e.id) && x.add(e.id), W(e.label) || r(`${n}.label`, "An added node needs a \"label\"."), W(e.type) ? u[e.type] ? e.type === "page" && W(e.label) && (e.label.startsWith("/") || r(`${n}.label`, `A page label "${e.label}" must start with a slash route (like "/meals"), as topology validate demands.`), e.label.includes(".html") && r(`${n}.label`, `A page label "${e.label}" must not contain ".html".`)) : r(`${n}.type`, `Unknown node type "${e.type}". Valid types: ${Object.keys(u).join(", ")}.`) : r(`${n}.type`, "An added node needs a \"type\".");
|
|
467
|
+
for (let t of ye) t in e && r(`${n}.${t}`, `"${t}" is set when the proposal is applied; leave it out.`);
|
|
468
|
+
if (e.type === "device" && !l.includes(e.kind) && r(`${n}.kind`, `A device needs "kind", one of: ${l.join(", ")}.`), e.type === "external" && e.kind !== void 0 && !a.includes(e.kind) && r(`${n}.kind`, `An external's "kind" is one of: ${a.join(", ")} (or none, until the registry draws it).`), W(e.id) && u[e.type] && i(e)) {
|
|
469
|
+
let t = p(e.id), i = e.type === "device" ? `live-device-${l.includes(e.kind) ? e.kind : "<kind>"}-<id>` : `live-${e.type}-<id>`;
|
|
470
|
+
!t || t.type !== e.type ? r(`${n}.id`, [
|
|
471
|
+
"floor",
|
|
472
|
+
"room",
|
|
473
|
+
"device"
|
|
474
|
+
].includes(e.type) ? `"${e.id}" is a ${e.type} only the live layer draws${e.type === "device" ? " (no code file derives it)" : ""}: its id must be ${i}.` : `"${e.id}" starts with "${d}", which only the live layer's floors, rooms and devices use (${H}).`) : t.kind && l.includes(e.kind) && t.kind !== e.kind && r(`${n}.kind`, `"${e.id}" names the kind "${t.kind}" but the node says "${e.kind}".`);
|
|
475
|
+
}
|
|
476
|
+
e.parent !== void 0 && (W(e.parent) ? e.parent === e.id ? r(`${n}.parent`, "A node cannot be its own parent.") : b(e.parent) ? y.has(e.parent) ? r(`${n}.parent`, `Parent "${e.parent}" is a node this proposal removes.`) : W(e.id) && S.set(J(Te(e)), `nodes.add[${t}].parent`) : r(`${n}.parent`, `Parent "${e.parent}" is in neither the map nor the added nodes.`, "dangling") : r(`${n}.parent`, "\"parent\" must be the id of a node."));
|
|
477
|
+
});
|
|
478
|
+
let C = /* @__PURE__ */ new Set();
|
|
479
|
+
m.change.forEach((e, t) => {
|
|
480
|
+
let n = `nodes.change[${t}]`;
|
|
481
|
+
if (!U(e)) return r(n, "A changed node is an object with an id, a set and a why.");
|
|
482
|
+
if (W(e.id) ? v.has(e.id) ? r(`${n}.id`, `Node "${e.id}" is added by this proposal: change its entry in nodes.add instead.`) : g.has(e.id) ? C.has(e.id) && r(`${n}.id`, `Node "${e.id}" is changed twice: merge the two sets.`) : r(`${n}.id`, `Node "${e.id}" does not exist in the map, so it cannot be changed.`, "missing-target") : r(`${n}.id`, "A changed node needs an \"id\"."), W(e.id) && C.add(e.id), !U(e.set) || Object.keys(e.set).length === 0) r(`${n}.set`, "\"set\" must be an object of the fields to change.");
|
|
483
|
+
else {
|
|
484
|
+
"id" in e.set && r(`${n}.set.id`, "A change cannot set \"id\": it names the node."), "parent" in e.set && r(`${n}.set.parent`, "\"parent\" is not a node field: remove the ownership edge and add a new one.");
|
|
485
|
+
for (let t of be) t in e.set && r(`${n}.set.${t}`, `"${t}" is set when the proposal is applied; leave it out of "set".`);
|
|
486
|
+
"type" in e.set && !u[e.set.type] && r(`${n}.set.type`, `Unknown node type "${e.set.type}". Valid types: ${Object.keys(u).join(", ")}.`);
|
|
487
|
+
}
|
|
488
|
+
W(e.why) || r(`${n}.why`, "A change needs a \"why\": the reason the maintainer reads.");
|
|
489
|
+
});
|
|
490
|
+
let w = /* @__PURE__ */ new Set();
|
|
491
|
+
m.remove.forEach((e, t) => {
|
|
492
|
+
let n = `nodes.remove[${t}]`;
|
|
493
|
+
if (!U(e)) return r(n, "A removed node is an object with an id and a why.");
|
|
494
|
+
W(e.id) ? v.has(e.id) ? r(`${n}.id`, `Node "${e.id}" is added by this proposal: drop its entry from nodes.add instead of removing it.`) : g.has(e.id) ? w.has(e.id) ? r(`${n}.id`, `Node "${e.id}" is removed twice.`) : C.has(e.id) && r(`${n}.id`, `Node "${e.id}" is both changed and removed.`) : r(`${n}.id`, `Node "${e.id}" does not exist in the map, so it cannot be removed.`, "missing-target") : r(`${n}.id`, "A removed node needs an \"id\"."), W(e.id) && w.add(e.id), W(e.why) || r(`${n}.why`, "A removal needs a \"why\".");
|
|
495
|
+
});
|
|
496
|
+
let te = new Map(m.change.filter((e) => U(e) && W(e.id) && U(e.set)).map((e) => [e.id, e.set])), T = new Map(m.add.filter((e) => U(e) && W(e.id)).map((e) => [e.id, e])), E = (e) => T.get(e) || (g.has(e) ? {
|
|
497
|
+
...g.get(e),
|
|
498
|
+
...te.get(e) || {}
|
|
499
|
+
} : void 0), D = (e, t) => {
|
|
500
|
+
W(e.from) || r(`${t}.from`, "An edge needs a \"from\" node id."), W(e.to) || r(`${t}.to`, "An edge needs a \"to\" node id.");
|
|
501
|
+
let n = W(e.from) && W(e.to);
|
|
502
|
+
return e.kind !== void 0 && !f.includes(e.kind) && (r(`${t}.kind`, `Unknown edge kind "${e.kind}". Valid kinds: ${f.join(", ")} (or none, for ownership).`), n = !1), e.kind === "flow" ? o.includes(e.flow) || (r(`${t}.flow`, `A flow edge needs "flow", one of: ${o.join(", ")}.`), n = !1) : e.flow !== void 0 && r(`${t}.flow`, "\"flow\" only goes on an edge of kind \"flow\"."), n ? J(e) : null;
|
|
503
|
+
}, O = (e) => `${e.from} -> ${e.to}${e.kind ? ` (${e.kind === "flow" ? `flow ${e.flow}` : e.kind})` : " (ownership)"}`, k = new Map([...S]);
|
|
504
|
+
h.add.forEach((e, t) => {
|
|
505
|
+
let n = `edges.add[${t}]`;
|
|
506
|
+
if (!U(e)) return r(n, "An added edge is an object with from, to and optionally a kind.");
|
|
507
|
+
let i = D(e, n);
|
|
508
|
+
for (let t of ye) t in e && r(`${n}.${t}`, `"${t}" is set when the proposal is applied; leave it out.`);
|
|
509
|
+
for (let t of ["from", "to"]) W(e[t]) && (b(e[t]) ? y.has(e[t]) && r(`${n}.${t}`, `Node "${e[t]}" is a node this proposal removes, so an edge cannot be added to it.`) : r(`${n}.${t}`, `Node "${e[t]}" is in neither the map nor the added nodes.`, "dangling"));
|
|
510
|
+
let a = E(e.from), o = E(e.to);
|
|
511
|
+
if (a && o) {
|
|
512
|
+
for (let t of ["when", "side"]) if (e[t] !== void 0) for (let i of s({
|
|
513
|
+
kind: e.kind,
|
|
514
|
+
[t]: e[t]
|
|
515
|
+
}, a, o)) r(`${n}.${t}`, `The edge ${i}`);
|
|
516
|
+
}
|
|
517
|
+
i && (_.has(i) ? r(n, `Edge ${O(e)} already exists in the map.`, "exists") : k.has(i) && r(n, `Edge ${O(e)} is already added by ${k.get(i)}.`), k.set(i, k.get(i) || n));
|
|
518
|
+
});
|
|
519
|
+
let A = /* @__PURE__ */ new Map(), j = (e, t, n) => {
|
|
520
|
+
let i = D(e, t);
|
|
521
|
+
return i ? (_.has(i) ? A.has(i) ? r(t, `Edge ${O(e)} is already ${A.get(i)} by this proposal.`) : A.set(i, n === "change" ? "changed" : "removed") : r(t, `Edge ${O(e)} does not exist in the map, so it cannot be ${n === "change" ? "changed" : "removed"}.`, "missing-target"), i) : null;
|
|
522
|
+
};
|
|
523
|
+
h.change.forEach((e, t) => {
|
|
524
|
+
let n = `edges.change[${t}]`;
|
|
525
|
+
if (!U(e)) return r(n, "A changed edge is an object with from, to, set and why.");
|
|
526
|
+
if (j(e, n, "change"), !U(e.set) || Object.keys(e.set).length === 0) r(`${n}.set`, "\"set\" must be an object of the fields to change.");
|
|
527
|
+
else {
|
|
528
|
+
for (let t of xe) t in e.set && r(`${n}.set.${t}`, `A change cannot set "${t}": it names the edge. Remove the edge and add a new one.`);
|
|
529
|
+
for (let t of be) t in e.set && r(`${n}.set.${t}`, `"${t}" is set when the proposal is applied; leave it out of "set".`);
|
|
530
|
+
}
|
|
531
|
+
W(e.why) || r(`${n}.why`, "A change needs a \"why\".");
|
|
532
|
+
}), h.remove.forEach((e, t) => {
|
|
533
|
+
let n = `edges.remove[${t}]`;
|
|
534
|
+
if (!U(e)) return r(n, "A removed edge is an object with from, to and why.");
|
|
535
|
+
j(e, n, "remove"), W(e.why) || r(`${n}.why`, "A removal needs a \"why\".");
|
|
536
|
+
});
|
|
537
|
+
function M(e, t) {
|
|
538
|
+
if (!W(e) || !_e.test(e)) return r(t, `"actor" must be a persona id: lower-case words joined by dashes, like "child" (got ${JSON.stringify(e)}).`);
|
|
539
|
+
let n = ee(e);
|
|
540
|
+
b(n) || r(t, `Actor "${e}" is no persona: "${n}" is in neither the map nor the added nodes.`, "dangling");
|
|
541
|
+
}
|
|
542
|
+
function N(e, t) {
|
|
543
|
+
if (!W(e)) return r(t, `"at" must be a node id or a live id (${H}).`);
|
|
544
|
+
b(e) || p(e) || (e.startsWith("live-") ? r(t, `"${e}" is not a live id: write ${H}.`) : r(t, `Step happens nowhere: "${e}" is in neither the map nor the added nodes, and is not a live id.`, "dangling"));
|
|
545
|
+
}
|
|
546
|
+
let P = "A check is { route, method } or { table, op, row? }";
|
|
547
|
+
function F(e, t) {
|
|
548
|
+
if (!U(e)) return r(t, `${P}.`);
|
|
549
|
+
let n = "route" in e || "method" in e, i = "table" in e || "op" in e || "row" in e;
|
|
550
|
+
if (n && i) return r(t, `${P}: either one, not both.`);
|
|
551
|
+
if (!n && !i) return r(t, `${P}.`);
|
|
552
|
+
let a = n ? ["route", "method"] : [
|
|
553
|
+
"table",
|
|
554
|
+
"op",
|
|
555
|
+
"row"
|
|
556
|
+
];
|
|
557
|
+
for (let i of Object.keys(e)) a.includes(i) || r(`${t}.${i}`, `Unknown key "${i}" in a ${n ? "route" : "table"} check. It has: ${a.join(", ")}.`);
|
|
558
|
+
n ? (W(e.route) && e.route.startsWith("/") || r(`${t}.route`, "\"route\" must be a path starting with a slash, as the map labels it (\"/api/v1/rooms/[id]\") or a concrete one."), pe.includes(e.method) || r(`${t}.method`, `"method" must be one of: ${pe.join(", ")}.`)) : (W(e.table) || r(`${t}.table`, "\"table\" must be the SQL table name."), me.includes(e.op) || r(`${t}.op`, `"op" must be one of: ${me.join(", ")}.`), e.row !== void 0 && !he.includes(e.row) && r(`${t}.row`, `"row" must be one of: ${he.join(", ")}.`));
|
|
559
|
+
}
|
|
560
|
+
function I(e, t) {
|
|
561
|
+
Array.isArray(e) ? e.forEach((e, n) => F(e, `${t}[${n}]`)) : F(e, t);
|
|
562
|
+
}
|
|
563
|
+
function L(e, t) {
|
|
564
|
+
if (!Array.isArray(e)) return r(t, "\"down\" must be a list of the cloud node ids the scenario takes down.");
|
|
565
|
+
if (e.length === 0) return r(t, "\"down\" needs at least one cloud node id; leave it out for a scenario that is no outage.");
|
|
566
|
+
let n = /* @__PURE__ */ new Set();
|
|
567
|
+
e.forEach((e, i) => {
|
|
568
|
+
let a = `${t}[${i}]`;
|
|
569
|
+
if (!W(e)) return r(a, "\"down\" holds node ids: strings like \"ext-cloudflare\".");
|
|
570
|
+
if (n.has(e)) return r(a, `"${e}" is down twice.`);
|
|
571
|
+
n.add(e);
|
|
572
|
+
let o = E(e);
|
|
573
|
+
if (!o) return r(a, `Down node "${e}" is in neither the map nor the added nodes.`, y.has(e) ? "missing-target" : "dangling");
|
|
574
|
+
if (o.type !== "external" || o.kind !== "cloud") {
|
|
575
|
+
let t = o.type === "external" ? o.kind === void 0 ? "an external with no kind" : `an external of kind ${o.kind}` : `a ${o.type}`;
|
|
576
|
+
r(a, `"${e}" is ${t}: only an external of kind cloud can be down (a container, a stack or a machine is the House view's; the public web is never down as a whole).`);
|
|
577
|
+
}
|
|
578
|
+
});
|
|
579
|
+
}
|
|
580
|
+
let ne = new Set(h.remove.filter((e) => U(e) && W(e.from) && W(e.to)).map(J)), R = (e, t) => ne.has(e) || y.has(t.from) || y.has(t.to);
|
|
581
|
+
t.scenarios !== void 0 && !Array.isArray(t.scenarios) && r("scenarios", "\"scenarios\" must be a list.");
|
|
582
|
+
let z = /* @__PURE__ */ new Set();
|
|
583
|
+
if (K(t.scenarios).forEach((e, t) => {
|
|
584
|
+
let n = `scenarios[${t}]`;
|
|
585
|
+
if (!U(e)) return r(n, "A scenario is an object with an id, a title and steps.");
|
|
586
|
+
W(e.id) ? z.has(e.id) && r(`${n}.id`, `Scenario id "${e.id}" is used twice.`) : r(`${n}.id`, "A scenario needs an \"id\"."), W(e.id) && z.add(e.id), W(e.title) || r(`${n}.title`, "A scenario needs a \"title\".");
|
|
587
|
+
for (let t of Object.keys(e)) fe.includes(t) || r(`${n}.${t}`, `Unknown key "${t}" in a scenario. A scenario has: ${fe.join(", ")}.`);
|
|
588
|
+
if (e.stepMs !== void 0 && !Se(e.stepMs) && r(`${n}.stepMs`, "\"stepMs\" must be a positive number of milliseconds."), e.linkNodes !== void 0 && typeof e.linkNodes != "boolean" && r(`${n}.linkNodes`, "\"linkNodes\" must be true or false."), e.actor !== void 0 && M(e.actor, `${n}.actor`), e.down !== void 0 && L(e.down, `${n}.down`), !Array.isArray(e.steps)) return r(`${n}.steps`, "\"steps\" must be a list.");
|
|
589
|
+
if (e.steps.length === 0) return r(`${n}.steps`, "A scenario needs at least one step.");
|
|
590
|
+
e.steps.forEach((t, i) => {
|
|
591
|
+
let a = `${n}.steps[${i}]`;
|
|
592
|
+
if (!U(t)) return r(a, "A step is an object with a \"node\" or an \"edge\", and some \"text\".");
|
|
593
|
+
for (let e of Object.keys(t)) V.includes(e) || r(`${a}.${e}`, `Unknown key "${e}" in a step. A step has "node" or "edge", and "text"; optionally ${V.slice(3).join(", ")}.`);
|
|
594
|
+
if (W(t.text) || r(`${a}.text`, "A step needs \"text\": what happens at this point."), t.ms !== void 0 && !Se(t.ms) && r(`${a}.ms`, "\"ms\" must be a positive number of milliseconds."), t.actor !== void 0 && M(t.actor, `${a}.actor`), t.at !== void 0 && N(t.at, `${a}.at`), t.check !== void 0 && I(t.check, `${a}.check`), t.expect !== void 0 && (ge.includes(t.expect) ? t.actor === void 0 && e.actor === void 0 && r(`${a}.expect`, "\"expect\" needs an actor, on the step or its scenario: a step with no actor is never checked.") : r(`${a}.expect`, `"expect" must be one of: ${ge.join(", ")}.`)), t.node === void 0 == (t.edge === void 0) && r(a, "A step points at exactly one of \"node\" or \"edge\"."), t.node !== void 0 && (W(t.node) ? b(t.node) || r(`${a}.node`, `Step points at nothing: node "${t.node}" is in neither the map nor the added nodes.`, y.has(t.node) ? "missing-target" : "dangling") : r(`${a}.node`, "\"node\" must be a node id.")), t.edge !== void 0) {
|
|
595
|
+
if (!U(t.edge)) return r(`${a}.edge`, "\"edge\" must be an object with from and to.");
|
|
596
|
+
let e = D(t.edge, `${a}.edge`);
|
|
597
|
+
e && !_.has(e) && !k.has(e) && r(`${a}.edge`, `Step points at nothing: edge ${O(t.edge)} is in neither the map nor the added edges.`, R(e, t.edge) ? "missing-target" : "dangling");
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
}), t.mockups !== void 0 && !Array.isArray(t.mockups)) r("mockups", "\"mockups\" must be a list.");
|
|
601
|
+
else if (Array.isArray(t.mockups)) {
|
|
602
|
+
t.mockups.length > 40 && r("mockups", "At most 40 mockups in one proposal.");
|
|
603
|
+
let e = /* @__PURE__ */ new Set([
|
|
604
|
+
...v.keys(),
|
|
605
|
+
...y,
|
|
606
|
+
...m.change.filter((e) => U(e) && W(e.id)).map((e) => e.id)
|
|
607
|
+
]), n = /* @__PURE__ */ new Set();
|
|
608
|
+
t.mockups.forEach((t, i) => {
|
|
609
|
+
let a = `mockups[${i}]`;
|
|
610
|
+
if (!U(t)) return r(a, "A mockup is an object with a node, a path and a title.");
|
|
611
|
+
for (let e of Object.keys(t)) ue.includes(e) || r(`${a}.${e}`, `Unknown key "${e}" in a mockup. A mockup has: ${ue.join(", ")}.`);
|
|
612
|
+
W(t.title) || r(`${a}.title`, "A mockup needs a \"title\": what the screen is. It is also its alt text.");
|
|
613
|
+
let o = Ce(t.path);
|
|
614
|
+
o ? r(`${a}.path`, o) : n.has(`${t.node}|${t.path}`) ? r(a, `Mockup "${t.path}" is listed twice for node "${t.node}".`) : n.add(`${t.node}|${t.path}`), W(t.node) ? e.has(t.node) || r(`${a}.node`, `Mockup is beside node "${t.node}", which this proposal does not add, change or remove. Name a node the proposal touches.`) : r(`${a}.node`, "A mockup needs the \"node\" it belongs to.");
|
|
615
|
+
});
|
|
616
|
+
}
|
|
617
|
+
return n;
|
|
618
|
+
}
|
|
619
|
+
var De = u.external;
|
|
620
|
+
function Oe(e, t) {
|
|
621
|
+
let n = e.nodes.map((e) => ({
|
|
622
|
+
...e,
|
|
623
|
+
mark: "none"
|
|
624
|
+
})), r = e.edges.map((e) => ({
|
|
625
|
+
...e,
|
|
626
|
+
mark: "none"
|
|
627
|
+
})), i = new Map(n.map((e) => [e.id, e])), a = /* @__PURE__ */ new Map();
|
|
628
|
+
for (let e of r) {
|
|
629
|
+
let t = J(e);
|
|
630
|
+
a.has(t) || a.set(t, []), a.get(t).push(e);
|
|
631
|
+
}
|
|
632
|
+
let o = (e) => ({
|
|
633
|
+
add: K(t[e]?.add),
|
|
634
|
+
change: K(t[e]?.change),
|
|
635
|
+
remove: K(t[e]?.remove)
|
|
636
|
+
}), s = o("nodes"), c = o("edges"), l = (e, t, n) => {
|
|
637
|
+
let r = {}, i = (t, n) => {
|
|
638
|
+
q(e[t], n) || (r[t] = e[t] === void 0 ? null : e[t], e[t] = G(n));
|
|
639
|
+
};
|
|
640
|
+
for (let [e, n] of Object.entries(t || {})) i(e, n);
|
|
641
|
+
e.mark = "changed", e.before = r, e.why = n;
|
|
642
|
+
};
|
|
643
|
+
for (let e of s.change) {
|
|
644
|
+
let t = i.get(e.id);
|
|
645
|
+
if (!t) continue;
|
|
646
|
+
let n = { ...e.set }, r = u[n.type];
|
|
647
|
+
r && ("color" in n || (n.color = r.color), "r" in n || (n.r = r.r)), l(t, n, e.why);
|
|
648
|
+
}
|
|
649
|
+
for (let e of c.change) for (let t of a.get(J(e)) || []) l(t, e.set, e.why);
|
|
650
|
+
for (let e of c.remove) for (let t of a.get(J(e)) || []) delete t.before, t.mark = "removed", t.why = e.why;
|
|
651
|
+
for (let e of s.remove) {
|
|
652
|
+
let t = i.get(e.id);
|
|
653
|
+
if (t) {
|
|
654
|
+
t.mark = "removed", t.why = e.why;
|
|
655
|
+
for (let t of r) (t.from === e.id || t.to === e.id) && t.mark !== "removed" && (delete t.before, t.mark = "removed", t.why = e.why);
|
|
656
|
+
}
|
|
657
|
+
}
|
|
658
|
+
let d = [], f = (e) => {
|
|
659
|
+
let t = a.get(J(e));
|
|
660
|
+
t ? t.forEach((e) => {
|
|
661
|
+
e.mark === "none" && (e.mark = "added");
|
|
662
|
+
}) : r.push({
|
|
663
|
+
...G(e),
|
|
664
|
+
mark: "added"
|
|
665
|
+
});
|
|
666
|
+
};
|
|
667
|
+
for (let e of s.add) {
|
|
668
|
+
let { parent: t, ...r } = G(e), a = u[e.type] || De, o = i.get(e.id);
|
|
669
|
+
o ? o.mark === "none" && (o.mark = "added") : n.push({
|
|
670
|
+
...r,
|
|
671
|
+
color: a.color,
|
|
672
|
+
r: e.r ?? a.r,
|
|
673
|
+
mark: "added"
|
|
674
|
+
}), t && d.push({
|
|
675
|
+
from: t,
|
|
676
|
+
to: e.id
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
for (let e of d) f(e);
|
|
680
|
+
for (let e of c.add) f(e);
|
|
681
|
+
return {
|
|
682
|
+
nodes: n,
|
|
683
|
+
edges: r
|
|
684
|
+
};
|
|
685
|
+
}
|
|
686
|
+
function ke(e, t) {
|
|
687
|
+
let n = new Map(e.nodes.map((e) => [e.id, e])), r = /* @__PURE__ */ new Map(), a = /* @__PURE__ */ new Map(), o = /* @__PURE__ */ new Map();
|
|
688
|
+
for (let t of e.edges) {
|
|
689
|
+
let e = J(t);
|
|
690
|
+
r.has(e) || r.set(e, t);
|
|
691
|
+
let n = `${t.from}|${t.to}`;
|
|
692
|
+
a.has(n) || a.set(n, /* @__PURE__ */ new Set()), a.get(n).add(e), !t.kind && !t.dashed && (o.has(t.to) || o.set(t.to, /* @__PURE__ */ new Set()), o.get(t.to).add(t.from));
|
|
693
|
+
}
|
|
694
|
+
let s = (e, t) => Object.entries(t || {}).every(([t, n]) => q(e[t], n)), c = (e, n) => K(t?.[e]?.[n]), l = new Set(c("nodes", "add").filter((e) => U(e) && i(e)).map((e) => e.id)), u = (e) => l.has(e) || typeof e == "string" && e.startsWith("live-"), d = [], f = (e, t, n, r) => d.push({
|
|
695
|
+
kind: e,
|
|
696
|
+
op: t,
|
|
697
|
+
key: n,
|
|
698
|
+
status: r
|
|
699
|
+
});
|
|
700
|
+
for (let e of c("nodes", "add")) {
|
|
701
|
+
if (l.has(e.id)) {
|
|
702
|
+
f("node", "add", e.id, "live");
|
|
703
|
+
continue;
|
|
704
|
+
}
|
|
705
|
+
let t = n.get(e.id);
|
|
706
|
+
f("node", "add", e.id, t ? t.type !== e.type || e.parent && !o.get(e.id)?.has(e.parent) ? "diverged" : "landed" : "pending");
|
|
707
|
+
}
|
|
708
|
+
for (let e of c("nodes", "change")) {
|
|
709
|
+
let t = n.get(e.id);
|
|
710
|
+
f("node", "change", e.id, t ? s(t, e.set) ? "landed" : "pending" : "diverged");
|
|
711
|
+
}
|
|
712
|
+
for (let e of c("nodes", "remove")) f("node", "remove", e.id, n.has(e.id) ? "pending" : "landed");
|
|
713
|
+
for (let e of c("edges", "add")) {
|
|
714
|
+
let t = J(e);
|
|
715
|
+
if (u(e.from) || u(e.to)) {
|
|
716
|
+
f("edge", "add", t, "live");
|
|
717
|
+
continue;
|
|
718
|
+
}
|
|
719
|
+
let n = [...a.get(`${e.from}|${e.to}`) || []].some((e) => e !== t);
|
|
720
|
+
f("edge", "add", t, r.has(t) ? "landed" : n ? "diverged" : "pending");
|
|
721
|
+
}
|
|
722
|
+
for (let e of c("edges", "change")) {
|
|
723
|
+
let t = J(e), n = r.get(t);
|
|
724
|
+
f("edge", "change", t, n ? s(n, e.set) ? "landed" : "pending" : "diverged");
|
|
725
|
+
}
|
|
726
|
+
for (let e of c("edges", "remove")) {
|
|
727
|
+
let t = J(e);
|
|
728
|
+
f("edge", "remove", t, r.has(t) ? "pending" : "landed");
|
|
729
|
+
}
|
|
730
|
+
let p = {
|
|
731
|
+
total: d.length,
|
|
732
|
+
pending: 0,
|
|
733
|
+
landed: 0,
|
|
734
|
+
diverged: 0,
|
|
735
|
+
live: 0
|
|
736
|
+
};
|
|
737
|
+
for (let e of d) p[e.status]++;
|
|
738
|
+
return {
|
|
739
|
+
items: d,
|
|
740
|
+
summary: p
|
|
741
|
+
};
|
|
742
|
+
}
|
|
743
|
+
function Ae(e, t) {
|
|
744
|
+
let n = Ee(e, t), r = !1;
|
|
745
|
+
if (n.some((e) => e.state === "exists" || e.state === "missing-target")) try {
|
|
746
|
+
r = ke(e, t).items.some((e) => e.op === "add" && e.status === "landed");
|
|
747
|
+
} catch {}
|
|
748
|
+
return {
|
|
749
|
+
errors: r ? n.filter((e) => e.state !== "exists" && e.state !== "missing-target") : n,
|
|
750
|
+
building: r
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
function je(e) {
|
|
754
|
+
let t = (e) => ({
|
|
755
|
+
added: K(e?.add).length,
|
|
756
|
+
changed: K(e?.change).length,
|
|
757
|
+
removed: K(e?.remove).length
|
|
758
|
+
}), n = t(e?.nodes), r = t(e?.edges);
|
|
759
|
+
return {
|
|
760
|
+
added: n.added + r.added,
|
|
761
|
+
changed: n.changed + r.changed,
|
|
762
|
+
removed: n.removed + r.removed,
|
|
763
|
+
scenarios: K(e?.scenarios).length,
|
|
764
|
+
nodes: n,
|
|
765
|
+
edges: r
|
|
766
|
+
};
|
|
767
|
+
}
|
|
768
|
+
// ../explorer/camera-frame.js
|
|
769
|
+
var Me = .18;
|
|
770
|
+
function Ne(e, t, n, r = 0) {
|
|
771
|
+
return e.every((e) => {
|
|
772
|
+
let i = t.x + e.x * t.zoom, a = t.y + e.y * t.zoom;
|
|
773
|
+
return i >= n.x + r && i <= n.x + n.width - r && a >= n.y + r && a <= n.y + n.height - r;
|
|
774
|
+
});
|
|
775
|
+
}
|
|
776
|
+
function Pe(e, t, { padding: n = 40, minZoom: r = Me } = {}) {
|
|
777
|
+
if (e.length < 2) return e;
|
|
778
|
+
let i = m(n, t), a = (t.width - i * 2) / r, o = (t.height - i * 2) / r, s = e.map(h), c = (t, n) => e.filter((e, r) => s[r].left >= t && s[r].right <= t + a && s[r].top >= n && s[r].bottom <= n + o), l = s.map((e) => e.left), u = s.map((e) => e.top), d = [], f = e.length <= 120 ? l.flatMap((e) => u.map((t) => [e, t])) : s.map((e) => [e.left, e.top]);
|
|
779
|
+
for (let [t, n] of f) {
|
|
780
|
+
if (d.length === e.length) break;
|
|
781
|
+
let r = c(t, n);
|
|
782
|
+
r.length > d.length && (d = r);
|
|
783
|
+
}
|
|
784
|
+
return d.length ? d : [e[0]];
|
|
785
|
+
}
|
|
786
|
+
function Fe(e, t, n, r = 0) {
|
|
787
|
+
let i = e.x + t.x * e.zoom, a = e.y + t.y * e.zoom, o = Math.min(r, (n.right - n.left) / 2), s = Math.min(r, (n.bottom - n.top) / 2), c = i < n.left + o || i > n.right - o, l = a < n.top + s || a > n.bottom - s;
|
|
788
|
+
return !c && !l ? null : {
|
|
789
|
+
x: c ? (n.left + n.right) / 2 - t.x * e.zoom : e.x,
|
|
790
|
+
y: l ? (n.top + n.bottom) / 2 - t.y * e.zoom : e.y,
|
|
791
|
+
zoom: e.zoom
|
|
792
|
+
};
|
|
793
|
+
}
|
|
794
|
+
var Ie = 0;
|
|
795
|
+
function Le(e, t = 5) {
|
|
796
|
+
if (e.length <= t + 1) return e.join("");
|
|
797
|
+
let n = `hx-more-${++Ie}`, r = e.length - t;
|
|
798
|
+
return `${e.slice(0, t).join("")}<div class="hx-more" id="${n}" hidden>${e.slice(t).join("")}</div><button data-corn="more" data-corn-kind="quiet" type="button" class="hx-btn hx-btn--quiet hx-textact hx-more-btn" data-more="${n}" data-rest="${r}" aria-expanded="false" aria-controls="${n}">and ${r} more</button>`;
|
|
799
|
+
}
|
|
800
|
+
function Re(e) {
|
|
801
|
+
let t = e.closest && e.closest("[data-more]");
|
|
802
|
+
if (!t) return !1;
|
|
803
|
+
let n = t.previousElementSibling, r = n && n.id === t.dataset.more ? n : null, i = t.getAttribute("aria-expanded") !== "true";
|
|
804
|
+
return r && (r.hidden = !i), t.setAttribute("aria-expanded", String(i)), t.textContent = i ? "Show fewer" : `and ${t.dataset.rest} more`, !0;
|
|
805
|
+
}
|
|
806
|
+
// ../explorer/cloud-panel.js
|
|
807
|
+
var Y = {
|
|
808
|
+
free: "Free",
|
|
809
|
+
paid: "Paid",
|
|
810
|
+
unknown: "Plan unknown",
|
|
811
|
+
off: "Off"
|
|
812
|
+
};
|
|
813
|
+
function ze(e) {
|
|
814
|
+
return !e || !Y[e.tier] ? "" : e.note ? `${Y[e.tier]} · ${e.note}` : Y[e.tier];
|
|
815
|
+
}
|
|
816
|
+
var Be = {
|
|
817
|
+
container: ["container", "containers"],
|
|
818
|
+
machine: ["machine", "machines"],
|
|
819
|
+
app: ["app", "apps"],
|
|
820
|
+
service: ["service", "services"],
|
|
821
|
+
page: ["endpoint", "endpoints"],
|
|
822
|
+
external: ["cloud service", "cloud services"]
|
|
823
|
+
}, X = (e, t) => {
|
|
824
|
+
let n = Be[e] || [e, `${e}s`];
|
|
825
|
+
return t === 1 ? n[0] : n[1];
|
|
826
|
+
};
|
|
827
|
+
function Ve(t, n, i) {
|
|
828
|
+
let a = new Map(n.map((e) => [e.id, e])), o = new Map(Object.keys(e).map((e) => [e, /* @__PURE__ */ new Map()]));
|
|
829
|
+
for (let e of i) {
|
|
830
|
+
if (e.kind !== "calls" || e.to !== t.id) continue;
|
|
831
|
+
let n = o.get(r(e)), i = a.get(e.from) || {
|
|
832
|
+
id: e.from,
|
|
833
|
+
label: e.from,
|
|
834
|
+
type: "node"
|
|
835
|
+
}, s = n.get(e.from) || {
|
|
836
|
+
id: e.from,
|
|
837
|
+
label: String(i.label || e.from),
|
|
838
|
+
type: i.type,
|
|
839
|
+
vias: [],
|
|
840
|
+
browser: !1
|
|
841
|
+
};
|
|
842
|
+
e.label && !s.vias.includes(e.label) && s.vias.push(e.label), e.side === "browser" && (s.browser = !0), n.set(e.from, s);
|
|
843
|
+
}
|
|
844
|
+
let s = [];
|
|
845
|
+
for (let [t, n] of o) {
|
|
846
|
+
if (n.size === 0) continue;
|
|
847
|
+
let r = /* @__PURE__ */ new Map();
|
|
848
|
+
for (let { vias: e, ...t } of n.values()) r.has(t.type) || r.set(t.type, []), r.get(t.type).push({
|
|
849
|
+
...t,
|
|
850
|
+
via: e.join(", ")
|
|
851
|
+
});
|
|
852
|
+
let i = [...r].map(([e, t]) => ({
|
|
853
|
+
type: e,
|
|
854
|
+
noun: X(e, 1),
|
|
855
|
+
items: t.sort((e, t) => e.label.localeCompare(t.label))
|
|
856
|
+
})).sort((e, t) => t.items.length - e.items.length || e.type.localeCompare(t.type)), { title: a, color: o } = e[t];
|
|
857
|
+
s.push({
|
|
858
|
+
when: t,
|
|
859
|
+
title: a,
|
|
860
|
+
color: o,
|
|
861
|
+
count: n.size,
|
|
862
|
+
types: i
|
|
863
|
+
});
|
|
864
|
+
}
|
|
865
|
+
return s;
|
|
866
|
+
}
|
|
867
|
+
var He = {
|
|
868
|
+
run: "Breaks now",
|
|
869
|
+
deploy: "Breaks on deploy",
|
|
870
|
+
renew: "Breaks on renewal"
|
|
871
|
+
}, Z = (e, n) => n.length ? `<div class="hx-fact" data-corn="section"><div class="hx-fact-k">${t(e)}</div><div class="hx-fact-v">${Le(n)}</div></div>` : "", Q = (e) => `<div class="hx-line">${e}</div>`, $ = (e) => `<span class="hx-name">${t(e)}</span>`;
|
|
872
|
+
function Ue(e, n) {
|
|
873
|
+
let r = e.browser ? " <span class=\"hx-cloud-browser\">(browser)</span>" : "", i = [n ? X(e.type, 1) : "", e.via].filter(Boolean);
|
|
874
|
+
return Q(`<span>${$(e.label)}${r}${i.length ? `<span class="hx-faint"> · ${t(i.join(" · "))}</span>` : ""}</span>`);
|
|
875
|
+
}
|
|
876
|
+
var We = (e) => `<button data-corn-kind="quiet" type="button" class="hx-btn hx-btn--quiet hx-cloud-play" data-action="play-outage" data-id="${t(e.id)}">Play: ${t(String(e.label || e.id))} is down</button>`;
|
|
877
|
+
function Ge(e, n, r) {
|
|
878
|
+
let i = new Map(n.map((e) => [e.id, e])), a = (e) => String((i.get(e) || { label: e }).label || e), o = e.kind === "web", s = o ? [] : e.roles || [], c = Ve(e, n, r).map((e) => {
|
|
879
|
+
let t = e.types.length > 1;
|
|
880
|
+
return Z(He[e.when], e.types.flatMap((e) => e.items.map((e) => Ue(e, t))));
|
|
881
|
+
}).join("") || Z("Used by", [Q("<span class=\"hx-faint\">Nothing on the map uses it.</span>")]), l = r.filter((t) => t.kind === "calls" && t.from === e.id && (i.get(t.to) || {}).type === "external").map((e) => Q(`<span>${$(a(e.to))}${e.label ? `<span class="hx-faint"> · ${t(e.label)}</span>` : ""}</span>`)), u = r.filter((t) => t.kind === "delivers" && t.from === e.id).map((e) => Q($(a(e.to))));
|
|
882
|
+
return (o ? "" : Z("Plan", [Q(t(ze(e.plan) || Y.unknown))])) + Z("Roles", s.length ? [Q(t(s.join(", ")))] : []) + Z("If it's down", [Q(t(e.breaks || "Not described yet."))]) + c + Z("Relies on", l) + Z("Pushes to", u) + (o ? "" : We(e));
|
|
883
|
+
}
|
|
884
|
+
export { O as A, oe as C, ne as D, se as E, S as F, b as I, x as L, w as M, C as N, B as O, y as P, k as S, ae as T, te as _, Re as a, I as b, Pe as c, J as d, we as f, L as g, T as h, Le as i, ce as j, ie as k, Fe as l, je as m, Ve as n, Me as o, Ae as p, X as r, Ne as s, Ge as t, Oe as u, D as v, N as w, M as x, E as y };
|