@graview/core 0.1.64 → 0.1.66

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 (142) hide show
  1. package/dist/archived-seen.js +2 -2
  2. package/dist/archived-seen.js.map +1 -1
  3. package/dist/capital.d.ts +8 -0
  4. package/dist/capital.d.ts.map +1 -1
  5. package/dist/capital.js +8 -0
  6. package/dist/capital.js.map +1 -1
  7. package/dist/catalog.d.ts +32 -2
  8. package/dist/catalog.d.ts.map +1 -1
  9. package/dist/catalog.js +1 -0
  10. package/dist/catalog.js.map +1 -1
  11. package/dist/columns.js +2 -2
  12. package/dist/columns.js.map +1 -1
  13. package/dist/compose.d.ts +25 -1
  14. package/dist/compose.d.ts.map +1 -1
  15. package/dist/compose.js +56 -0
  16. package/dist/compose.js.map +1 -1
  17. package/dist/conformance/index.d.ts +8 -0
  18. package/dist/conformance/index.d.ts.map +1 -1
  19. package/dist/conformance/index.js +4 -0
  20. package/dist/conformance/index.js.map +1 -1
  21. package/dist/conformance/plan-host.d.ts +73 -0
  22. package/dist/conformance/plan-host.d.ts.map +1 -0
  23. package/dist/conformance/plan-host.js +64 -0
  24. package/dist/conformance/plan-host.js.map +1 -0
  25. package/dist/conformance/told-host.d.ts +40 -0
  26. package/dist/conformance/told-host.d.ts.map +1 -0
  27. package/dist/conformance/told-host.js +57 -0
  28. package/dist/conformance/told-host.js.map +1 -0
  29. package/dist/conformance/view-fork-host.d.ts +26 -0
  30. package/dist/conformance/view-fork-host.d.ts.map +1 -0
  31. package/dist/conformance/view-fork-host.js +47 -0
  32. package/dist/conformance/view-fork-host.js.map +1 -0
  33. package/dist/conformance/view-revision-host.d.ts +36 -0
  34. package/dist/conformance/view-revision-host.d.ts.map +1 -0
  35. package/dist/conformance/view-revision-host.js +42 -0
  36. package/dist/conformance/view-revision-host.js.map +1 -0
  37. package/dist/css/tables.d.ts.map +1 -1
  38. package/dist/css/tables.js +5 -1
  39. package/dist/css/tables.js.map +1 -1
  40. package/dist/document/compile.d.ts.map +1 -1
  41. package/dist/document/compile.js +6 -2
  42. package/dist/document/compile.js.map +1 -1
  43. package/dist/document.schema.json +2 -2
  44. package/dist/friction-record.d.ts +2 -1
  45. package/dist/friction-record.d.ts.map +1 -1
  46. package/dist/friction.d.ts +4 -0
  47. package/dist/friction.d.ts.map +1 -1
  48. package/dist/friction.js +5 -4
  49. package/dist/friction.js.map +1 -1
  50. package/dist/graph/graph.d.ts.map +1 -1
  51. package/dist/graph/graph.js +3 -3
  52. package/dist/graph/graph.js.map +1 -1
  53. package/dist/index.d.ts +4 -3
  54. package/dist/index.d.ts.map +1 -1
  55. package/dist/index.js +3 -2
  56. package/dist/index.js.map +1 -1
  57. package/dist/intelligence-bridge.d.ts +9 -0
  58. package/dist/intelligence-bridge.d.ts.map +1 -1
  59. package/dist/mutations/derive-edits.d.ts.map +1 -1
  60. package/dist/mutations/derive-edits.js +3 -5
  61. package/dist/mutations/derive-edits.js.map +1 -1
  62. package/dist/ops/declines.d.ts +41 -0
  63. package/dist/ops/declines.d.ts.map +1 -0
  64. package/dist/ops/declines.js +118 -0
  65. package/dist/ops/declines.js.map +1 -0
  66. package/dist/ops/log.d.ts +12 -0
  67. package/dist/ops/log.d.ts.map +1 -1
  68. package/dist/ops/log.js.map +1 -1
  69. package/dist/ops/provenance.js +2 -2
  70. package/dist/ops/provenance.js.map +1 -1
  71. package/dist/ops/tidying.d.ts +23 -17
  72. package/dist/ops/tidying.d.ts.map +1 -1
  73. package/dist/ops/tidying.js +1 -76
  74. package/dist/ops/tidying.js.map +1 -1
  75. package/dist/plan-edits.d.ts +55 -0
  76. package/dist/plan-edits.d.ts.map +1 -0
  77. package/dist/plan-edits.js +84 -0
  78. package/dist/plan-edits.js.map +1 -0
  79. package/dist/presence.d.ts +10 -0
  80. package/dist/presence.d.ts.map +1 -1
  81. package/dist/presence.js.map +1 -1
  82. package/dist/revisions/beyond.d.ts +56 -0
  83. package/dist/revisions/beyond.d.ts.map +1 -0
  84. package/dist/revisions/beyond.js +112 -0
  85. package/dist/revisions/beyond.js.map +1 -0
  86. package/dist/revisions/pictured.d.ts +52 -0
  87. package/dist/revisions/pictured.d.ts.map +1 -0
  88. package/dist/revisions/pictured.js +85 -0
  89. package/dist/revisions/pictured.js.map +1 -0
  90. package/dist/revisions/pinned-dates.d.ts +30 -0
  91. package/dist/revisions/pinned-dates.d.ts.map +1 -0
  92. package/dist/revisions/pinned-dates.js +120 -0
  93. package/dist/revisions/pinned-dates.js.map +1 -0
  94. package/dist/revisions/problems.d.ts +57 -0
  95. package/dist/revisions/problems.d.ts.map +1 -0
  96. package/dist/revisions/problems.js +51 -0
  97. package/dist/revisions/problems.js.map +1 -0
  98. package/dist/revisions/sections.d.ts +18 -0
  99. package/dist/revisions/sections.d.ts.map +1 -0
  100. package/dist/revisions/sections.js +91 -0
  101. package/dist/revisions/sections.js.map +1 -0
  102. package/dist/revisions/touched.d.ts +59 -0
  103. package/dist/revisions/touched.d.ts.map +1 -0
  104. package/dist/revisions/touched.js +72 -0
  105. package/dist/revisions/touched.js.map +1 -0
  106. package/dist/revisions/view.d.ts +71 -0
  107. package/dist/revisions/view.d.ts.map +1 -0
  108. package/dist/revisions/view.js +338 -0
  109. package/dist/revisions/view.js.map +1 -0
  110. package/dist/revisions.d.ts +15 -0
  111. package/dist/revisions.d.ts.map +1 -0
  112. package/dist/revisions.js +24 -0
  113. package/dist/revisions.js.map +1 -0
  114. package/dist/scaffold/ui.d.ts.map +1 -1
  115. package/dist/scaffold/ui.js +30 -44
  116. package/dist/scaffold/ui.js.map +1 -1
  117. package/dist/schema/define-node.d.ts +7 -0
  118. package/dist/schema/define-node.d.ts.map +1 -1
  119. package/dist/schema/define-node.js +8 -1
  120. package/dist/schema/define-node.js.map +1 -1
  121. package/dist/seen.js +1 -1
  122. package/dist/seen.js.map +1 -1
  123. package/dist/store.d.ts +5 -1
  124. package/dist/store.d.ts.map +1 -1
  125. package/dist/store.js +12 -4
  126. package/dist/store.js.map +1 -1
  127. package/dist/tidying.d.ts +5 -2
  128. package/dist/tidying.d.ts.map +1 -1
  129. package/dist/tidying.js +12 -3
  130. package/dist/tidying.js.map +1 -1
  131. package/dist/told.d.ts +306 -0
  132. package/dist/told.d.ts.map +1 -0
  133. package/dist/told.js +409 -0
  134. package/dist/told.js.map +1 -0
  135. package/dist/version.d.ts +1 -1
  136. package/dist/version.js +1 -1
  137. package/dist/views/kept.d.ts +96 -0
  138. package/dist/views/kept.d.ts.map +1 -1
  139. package/dist/views/kept.js +75 -0
  140. package/dist/views/kept.js.map +1 -1
  141. package/dist/workflows/step-classify.js +1 -1
  142. package/package.json +9 -1
@@ -0,0 +1,112 @@
1
+ /** Every string an act's arguments hold, however deep. */
2
+ function stringsIn(value, into) {
3
+ if (typeof value === "string")
4
+ into.add(value);
5
+ else if (Array.isArray(value))
6
+ for (const one of value)
7
+ stringsIn(one, into);
8
+ else if (typeof value === "object" && value !== null)
9
+ for (const one of Object.values(value))
10
+ stringsIn(one, into);
11
+ return into;
12
+ }
13
+ const sameAuthor = (a, b) => a.kind === b.kind && (a.id ?? "") === (b.id ?? "");
14
+ /** The record ids a primitive touches. */
15
+ function touched(primitive) {
16
+ switch (primitive.op) {
17
+ case "add-node":
18
+ case "remove-node":
19
+ return [primitive.node.id];
20
+ case "patch-node":
21
+ case "splice-text":
22
+ return [primitive.id];
23
+ case "add-edge":
24
+ case "remove-edge":
25
+ return [primitive.edge.from, primitive.edge.to];
26
+ }
27
+ }
28
+ const nameOf = (node) => [node["title"], node["name"], node["label"]].find((one) => typeof one === "string" && one.length > 0);
29
+ /**
30
+ * WHAT AN ANSWER CHANGED BEYOND WHAT WAS ASKED: every record added,
31
+ * removed or changed, and every link made or taken, that is not the asking
32
+ * act's own — its own being the records the act's arguments name and the
33
+ * first record it made, and a link between two of those.
34
+ */
35
+ export function beyondAsked(answer, options = {}) {
36
+ const askedNames = options.asked ? new Set(options.asked.map((call) => call.name)) : undefined;
37
+ const first = answer.ops[0]?.author;
38
+ const names = new Map();
39
+ const asked = [];
40
+ const beyond = [];
41
+ const changedAt = new Map();
42
+ for (const op of answer.ops) {
43
+ const act = op.mutation?.name ?? null;
44
+ for (const primitive of op.primitives)
45
+ if ((primitive.op === "add-node" || primitive.op === "remove-node") && nameOf(primitive.node))
46
+ names.set(primitive.node.id, nameOf(primitive.node));
47
+ /* An op is asked when it is an act, by whoever asked the first, and one of the acts asked: anything else in the answer is beyond it whole. */
48
+ const isAsked = act !== null && (!first || sameAuthor(op.author, first)) && (!askedNames || askedNames.has(act));
49
+ const ids = new Set(op.primitives.flatMap(touched));
50
+ const targets = new Set();
51
+ if (isAsked) {
52
+ for (const one of stringsIn(op.mutation.args, new Set()))
53
+ if (ids.has(one))
54
+ targets.add(one);
55
+ const made = op.primitives.find((primitive) => primitive.op === "add-node");
56
+ if (made)
57
+ targets.add(made.node.id);
58
+ asked.push({ op: op.id, act, records: [...targets] });
59
+ }
60
+ for (const primitive of op.primitives) {
61
+ if (primitive.op === "add-node" || primitive.op === "remove-node") {
62
+ if (!targets.has(primitive.node.id))
63
+ beyond.push({ change: primitive.op === "add-node" ? "added" : "removed", record: primitive.node.id, kind: primitive.node.kind, op: op.id, act });
64
+ }
65
+ else if (primitive.op === "patch-node" || primitive.op === "splice-text") {
66
+ if (targets.has(primitive.id))
67
+ continue;
68
+ const fields = primitive.op === "patch-node" ? Object.keys(primitive.after) : [primitive.field];
69
+ const key = `${op.id} ${primitive.id}`;
70
+ const at = changedAt.get(key);
71
+ if (at)
72
+ for (const field of fields)
73
+ at.fields.add(field);
74
+ else {
75
+ changedAt.set(key, { fields: new Set(fields), entry: beyond.length });
76
+ beyond.push({ change: "changed", record: primitive.id, fields, op: op.id, act });
77
+ }
78
+ }
79
+ else if (!(targets.has(primitive.edge.from) && targets.has(primitive.edge.to))) {
80
+ beyond.push({ change: primitive.op === "add-edge" ? "linked" : "unlinked", edge: primitive.edge, op: op.id, act });
81
+ }
82
+ }
83
+ }
84
+ for (const { fields, entry } of changedAt.values()) {
85
+ const one = beyond[entry];
86
+ beyond[entry] = { ...one, fields: [...fields] };
87
+ }
88
+ const label = (id) => {
89
+ const name = options.label?.(id) ?? names.get(id);
90
+ return name ? `"${name}"` : id;
91
+ };
92
+ const groups = [];
93
+ const of = (change) => beyond.filter((one) => one.change === change);
94
+ const changed = of("changed");
95
+ if (changed.length > 0)
96
+ groups.push(`changed ${changed.map((one) => `${label(one.record)} (${one.fields.join(", ")})`).join(", ")}`);
97
+ const added = of("added");
98
+ if (added.length > 0)
99
+ groups.push(`added ${added.map((one) => `${one.kind} ${label(one.record)}`).join(", ")}`);
100
+ const removed = of("removed");
101
+ if (removed.length > 0)
102
+ groups.push(`removed ${removed.map((one) => `${one.kind} ${label(one.record)}`).join(", ")}`);
103
+ const linked = of("linked");
104
+ if (linked.length > 0)
105
+ groups.push(`linked ${linked.map((one) => `${label(one.edge.from)} ${one.edge.kind} ${label(one.edge.to)}`).join(", ")}`);
106
+ const unlinked = of("unlinked");
107
+ if (unlinked.length > 0)
108
+ groups.push(`took the link ${unlinked.map((one) => `${label(one.edge.from)} ${one.edge.kind} ${label(one.edge.to)}`).join(", ")}`);
109
+ const said = groups.length > 0 ? [`Besides what was asked, it also ${groups.join("; ")}.`] : [];
110
+ return { asked, beyond, said, text: said[0] ?? "It changed only what was asked." };
111
+ }
112
+ //# sourceMappingURL=beyond.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"beyond.js","sourceRoot":"","sources":["../../src/revisions/beyond.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,52 @@
1
+ import type { DrawnSection } from "./sections.js";
2
+ /** A section of a page where it stands, in CSS pixels from the top of what scrolls. */
3
+ export interface PlacedSection extends DrawnSection {
4
+ readonly top: number;
5
+ readonly bottom: number;
6
+ }
7
+ /** A page as `MEASURE_PICTURED_PAGE` measured it. */
8
+ export interface PageMeasure {
9
+ /** How tall the whole place is: the height of what scrolls. */
10
+ readonly height: number;
11
+ /** How far it was scrolled when measured. */
12
+ readonly top: number;
13
+ /** How much of it a window shows: what a picture of the window holds. */
14
+ readonly window: number;
15
+ readonly sections: readonly PlacedSection[];
16
+ }
17
+ /** How much of a page a picture held, and what it left out. */
18
+ export interface PictureCoverage {
19
+ /** True when the picture held the whole page. */
20
+ readonly whole: boolean;
21
+ readonly height: number;
22
+ /** The part of the page pictured, top and bottom, in CSS pixels. */
23
+ readonly pictured: {
24
+ readonly top: number;
25
+ readonly bottom: number;
26
+ };
27
+ /** Sections wholly above the picture, and wholly below it. */
28
+ readonly above: readonly PlacedSection[];
29
+ readonly below: readonly PlacedSection[];
30
+ /** In a sentence: "First screen only (900 of 5,100px); not shown: This week, Dinner." */
31
+ readonly said: string;
32
+ }
33
+ /**
34
+ * MEASURE THE PAGE AS IT IS PICTURED: evaluate it in the page (Playwright's
35
+ * `page.evaluate`, a host's own browser) right before the picture is taken,
36
+ * and hand what it answers to `picturedCoverage`. It reads the box the
37
+ * place scrolls in — an embed's `[data-embed-content]`, the tallest box that
38
+ * scrolls, or the document — and every section on it, a worker view's
39
+ * among them (each view draws into an open shadow root).
40
+ */
41
+ export declare const MEASURE_PICTURED_PAGE = "(() => {\n const scrolls = (el) => /(auto|scroll)/.test(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight + 1;\n const content = document.querySelector(\"[data-embed-content]\");\n const box = content && scrolls(content)\n ? content\n : [...document.querySelectorAll(\"body *\")].filter((el) => scrolls(el) && el.clientHeight >= innerHeight / 2).sort((a, b) => b.clientHeight - a.clientHeight)[0];\n const doc = document.scrollingElement || document.documentElement;\n const height = box ? box.scrollHeight : Math.max(doc.scrollHeight, document.body ? document.body.scrollHeight : 0);\n const top = box ? box.scrollTop : scrollY;\n const windowHeight = box ? box.clientHeight : innerHeight;\n const origin = box ? box.getBoundingClientRect().top - box.scrollTop : -scrollY;\n const LANDMARKS = { section: null, article: null, form: null, region: null, nav: \"navigation\", navigation: \"navigation\", main: \"main content\", header: \"header\", banner: \"header\", footer: \"footer\", contentinfo: \"footer\", aside: \"aside\", complementary: \"aside\", search: \"search\" };\n const said = (text) => (text || \"\").replace(/\\s+/g, \" \").trim();\n const tagOf = (el) => (el.getAttribute(\"data-graview-as\") || el.localName || \"\").toLowerCase();\n const level = (el) => /^h[1-6]$/.test(tagOf(el)) ? 1 : el.getAttribute(\"role\") === \"heading\" ? 1 : 0;\n const all = [];\n const walk = (root) => {\n for (const el of root.querySelectorAll(\"*\")) {\n all.push(el);\n if (el.shadowRoot) walk(el.shadowRoot);\n }\n };\n walk(document);\n const sections = [];\n const seen = new Set();\n for (const el of all) {\n if (el.closest(\"[data-testid=app-bar], [role=dialog]\")) continue;\n const rect = el.getBoundingClientRect();\n if (rect.height <= 0 || rect.width <= 0 || getComputedStyle(el).visibility === \"hidden\") continue;\n let name = \"\";\n let as = \"\";\n if (level(el)) {\n name = said(el.textContent);\n as = \"heading\";\n } else {\n const role = (el.getAttribute(\"role\") || \"\").toLowerCase();\n const tag = tagOf(el);\n const what = role in LANDMARKS ? role : tag in LANDMARKS ? tag : \"\";\n if (!what) continue;\n const root = el.getRootNode();\n const namedBy = (el.getAttribute(\"aria-labelledby\") || \"\").split(/\\s+/).map((id) => id && root.getElementById ? root.getElementById(id) : null).filter(Boolean).map((one) => said(one.textContent)).join(\" \");\n const heading = [...el.querySelectorAll(\"*\")].find(level);\n name = said(el.getAttribute(\"aria-label\")) || namedBy || (heading ? said(heading.textContent) : \"\") || LANDMARKS[what] || \"\";\n as = what === \"region\" ? \"section\" : what;\n }\n if (!name || seen.has(name.toLowerCase())) continue;\n seen.add(name.toLowerCase());\n sections.push({ name: name.length > 80 ? name.slice(0, 79) + \"\u2026\" : name, as, top: Math.round(rect.top - origin), bottom: Math.round(rect.bottom - origin) });\n }\n return { height: Math.ceil(height), top: Math.round(top), window: Math.round(windowHeight), sections };\n})()";
42
+ /**
43
+ * HOW MUCH OF A PAGE A PICTURE HELD. `pictured` is the part of the page in
44
+ * the picture, from the top of what scrolls; left out, it is the window
45
+ * where the page was measured. A section is shown when any of it is in the
46
+ * picture; one wholly above or below is named as not shown.
47
+ */
48
+ export declare function picturedCoverage(measure: PageMeasure, pictured?: {
49
+ readonly top: number;
50
+ readonly height: number;
51
+ }): PictureCoverage;
52
+ //# sourceMappingURL=pictured.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pictured.d.ts","sourceRoot":"","sources":["../../src/revisions/pictured.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,uFAAuF;AACvF,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED,qDAAqD;AACrD,MAAM,WAAW,WAAW;IAC1B,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,6CAA6C;IAC7C,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CAC7C;AAED,+DAA+D;AAC/D,MAAM,WAAW,eAAe;IAC9B,iDAAiD;IACjD,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,oEAAoE;IACpE,QAAQ,CAAC,QAAQ,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACrE,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,aAAa,EAAE,CAAC;IACzC,yFAAyF;IACzF,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,qBAAqB,qlGAkD7B,CAAC;AAMN;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,EAAE;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAAG,eAAe,CAcpI"}
@@ -0,0 +1,85 @@
1
+ /**
2
+ * MEASURE THE PAGE AS IT IS PICTURED: evaluate it in the page (Playwright's
3
+ * `page.evaluate`, a host's own browser) right before the picture is taken,
4
+ * and hand what it answers to `picturedCoverage`. It reads the box the
5
+ * place scrolls in — an embed's `[data-embed-content]`, the tallest box that
6
+ * scrolls, or the document — and every section on it, a worker view's
7
+ * among them (each view draws into an open shadow root).
8
+ */
9
+ export const MEASURE_PICTURED_PAGE = `(() => {
10
+ const scrolls = (el) => /(auto|scroll)/.test(getComputedStyle(el).overflowY) && el.scrollHeight > el.clientHeight + 1;
11
+ const content = document.querySelector("[data-embed-content]");
12
+ const box = content && scrolls(content)
13
+ ? content
14
+ : [...document.querySelectorAll("body *")].filter((el) => scrolls(el) && el.clientHeight >= innerHeight / 2).sort((a, b) => b.clientHeight - a.clientHeight)[0];
15
+ const doc = document.scrollingElement || document.documentElement;
16
+ const height = box ? box.scrollHeight : Math.max(doc.scrollHeight, document.body ? document.body.scrollHeight : 0);
17
+ const top = box ? box.scrollTop : scrollY;
18
+ const windowHeight = box ? box.clientHeight : innerHeight;
19
+ const origin = box ? box.getBoundingClientRect().top - box.scrollTop : -scrollY;
20
+ const LANDMARKS = { section: null, article: null, form: null, region: null, nav: "navigation", navigation: "navigation", main: "main content", header: "header", banner: "header", footer: "footer", contentinfo: "footer", aside: "aside", complementary: "aside", search: "search" };
21
+ const said = (text) => (text || "").replace(/\\s+/g, " ").trim();
22
+ const tagOf = (el) => (el.getAttribute("data-graview-as") || el.localName || "").toLowerCase();
23
+ const level = (el) => /^h[1-6]$/.test(tagOf(el)) ? 1 : el.getAttribute("role") === "heading" ? 1 : 0;
24
+ const all = [];
25
+ const walk = (root) => {
26
+ for (const el of root.querySelectorAll("*")) {
27
+ all.push(el);
28
+ if (el.shadowRoot) walk(el.shadowRoot);
29
+ }
30
+ };
31
+ walk(document);
32
+ const sections = [];
33
+ const seen = new Set();
34
+ for (const el of all) {
35
+ if (el.closest("[data-testid=app-bar], [role=dialog]")) continue;
36
+ const rect = el.getBoundingClientRect();
37
+ if (rect.height <= 0 || rect.width <= 0 || getComputedStyle(el).visibility === "hidden") continue;
38
+ let name = "";
39
+ let as = "";
40
+ if (level(el)) {
41
+ name = said(el.textContent);
42
+ as = "heading";
43
+ } else {
44
+ const role = (el.getAttribute("role") || "").toLowerCase();
45
+ const tag = tagOf(el);
46
+ const what = role in LANDMARKS ? role : tag in LANDMARKS ? tag : "";
47
+ if (!what) continue;
48
+ const root = el.getRootNode();
49
+ const namedBy = (el.getAttribute("aria-labelledby") || "").split(/\\s+/).map((id) => id && root.getElementById ? root.getElementById(id) : null).filter(Boolean).map((one) => said(one.textContent)).join(" ");
50
+ const heading = [...el.querySelectorAll("*")].find(level);
51
+ name = said(el.getAttribute("aria-label")) || namedBy || (heading ? said(heading.textContent) : "") || LANDMARKS[what] || "";
52
+ as = what === "region" ? "section" : what;
53
+ }
54
+ if (!name || seen.has(name.toLowerCase())) continue;
55
+ seen.add(name.toLowerCase());
56
+ sections.push({ name: name.length > 80 ? name.slice(0, 79) + "…" : name, as, top: Math.round(rect.top - origin), bottom: Math.round(rect.bottom - origin) });
57
+ }
58
+ return { height: Math.ceil(height), top: Math.round(top), window: Math.round(windowHeight), sections };
59
+ })()`;
60
+ const MOST_NAMED = 8;
61
+ const px = (n) => Math.round(n).toLocaleString("en-US");
62
+ const names = (sections) => (sections.length <= MOST_NAMED ? sections.map((one) => one.name).join(", ") : `${sections.slice(0, MOST_NAMED).map((one) => one.name).join(", ")} and ${sections.length - MOST_NAMED} more`);
63
+ /**
64
+ * HOW MUCH OF A PAGE A PICTURE HELD. `pictured` is the part of the page in
65
+ * the picture, from the top of what scrolls; left out, it is the window
66
+ * where the page was measured. A section is shown when any of it is in the
67
+ * picture; one wholly above or below is named as not shown.
68
+ */
69
+ export function picturedCoverage(measure, pictured) {
70
+ const top = Math.max(0, pictured?.top ?? measure.top);
71
+ const bottom = Math.min(measure.height, top + (pictured?.height ?? measure.window));
72
+ const whole = top <= 0 && bottom >= measure.height - 1;
73
+ const above = measure.sections.filter((one) => one.bottom <= top);
74
+ const below = measure.sections.filter((one) => one.top >= bottom);
75
+ let said;
76
+ if (whole)
77
+ said = `The whole page is pictured (${px(measure.height)}px).`;
78
+ else {
79
+ const part = top <= 0 ? `First screen only (${px(bottom)} of ${px(measure.height)}px)` : `Only ${px(top)}–${px(bottom)} of ${px(measure.height)}px`;
80
+ const left = [...(above.length > 0 ? [`above it, ${names(above)}`] : []), ...(below.length > 0 ? [`${above.length > 0 ? "below it, " : ""}${names(below)}`] : [])];
81
+ said = left.length > 0 ? `${part}; not shown: ${left.join("; ")}.` : `${part}; no named section is wholly outside it.`;
82
+ }
83
+ return { whole, height: measure.height, pictured: { top, bottom }, above, below, said };
84
+ }
85
+ //# sourceMappingURL=pictured.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pictured.js","sourceRoot":"","sources":["../../src/revisions/pictured.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ /** One thing in a view's source that pins a day, and the sentence that says so. */
2
+ export interface PinnedDate {
3
+ /** Where in the source: `source line 12`. */
4
+ readonly at: string;
5
+ /** The words as the source writes them: `TODAY = "2026-11-01"`, `Tomorrow · Mon 2 Nov`, `due Fri 30 Oct`. */
6
+ readonly phrase: string;
7
+ /** `today`, a date given to a name that means today; `day-words`, today's words beside a written date; `past`, a written date already gone by. */
8
+ readonly why: "today" | "day-words" | "past";
9
+ /** "Home may be out of date: it says “Tomorrow · Mon 2 Nov” and today is Wed, Nov 4. Read today from graview instead." */
10
+ readonly says: string;
11
+ }
12
+ export interface DatesPinnedOptions {
13
+ /** The app's today, `YYYY-MM-DD` (`store.today() ?? isoToday()`). */
14
+ readonly today: string;
15
+ /** What the view is called in the sentence: its place's title ("Home"). "This view" when unsaid. */
16
+ readonly title?: string;
17
+ /** The locale today is said in. The app's when unsaid. */
18
+ readonly locale?: string;
19
+ /** How many days back a written date counts as pinning today: 31 by default, so a founding year or a launch long gone is not one. */
20
+ readonly pastDays?: number;
21
+ }
22
+ /**
23
+ * WHAT IN A VIEW'S SOURCE PINS A DAY, each said against the app's today:
24
+ * a date given to a name that means today, today's words beside a written
25
+ * date ("Tomorrow · Mon 2 Nov"), and a written date that has gone by in the
26
+ * last month ("due Fri 30 Oct"). Empty for a view that reads today from
27
+ * `graview`.
28
+ */
29
+ export declare function datesPinned(source: string, options: DatesPinnedOptions): readonly PinnedDate[];
30
+ //# sourceMappingURL=pinned-dates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinned-dates.d.ts","sourceRoot":"","sources":["../../src/revisions/pinned-dates.ts"],"names":[],"mappings":"AAkBA,mFAAmF;AACnF,MAAM,WAAW,UAAU;IACzB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,6GAA6G;IAC7G,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,kJAAkJ;IAClJ,QAAQ,CAAC,GAAG,EAAE,OAAO,GAAG,WAAW,GAAG,MAAM,CAAC;IAC7C,0HAA0H;IAC1H,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oGAAoG;IACpG,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,0DAA0D;IAC1D,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,qIAAqI;IACrI,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;CAC5B;AAqDD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,kBAAkB,GAAG,SAAS,UAAU,EAAE,CA+C9F"}
@@ -0,0 +1,120 @@
1
+ /*
2
+ * A VIEW THAT PINS TODAY (Roadmap f-views-know-today).
3
+ *
4
+ * A chat added records to a Cloud app, every act succeeded, and the app's
5
+ * home went on saying the day before: its view held `TODAY = "2026-11-01"`,
6
+ * "Tomorrow · Mon 2 Nov" and "due Fri 30 Oct" as written text. Nothing
7
+ * told the agent its home was now wrong, so it said it was done. This
8
+ * reads a view's source for what pins a day — a date given to a name that
9
+ * means today, day words beside a written date, and a written date already
10
+ * past — and says each in a sentence against the app's today, so a check,
11
+ * an act's answer and a headless run can carry it.
12
+ *
13
+ * Read from the source's text alone: a date the view works out from
14
+ * `graview.today` is never written in it, so it is never said.
15
+ */
16
+ import { weekdayAsRead } from "../days.js";
17
+ import { addDays } from "../wall-time.js";
18
+ const WEEKDAY = String.raw `(?:Mon(?:day)?|Tue(?:s(?:day)?)?|Wed(?:nesday)?|Thu(?:r(?:s(?:day)?)?)?|Fri(?:day)?|Sat(?:urday)?|Sun(?:day)?)\.?`;
19
+ const MONTHS = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"];
20
+ const MONTH = String.raw `(?:Jan(?:uary)?|Feb(?:ruary)?|Mar(?:ch)?|Apr(?:il)?|May|June?|July?|Aug(?:ust)?|Sept?(?:ember)?|Oct(?:ober)?|Nov(?:ember)?|Dec(?:ember)?)\.?`;
21
+ const ORDINAL = String.raw `(?:st|nd|rd|th)?`;
22
+ /** A written date: `2026-11-01`, `Mon 2 Nov`, `2 November 2026`, `Fri, Oct 30`, `Nov 2, 2026`. */
23
+ const DATES = [
24
+ /\b(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})\b/g,
25
+ new RegExp(String.raw `\b(?:${WEEKDAY},?\s+)?(?<day>\d{1,2})${ORDINAL}\s+(?<name>${MONTH})(?![a-z])(?:,?\s+(?<year>\d{4})\b)?`, "g"),
26
+ new RegExp(String.raw `\b(?:${WEEKDAY},?\s+)?(?<name>${MONTH})\s+(?<day>\d{1,2})${ORDINAL}(?!\d)\b(?:,?\s+(?<year>\d{4})\b)?`, "g"),
27
+ ];
28
+ /** A name that means today: `TODAY`, `today`, `now`, `currentDay`, `CURRENT_DATE`. */
29
+ const TODAY_NAME = /^(?:.*today.*|now|current_?(?:day|date))$/i;
30
+ /** A date given to a name: `const TODAY = "2026-11-01"`, `today: "2026-11-01"`, `now = new Date("2026-11-01")`. */
31
+ const ASSIGNED = /\b([A-Za-z_$][\w$]*)\s*[:=]\s*(?:new\s+Date\(\s*)?(["'`])(\d{4}-\d{2}-\d{2})[^"'`\n]*\2/g;
32
+ const DAY_WORD = String.raw `(?:today|tomorrow|yesterday|tonight)`;
33
+ const BETWEEN = String.raw `[\s·•|,:()\-–—]{1,5}`;
34
+ /** The day a written date names, its year the one nearest today where it says none. */
35
+ function dayOf(groups, today) {
36
+ const month = groups["month"] !== undefined ? Number(groups["month"]) : MONTHS.indexOf(groups["name"].slice(0, 3)) + 1;
37
+ const date = Number(groups["day"]);
38
+ if (!(month >= 1 && month <= 12 && date >= 1 && date <= 31))
39
+ return undefined;
40
+ const at = (year) => `${year}-${String(month).padStart(2, "0")}-${String(date).padStart(2, "0")}`;
41
+ if (groups["year"] !== undefined)
42
+ return at(Number(groups["year"]));
43
+ const year = Number(today.slice(0, 4));
44
+ const away = (day) => Math.abs(Date.parse(day) - Date.parse(today));
45
+ return [year - 1, year, year + 1].map(at).sort((a, b) => away(a) - away(b))[0];
46
+ }
47
+ function writtenDates(source, today) {
48
+ const out = [];
49
+ for (const pattern of DATES) {
50
+ for (const match of source.matchAll(pattern)) {
51
+ const from = match.index;
52
+ const to = from + match[0].length;
53
+ if (out.some((one) => from < one.to && to > one.from))
54
+ continue;
55
+ const day = dayOf(match.groups ?? {}, today);
56
+ if (day !== undefined && !Number.isNaN(Date.parse(day)))
57
+ out.push({ from, to, day });
58
+ }
59
+ }
60
+ return out.sort((a, b) => a.from - b.from);
61
+ }
62
+ const lineAt = (source, index) => `source line ${source.slice(0, index).split("\n").length}`;
63
+ /**
64
+ * WHAT IN A VIEW'S SOURCE PINS A DAY, each said against the app's today:
65
+ * a date given to a name that means today, today's words beside a written
66
+ * date ("Tomorrow · Mon 2 Nov"), and a written date that has gone by in the
67
+ * last month ("due Fri 30 Oct"). Empty for a view that reads today from
68
+ * `graview`.
69
+ */
70
+ export function datesPinned(source, options) {
71
+ if (typeof source !== "string" || !/^\d{4}-\d{2}-\d{2}$/.test(options.today))
72
+ return [];
73
+ const { today } = options;
74
+ const title = options.title?.trim() || "This view";
75
+ const todaySaid = weekdayAsRead(today, { weekday: "short", year: false }, options.locale);
76
+ const say = (phrase) => `${title} may be out of date: it says “${phrase}” and today is ${todaySaid}. Read today from graview instead.`;
77
+ const out = [];
78
+ const taken = (from, to) => out.some((one) => from < one.to && to > one.from);
79
+ for (const match of source.matchAll(ASSIGNED)) {
80
+ if (!TODAY_NAME.test(match[1]))
81
+ continue;
82
+ const phrase = `${match[1]} = "${match[3]}"`;
83
+ out.push({ at: lineAt(source, match.index), phrase, why: "today", says: say(phrase), from: match.index, to: match.index + match[0].length });
84
+ }
85
+ const before = new RegExp(String.raw `\b${DAY_WORD}${BETWEEN}$`, "i");
86
+ const after = new RegExp(String.raw `^${BETWEEN}${DAY_WORD}\b`, "i");
87
+ const leading = /\b(?:due|by|until|on)\s+$/i;
88
+ const oldest = addDays(today, -(options.pastDays ?? 31));
89
+ for (const date of writtenDates(source, today)) {
90
+ if (taken(date.from, date.to))
91
+ continue;
92
+ /* A day handed to graview.fromToday is said against today, whatever today is. */
93
+ if (/fromToday\(\s*["'`]$/.test(source.slice(Math.max(0, date.from - 24), date.from)))
94
+ continue;
95
+ const ahead = source.slice(Math.max(0, date.from - 16), date.from);
96
+ const behind = source.slice(date.to, date.to + 16);
97
+ const word = before.exec(ahead);
98
+ const wordAfter = after.exec(behind);
99
+ if (word || wordAfter) {
100
+ const from = word ? date.from - word[0].length : date.from;
101
+ const to = wordAfter ? date.to + wordAfter[0].length : date.to;
102
+ const phrase = source.slice(from, to).replace(/\s+/g, " ").trim();
103
+ out.push({ at: lineAt(source, from), phrase, why: "day-words", says: say(phrase), from, to });
104
+ continue;
105
+ }
106
+ if (date.day < today && date.day >= oldest) {
107
+ const lead = leading.exec(ahead);
108
+ const from = lead ? date.from - lead[0].length : date.from;
109
+ const phrase = source.slice(from, date.to).replace(/\s+/g, " ").trim();
110
+ out.push({ at: lineAt(source, from), phrase, why: "past", says: say(phrase), from, to: date.to });
111
+ }
112
+ }
113
+ /* Each phrase once, in the order the source says them. */
114
+ const seen = new Set();
115
+ return out
116
+ .sort((a, b) => a.from - b.from)
117
+ .filter((one) => !seen.has(one.phrase) && seen.add(one.phrase))
118
+ .map(({ at, phrase, why, says }) => ({ at, phrase, why, says }));
119
+ }
120
+ //# sourceMappingURL=pinned-dates.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pinned-dates.js","sourceRoot":"","sources":["../../src/revisions/pinned-dates.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,57 @@
1
+ import type { InvariantDefinition, Violation } from "../invariants/types.js";
2
+ /** A problem a view says: the view by name, where in it, and what it says (a headless run's `description.problems`). */
3
+ export interface ViewProblem {
4
+ readonly view: string;
5
+ readonly at?: string;
6
+ readonly says: string;
7
+ }
8
+ /** What was judged at one moment: the rules' problems and the views'. */
9
+ export interface ProblemSet {
10
+ readonly rules?: readonly Violation[];
11
+ readonly views?: readonly ViewProblem[];
12
+ }
13
+ /** A problem one side has and the other does not. */
14
+ export type ChangedProblem = {
15
+ readonly key: string;
16
+ readonly kind: "rule";
17
+ readonly rule: string;
18
+ /** The record it is about, where it is about one. */
19
+ readonly subject?: string;
20
+ readonly says: string;
21
+ /** The act the rule names to repair it, first; `missing` is what its caller still chooses. */
22
+ readonly repair?: {
23
+ readonly act: string;
24
+ readonly label: string;
25
+ readonly args?: Readonly<Record<string, unknown>>;
26
+ readonly missing?: readonly string[];
27
+ };
28
+ readonly violation: Violation;
29
+ } | {
30
+ readonly key: string;
31
+ readonly kind: "view";
32
+ readonly view: string;
33
+ readonly at?: string;
34
+ readonly says: string;
35
+ };
36
+ /** What a change broke and mended, as entries and in words. */
37
+ export interface ProblemsMade {
38
+ /** Problems after it that were not before: rules that held and fail, and view problems new after. */
39
+ readonly made: readonly ChangedProblem[];
40
+ /** Problems before it that are not after. */
41
+ readonly mended: readonly ChangedProblem[];
42
+ readonly said: readonly string[];
43
+ /** "This change broke: …", or that it broke nothing. */
44
+ readonly text: string;
45
+ }
46
+ /** A view problem's key: its view, where, and its words. */
47
+ export declare const viewProblemKey: (problem: ViewProblem) => string;
48
+ /**
49
+ * WHAT A CHANGE BROKE: the problems after it that were not before, and
50
+ * those it mended. `rules` are the app's rules, so a rule written in the
51
+ * rule language is one problem whether or not its words were loaded
52
+ * (`shapedRules`); without them, a problem is known by its words.
53
+ */
54
+ export declare function problemsMade(before: ProblemSet, after: ProblemSet, options?: {
55
+ readonly rules?: readonly Pick<InvariantDefinition, "name" | "shape">[];
56
+ }): ProblemsMade;
57
+ //# sourceMappingURL=problems.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"problems.d.ts","sourceRoot":"","sources":["../../src/revisions/problems.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EAAE,mBAAmB,EAAU,SAAS,EAAE,MAAM,wBAAwB,CAAC;AAGrF,wHAAwH;AACxH,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,yEAAyE;AACzE,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,SAAS,EAAE,CAAC;IACtC,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,WAAW,EAAE,CAAC;CACzC;AAED,qDAAqD;AACrD,MAAM,MAAM,cAAc,GACtB;IACE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qDAAqD;IACrD,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,CAAC,EAAE;QAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;QAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;KAAE,CAAC;IAC5J,QAAQ,CAAC,SAAS,EAAE,SAAS,CAAC;CAC/B,GACD;IAAE,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAExH,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,qGAAqG;IACrG,QAAQ,CAAC,IAAI,EAAE,SAAS,cAAc,EAAE,CAAC;IACzC,6CAA6C;IAC7C,QAAQ,CAAC,MAAM,EAAE,SAAS,cAAc,EAAE,CAAC;IAC3C,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,4DAA4D;AAC5D,eAAO,MAAM,cAAc,GAAI,SAAS,WAAW,KAAG,MAAoE,CAAC;AAkB3H;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE;IAAE,QAAQ,CAAC,KAAK,CAAC,EAAE,SAAS,IAAI,CAAC,mBAAmB,EAAE,MAAM,GAAG,OAAO,CAAC,EAAE,CAAA;CAAO,GAAG,YAAY,CAa3K"}
@@ -0,0 +1,51 @@
1
+ /*
2
+ * THE PROBLEMS A CHANGE MADE (Roadmap f-revisions-say-what-broke).
3
+ *
4
+ * An act, a batch or a proposed view can break what held: a rule that held
5
+ * before fails after, a view says a problem it did not. A host that judged
6
+ * the app before and after a change — the store's `violations()`, a
7
+ * headless run's problems — hands both sets here and is told what is new,
8
+ * each keyed as it will be keyed next time (a rule's problem by
9
+ * `violationKey`, a view's by its view, where and words), in words, and with
10
+ * the act a rule names to repair it, so an answer can carry "this change
11
+ * broke: …" and how to mend it rather than leave it to a later look.
12
+ */
13
+ import { problemWords } from "../invariants/line.js";
14
+ import { problemsMoved, violationKey, shapedRules } from "../store.js";
15
+ /** A view problem's key: its view, where, and its words. */
16
+ export const viewProblemKey = (problem) => `view:${problem.view}|${problem.at ?? ""}|${problem.says}`;
17
+ /** Only a rule that judged and failed is broken: one that could not judge (`could-not-judge`, `over-budget`) is not said as made. */
18
+ const failed = (v) => v.status === undefined || v.status === "violated";
19
+ const repairOf = (repair) => repair ? { repair: { act: repair.mutation, label: repair.label, ...(repair.args ? { args: repair.args } : {}), ...(repair.missing && repair.missing.length > 0 ? { missing: repair.missing } : {}) } } : {};
20
+ function ruleEntry(v, shaped) {
21
+ return { key: violationKey(v, shaped), kind: "rule", rule: v.invariant, ...(v.subjectId ? { subject: v.subjectId } : {}), says: problemWords(v), ...repairOf(v.repairs[0]), violation: v };
22
+ }
23
+ function sayProblem(problem) {
24
+ if (problem.kind === "view")
25
+ return `the view "${problem.view}"${problem.at ? ` at ${problem.at}` : ""} says: ${problem.says.replace(/[.\s]+$/, "")}`;
26
+ const repair = problem.repair ? ` (repair: ${problem.repair.act}${problem.repair.missing ? `, choosing ${problem.repair.missing.join(", ")}` : ""} — ${problem.repair.label})` : "";
27
+ return `${problem.says.replace(/[.\s]+$/, "")}${repair}`;
28
+ }
29
+ /**
30
+ * WHAT A CHANGE BROKE: the problems after it that were not before, and
31
+ * those it mended. `rules` are the app's rules, so a rule written in the
32
+ * rule language is one problem whether or not its words were loaded
33
+ * (`shapedRules`); without them, a problem is known by its words.
34
+ */
35
+ export function problemsMade(before, after, options = {}) {
36
+ const rules = options.rules ?? [];
37
+ const shaped = shapedRules(rules);
38
+ const moved = problemsMoved(rules, (before.rules ?? []).filter(failed), (after.rules ?? []).filter(failed));
39
+ const viewsBefore = new Set((before.views ?? []).map(viewProblemKey));
40
+ const viewsAfter = new Set((after.views ?? []).map(viewProblemKey));
41
+ const viewEntry = (problem) => ({ key: viewProblemKey(problem), kind: "view", view: problem.view, ...(problem.at ? { at: problem.at } : {}), says: problem.says });
42
+ const made = [...moved.introduces.map((v) => ruleEntry(v, shaped)), ...(after.views ?? []).filter((one) => !viewsBefore.has(viewProblemKey(one))).map(viewEntry)];
43
+ const mended = [...moved.resolves.map((v) => ruleEntry(v, shaped)), ...(before.views ?? []).filter((one) => !viewsAfter.has(viewProblemKey(one))).map(viewEntry)];
44
+ const said = [];
45
+ if (made.length > 0)
46
+ said.push(`This change broke ${made.length === 1 ? "one thing that held" : `${made.length} things that held`}: ${made.map(sayProblem).join("; ")}. Fix ${made.length === 1 ? "it" : "them"} before going on.`);
47
+ if (mended.length > 0)
48
+ said.push(`It mended ${mended.length === 1 ? "one problem" : `${mended.length} problems`}: ${mended.map(sayProblem).join("; ")}.`);
49
+ return { made, mended, said, text: made.length > 0 ? said.join(" ") : `This change broke nothing that held.${mended.length > 0 ? ` ${said.join(" ")}` : ""}` };
50
+ }
51
+ //# sourceMappingURL=problems.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"problems.js","sourceRoot":"","sources":["../../src/revisions/problems.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ /** Anything that reads like an element: a DOM `Element`, or a headless run's `TreeElement`. */
2
+ export interface ElementLike {
3
+ readonly localName?: string;
4
+ readonly nodeType?: number;
5
+ getAttribute(name: string): string | null;
6
+ readonly childNodes: ArrayLike<unknown>;
7
+ readonly textContent: string | null;
8
+ }
9
+ /** One section of a drawing: what a person would call it, and what it is (`heading`, `section`, `nav` …). */
10
+ export interface DrawnSection {
11
+ readonly name: string;
12
+ readonly as: string;
13
+ }
14
+ /** Every element under `root`, `root` first, in document order. */
15
+ export declare function elementsOf(root: ElementLike): Generator<ElementLike>;
16
+ /** The sections a drawing has, each once by name, in document order. */
17
+ export declare function sectionsOfDrawing(root: ElementLike): DrawnSection[];
18
+ //# sourceMappingURL=sections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sections.d.ts","sourceRoot":"","sources":["../../src/revisions/sections.ts"],"names":[],"mappings":"AAcA,+FAA+F;AAC/F,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC1C,QAAQ,CAAC,UAAU,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACxC,QAAQ,CAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CACrC;AAED,6GAA6G;AAC7G,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;CACrB;AAwBD,mEAAmE;AACnE,wBAAiB,UAAU,CAAC,IAAI,EAAE,WAAW,GAAG,SAAS,CAAC,WAAW,CAAC,CAGrE;AAYD,wEAAwE;AACxE,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,WAAW,GAAG,YAAY,EAAE,CAmCnE"}