@graview/core 0.1.63 → 0.1.65

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 (144) hide show
  1. package/dist/catalog.d.ts +32 -2
  2. package/dist/catalog.d.ts.map +1 -1
  3. package/dist/catalog.js +1 -0
  4. package/dist/catalog.js.map +1 -1
  5. package/dist/compose.d.ts +25 -1
  6. package/dist/compose.d.ts.map +1 -1
  7. package/dist/compose.js +56 -0
  8. package/dist/compose.js.map +1 -1
  9. package/dist/conformance/index.d.ts +6 -0
  10. package/dist/conformance/index.d.ts.map +1 -1
  11. package/dist/conformance/index.js +3 -0
  12. package/dist/conformance/index.js.map +1 -1
  13. package/dist/conformance/plan-host.d.ts +73 -0
  14. package/dist/conformance/plan-host.d.ts.map +1 -0
  15. package/dist/conformance/plan-host.js +64 -0
  16. package/dist/conformance/plan-host.js.map +1 -0
  17. package/dist/conformance/told-host.d.ts +40 -0
  18. package/dist/conformance/told-host.d.ts.map +1 -0
  19. package/dist/conformance/told-host.js +57 -0
  20. package/dist/conformance/told-host.js.map +1 -0
  21. package/dist/conformance/view-revision-host.d.ts +36 -0
  22. package/dist/conformance/view-revision-host.d.ts.map +1 -0
  23. package/dist/conformance/view-revision-host.js +42 -0
  24. package/dist/conformance/view-revision-host.js.map +1 -0
  25. package/dist/document/brand-check.d.ts.map +1 -1
  26. package/dist/document/brand-check.js +8 -2
  27. package/dist/document/brand-check.js.map +1 -1
  28. package/dist/document/connection-findings.js +15 -8
  29. package/dist/document/connection-findings.js.map +1 -1
  30. package/dist/document/connection-spec.d.ts +22 -0
  31. package/dist/document/connection-spec.d.ts.map +1 -1
  32. package/dist/document/connection-spec.js +24 -2
  33. package/dist/document/connection-spec.js.map +1 -1
  34. package/dist/document/edit.js +1 -1
  35. package/dist/document/edit.js.map +1 -1
  36. package/dist/document/expr/evaluate.d.ts.map +1 -1
  37. package/dist/document/expr/evaluate.js +29 -2
  38. package/dist/document/expr/evaluate.js.map +1 -1
  39. package/dist/document/schema.d.ts +10 -0
  40. package/dist/document/schema.d.ts.map +1 -1
  41. package/dist/document/schema.js +4 -1
  42. package/dist/document/schema.js.map +1 -1
  43. package/dist/document.schema.json +45 -2
  44. package/dist/head.d.ts +81 -0
  45. package/dist/head.d.ts.map +1 -0
  46. package/dist/head.js +123 -0
  47. package/dist/head.js.map +1 -0
  48. package/dist/index.d.ts +3 -3
  49. package/dist/index.d.ts.map +1 -1
  50. package/dist/index.js +2 -2
  51. package/dist/index.js.map +1 -1
  52. package/dist/intelligence-bridge.d.ts +2 -0
  53. package/dist/intelligence-bridge.d.ts.map +1 -1
  54. package/dist/plan-edits.d.ts +55 -0
  55. package/dist/plan-edits.d.ts.map +1 -0
  56. package/dist/plan-edits.js +84 -0
  57. package/dist/plan-edits.js.map +1 -0
  58. package/dist/presence.d.ts +10 -0
  59. package/dist/presence.d.ts.map +1 -1
  60. package/dist/presence.js.map +1 -1
  61. package/dist/revisions/beyond.d.ts +56 -0
  62. package/dist/revisions/beyond.d.ts.map +1 -0
  63. package/dist/revisions/beyond.js +112 -0
  64. package/dist/revisions/beyond.js.map +1 -0
  65. package/dist/revisions/pictured.d.ts +52 -0
  66. package/dist/revisions/pictured.d.ts.map +1 -0
  67. package/dist/revisions/pictured.js +85 -0
  68. package/dist/revisions/pictured.js.map +1 -0
  69. package/dist/revisions/problems.d.ts +57 -0
  70. package/dist/revisions/problems.d.ts.map +1 -0
  71. package/dist/revisions/problems.js +51 -0
  72. package/dist/revisions/problems.js.map +1 -0
  73. package/dist/revisions/sections.d.ts +18 -0
  74. package/dist/revisions/sections.d.ts.map +1 -0
  75. package/dist/revisions/sections.js +91 -0
  76. package/dist/revisions/sections.js.map +1 -0
  77. package/dist/revisions/view.d.ts +71 -0
  78. package/dist/revisions/view.d.ts.map +1 -0
  79. package/dist/revisions/view.js +338 -0
  80. package/dist/revisions/view.js.map +1 -0
  81. package/dist/revisions.d.ts +11 -0
  82. package/dist/revisions.d.ts.map +1 -0
  83. package/dist/revisions.js +20 -0
  84. package/dist/revisions.js.map +1 -0
  85. package/dist/scene.d.ts +2 -2
  86. package/dist/scene.d.ts.map +1 -1
  87. package/dist/scene.js +1 -1
  88. package/dist/scene.js.map +1 -1
  89. package/dist/sync/connection.d.ts.map +1 -1
  90. package/dist/sync/connection.js +12 -8
  91. package/dist/sync/connection.js.map +1 -1
  92. package/dist/sync/engine.d.ts +14 -0
  93. package/dist/sync/engine.d.ts.map +1 -1
  94. package/dist/sync/engine.js +8 -1
  95. package/dist/sync/engine.js.map +1 -1
  96. package/dist/sync/index.d.ts +2 -2
  97. package/dist/sync/index.d.ts.map +1 -1
  98. package/dist/sync/index.js +1 -1
  99. package/dist/sync/index.js.map +1 -1
  100. package/dist/sync/notion.d.ts +2 -1
  101. package/dist/sync/notion.d.ts.map +1 -1
  102. package/dist/sync/notion.js +28 -16
  103. package/dist/sync/notion.js.map +1 -1
  104. package/dist/sync/status.d.ts +1 -1
  105. package/dist/sync/status.d.ts.map +1 -1
  106. package/dist/sync/status.js +2 -1
  107. package/dist/sync/status.js.map +1 -1
  108. package/dist/sync/types.d.ts +5 -0
  109. package/dist/sync/types.d.ts.map +1 -1
  110. package/dist/sync/types.js.map +1 -1
  111. package/dist/theme/marks.d.ts +12 -0
  112. package/dist/theme/marks.d.ts.map +1 -1
  113. package/dist/theme/marks.js +5 -0
  114. package/dist/theme/marks.js.map +1 -1
  115. package/dist/told.d.ts +306 -0
  116. package/dist/told.d.ts.map +1 -0
  117. package/dist/told.js +409 -0
  118. package/dist/told.js.map +1 -0
  119. package/dist/version.d.ts +1 -1
  120. package/dist/version.js +1 -1
  121. package/dist/views/kept.d.ts +44 -0
  122. package/dist/views/kept.d.ts.map +1 -1
  123. package/dist/views/kept.js +30 -0
  124. package/dist/views/kept.js.map +1 -1
  125. package/dist/workflow-shape.d.ts +12 -6
  126. package/dist/workflow-shape.d.ts.map +1 -1
  127. package/dist/workflow-shape.js.map +1 -1
  128. package/dist/workflows/on-the-map.d.ts +14 -5
  129. package/dist/workflows/on-the-map.d.ts.map +1 -1
  130. package/dist/workflows/on-the-map.js +6 -4
  131. package/dist/workflows/on-the-map.js.map +1 -1
  132. package/dist/workflows/step-classify.d.ts +2 -0
  133. package/dist/workflows/step-classify.d.ts.map +1 -1
  134. package/dist/workflows/step-classify.js +26 -9
  135. package/dist/workflows/step-classify.js.map +1 -1
  136. package/dist/workflows/triggered.d.ts +14 -1
  137. package/dist/workflows/triggered.d.ts.map +1 -1
  138. package/dist/workflows/triggered.js +19 -2
  139. package/dist/workflows/triggered.js.map +1 -1
  140. package/dist/workflows.d.ts +2 -2
  141. package/dist/workflows.d.ts.map +1 -1
  142. package/dist/workflows.js +2 -2
  143. package/dist/workflows.js.map +1 -1
  144. package/package.json +13 -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,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"}
@@ -0,0 +1,91 @@
1
+ /*
2
+ * THE SECTIONS OF A DRAWING, BY NAME (Roadmap f-revisions-say-what-broke).
3
+ *
4
+ * What a person would call a part of a page: a heading's words, and a
5
+ * landmark — a `<section>` or a `role="region"` named by its `aria-label`,
6
+ * its `aria-labelledby` or its own first heading; a `<nav>`, a `<main>`, a
7
+ * header, a footer or an aside, by its name or by what it is. A worker
8
+ * view's host draws a landmark's element as a `<div>` that says what it was
9
+ * asked to be (`data-graview-as`), and that is read as the landmark.
10
+ *
11
+ * Read from anything shaped like an element — a page's DOM, a headless
12
+ * run's tree (`@graview/guest/headless`) — and nothing is laid out here.
13
+ */
14
+ const HEADING = /^h([1-6])$/;
15
+ /** The landmarks a page is read by, and what one with no name of its own is called. */
16
+ const LANDMARKS = {
17
+ section: null,
18
+ article: null,
19
+ form: null,
20
+ region: null,
21
+ nav: "navigation",
22
+ navigation: "navigation",
23
+ main: "main content",
24
+ header: "header",
25
+ banner: "header",
26
+ footer: "footer",
27
+ contentinfo: "footer",
28
+ aside: "aside",
29
+ complementary: "aside",
30
+ search: "search",
31
+ };
32
+ const isElement = (node) => typeof node === "object" && node !== null && typeof node.getAttribute === "function" && (node.nodeType === undefined || node.nodeType === 1);
33
+ const said = (text) => (text ?? "").replace(/\s+/g, " ").trim();
34
+ /** Every element under `root`, `root` first, in document order. */
35
+ export function* elementsOf(root) {
36
+ yield root;
37
+ for (const child of Array.from(root.childNodes))
38
+ if (isElement(child))
39
+ yield* elementsOf(child);
40
+ }
41
+ /** What an element is asked to be: the landmark a host drew as a `<div>`, else its own name. */
42
+ const tagOf = (element) => (element.getAttribute("data-graview-as") ?? element.localName ?? "").toLowerCase();
43
+ /** The heading level an element is, if it is one. */
44
+ function headingLevel(element) {
45
+ const tag = HEADING.exec(tagOf(element));
46
+ if (tag)
47
+ return Number(tag[1]);
48
+ return element.getAttribute("role") === "heading" ? Number(element.getAttribute("aria-level") ?? 2) : undefined;
49
+ }
50
+ /** The sections a drawing has, each once by name, in document order. */
51
+ export function sectionsOfDrawing(root) {
52
+ const all = [...elementsOf(root)];
53
+ const byId = new Map();
54
+ for (const element of all) {
55
+ const id = element.getAttribute("id");
56
+ if (id)
57
+ byId.set(id, element);
58
+ }
59
+ const out = [];
60
+ const seen = new Set();
61
+ const add = (name, as) => {
62
+ const key = name.toLowerCase();
63
+ if (!name || seen.has(key))
64
+ return;
65
+ seen.add(key);
66
+ out.push({ name: name.length > 80 ? `${name.slice(0, 79)}…` : name, as });
67
+ };
68
+ for (const element of all) {
69
+ if (element.getAttribute("aria-hidden") === "true" || element.getAttribute("hidden") !== null)
70
+ continue;
71
+ const level = headingLevel(element);
72
+ if (level !== undefined) {
73
+ add(said(element.textContent), "heading");
74
+ continue;
75
+ }
76
+ const tag = tagOf(element);
77
+ const role = (element.getAttribute("role") ?? "").toLowerCase();
78
+ const what = role in LANDMARKS ? role : tag in LANDMARKS ? tag : undefined;
79
+ if (!what)
80
+ continue;
81
+ const namedBy = (element.getAttribute("aria-labelledby") ?? "")
82
+ .split(/\s+/)
83
+ .flatMap((id) => (byId.get(id) ? [said(byId.get(id).textContent)] : []))
84
+ .join(" ");
85
+ const heading = [...elementsOf(element)].find((one) => one !== element && headingLevel(one) !== undefined);
86
+ const name = said(element.getAttribute("aria-label")) || namedBy || (heading ? said(heading.textContent) : "") || LANDMARKS[what] || "";
87
+ add(name, what === "region" ? "section" : what);
88
+ }
89
+ return out;
90
+ }
91
+ //# sourceMappingURL=sections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sections.js","sourceRoot":"","sources":["../../src/revisions/sections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,71 @@
1
+ import { type DrawnSection, type ElementLike } from "./sections.js";
2
+ /** One side of a revision: the view's source, and what a run of it drew where the host has it. */
3
+ export interface ViewRevisionSide {
4
+ /** The view's whole source. */
5
+ readonly source: string;
6
+ /** The stylesheet it drew with (`HeadlessDescribed.css`, or the page's): read from the source's strings when left out. */
7
+ readonly css?: string;
8
+ /** What it drew (`HeadlessDescribed.drawing.root`, or a page's element): its classes and sections are read from it. */
9
+ readonly drawing?: ElementLike;
10
+ /** The classes its drawing uses, where the host has a list and no tree. */
11
+ readonly classes?: readonly string[];
12
+ /** How tall the page it is drawn on is, in CSS pixels, where the host measured it. */
13
+ readonly height?: number;
14
+ }
15
+ /** A class the revision still draws that a rule styled before and none styles now. */
16
+ export interface UnstyledClass {
17
+ readonly class: string;
18
+ /** The selectors that styled it before. */
19
+ readonly styledBy: readonly string[];
20
+ }
21
+ /** A selector the revision took out, while the markup it matched is still drawn. */
22
+ export interface RemovedSelector {
23
+ readonly selector: string;
24
+ /** The classes (`.name`) and ids (`#name`) in it, each still drawn. */
25
+ readonly names: readonly string[];
26
+ }
27
+ export interface HeightChange {
28
+ readonly before: number;
29
+ readonly after: number;
30
+ /** `after - before`, in CSS pixels. */
31
+ readonly change: number;
32
+ /** The change as a part of `before`: -0.5 is half as tall. */
33
+ readonly ratio: number;
34
+ }
35
+ /** What a revision broke, as entries and in words. */
36
+ export interface ViewRevision {
37
+ /** True when anything below was found; a height that moved less than a tenth is not. */
38
+ readonly regressed: boolean;
39
+ readonly unstyled: readonly UnstyledClass[];
40
+ readonly selectorsRemoved: readonly RemovedSelector[];
41
+ /** Sections drawn before and not now, by name. */
42
+ readonly sectionsMissing: readonly DrawnSection[];
43
+ readonly height?: HeightChange;
44
+ /** Where each side was read from: its drawing and stylesheet, or its source alone. */
45
+ readonly read: {
46
+ readonly before: "drawing" | "source";
47
+ readonly after: "drawing" | "source";
48
+ };
49
+ /** One sentence per finding. */
50
+ readonly said: readonly string[];
51
+ /** The sentences together, or one saying nothing was lost. */
52
+ readonly text: string;
53
+ }
54
+ /**
55
+ * THE STRINGS A SCRIPT SAYS: each quoted string and template's text, an
56
+ * interpolation left as a hole. Comments and regular expressions are passed
57
+ * over; nothing is run.
58
+ */
59
+ export declare function stringsOfSource(source: string): string[];
60
+ /** Every style rule's selector in a stylesheet, each once, in order. A keyframe's steps and a font's face are not selectors. */
61
+ export declare function selectorsOfStylesheet(css: string): string[];
62
+ /** The classes and ids a selector names, as `.name` and `#name`; what is inside `[…]` and strings is not read. */
63
+ export declare function namesInSelector(selector: string): string[];
64
+ /**
65
+ * WHAT A REVISION OF A VIEW BROKE, against the version it replaces: the
66
+ * classes it still draws that lost every rule styling them, the selectors
67
+ * taken out while the markup they matched is still drawn, the sections
68
+ * drawn before and not now, and how the page's height moved.
69
+ */
70
+ export declare function compareViewRevision(before: ViewRevisionSide, after: ViewRevisionSide): ViewRevision;
71
+ //# sourceMappingURL=view.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"view.d.ts","sourceRoot":"","sources":["../../src/revisions/view.ts"],"names":[],"mappings":"AAkBA,OAAO,EAAiC,KAAK,YAAY,EAAE,KAAK,WAAW,EAAE,MAAM,eAAe,CAAC;AAEnG,kGAAkG;AAClG,MAAM,WAAW,gBAAgB;IAC/B,+BAA+B;IAC/B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,0HAA0H;IAC1H,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,uHAAuH;IACvH,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;IAC/B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACrC,sFAAsF;IACtF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED,sFAAsF;AACtF,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,QAAQ,CAAC,QAAQ,EAAE,SAAS,MAAM,EAAE,CAAC;CACtC;AAED,oFAAoF;AACpF,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,uEAAuE;IACvE,QAAQ,CAAC,KAAK,EAAE,SAAS,MAAM,EAAE,CAAC;CACnC;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,uCAAuC;IACvC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8DAA8D;IAC9D,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;CACxB;AAED,sDAAsD;AACtD,MAAM,WAAW,YAAY;IAC3B,wFAAwF;IACxF,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;IAC5C,QAAQ,CAAC,gBAAgB,EAAE,SAAS,eAAe,EAAE,CAAC;IACtD,kDAAkD;IAClD,QAAQ,CAAC,eAAe,EAAE,SAAS,YAAY,EAAE,CAAC;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,YAAY,CAAC;IAC/B,sFAAsF;IACtF,QAAQ,CAAC,IAAI,EAAE;QAAE,QAAQ,CAAC,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAC;QAAC,QAAQ,CAAC,KAAK,EAAE,SAAS,GAAG,QAAQ,CAAA;KAAE,CAAC;IAC/F,gCAAgC;IAChC,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,8DAA8D;IAC9D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAKD;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAoFxD;AA8BD,gIAAgI;AAChI,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,EAAE,CAwD3D;AAED,kHAAkH;AAClH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,EAAE,CAG1D;AA6DD;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,gBAAgB,EAAE,KAAK,EAAE,gBAAgB,GAAG,YAAY,CAgDnG"}