@graview/core 0.1.0 → 0.1.2

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 (292) hide show
  1. package/README.md +7 -0
  2. package/dist/app.d.ts +17 -0
  3. package/dist/app.d.ts.map +1 -1
  4. package/dist/app.js.map +1 -1
  5. package/dist/arrange.d.ts +3 -2
  6. package/dist/arrange.d.ts.map +1 -1
  7. package/dist/arrange.js +19 -2
  8. package/dist/arrange.js.map +1 -1
  9. package/dist/beginning.d.ts +5 -2
  10. package/dist/beginning.d.ts.map +1 -1
  11. package/dist/beginning.js +28 -0
  12. package/dist/beginning.js.map +1 -1
  13. package/dist/capabilities.d.ts +32 -0
  14. package/dist/capabilities.d.ts.map +1 -0
  15. package/dist/capabilities.js +31 -0
  16. package/dist/capabilities.js.map +1 -0
  17. package/dist/cli/check/index.d.ts +1 -0
  18. package/dist/cli/check/index.d.ts.map +1 -1
  19. package/dist/cli/check/index.js +1 -0
  20. package/dist/cli/check/index.js.map +1 -1
  21. package/dist/cli/check/lenses.d.ts.map +1 -1
  22. package/dist/cli/check/lenses.js +25 -0
  23. package/dist/cli/check/lenses.js.map +1 -1
  24. package/dist/cli/check/policy.d.ts.map +1 -1
  25. package/dist/cli/check/policy.js +35 -0
  26. package/dist/cli/check/policy.js.map +1 -1
  27. package/dist/cli/check/relations.d.ts.map +1 -1
  28. package/dist/cli/check/relations.js +31 -0
  29. package/dist/cli/check/relations.js.map +1 -1
  30. package/dist/cli/check/views.d.ts +14 -0
  31. package/dist/cli/check/views.d.ts.map +1 -0
  32. package/dist/cli/check/views.js +27 -0
  33. package/dist/cli/check/views.js.map +1 -0
  34. package/dist/cli/check.d.ts.map +1 -1
  35. package/dist/cli/check.js +2 -1
  36. package/dist/cli/check.js.map +1 -1
  37. package/dist/cli/create.d.ts +1 -1
  38. package/dist/cli/create.d.ts.map +1 -1
  39. package/dist/cli/create.js +63 -1
  40. package/dist/cli/create.js.map +1 -1
  41. package/dist/cli/index.d.ts +18 -1
  42. package/dist/cli/index.d.ts.map +1 -1
  43. package/dist/cli/index.js +66 -1
  44. package/dist/cli/index.js.map +1 -1
  45. package/dist/conformance/fixtures.d.ts +41 -0
  46. package/dist/conformance/fixtures.d.ts.map +1 -0
  47. package/dist/conformance/fixtures.js +950 -0
  48. package/dist/conformance/fixtures.js.map +1 -0
  49. package/dist/conformance/index.d.ts +54 -0
  50. package/dist/conformance/index.d.ts.map +1 -0
  51. package/dist/conformance/index.js +81 -0
  52. package/dist/conformance/index.js.map +1 -0
  53. package/dist/document/canonical.d.ts +4 -0
  54. package/dist/document/canonical.d.ts.map +1 -0
  55. package/dist/document/canonical.js +29 -0
  56. package/dist/document/canonical.js.map +1 -0
  57. package/dist/document/compile.d.ts +43 -0
  58. package/dist/document/compile.d.ts.map +1 -0
  59. package/dist/document/compile.js +787 -0
  60. package/dist/document/compile.js.map +1 -0
  61. package/dist/document/diff.d.ts +32 -0
  62. package/dist/document/diff.d.ts.map +1 -0
  63. package/dist/document/diff.js +143 -0
  64. package/dist/document/diff.js.map +1 -0
  65. package/dist/document/edit.d.ts +63 -0
  66. package/dist/document/edit.d.ts.map +1 -0
  67. package/dist/document/edit.js +1420 -0
  68. package/dist/document/edit.js.map +1 -0
  69. package/dist/document/expr/analyze.d.ts +14 -0
  70. package/dist/document/expr/analyze.d.ts.map +1 -0
  71. package/dist/document/expr/analyze.js +52 -0
  72. package/dist/document/expr/analyze.js.map +1 -0
  73. package/dist/document/expr/evaluate.d.ts +36 -0
  74. package/dist/document/expr/evaluate.d.ts.map +1 -0
  75. package/dist/document/expr/evaluate.js +344 -0
  76. package/dist/document/expr/evaluate.js.map +1 -0
  77. package/dist/document/expr/index.d.ts +8 -0
  78. package/dist/document/expr/index.d.ts.map +1 -0
  79. package/dist/document/expr/index.js +5 -0
  80. package/dist/document/expr/index.js.map +1 -0
  81. package/dist/document/expr/parse.d.ts +50 -0
  82. package/dist/document/expr/parse.d.ts.map +1 -0
  83. package/dist/document/expr/parse.js +240 -0
  84. package/dist/document/expr/parse.js.map +1 -0
  85. package/dist/document/expr/print.d.ts +4 -0
  86. package/dist/document/expr/print.d.ts.map +1 -0
  87. package/dist/document/expr/print.js +81 -0
  88. package/dist/document/expr/print.js.map +1 -0
  89. package/dist/document/findings.d.ts +15 -0
  90. package/dist/document/findings.d.ts.map +1 -0
  91. package/dist/document/findings.js +30 -0
  92. package/dist/document/findings.js.map +1 -0
  93. package/dist/document/graview-template.d.ts +148 -0
  94. package/dist/document/graview-template.d.ts.map +1 -0
  95. package/dist/document/graview-template.js +450 -0
  96. package/dist/document/graview-template.js.map +1 -0
  97. package/dist/document/index.d.ts +27 -0
  98. package/dist/document/index.d.ts.map +1 -0
  99. package/dist/document/index.js +16 -0
  100. package/dist/document/index.js.map +1 -0
  101. package/dist/document/migrate.d.ts +41 -0
  102. package/dist/document/migrate.d.ts.map +1 -0
  103. package/dist/document/migrate.js +252 -0
  104. package/dist/document/migrate.js.map +1 -0
  105. package/dist/document/patch.d.ts +16 -0
  106. package/dist/document/patch.d.ts.map +1 -0
  107. package/dist/document/patch.js +79 -0
  108. package/dist/document/patch.js.map +1 -0
  109. package/dist/document/rules.d.ts +40 -0
  110. package/dist/document/rules.d.ts.map +1 -0
  111. package/dist/document/rules.js +88 -0
  112. package/dist/document/rules.js.map +1 -0
  113. package/dist/document/schema.d.ts +459 -0
  114. package/dist/document/schema.d.ts.map +1 -0
  115. package/dist/document/schema.js +197 -0
  116. package/dist/document/schema.js.map +1 -0
  117. package/dist/document/template.d.ts +28 -0
  118. package/dist/document/template.d.ts.map +1 -0
  119. package/dist/document/template.js +117 -0
  120. package/dist/document/template.js.map +1 -0
  121. package/dist/document/to-document.d.ts +34 -0
  122. package/dist/document/to-document.d.ts.map +1 -0
  123. package/dist/document/to-document.js +182 -0
  124. package/dist/document/to-document.js.map +1 -0
  125. package/dist/document/upgrade.d.ts +9 -0
  126. package/dist/document/upgrade.d.ts.map +1 -0
  127. package/dist/document/upgrade.js +19 -0
  128. package/dist/document/upgrade.js.map +1 -0
  129. package/dist/document/views.d.ts +65 -0
  130. package/dist/document/views.d.ts.map +1 -0
  131. package/dist/document/views.js +264 -0
  132. package/dist/document/views.js.map +1 -0
  133. package/dist/formats.d.ts +50 -0
  134. package/dist/formats.d.ts.map +1 -0
  135. package/dist/formats.js +75 -0
  136. package/dist/formats.js.map +1 -0
  137. package/dist/graph/graph.d.ts +52 -3
  138. package/dist/graph/graph.d.ts.map +1 -1
  139. package/dist/graph/graph.js +169 -16
  140. package/dist/graph/graph.js.map +1 -1
  141. package/dist/index.d.ts +40 -17
  142. package/dist/index.d.ts.map +1 -1
  143. package/dist/index.js +29 -10
  144. package/dist/index.js.map +1 -1
  145. package/dist/integrity.d.ts +46 -0
  146. package/dist/integrity.d.ts.map +1 -0
  147. package/dist/integrity.js +179 -0
  148. package/dist/integrity.js.map +1 -0
  149. package/dist/invariants/engine.d.ts +8 -0
  150. package/dist/invariants/engine.d.ts.map +1 -1
  151. package/dist/invariants/engine.js +40 -2
  152. package/dist/invariants/engine.js.map +1 -1
  153. package/dist/invariants/types.d.ts +19 -0
  154. package/dist/invariants/types.d.ts.map +1 -1
  155. package/dist/labels.d.ts +65 -0
  156. package/dist/labels.d.ts.map +1 -0
  157. package/dist/labels.js +123 -0
  158. package/dist/labels.js.map +1 -0
  159. package/dist/mutations/define-mutation.d.ts.map +1 -1
  160. package/dist/mutations/define-mutation.js +2 -3
  161. package/dist/mutations/define-mutation.js.map +1 -1
  162. package/dist/mutations/derive-edits.d.ts.map +1 -1
  163. package/dist/mutations/derive-edits.js +20 -1
  164. package/dist/mutations/derive-edits.js.map +1 -1
  165. package/dist/mutations/form.d.ts +9 -0
  166. package/dist/mutations/form.d.ts.map +1 -1
  167. package/dist/mutations/form.js +20 -0
  168. package/dist/mutations/form.js.map +1 -1
  169. package/dist/mutations/node-ref.d.ts +6 -0
  170. package/dist/mutations/node-ref.d.ts.map +1 -1
  171. package/dist/mutations/node-ref.js +22 -8
  172. package/dist/mutations/node-ref.js.map +1 -1
  173. package/dist/mutations/types.d.ts +8 -0
  174. package/dist/mutations/types.d.ts.map +1 -1
  175. package/dist/mutations/words.d.ts +49 -0
  176. package/dist/mutations/words.d.ts.map +1 -0
  177. package/dist/mutations/words.js +61 -0
  178. package/dist/mutations/words.js.map +1 -0
  179. package/dist/ops/log.d.ts +145 -4
  180. package/dist/ops/log.d.ts.map +1 -1
  181. package/dist/ops/log.js +220 -51
  182. package/dist/ops/log.js.map +1 -1
  183. package/dist/ops/revisions.d.ts +66 -0
  184. package/dist/ops/revisions.d.ts.map +1 -0
  185. package/dist/ops/revisions.js +97 -0
  186. package/dist/ops/revisions.js.map +1 -0
  187. package/dist/ops/types.d.ts +49 -1
  188. package/dist/ops/types.d.ts.map +1 -1
  189. package/dist/ops/undo.d.ts +23 -2
  190. package/dist/ops/undo.d.ts.map +1 -1
  191. package/dist/ops/undo.js +107 -1
  192. package/dist/ops/undo.js.map +1 -1
  193. package/dist/ops/withheld.d.ts +37 -0
  194. package/dist/ops/withheld.d.ts.map +1 -0
  195. package/dist/ops/withheld.js +84 -0
  196. package/dist/ops/withheld.js.map +1 -0
  197. package/dist/permissions/policy.d.ts +15 -0
  198. package/dist/permissions/policy.d.ts.map +1 -1
  199. package/dist/permissions/policy.js +28 -1
  200. package/dist/permissions/policy.js.map +1 -1
  201. package/dist/permissions/sight.d.ts +50 -0
  202. package/dist/permissions/sight.d.ts.map +1 -0
  203. package/dist/permissions/sight.js +76 -0
  204. package/dist/permissions/sight.js.map +1 -0
  205. package/dist/permissions/types.d.ts +26 -0
  206. package/dist/permissions/types.d.ts.map +1 -1
  207. package/dist/permissions/types.js.map +1 -1
  208. package/dist/persistence/memory.d.ts.map +1 -1
  209. package/dist/persistence/memory.js +25 -0
  210. package/dist/persistence/memory.js.map +1 -1
  211. package/dist/persistence/sql.d.ts +43 -0
  212. package/dist/persistence/sql.d.ts.map +1 -0
  213. package/dist/persistence/sql.js +154 -0
  214. package/dist/persistence/sql.js.map +1 -0
  215. package/dist/persistence/sqlite.d.ts +17 -3
  216. package/dist/persistence/sqlite.d.ts.map +1 -1
  217. package/dist/persistence/sqlite.js +32 -96
  218. package/dist/persistence/sqlite.js.map +1 -1
  219. package/dist/persistence/types.d.ts +19 -0
  220. package/dist/persistence/types.d.ts.map +1 -1
  221. package/dist/presence.d.ts +31 -0
  222. package/dist/presence.d.ts.map +1 -1
  223. package/dist/presence.js +36 -0
  224. package/dist/presence.js.map +1 -1
  225. package/dist/scaffold/from-template.d.ts +16 -0
  226. package/dist/scaffold/from-template.d.ts.map +1 -0
  227. package/dist/scaffold/from-template.js +157 -0
  228. package/dist/scaffold/from-template.js.map +1 -0
  229. package/dist/scaffold/index.d.ts +10 -1
  230. package/dist/scaffold/index.d.ts.map +1 -1
  231. package/dist/scaffold/index.js +35 -7
  232. package/dist/scaffold/index.js.map +1 -1
  233. package/dist/scaffold/names.d.ts +4 -0
  234. package/dist/scaffold/names.d.ts.map +1 -1
  235. package/dist/scaffold/names.js.map +1 -1
  236. package/dist/scaffold/project.d.ts +1 -1
  237. package/dist/scaffold/project.d.ts.map +1 -1
  238. package/dist/scaffold/project.js +44 -13
  239. package/dist/scaffold/project.js.map +1 -1
  240. package/dist/scaffold/ui.d.ts.map +1 -1
  241. package/dist/scaffold/ui.js +19 -10
  242. package/dist/scaffold/ui.js.map +1 -1
  243. package/dist/schema/define-node.d.ts +20 -0
  244. package/dist/schema/define-node.d.ts.map +1 -1
  245. package/dist/schema/define-node.js +27 -2
  246. package/dist/schema/define-node.js.map +1 -1
  247. package/dist/schema/path.d.ts +19 -0
  248. package/dist/schema/path.d.ts.map +1 -0
  249. package/dist/schema/path.js +34 -0
  250. package/dist/schema/path.js.map +1 -0
  251. package/dist/schema/types.d.ts +6 -0
  252. package/dist/schema/types.d.ts.map +1 -1
  253. package/dist/seen.d.ts +58 -0
  254. package/dist/seen.d.ts.map +1 -0
  255. package/dist/seen.js +194 -0
  256. package/dist/seen.js.map +1 -0
  257. package/dist/store.d.ts +317 -8
  258. package/dist/store.d.ts.map +1 -1
  259. package/dist/store.js +720 -37
  260. package/dist/store.js.map +1 -1
  261. package/dist/testing.d.ts +6 -0
  262. package/dist/testing.d.ts.map +1 -1
  263. package/dist/testing.js +3 -1
  264. package/dist/testing.js.map +1 -1
  265. package/dist/theme/palettes.d.ts.map +1 -1
  266. package/dist/theme/palettes.js +4 -0
  267. package/dist/theme/palettes.js.map +1 -1
  268. package/dist/theme/types.d.ts +9 -0
  269. package/dist/theme/types.d.ts.map +1 -1
  270. package/dist/theme/types.js +4 -0
  271. package/dist/theme/types.js.map +1 -1
  272. package/dist/validate-graph.d.ts +83 -0
  273. package/dist/validate-graph.d.ts.map +1 -0
  274. package/dist/validate-graph.js +288 -0
  275. package/dist/validate-graph.js.map +1 -0
  276. package/dist/version.d.ts +3 -0
  277. package/dist/version.d.ts.map +1 -0
  278. package/dist/version.js +3 -0
  279. package/dist/version.js.map +1 -0
  280. package/dist/views/types.d.ts +8 -0
  281. package/dist/views/types.d.ts.map +1 -1
  282. package/dist/views/types.js +5 -0
  283. package/dist/views/types.js.map +1 -1
  284. package/dist/watched.d.ts +39 -0
  285. package/dist/watched.d.ts.map +1 -1
  286. package/dist/watched.js +94 -1
  287. package/dist/watched.js.map +1 -1
  288. package/dist/who.d.ts +24 -1
  289. package/dist/who.d.ts.map +1 -1
  290. package/dist/who.js +49 -2
  291. package/dist/who.js.map +1 -1
  292. package/package.json +9 -1
@@ -0,0 +1,264 @@
1
+ import { analyzeExpr } from "./expr/analyze.js";
2
+ import { ExprSyntaxError, parseExpr } from "./expr/parse.js";
3
+ import { error } from "./findings.js";
4
+ import { parseTemplate, TemplateError } from "./template.js";
5
+ /*
6
+ * VIEW SPECS — Tier 1 custom UI, as data (ADR 0004, docs/declaration-document.md).
7
+ *
8
+ * "views": { "vendor": { "card": [ { "title": "{name}" }, { "badge": "{status}", "tone": … } ] } }
9
+ *
10
+ * A view spec is a short list of BLOCKS from a closed set, bound to the
11
+ * record by the same templates and rule-language expressions the rest of the
12
+ * document uses. There is no CSS, no HTML and no URL a block can carry: the
13
+ * only link a view ever draws is a `url` FIELD's own value, and only when it
14
+ * is http(s). The renderer (packages/client/src/views.tsx) styles blocks
15
+ * with the theme's tokens and a fixed set of classes.
16
+ *
17
+ * Checked here into findings with JSON paths, so a model that writes
18
+ * `{"badge": "{status}", "tone": "green"}` is told which tone set it meant.
19
+ *
20
+ * The document's view vocabulary is checked here; drawing it is FR-03's.
21
+ */
22
+ export const VIEW_SLOTS = ["card", "row", "page"];
23
+ export const VIEW_TONES = ["good", "warn", "bad", "neutral", "accent"];
24
+ export const VIEW_FIELD_FORMATS = ["money", "percent", "date", "relative", "count"];
25
+ /** Groups and conditions nest; four deep is more than any card needs. */
26
+ export const MAX_VIEW_DEPTH = 4;
27
+ /** Blocks in one view, counting nested ones. */
28
+ export const MAX_VIEW_BLOCKS = 40;
29
+ /** What each block may say besides the key that names it. */
30
+ const BLOCK_KEYS = {
31
+ title: [],
32
+ text: ["tone"],
33
+ badge: ["tone"],
34
+ field: ["as", "label"],
35
+ progress: ["label"],
36
+ group: ["direction"],
37
+ when: ["show"],
38
+ divider: [],
39
+ figure: [],
40
+ };
41
+ const BLOCK_TYPES = Object.keys(BLOCK_KEYS);
42
+ const SHAPES = '{"title": "{name}"}, {"text": "…", "tone"?}, {"badge": "{status}", "tone"?}, {"field": "quote", "as"?, "label"?}, {"progress": {"value": expr, "max": expr}, "label"?}, {"group": [blocks], "direction"?: "row"|"column"}, {"when": expr, "show": [blocks]}, {"divider": true}, {"figure": true}';
43
+ /** The view specs of a document that has been read; empty when it has none. */
44
+ export function viewsOf(document) {
45
+ return (document.views ?? {});
46
+ }
47
+ const isObject = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
48
+ function names(expr, path, scope) {
49
+ const shape = analyzeExpr(expr);
50
+ for (const fn of shape.unknownFunctions)
51
+ scope.findings.push(error("unknown-function", path, `"${fn}" is not a function the rule language knows`, "see docs/declaration-document.md#expression-language"));
52
+ for (const n of shape.names) {
53
+ if (n === "id" || scope.spec.field(n) || scope.spec.relation(n))
54
+ continue;
55
+ scope.findings.push(error("view-name", path, `${scope.kind} has no field or relation called "${n}"`));
56
+ }
57
+ for (const e of shape.edges)
58
+ if (!scope.edges.has(e))
59
+ scope.findings.push(error("view-edge", path, `"${e}" is not a relation any kind declares`));
60
+ for (const k of shape.sweeps)
61
+ if (!scope.kinds.has(k))
62
+ scope.findings.push(error("view-kind", path, `"${k}" is not a kind this document declares`));
63
+ }
64
+ function expression(source, path, scope) {
65
+ if (typeof source !== "string" || source.length === 0 || source.length > 2000) {
66
+ scope.findings.push(error("view-expression", path, "an expression is a line of the rule language, like \"status == 'booked'\""));
67
+ return;
68
+ }
69
+ try {
70
+ names(parseExpr(source), path, scope);
71
+ }
72
+ catch (e) {
73
+ if (!(e instanceof ExprSyntaxError))
74
+ throw e;
75
+ scope.findings.push(error("expression", path, `${e.sentence} (at character ${e.at + 1})`));
76
+ }
77
+ }
78
+ function template(source, path, scope) {
79
+ if (typeof source !== "string" || source.length === 0 || source.length > 300) {
80
+ scope.findings.push(error("view-template", path, 'a template is words with {field} in braces, like "{name}" or "{quote|money}", at most 300 characters'));
81
+ return;
82
+ }
83
+ let parts;
84
+ try {
85
+ parts = parseTemplate(source);
86
+ }
87
+ catch (e) {
88
+ if (e instanceof TemplateError || e instanceof ExprSyntaxError) {
89
+ scope.findings.push(error("template", path, e.sentence));
90
+ return;
91
+ }
92
+ throw e;
93
+ }
94
+ for (const part of parts)
95
+ if (part.expr)
96
+ names(part.expr, path, scope);
97
+ }
98
+ function tone(value, path, scope) {
99
+ if (typeof value === "string") {
100
+ if (!VIEW_TONES.includes(value))
101
+ scope.findings.push(error("view-tone", path, `"${value}" is not a tone`, `use one of ${VIEW_TONES.join(", ")}, or {"expr": "if(status == 'booked', 'good', 'neutral')"}`));
102
+ return;
103
+ }
104
+ if (isObject(value) && Object.keys(value).length === 1 && "expr" in value) {
105
+ expression(value["expr"], `${path}.expr`, scope);
106
+ return;
107
+ }
108
+ scope.findings.push(error("view-tone", path, "a tone is a word or {\"expr\": …}", `one of ${VIEW_TONES.join(", ")}`));
109
+ }
110
+ function blocks(list, path, depth, scope) {
111
+ if (!Array.isArray(list)) {
112
+ scope.findings.push(error("view-shape", path, "a view is a list of blocks"));
113
+ return;
114
+ }
115
+ if (depth > MAX_VIEW_DEPTH) {
116
+ scope.findings.push(error("view-depth", path, `blocks nest at most ${MAX_VIEW_DEPTH} deep`, "flatten a group or a condition"));
117
+ return;
118
+ }
119
+ list.forEach((block, i) => oneBlock(block, `${path}.${i}`, depth, scope));
120
+ }
121
+ function oneBlock(raw, path, depth, scope) {
122
+ scope.count++;
123
+ if (!isObject(raw)) {
124
+ scope.findings.push(error("view-block", path, "a block is an object naming what it shows", `one of ${SHAPES}`));
125
+ return;
126
+ }
127
+ const keys = Object.keys(raw);
128
+ const types = keys.filter((k) => BLOCK_TYPES.includes(k));
129
+ if (types.length === 0) {
130
+ scope.findings.push(error("view-block", path, `${keys.length > 0 ? keys.map((k) => `"${k}"`).join(", ") : "an empty object"} is not a block Graview knows`, `one of ${SHAPES}`));
131
+ return;
132
+ }
133
+ if (types.length > 1) {
134
+ scope.findings.push(error("view-block", path, `a block is one thing, and this says ${types.map((k) => `"${k}"`).join(" and ")}`, "split it into two blocks"));
135
+ return;
136
+ }
137
+ const type = types[0];
138
+ for (const k of keys)
139
+ if (k !== type && !BLOCK_KEYS[type].includes(k))
140
+ scope.findings.push(error("unknown-key", `${path}.${k}`, `"${k}" is not part of a ${type} block`, BLOCK_KEYS[type].length > 0 ? `a ${type} block may also say ${BLOCK_KEYS[type].map((x) => `"${x}"`).join(", ")}` : `a ${type} block says nothing else`));
141
+ const value = raw[type];
142
+ switch (type) {
143
+ case "title":
144
+ case "text":
145
+ case "badge":
146
+ template(value, `${path}.${type}`, scope);
147
+ if ("tone" in raw)
148
+ tone(raw["tone"], `${path}.tone`, scope);
149
+ return;
150
+ case "field": {
151
+ if (typeof value !== "string" || !scope.spec.field(value)) {
152
+ const edge = typeof value === "string" && scope.spec.relation(value);
153
+ scope.findings.push(error("view-field", `${path}.field`, `${scope.kind} has no field ${typeof value === "string" ? `"${value}"` : "by that name"}`, edge ? `"${value}" is a relation; show it with {"text": "{${value}.name}"}` : undefined));
154
+ }
155
+ if ("as" in raw && !VIEW_FIELD_FORMATS.includes(raw["as"]))
156
+ scope.findings.push(error("view-format", `${path}.as`, `"${String(raw["as"])}" is not a way to show a field`, `use one of ${VIEW_FIELD_FORMATS.join(", ")}`));
157
+ if ("label" in raw)
158
+ label(raw["label"], `${path}.label`, scope);
159
+ return;
160
+ }
161
+ case "progress": {
162
+ if (!isObject(value) || Object.keys(value).some((k) => k !== "value" && k !== "max") || !("value" in value) || !("max" in value)) {
163
+ scope.findings.push(error("view-progress", `${path}.progress`, 'progress is {"value": expression, "max": expression}'));
164
+ }
165
+ else {
166
+ expression(value["value"], `${path}.progress.value`, scope);
167
+ expression(value["max"], `${path}.progress.max`, scope);
168
+ }
169
+ if ("label" in raw)
170
+ label(raw["label"], `${path}.label`, scope);
171
+ return;
172
+ }
173
+ case "group":
174
+ if ("direction" in raw && raw["direction"] !== "row" && raw["direction"] !== "column")
175
+ scope.findings.push(error("view-direction", `${path}.direction`, `a group runs "row" or "column", not "${String(raw["direction"])}"`));
176
+ blocks(value, `${path}.group`, depth + 1, scope);
177
+ return;
178
+ case "when":
179
+ expression(value, `${path}.when`, scope);
180
+ if (!("show" in raw))
181
+ scope.findings.push(error("view-when", path, 'a condition says what it shows: {"when": expr, "show": [blocks]}'));
182
+ else
183
+ blocks(raw["show"], `${path}.show`, depth + 1, scope);
184
+ return;
185
+ case "divider":
186
+ case "figure":
187
+ if (value !== true)
188
+ scope.findings.push(error("view-block", `${path}.${type}`, `write {"${type}": true}`));
189
+ if (type === "figure" && !scope.spec.figure)
190
+ scope.findings.push(error("view-figure", `${path}.figure`, `${scope.kind} has no figure to show`, 'give the kind a "figure", or leave this block out'));
191
+ return;
192
+ }
193
+ }
194
+ function label(value, path, scope) {
195
+ if (typeof value !== "string" || value.length === 0 || value.length > 60)
196
+ scope.findings.push(error("view-label", path, "a label is a few words, at most 60 characters"));
197
+ }
198
+ /** Every kind's specs, checked against what each kind holds, at `<at>.<kind>.<slot>`. */
199
+ function validateAll(specsByKind, at, namesOf, kinds, edges, declares) {
200
+ const findings = [];
201
+ if (!isObject(specsByKind)) {
202
+ findings.push(error("view-shape", at, 'views are an object of kinds, each with a "card", a "row" or a "page"'));
203
+ return findings;
204
+ }
205
+ for (const [kind, specs] of Object.entries(specsByKind)) {
206
+ const spec = namesOf(kind);
207
+ if (!spec) {
208
+ findings.push(error("view-kind", `${at}.${kind}`, `"${kind}" is not a kind this ${declares} declares`));
209
+ continue;
210
+ }
211
+ if (!isObject(specs)) {
212
+ findings.push(error("view-shape", `${at}.${kind}`, 'a kind\'s views are {"card": [blocks], "row": [blocks], "page": [blocks]}'));
213
+ continue;
214
+ }
215
+ for (const key of Object.keys(specs)) {
216
+ if (!VIEW_SLOTS.includes(key))
217
+ findings.push(error("view-slot", `${at}.${kind}.${key}`, `"${key}" is not a place a view is drawn`, `use ${VIEW_SLOTS.map((slot) => `"${slot}"`).join(", ")}`));
218
+ }
219
+ for (const slot of VIEW_SLOTS) {
220
+ const list = specs[slot];
221
+ if (list === undefined)
222
+ continue;
223
+ const scope = { kind, spec, kinds, edges, findings, count: 0 };
224
+ blocks(list, `${at}.${kind}.${slot}`, 1, scope);
225
+ if (scope.count > MAX_VIEW_BLOCKS)
226
+ findings.push(error("view-size", `${at}.${kind}.${slot}`, `this ${slot} has ${scope.count} blocks; a view has at most ${MAX_VIEW_BLOCKS}`, "show less, or move detail to the page"));
227
+ }
228
+ }
229
+ return findings;
230
+ }
231
+ /** Findings about a document's `views`, each at its JSON path. */
232
+ export function validateViews(document) {
233
+ const kinds = new Set(Object.keys(document.kinds));
234
+ const edges = new Set(Object.values(document.kinds).flatMap((k) => Object.keys(k.edges ?? {})));
235
+ return validateAll(viewsOf(document), "views", (kind) => {
236
+ const spec = document.kinds[kind];
237
+ return spec ? { field: (n) => spec.fields[n] !== undefined, relation: (n) => spec.edges?.[n] !== undefined, figure: spec.figure !== undefined } : undefined;
238
+ }, kinds, edges, "document");
239
+ }
240
+ /**
241
+ * Findings about a declaration's view specs (FR-03), each at
242
+ * `viewSpecs.<kind>.<slot>.<block>`: the vocabulary a document's `views`
243
+ * is held to, read against the declared schema — its fields, its relations,
244
+ * and its figures (the kind's own, or the brand's).
245
+ */
246
+ export function validateViewSpecs(schema, specs, options = {}) {
247
+ const declared = schema.kinds;
248
+ const kinds = new Set(declared);
249
+ const definitionOf = (kind) => schema.tryDefinition(kind);
250
+ const edges = new Set(declared.flatMap((kind) => Object.keys(definitionOf(kind)?.edges ?? {})));
251
+ return validateAll(specs, options.at ?? "viewSpecs", (kind) => {
252
+ if (!kinds.has(kind))
253
+ return undefined;
254
+ const definition = definitionOf(kind);
255
+ const fields = definition?.fields?.shape ?? {};
256
+ const relations = definition?.edges ?? {};
257
+ return {
258
+ field: (n) => n !== "id" && n !== "kind" && Object.prototype.hasOwnProperty.call(fields, n),
259
+ relation: (n) => Object.prototype.hasOwnProperty.call(relations, n),
260
+ figure: definition?.figure !== undefined || options.figures?.[kind] !== undefined,
261
+ };
262
+ }, kinds, edges, "app");
263
+ }
264
+ //# sourceMappingURL=views.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"views.js","sourceRoot":"","sources":["../../src/document/views.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ import type { Operation } from "./ops/types.js";
2
+ import type { GraphSnapshot } from "./graph/types.js";
3
+ /**
4
+ * STORED FORMATS CARRY THEIR VERSION (FR-31).
5
+ *
6
+ * What a version writes, the version before it must read — or know not to.
7
+ * A snapshot and an op are stamped with the format they were written in;
8
+ * a reader meeting a NEWER format than it knows says so (`NewerFormatError`)
9
+ * rather than folding what it would misread, so a host refolds from the log
10
+ * or rolls forward. An older format is brought up by `upgradeSnapshot` and
11
+ * `upgradeOp`, one step per format change, each shipped with a test over
12
+ * the previous format's fixtures.
13
+ *
14
+ * Everything written before stamps existed is format 1: nothing has changed
15
+ * format yet. Ops and primitives are the stable contract — a format change
16
+ * within a major is additive and needs no step; a major brings its steps.
17
+ */
18
+ export declare const FORMATS: {
19
+ readonly snapshot: 1;
20
+ readonly op: 1;
21
+ };
22
+ export type FormatName = keyof typeof FORMATS;
23
+ /** What a stored thing says about who wrote it and in what shape. */
24
+ export interface FormatStamp {
25
+ /** The framework version that wrote it (`FRAMEWORK_VERSION`). */
26
+ readonly framework: string;
27
+ readonly formats: {
28
+ readonly [K in FormatName]: number;
29
+ };
30
+ }
31
+ /** The stamp this build writes. */
32
+ export declare function formatStamp(): FormatStamp;
33
+ /** Something written in a format newer than this build reads. Fold the log, or upgrade the framework. */
34
+ export declare class NewerFormatError extends Error {
35
+ readonly what: FormatName;
36
+ readonly found: number;
37
+ readonly supported: number;
38
+ readonly writtenBy?: string | undefined;
39
+ constructor(what: FormatName, found: number, supported: number, writtenBy?: string | undefined);
40
+ }
41
+ /** Throws `NewerFormatError` when a stamp says a format this build cannot read; absent formats are format 1. */
42
+ export declare function assertReadable(stamp: {
43
+ readonly framework?: string;
44
+ readonly formats?: Partial<Record<FormatName, number>>;
45
+ } | null | undefined): void;
46
+ /** A snapshot written in format `from`, brought up to the format this build writes. */
47
+ export declare function upgradeSnapshot(snapshot: GraphSnapshot, from: number): GraphSnapshot;
48
+ /** An op written in format `from`, brought up to the format this build writes. */
49
+ export declare function upgradeOp(op: Operation, from: number): Operation;
50
+ //# sourceMappingURL=formats.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formats.d.ts","sourceRoot":"","sources":["../src/formats.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,OAAO;;;CAAkC,CAAC;AACvD,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,OAAO,CAAC;AAE9C,qEAAqE;AACrE,MAAM,WAAW,WAAW;IAC1B,iEAAiE;IACjE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,EAAE,CAAC,IAAI,UAAU,GAAG,MAAM;KAAE,CAAC;CAC1D;AAED,mCAAmC;AACnC,wBAAgB,WAAW,IAAI,WAAW,CAEzC;AAED,yGAAyG;AACzG,qBAAa,gBAAiB,SAAQ,KAAK;IAEvC,QAAQ,CAAC,IAAI,EAAE,UAAU;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM;IACtB,QAAQ,CAAC,SAAS,EAAE,MAAM;IAC1B,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM;gBAHlB,IAAI,EAAE,UAAU,EAChB,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,MAAM,EACjB,SAAS,CAAC,EAAE,MAAM,YAAA;CAQ9B;AAED,gHAAgH;AAChH,wBAAgB,cAAc,CAAC,KAAK,EAAE;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,GAAG,IAAI,CAKtJ;AAuBD,uFAAuF;AACvF,wBAAgB,eAAe,CAAC,QAAQ,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAEpF;AAED,kFAAkF;AAClF,wBAAgB,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,SAAS,CAEhE"}
@@ -0,0 +1,75 @@
1
+ import { FRAMEWORK_VERSION } from "./version.js";
2
+ /**
3
+ * STORED FORMATS CARRY THEIR VERSION (FR-31).
4
+ *
5
+ * What a version writes, the version before it must read — or know not to.
6
+ * A snapshot and an op are stamped with the format they were written in;
7
+ * a reader meeting a NEWER format than it knows says so (`NewerFormatError`)
8
+ * rather than folding what it would misread, so a host refolds from the log
9
+ * or rolls forward. An older format is brought up by `upgradeSnapshot` and
10
+ * `upgradeOp`, one step per format change, each shipped with a test over
11
+ * the previous format's fixtures.
12
+ *
13
+ * Everything written before stamps existed is format 1: nothing has changed
14
+ * format yet. Ops and primitives are the stable contract — a format change
15
+ * within a major is additive and needs no step; a major brings its steps.
16
+ */
17
+ export const FORMATS = { snapshot: 1, op: 1 };
18
+ /** The stamp this build writes. */
19
+ export function formatStamp() {
20
+ return { framework: FRAMEWORK_VERSION, formats: { ...FORMATS } };
21
+ }
22
+ /** Something written in a format newer than this build reads. Fold the log, or upgrade the framework. */
23
+ export class NewerFormatError extends Error {
24
+ what;
25
+ found;
26
+ supported;
27
+ writtenBy;
28
+ constructor(what, found, supported, writtenBy) {
29
+ super(`This ${what} is in a newer format (${found}${writtenBy ? `, written by @graview ${writtenBy}` : ""}) than @graview ${FRAMEWORK_VERSION} reads (${supported}). ` +
30
+ (what === "snapshot" ? "Refold it from the log, or upgrade the framework." : "Upgrade the framework to read it."));
31
+ this.what = what;
32
+ this.found = found;
33
+ this.supported = supported;
34
+ this.writtenBy = writtenBy;
35
+ this.name = "NewerFormatError";
36
+ }
37
+ }
38
+ /** Throws `NewerFormatError` when a stamp says a format this build cannot read; absent formats are format 1. */
39
+ export function assertReadable(stamp) {
40
+ for (const what of Object.keys(FORMATS)) {
41
+ const found = stamp?.formats?.[what] ?? 1;
42
+ if (found > FORMATS[what])
43
+ throw new NewerFormatError(what, found, FORMATS[what], stamp?.framework);
44
+ }
45
+ }
46
+ /**
47
+ * One step per format change, keyed by the format it upgrades FROM. Empty
48
+ * while nothing has changed format; the next format change adds its step
49
+ * here, and a fixture of the format before it under tests/fixtures/formats.
50
+ */
51
+ const SNAPSHOT_STEPS = {};
52
+ const OP_STEPS = {};
53
+ function upgrade(what, value, from, steps) {
54
+ if (!Number.isInteger(from) || from < 1)
55
+ throw new Error(`No ${what} format ${from}: formats start at 1.`);
56
+ if (from > FORMATS[what])
57
+ throw new NewerFormatError(what, from, FORMATS[what]);
58
+ let current = value;
59
+ for (let at = from; at < FORMATS[what]; at++) {
60
+ const step = steps[at];
61
+ if (!step)
62
+ throw new Error(`No step upgrades a ${what} from format ${at} to ${at + 1}.`);
63
+ current = step(current);
64
+ }
65
+ return current;
66
+ }
67
+ /** A snapshot written in format `from`, brought up to the format this build writes. */
68
+ export function upgradeSnapshot(snapshot, from) {
69
+ return upgrade("snapshot", snapshot, from, SNAPSHOT_STEPS);
70
+ }
71
+ /** An op written in format `from`, brought up to the format this build writes. */
72
+ export function upgradeOp(op, from) {
73
+ return upgrade("op", op, from, OP_STEPS);
74
+ }
75
+ //# sourceMappingURL=formats.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formats.js","sourceRoot":"","sources":["../src/formats.ts"],"names":[],"mappings":"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"}
@@ -3,9 +3,30 @@ import { type GraphDiff } from "./diff.js";
3
3
  import { type Primitive } from "./primitives.js";
4
4
  import { type GraphEdge, type GraphReader, type GraphSnapshot } from "./types.js";
5
5
  export interface GraphOptions {
6
- /** Validate every node against its declared fields on the way in. */
6
+ /**
7
+ * Hold every WRITE to the declaration: a node added or patched must fit
8
+ * its kind, an edge must be declared between its ends. What is LOADED is
9
+ * held as it is (FR-28): a graph opens over records an older declaration
10
+ * wrote, and `validateGraph` says what no longer fits.
11
+ */
7
12
  readonly validate?: boolean;
8
13
  }
14
+ export interface ApplyPrimitivesOptions {
15
+ /**
16
+ * The primitives put back what was there — an undo, or history folded
17
+ * again — rather than write something new. Records are then held as they
18
+ * are, as a load holds them: an undo of a repair puts back the misfit it
19
+ * repaired. A node still has to be there to be patched or removed.
20
+ */
21
+ readonly restoring?: boolean;
22
+ /**
23
+ * What is put back goes back WHERE IT STOOD, not at the end: a rollback
24
+ * (`Store.rebase`) undoing ops this graph applied is exact, order and all.
25
+ * An undo is not a rollback — it adds at the end, as a client that loaded
26
+ * after the removal would, so every copy of the graph agrees.
27
+ */
28
+ readonly inPlace?: boolean;
29
+ }
9
30
  export type GraphListener<S extends AnySchema> = (diff: GraphDiff<NodeOfSchema<S>>) => void;
10
31
  export declare class GraphError extends Error {
11
32
  readonly hint?: string | undefined;
@@ -22,6 +43,10 @@ export declare class Graph<S extends AnySchema> implements GraphReader<NodeOfSch
22
43
  private readonly edges;
23
44
  private readonly outIndex;
24
45
  private readonly inIndex;
46
+ private rank;
47
+ private readonly ranks;
48
+ private readonly lapsed;
49
+ private reordered;
25
50
  private readonly listeners;
26
51
  private readonly validate;
27
52
  constructor(schema: S, options?: GraphOptions);
@@ -52,13 +77,37 @@ export declare class Graph<S extends AnySchema> implements GraphReader<NodeOfSch
52
77
  * Applies primitives as one batch and emits a single diff. Nothing outside
53
78
  * the op log should call this directly — attribution lives in the log.
54
79
  */
55
- applyPrimitives(primitives: readonly Primitive[]): GraphDiff<NodeOfSchema<S>>;
80
+ applyPrimitives(primitives: readonly Primitive[], options?: ApplyPrimitivesOptions): GraphDiff<NodeOfSchema<S>>;
56
81
  /** Applies primitives to a throwaway copy — used for previewing a diff. */
57
- preview(primitives: readonly Primitive[]): GraphDiff<NodeOfSchema<S>>;
82
+ preview(primitives: readonly Primitive[], options?: ApplyPrimitivesOptions): GraphDiff<NodeOfSchema<S>>;
58
83
  subscribe(listener: GraphListener<S>): () => void;
84
+ /** Puts the graph back to a snapshot it held, silently: nothing a listener saw ever changed. */
85
+ private restore;
86
+ private forgetRanks;
87
+ /** A rank for what just went in: the one it had, when it is being put back in place; the next one otherwise. */
88
+ private place;
89
+ /** What was taken out keeps its rank, for a while: a rollback only ever reaches the recent past. */
90
+ private lapse;
91
+ /** After an in-place put-back, the maps in rank order again. */
92
+ private settleOrder;
59
93
  private emit;
60
94
  private applyOne;
61
95
  private check;
96
+ /**
97
+ * A PATCH IS JUDGED ON WHAT IT WRITES (FR-28). The fields it writes must
98
+ * fit, and are taken as the declaration reads them (a cleared field with
99
+ * a default takes it). The record as a whole may not come out fitting
100
+ * less than it went in — but a misfit it already held, in a field the
101
+ * patch does not touch, stays as stored: renaming a person is not refused
102
+ * because of an address an older declaration accepted, and nothing the
103
+ * patch did not write is parsed into something else.
104
+ */
105
+ private checkPatch;
106
+ /** What about a node does not fit: undefined when it fits; `""` stands for a failure that names no field. */
107
+ private failing;
108
+ /** Why a node was refused, in the app's own words. */
109
+ private refusal;
110
+ /** `held`: put in as it is (a load, a restore), not judged as a write. */
62
111
  private insertNode;
63
112
  private insertEdge;
64
113
  private deleteEdge;
@@ -1 +1 @@
1
- {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/graph/graph.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/graph/graph.ts"],"names":[],"mappings":"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"}