@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.
- package/README.md +7 -0
- package/dist/app.d.ts +17 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js.map +1 -1
- package/dist/arrange.d.ts +3 -2
- package/dist/arrange.d.ts.map +1 -1
- package/dist/arrange.js +19 -2
- package/dist/arrange.js.map +1 -1
- package/dist/beginning.d.ts +5 -2
- package/dist/beginning.d.ts.map +1 -1
- package/dist/beginning.js +28 -0
- package/dist/beginning.js.map +1 -1
- package/dist/capabilities.d.ts +32 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +31 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/cli/check/index.d.ts +1 -0
- package/dist/cli/check/index.d.ts.map +1 -1
- package/dist/cli/check/index.js +1 -0
- package/dist/cli/check/index.js.map +1 -1
- package/dist/cli/check/lenses.d.ts.map +1 -1
- package/dist/cli/check/lenses.js +25 -0
- package/dist/cli/check/lenses.js.map +1 -1
- package/dist/cli/check/policy.d.ts.map +1 -1
- package/dist/cli/check/policy.js +35 -0
- package/dist/cli/check/policy.js.map +1 -1
- package/dist/cli/check/relations.d.ts.map +1 -1
- package/dist/cli/check/relations.js +31 -0
- package/dist/cli/check/relations.js.map +1 -1
- package/dist/cli/check/views.d.ts +14 -0
- package/dist/cli/check/views.d.ts.map +1 -0
- package/dist/cli/check/views.js +27 -0
- package/dist/cli/check/views.js.map +1 -0
- package/dist/cli/check.d.ts.map +1 -1
- package/dist/cli/check.js +2 -1
- package/dist/cli/check.js.map +1 -1
- package/dist/cli/create.d.ts +1 -1
- package/dist/cli/create.d.ts.map +1 -1
- package/dist/cli/create.js +63 -1
- package/dist/cli/create.js.map +1 -1
- package/dist/cli/index.d.ts +18 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +66 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/conformance/fixtures.d.ts +41 -0
- package/dist/conformance/fixtures.d.ts.map +1 -0
- package/dist/conformance/fixtures.js +950 -0
- package/dist/conformance/fixtures.js.map +1 -0
- package/dist/conformance/index.d.ts +54 -0
- package/dist/conformance/index.d.ts.map +1 -0
- package/dist/conformance/index.js +81 -0
- package/dist/conformance/index.js.map +1 -0
- package/dist/document/canonical.d.ts +4 -0
- package/dist/document/canonical.d.ts.map +1 -0
- package/dist/document/canonical.js +29 -0
- package/dist/document/canonical.js.map +1 -0
- package/dist/document/compile.d.ts +43 -0
- package/dist/document/compile.d.ts.map +1 -0
- package/dist/document/compile.js +787 -0
- package/dist/document/compile.js.map +1 -0
- package/dist/document/diff.d.ts +32 -0
- package/dist/document/diff.d.ts.map +1 -0
- package/dist/document/diff.js +143 -0
- package/dist/document/diff.js.map +1 -0
- package/dist/document/edit.d.ts +63 -0
- package/dist/document/edit.d.ts.map +1 -0
- package/dist/document/edit.js +1420 -0
- package/dist/document/edit.js.map +1 -0
- package/dist/document/expr/analyze.d.ts +14 -0
- package/dist/document/expr/analyze.d.ts.map +1 -0
- package/dist/document/expr/analyze.js +52 -0
- package/dist/document/expr/analyze.js.map +1 -0
- package/dist/document/expr/evaluate.d.ts +36 -0
- package/dist/document/expr/evaluate.d.ts.map +1 -0
- package/dist/document/expr/evaluate.js +344 -0
- package/dist/document/expr/evaluate.js.map +1 -0
- package/dist/document/expr/index.d.ts +8 -0
- package/dist/document/expr/index.d.ts.map +1 -0
- package/dist/document/expr/index.js +5 -0
- package/dist/document/expr/index.js.map +1 -0
- package/dist/document/expr/parse.d.ts +50 -0
- package/dist/document/expr/parse.d.ts.map +1 -0
- package/dist/document/expr/parse.js +240 -0
- package/dist/document/expr/parse.js.map +1 -0
- package/dist/document/expr/print.d.ts +4 -0
- package/dist/document/expr/print.d.ts.map +1 -0
- package/dist/document/expr/print.js +81 -0
- package/dist/document/expr/print.js.map +1 -0
- package/dist/document/findings.d.ts +15 -0
- package/dist/document/findings.d.ts.map +1 -0
- package/dist/document/findings.js +30 -0
- package/dist/document/findings.js.map +1 -0
- package/dist/document/graview-template.d.ts +148 -0
- package/dist/document/graview-template.d.ts.map +1 -0
- package/dist/document/graview-template.js +450 -0
- package/dist/document/graview-template.js.map +1 -0
- package/dist/document/index.d.ts +27 -0
- package/dist/document/index.d.ts.map +1 -0
- package/dist/document/index.js +16 -0
- package/dist/document/index.js.map +1 -0
- package/dist/document/migrate.d.ts +41 -0
- package/dist/document/migrate.d.ts.map +1 -0
- package/dist/document/migrate.js +252 -0
- package/dist/document/migrate.js.map +1 -0
- package/dist/document/patch.d.ts +16 -0
- package/dist/document/patch.d.ts.map +1 -0
- package/dist/document/patch.js +79 -0
- package/dist/document/patch.js.map +1 -0
- package/dist/document/rules.d.ts +40 -0
- package/dist/document/rules.d.ts.map +1 -0
- package/dist/document/rules.js +88 -0
- package/dist/document/rules.js.map +1 -0
- package/dist/document/schema.d.ts +459 -0
- package/dist/document/schema.d.ts.map +1 -0
- package/dist/document/schema.js +197 -0
- package/dist/document/schema.js.map +1 -0
- package/dist/document/template.d.ts +28 -0
- package/dist/document/template.d.ts.map +1 -0
- package/dist/document/template.js +117 -0
- package/dist/document/template.js.map +1 -0
- package/dist/document/to-document.d.ts +34 -0
- package/dist/document/to-document.d.ts.map +1 -0
- package/dist/document/to-document.js +182 -0
- package/dist/document/to-document.js.map +1 -0
- package/dist/document/upgrade.d.ts +9 -0
- package/dist/document/upgrade.d.ts.map +1 -0
- package/dist/document/upgrade.js +19 -0
- package/dist/document/upgrade.js.map +1 -0
- package/dist/document/views.d.ts +65 -0
- package/dist/document/views.d.ts.map +1 -0
- package/dist/document/views.js +264 -0
- package/dist/document/views.js.map +1 -0
- package/dist/formats.d.ts +50 -0
- package/dist/formats.d.ts.map +1 -0
- package/dist/formats.js +75 -0
- package/dist/formats.js.map +1 -0
- package/dist/graph/graph.d.ts +52 -3
- package/dist/graph/graph.d.ts.map +1 -1
- package/dist/graph/graph.js +169 -16
- package/dist/graph/graph.js.map +1 -1
- package/dist/index.d.ts +40 -17
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +29 -10
- package/dist/index.js.map +1 -1
- package/dist/integrity.d.ts +46 -0
- package/dist/integrity.d.ts.map +1 -0
- package/dist/integrity.js +179 -0
- package/dist/integrity.js.map +1 -0
- package/dist/invariants/engine.d.ts +8 -0
- package/dist/invariants/engine.d.ts.map +1 -1
- package/dist/invariants/engine.js +40 -2
- package/dist/invariants/engine.js.map +1 -1
- package/dist/invariants/types.d.ts +19 -0
- package/dist/invariants/types.d.ts.map +1 -1
- package/dist/labels.d.ts +65 -0
- package/dist/labels.d.ts.map +1 -0
- package/dist/labels.js +123 -0
- package/dist/labels.js.map +1 -0
- package/dist/mutations/define-mutation.d.ts.map +1 -1
- package/dist/mutations/define-mutation.js +2 -3
- package/dist/mutations/define-mutation.js.map +1 -1
- package/dist/mutations/derive-edits.d.ts.map +1 -1
- package/dist/mutations/derive-edits.js +20 -1
- package/dist/mutations/derive-edits.js.map +1 -1
- package/dist/mutations/form.d.ts +9 -0
- package/dist/mutations/form.d.ts.map +1 -1
- package/dist/mutations/form.js +20 -0
- package/dist/mutations/form.js.map +1 -1
- package/dist/mutations/node-ref.d.ts +6 -0
- package/dist/mutations/node-ref.d.ts.map +1 -1
- package/dist/mutations/node-ref.js +22 -8
- package/dist/mutations/node-ref.js.map +1 -1
- package/dist/mutations/types.d.ts +8 -0
- package/dist/mutations/types.d.ts.map +1 -1
- package/dist/mutations/words.d.ts +49 -0
- package/dist/mutations/words.d.ts.map +1 -0
- package/dist/mutations/words.js +61 -0
- package/dist/mutations/words.js.map +1 -0
- package/dist/ops/log.d.ts +145 -4
- package/dist/ops/log.d.ts.map +1 -1
- package/dist/ops/log.js +220 -51
- package/dist/ops/log.js.map +1 -1
- package/dist/ops/revisions.d.ts +66 -0
- package/dist/ops/revisions.d.ts.map +1 -0
- package/dist/ops/revisions.js +97 -0
- package/dist/ops/revisions.js.map +1 -0
- package/dist/ops/types.d.ts +49 -1
- package/dist/ops/types.d.ts.map +1 -1
- package/dist/ops/undo.d.ts +23 -2
- package/dist/ops/undo.d.ts.map +1 -1
- package/dist/ops/undo.js +107 -1
- package/dist/ops/undo.js.map +1 -1
- package/dist/ops/withheld.d.ts +37 -0
- package/dist/ops/withheld.d.ts.map +1 -0
- package/dist/ops/withheld.js +84 -0
- package/dist/ops/withheld.js.map +1 -0
- package/dist/permissions/policy.d.ts +15 -0
- package/dist/permissions/policy.d.ts.map +1 -1
- package/dist/permissions/policy.js +28 -1
- package/dist/permissions/policy.js.map +1 -1
- package/dist/permissions/sight.d.ts +50 -0
- package/dist/permissions/sight.d.ts.map +1 -0
- package/dist/permissions/sight.js +76 -0
- package/dist/permissions/sight.js.map +1 -0
- package/dist/permissions/types.d.ts +26 -0
- package/dist/permissions/types.d.ts.map +1 -1
- package/dist/permissions/types.js.map +1 -1
- package/dist/persistence/memory.d.ts.map +1 -1
- package/dist/persistence/memory.js +25 -0
- package/dist/persistence/memory.js.map +1 -1
- package/dist/persistence/sql.d.ts +43 -0
- package/dist/persistence/sql.d.ts.map +1 -0
- package/dist/persistence/sql.js +154 -0
- package/dist/persistence/sql.js.map +1 -0
- package/dist/persistence/sqlite.d.ts +17 -3
- package/dist/persistence/sqlite.d.ts.map +1 -1
- package/dist/persistence/sqlite.js +32 -96
- package/dist/persistence/sqlite.js.map +1 -1
- package/dist/persistence/types.d.ts +19 -0
- package/dist/persistence/types.d.ts.map +1 -1
- package/dist/presence.d.ts +31 -0
- package/dist/presence.d.ts.map +1 -1
- package/dist/presence.js +36 -0
- package/dist/presence.js.map +1 -1
- package/dist/scaffold/from-template.d.ts +16 -0
- package/dist/scaffold/from-template.d.ts.map +1 -0
- package/dist/scaffold/from-template.js +157 -0
- package/dist/scaffold/from-template.js.map +1 -0
- package/dist/scaffold/index.d.ts +10 -1
- package/dist/scaffold/index.d.ts.map +1 -1
- package/dist/scaffold/index.js +35 -7
- package/dist/scaffold/index.js.map +1 -1
- package/dist/scaffold/names.d.ts +4 -0
- package/dist/scaffold/names.d.ts.map +1 -1
- package/dist/scaffold/names.js.map +1 -1
- package/dist/scaffold/project.d.ts +1 -1
- package/dist/scaffold/project.d.ts.map +1 -1
- package/dist/scaffold/project.js +44 -13
- package/dist/scaffold/project.js.map +1 -1
- package/dist/scaffold/ui.d.ts.map +1 -1
- package/dist/scaffold/ui.js +19 -10
- package/dist/scaffold/ui.js.map +1 -1
- package/dist/schema/define-node.d.ts +20 -0
- package/dist/schema/define-node.d.ts.map +1 -1
- package/dist/schema/define-node.js +27 -2
- package/dist/schema/define-node.js.map +1 -1
- package/dist/schema/path.d.ts +19 -0
- package/dist/schema/path.d.ts.map +1 -0
- package/dist/schema/path.js +34 -0
- package/dist/schema/path.js.map +1 -0
- package/dist/schema/types.d.ts +6 -0
- package/dist/schema/types.d.ts.map +1 -1
- package/dist/seen.d.ts +58 -0
- package/dist/seen.d.ts.map +1 -0
- package/dist/seen.js +194 -0
- package/dist/seen.js.map +1 -0
- package/dist/store.d.ts +317 -8
- package/dist/store.d.ts.map +1 -1
- package/dist/store.js +720 -37
- package/dist/store.js.map +1 -1
- package/dist/testing.d.ts +6 -0
- package/dist/testing.d.ts.map +1 -1
- package/dist/testing.js +3 -1
- package/dist/testing.js.map +1 -1
- package/dist/theme/palettes.d.ts.map +1 -1
- package/dist/theme/palettes.js +4 -0
- package/dist/theme/palettes.js.map +1 -1
- package/dist/theme/types.d.ts +9 -0
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/theme/types.js +4 -0
- package/dist/theme/types.js.map +1 -1
- package/dist/validate-graph.d.ts +83 -0
- package/dist/validate-graph.d.ts.map +1 -0
- package/dist/validate-graph.js +288 -0
- package/dist/validate-graph.js.map +1 -0
- package/dist/version.d.ts +3 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +3 -0
- package/dist/version.js.map +1 -0
- package/dist/views/types.d.ts +8 -0
- package/dist/views/types.d.ts.map +1 -1
- package/dist/views/types.js +5 -0
- package/dist/views/types.js.map +1 -1
- package/dist/watched.d.ts +39 -0
- package/dist/watched.d.ts.map +1 -1
- package/dist/watched.js +94 -1
- package/dist/watched.js.map +1 -1
- package/dist/who.d.ts +24 -1
- package/dist/who.d.ts.map +1 -1
- package/dist/who.js +49 -2
- package/dist/who.js.map +1 -1
- 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"}
|
package/dist/formats.js
ADDED
|
@@ -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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"}
|
package/dist/graph/graph.d.ts
CHANGED
|
@@ -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
|
-
/**
|
|
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":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnE,OAAO,EAAiB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAW,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC1D,OAAO,EAAU,KAAK,SAAS,EAAE,KAAK,WAAW,EAAE,KAAK,aAAa,EAAE,MAAM,YAAY,CAAC;AAE1F,MAAM,WAAW,YAAY;IAC3B
|
|
1
|
+
{"version":3,"file":"graph.d.ts","sourceRoot":"","sources":["../../src/graph/graph.ts"],"names":[],"mappings":"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"}
|