@graview/core 0.1.12 → 0.1.14
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 +23 -2
- package/dist/address.d.ts +31 -0
- package/dist/address.d.ts.map +1 -0
- package/dist/address.js +53 -0
- package/dist/address.js.map +1 -0
- package/dist/app.d.ts +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/arrange.d.ts +13 -183
- package/dist/arrange.d.ts.map +1 -1
- package/dist/arrange.js +12 -470
- package/dist/arrange.js.map +1 -1
- package/dist/arrangement.d.ts +169 -0
- package/dist/arrangement.d.ts.map +1 -0
- package/dist/arrangement.js +220 -0
- package/dist/arrangement.js.map +1 -0
- package/dist/arranging.d.ts +28 -0
- package/dist/arranging.d.ts.map +1 -0
- package/dist/arranging.js +264 -0
- package/dist/arranging.js.map +1 -0
- package/dist/capabilities.js +1 -1
- package/dist/capabilities.js.map +1 -1
- package/dist/cli/check/hidden-reads.d.ts.map +1 -1
- package/dist/cli/check/hidden-reads.js +31 -0
- package/dist/cli/check/hidden-reads.js.map +1 -1
- package/dist/cli/check/lenses.d.ts.map +1 -1
- package/dist/cli/check/lenses.js +29 -1
- package/dist/cli/check/lenses.js.map +1 -1
- package/dist/cli/describe.d.ts.map +1 -1
- package/dist/cli/describe.js +16 -6
- package/dist/cli/describe.js.map +1 -1
- package/dist/cli/docs.js +1 -1
- package/dist/cli/docs.js.map +1 -1
- package/dist/columns.d.ts +48 -16
- package/dist/columns.d.ts.map +1 -1
- package/dist/columns.js +65 -22
- package/dist/columns.js.map +1 -1
- package/dist/conformance/fixtures.d.ts.map +1 -1
- package/dist/conformance/fixtures.js +19 -1
- package/dist/conformance/fixtures.js.map +1 -1
- package/dist/describe.d.ts +2 -2
- package/dist/describe.d.ts.map +1 -1
- package/dist/describe.js +1 -1
- package/dist/describe.js.map +1 -1
- package/dist/document/act-findings.d.ts +5 -0
- package/dist/document/act-findings.d.ts.map +1 -0
- package/dist/document/act-findings.js +84 -0
- package/dist/document/act-findings.js.map +1 -0
- package/dist/document/compile-checked.d.ts.map +1 -1
- package/dist/document/compile-checked.js +11 -4
- package/dist/document/compile-checked.js.map +1 -1
- package/dist/document/compile.d.ts +15 -4
- package/dist/document/compile.d.ts.map +1 -1
- package/dist/document/compile.js +102 -18
- package/dist/document/compile.js.map +1 -1
- package/dist/document/describe-coverage.d.ts +37 -0
- package/dist/document/describe-coverage.d.ts.map +1 -0
- package/dist/document/describe-coverage.js +162 -0
- package/dist/document/describe-coverage.js.map +1 -0
- package/dist/document/describe-place.d.ts.map +1 -1
- package/dist/document/describe-place.js +14 -1
- package/dist/document/describe-place.js.map +1 -1
- package/dist/document/diff.d.ts +5 -0
- package/dist/document/diff.d.ts.map +1 -1
- package/dist/document/diff.js +12 -3
- package/dist/document/diff.js.map +1 -1
- package/dist/document/edit.d.ts +1 -1
- package/dist/document/edit.d.ts.map +1 -1
- package/dist/document/edit.js +63 -6
- package/dist/document/edit.js.map +1 -1
- package/dist/document/far-end.d.ts +15 -0
- package/dist/document/far-end.d.ts.map +1 -0
- package/dist/document/far-end.js +26 -0
- package/dist/document/far-end.js.map +1 -0
- package/dist/document/index.d.ts +1 -1
- package/dist/document/index.d.ts.map +1 -1
- package/dist/document/migrate.d.ts.map +1 -1
- package/dist/document/migrate.js +7 -5
- package/dist/document/migrate.js.map +1 -1
- package/dist/document/range.d.ts +17 -0
- package/dist/document/range.d.ts.map +1 -0
- package/dist/document/range.js +46 -0
- package/dist/document/range.js.map +1 -0
- package/dist/document/schema.d.ts +23 -0
- package/dist/document/schema.d.ts.map +1 -1
- package/dist/document/schema.js +16 -0
- package/dist/document/schema.js.map +1 -1
- package/dist/document/thumbnail.d.ts +21 -0
- package/dist/document/thumbnail.d.ts.map +1 -1
- package/dist/document/thumbnail.js +139 -32
- package/dist/document/thumbnail.js.map +1 -1
- package/dist/document/to-document.d.ts.map +1 -1
- package/dist/document/to-document.js +16 -2
- package/dist/document/to-document.js.map +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/mutations/define-mutation.d.ts.map +1 -1
- package/dist/mutations/define-mutation.js +9 -1
- package/dist/mutations/define-mutation.js.map +1 -1
- package/dist/mutations/derive-edits.d.ts +8 -0
- package/dist/mutations/derive-edits.d.ts.map +1 -1
- package/dist/mutations/derive-edits.js +30 -7
- package/dist/mutations/derive-edits.js.map +1 -1
- package/dist/mutations/form.d.ts +2 -0
- package/dist/mutations/form.d.ts.map +1 -1
- package/dist/mutations/form.js +1 -0
- package/dist/mutations/form.js.map +1 -1
- package/dist/mutations/node-ref.d.ts +4 -1
- package/dist/mutations/node-ref.d.ts.map +1 -1
- package/dist/mutations/node-ref.js +6 -0
- package/dist/mutations/node-ref.js.map +1 -1
- package/dist/mutations/types.d.ts +16 -0
- package/dist/mutations/types.d.ts.map +1 -1
- package/dist/places.js +1 -1
- package/dist/places.js.map +1 -1
- package/dist/refusal.d.ts.map +1 -1
- package/dist/refusal.js +4 -0
- package/dist/refusal.js.map +1 -1
- package/dist/refused.d.ts +20 -0
- package/dist/refused.d.ts.map +1 -0
- package/dist/refused.js +24 -0
- package/dist/refused.js.map +1 -0
- package/dist/scaffold/project.d.ts.map +1 -1
- package/dist/scaffold/project.js +3 -0
- package/dist/scaffold/project.js.map +1 -1
- package/dist/search.d.ts +1 -1
- package/dist/search.d.ts.map +1 -1
- package/dist/search.js +1 -1
- package/dist/search.js.map +1 -1
- package/dist/theme/derive.d.ts.map +1 -1
- package/dist/theme/derive.js +5 -4
- package/dist/theme/derive.js.map +1 -1
- package/dist/theme/types.d.ts.map +1 -1
- package/dist/theme/types.js +5 -0
- package/dist/theme/types.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +5 -1
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { withArticle } from "../schema/define-node.js";
|
|
2
|
+
import { farEnd } from "./far-end.js";
|
|
3
|
+
import { error } from "./findings.js";
|
|
4
|
+
import { outsideRange } from "./range.js";
|
|
5
|
+
/*
|
|
6
|
+
* WHAT A DOCUMENT SAYS OF ITS RANGES AND OF THE OTHER END OF ITS LINKS
|
|
7
|
+
* (FR-114, FR-115), judged with the checker (`compileDocument`) and not by
|
|
8
|
+
* a page that compiles a document its host has already judged: these are
|
|
9
|
+
* the host's to refuse when the document is kept, and the hosted page does
|
|
10
|
+
* not carry them (FR-57).
|
|
11
|
+
*/
|
|
12
|
+
const asArray = (v) => (v === undefined ? [] : Array.isArray(v) ? v : [v]);
|
|
13
|
+
/** A number field's range, and its default against it (FR-114). */
|
|
14
|
+
function rangeFindings(document) {
|
|
15
|
+
const out = [];
|
|
16
|
+
for (const [kind, spec] of Object.entries(document.kinds)) {
|
|
17
|
+
for (const [field, f] of Object.entries(spec.fields)) {
|
|
18
|
+
const at = `kinds.${kind}.fields.${field}`;
|
|
19
|
+
const numeric = f.type === "number" || f.type === "integer";
|
|
20
|
+
for (const key of ["min", "max", "step"])
|
|
21
|
+
if (!numeric && f[key] !== undefined)
|
|
22
|
+
out.push(error("field-range", `${at}.${key}`, `"${key}" belongs only on a number or integer field`));
|
|
23
|
+
if (numeric && f.min !== undefined && f.max !== undefined && f.min > f.max)
|
|
24
|
+
out.push(error("field-range", `${at}.max`, `"max" (${f.max}) is below "min" (${f.min})`));
|
|
25
|
+
if (numeric && f.step !== undefined && !(f.step > 0))
|
|
26
|
+
out.push(error("field-range", `${at}.step`, '"step" is more than zero, like 1 or 0.5'));
|
|
27
|
+
// A default is a value the field takes, so it is inside the field's range.
|
|
28
|
+
const outside = f.default !== undefined ? outsideRange(f.default, f, field) : undefined;
|
|
29
|
+
if (outside)
|
|
30
|
+
out.push(error("default-range", `${at}.default`, outside));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* What an act says of the other end of what it connects (FR-115): a
|
|
37
|
+
* `setsOther` needs a relation to have an other end, and sets fields that
|
|
38
|
+
* record has; a `replaces` needs a link it is making, and names relations
|
|
39
|
+
* that join the subject to the kinds that link does.
|
|
40
|
+
*/
|
|
41
|
+
function otherEndFindings(name, act, document) {
|
|
42
|
+
const out = [];
|
|
43
|
+
const at = `acts.${name}`;
|
|
44
|
+
const subject = asArray(act.on);
|
|
45
|
+
const relation = act.connects ?? act.severs;
|
|
46
|
+
const end = relation ? farEnd(document.kinds, relation, subject) : undefined;
|
|
47
|
+
if (act.setsOther) {
|
|
48
|
+
if (!relation)
|
|
49
|
+
out.push(error("act-sets-other", `${at}.setsOther`, `"${name}" sets the record at the other end of what it connects, and connects nothing`, 'say what it "connects" (or "severs"), or set its subject with "sets"'));
|
|
50
|
+
else if (end && end.kinds !== "*") {
|
|
51
|
+
for (const field of Object.keys(act.setsOther)) {
|
|
52
|
+
for (const kind of end.kinds) {
|
|
53
|
+
const spec = document.kinds[kind];
|
|
54
|
+
if (!spec || spec.fields[field])
|
|
55
|
+
continue;
|
|
56
|
+
if (spec.computed?.[field] !== undefined)
|
|
57
|
+
out.push(error("computed-written", `${at}.setsOther.${field}`, `${kind}'s ${field} is worked out, not written: no act can set it`, "set the stored fields it is worked out from"));
|
|
58
|
+
else
|
|
59
|
+
out.push(error("act-field", `${at}.setsOther.${field}`, `${kind} has no field "${field}"`));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
if (act.replaces) {
|
|
65
|
+
if (!act.connects)
|
|
66
|
+
out.push(error("act-replaces", `${at}.replaces`, `"${name}" replaces the links of what it connects, and connects nothing`, 'say what it "connects", or sever with "severs"'));
|
|
67
|
+
else if (act.replaces !== true && end && end.kinds !== "*") {
|
|
68
|
+
const toward = end.kinds;
|
|
69
|
+
for (const other of act.replaces) {
|
|
70
|
+
const there = farEnd(document.kinds, other, subject);
|
|
71
|
+
if (!there)
|
|
72
|
+
out.push(error("act-edge", `${at}.replaces`, `"${other}" is not a relation any kind declares`));
|
|
73
|
+
else if (there.kinds !== "*" && !there.kinds.some((kind) => toward.includes(kind)))
|
|
74
|
+
out.push(error("act-replaces", `${at}.replaces`, `"${other}" does not join ${subject.join(" or ")} to ${withArticle(toward[0] ?? "record")}, so "${name}" has no such links to replace`));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return out;
|
|
79
|
+
}
|
|
80
|
+
/** Every range and other-end finding of a document, in its order: fields, then acts. */
|
|
81
|
+
export function actFindings(document) {
|
|
82
|
+
return [...rangeFindings(document), ...Object.entries(document.acts ?? {}).flatMap(([name, act]) => otherEndFindings(name, act, document))];
|
|
83
|
+
}
|
|
84
|
+
//# sourceMappingURL=act-findings.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"act-findings.js","sourceRoot":"","sources":["../../src/document/act-findings.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile-checked.d.ts","sourceRoot":"","sources":["../../src/document/compile-checked.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"compile-checked.d.ts","sourceRoot":"","sources":["../../src/document/compile-checked.ts"],"names":[],"mappings":"AAEA,OAAO,EAA6E,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAW3K;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,gBAAgB,GAAG,eAAe,CAqB9G"}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { checkApp } from "../cli/check.js";
|
|
2
|
-
import {
|
|
2
|
+
import { actFindings } from "./act-findings.js";
|
|
3
|
+
import { compileDocumentWithoutCheck, frameworkPath, inDocumentWords, readDocument } from "./compile.js";
|
|
3
4
|
import { hasErrors } from "./findings.js";
|
|
4
5
|
import { viewBraces } from "./views.js";
|
|
5
6
|
/*
|
|
@@ -16,11 +17,17 @@ import { viewBraces } from "./views.js";
|
|
|
16
17
|
*/
|
|
17
18
|
export function compileDocument(raw, options = {}) {
|
|
18
19
|
const compiled = compileDocumentWithoutCheck(raw, options);
|
|
19
|
-
if (!compiled.ok)
|
|
20
|
-
|
|
20
|
+
if (!compiled.ok) {
|
|
21
|
+
// A range and the other end of a link are judged here too (FR-114, FR-115), so a refusal says all of what is wrong.
|
|
22
|
+
const read = readDocument(raw).document;
|
|
23
|
+
return read ? { ok: false, findings: [...compiled.findings, ...actFindings(read)] } : compiled;
|
|
24
|
+
}
|
|
21
25
|
const { app, document } = compiled;
|
|
26
|
+
const own = actFindings(document);
|
|
27
|
+
if (hasErrors(own))
|
|
28
|
+
return { ok: false, findings: [...compiled.findings, ...own] };
|
|
22
29
|
// Braces in a block's plain words (FR-99): asked here, with the checker, and not of a page that compiles without it.
|
|
23
|
-
const findings = [...compiled.findings, ...viewBraces(document.views, "views", undefined, document.lenses)];
|
|
30
|
+
const findings = [...compiled.findings, ...own, ...viewBraces(document.views, "views", undefined, document.lenses)];
|
|
24
31
|
const check = checkApp(app);
|
|
25
32
|
for (const f of check.findings) {
|
|
26
33
|
const finding = { severity: f.severity === "error" ? "error" : f.severity === "warning" ? "warning" : "note", code: `check:${f.code}`, path: frameworkPath(f.where, document), message: f.message, ...(f.fix ? { fix: f.fix } : {}) };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile-checked.js","sourceRoot":"","sources":["../../src/document/compile-checked.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,OAAO,EAAE,2BAA2B,EAAE,aAAa,EAAE,eAAe,EAAoE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"compile-checked.js","sourceRoot":"","sources":["../../src/document/compile-checked.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type GraviewApp } from "../index.js";
|
|
2
|
+
import { ActRefusal } from "../refused.js";
|
|
2
3
|
import { type KindShape } from "./expr/evaluate.js";
|
|
3
4
|
import { type Finding } from "./findings.js";
|
|
4
5
|
import { type ActSpec, type EffectSpec, type GraviewDocument, type SightSpec } from "./schema.js";
|
|
@@ -32,10 +33,20 @@ export declare function readDocument(raw: unknown): {
|
|
|
32
33
|
readonly findings: readonly Finding[];
|
|
33
34
|
};
|
|
34
35
|
export declare function kindShapes(document: GraviewDocument): Map<string, KindShape>;
|
|
35
|
-
/**
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
/**
|
|
37
|
+
* What `replaces` means (FR-115): before the act connects, the subject's
|
|
38
|
+
* links of these relations are severed — each at the subject's own end —
|
|
39
|
+
* all but the link the act is making. Only an act's shorthand says it.
|
|
40
|
+
*/
|
|
41
|
+
export interface ReplaceEffect {
|
|
42
|
+
readonly replace: readonly string[];
|
|
43
|
+
/** The relation the act connects: its link to `$to` is the one kept. */
|
|
44
|
+
readonly keep: string;
|
|
38
45
|
}
|
|
46
|
+
/** An effect as an act means it: one a document lists, or what a shorthand alone says. */
|
|
47
|
+
export type ActEffect = EffectSpec | ReplaceEffect;
|
|
48
|
+
/** The effects an act's shorthands mean, in order. */
|
|
49
|
+
export declare function effectsOf(act: ActSpec, document: GraviewDocument): readonly ActEffect[];
|
|
39
50
|
/**
|
|
40
51
|
* A DOCUMENT COMPILED WITHOUT THE FRAMEWORK'S CHECKER: its own sentences
|
|
41
52
|
* still judged, `checkApp` not asked. For a page drawing a document its host
|
|
@@ -53,5 +64,5 @@ export declare function frameworkPath(where: string, document: GraviewDocument):
|
|
|
53
64
|
* and the same first three, in the words of the format they hold.
|
|
54
65
|
*/
|
|
55
66
|
export declare function inDocumentWords(finding: Finding, where: string, document: GraviewDocument): Finding;
|
|
56
|
-
export {
|
|
67
|
+
export { ActRefusal };
|
|
57
68
|
//# sourceMappingURL=compile.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/document/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAaL,KAAK,UAAU,EAMhB,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"compile.d.ts","sourceRoot":"","sources":["../../src/document/compile.ts"],"names":[],"mappings":"AAAA,OAAO,EAaL,KAAK,UAAU,EAMhB,MAAM,aAAa,CAAC;AAGrB,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAG3C,OAAO,EAAgD,KAAK,SAAS,EAAc,MAAM,oBAAoB,CAAC;AAE9G,OAAO,EAA6B,KAAK,OAAO,EAAE,MAAM,eAAe,CAAC;AACxE,OAAO,EAGL,KAAK,OAAO,EACZ,KAAK,UAAU,EAEf,KAAK,eAAe,EAEpB,KAAK,SAAS,EAEf,MAAM,aAAa,CAAC;AAmBrB,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAC;IACzB,QAAQ,CAAC,QAAQ,EAAE,eAAe,CAAC;IACnC,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;IACtC,2EAA2E;IAC3E,QAAQ,CAAC,MAAM,EAAE,SAAS,SAAS,EAAE,GAAG,SAAS,CAAC;IAClD,QAAQ,CAAC,KAAK,EAAE,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IACnB,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,cAAc;IAC7B,6DAA6D;IAC7D,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,MAAM,CAAC;IAC9B;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;CACrC;AAKD,mGAAmG;AACnG,wBAAgB,YAAY,CAAC,GAAG,EAAE,OAAO,GAAG;IAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,SAAS,OAAO,EAAE,CAAA;CAAE,CAoCzH;AA2BD,wBAAgB,UAAU,CAAC,QAAQ,EAAE,eAAe,GAAG,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAW5E;AAED;;;;GAIG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,wEAAwE;IACxE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,0FAA0F;AAC1F,MAAM,MAAM,SAAS,GAAG,UAAU,GAAG,aAAa,CAAC;AAEnD,sDAAsD;AACtD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,GAAG,SAAS,SAAS,EAAE,CA+BvF;AA4TD;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,gBAAgB,GAAG,eAAe,CA+V1H;AAED,4GAA4G;AAC5G,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,MAAM,CAM9E;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,QAAQ,EAAE,eAAe,GAAG,OAAO,CAMnG;AAED,OAAO,EAAE,UAAU,EAAE,CAAC"}
|
package/dist/document/compile.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { RuleBudgetError, withArticle, brandFromAccent, createSchema, defineInvariant, defineMutation, defineNode, SCHEMES, } from "../index.js";
|
|
2
2
|
import * as z from "../schema/zod.js";
|
|
3
3
|
import { refTo } from "../mutations/node-ref.js";
|
|
4
|
+
import { ActRefusal } from "../refused.js";
|
|
4
5
|
import { analyzeExpr } from "./expr/analyze.js";
|
|
5
6
|
import { rememberDocument } from "./to-document.js";
|
|
6
7
|
import { evaluateExpr, ExprBudgetError, ExprEvalError } from "./expr/evaluate.js";
|
|
@@ -10,6 +11,7 @@ import { DocumentSpec, MAX_DOCUMENT_BYTES, } from "./schema.js";
|
|
|
10
11
|
import { parseTemplate, renderTemplate, TemplateError } from "./template.js";
|
|
11
12
|
import { upgradeDocument } from "./upgrade.js";
|
|
12
13
|
import { homeOf, validateViews, viewsOf } from "./views.js";
|
|
14
|
+
import { farEnd } from "./far-end.js";
|
|
13
15
|
import { computedOf, parsedComputed, validateComputed, workedOutAlone } from "./computed.js";
|
|
14
16
|
const BUILTIN_REFS = new Set(["subject", "now", "today"]);
|
|
15
17
|
const SUBJECT_ARG = "id";
|
|
@@ -88,6 +90,13 @@ export function kindShapes(document) {
|
|
|
88
90
|
export function effectsOf(act, document) {
|
|
89
91
|
// Shorthands first, then any listed effects: an act may say "writes quote" and also set a status.
|
|
90
92
|
const effects = [];
|
|
93
|
+
const subject = asArray(act.on);
|
|
94
|
+
// A relation joins its subject from whichever end the declaration puts it (FR-115): `owns` on a component links from the person given.
|
|
95
|
+
const link = (relation, verb) => {
|
|
96
|
+
const reversed = farEnd(document.kinds, relation, subject)?.reversed === true;
|
|
97
|
+
const [from, to] = reversed ? ["$to", "$subject"] : ["$subject", "$to"];
|
|
98
|
+
return verb === "connect" ? { connect: relation, from, to } : { sever: relation, from, to };
|
|
99
|
+
};
|
|
91
100
|
if (act.creates) {
|
|
92
101
|
const kind = document.kinds[act.creates];
|
|
93
102
|
const set = {};
|
|
@@ -104,10 +113,16 @@ export function effectsOf(act, document) {
|
|
|
104
113
|
// An act that makes a record already asks for each of its fields: `writes` beside `creates` (and no `on`) names some of them again, not a subject.
|
|
105
114
|
if (act.writes && !(act.creates && act.on === undefined))
|
|
106
115
|
effects.push({ set: Object.fromEntries(act.writes.map((f) => [f, `$${f}`])) });
|
|
107
|
-
if (act.connects)
|
|
108
|
-
|
|
116
|
+
if (act.connects) {
|
|
117
|
+
if (act.replaces)
|
|
118
|
+
effects.push({ replace: act.replaces === true ? [act.connects] : [...act.replaces], keep: act.connects });
|
|
119
|
+
effects.push(link(act.connects, "connect"));
|
|
120
|
+
}
|
|
109
121
|
if (act.severs)
|
|
110
|
-
effects.push(
|
|
122
|
+
effects.push(link(act.severs, "sever"));
|
|
123
|
+
// What it sets on the record at the other end (FR-115): that record is its `$to`.
|
|
124
|
+
if (act.setsOther && (act.connects || act.severs))
|
|
125
|
+
effects.push({ set: act.setsOther, target: "$to" });
|
|
111
126
|
if (act.removes)
|
|
112
127
|
effects.push({ remove: "$subject" });
|
|
113
128
|
if (act.effects)
|
|
@@ -352,11 +367,17 @@ function fieldSchema(spec, optional) {
|
|
|
352
367
|
schema = z.string().check(z.maxLength(20_000));
|
|
353
368
|
break;
|
|
354
369
|
case "number":
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
370
|
+
case "integer": {
|
|
371
|
+
// Its range (FR-114) is the schema's: every form, tool and apply reads it from here.
|
|
372
|
+
const range = [
|
|
373
|
+
...(spec.type === "integer" ? [z.int()] : []),
|
|
374
|
+
...(spec.min === undefined ? [] : [z.gte(spec.min)]),
|
|
375
|
+
...(spec.max === undefined ? [] : [z.lte(spec.max)]),
|
|
376
|
+
...(spec.step === undefined ? [] : [z.multipleOf(spec.step)]),
|
|
377
|
+
];
|
|
378
|
+
schema = range.length > 0 ? z.number().check(...range) : z.number();
|
|
359
379
|
break;
|
|
380
|
+
}
|
|
360
381
|
case "boolean":
|
|
361
382
|
schema = z.boolean();
|
|
362
383
|
break;
|
|
@@ -394,16 +415,24 @@ function argsOf(name, act, effects, document, edges) {
|
|
|
394
415
|
const args = new Map();
|
|
395
416
|
const subjectKinds = asArray(act.on);
|
|
396
417
|
const created = new Map();
|
|
418
|
+
/** The kinds a record argument names, by argument: what a `set` on it (a `setsOther`) is checked against. */
|
|
419
|
+
const named = new Map();
|
|
397
420
|
const usesSubject = subjectKinds.length > 0 ||
|
|
398
421
|
effects.some((e) => ("remove" in e && refName(e.remove) === "subject") || ("from" in e && (refName(e.from) === "subject" || refName(e.to) === "subject")) || ("set" in e && !("create" in e) && refName(e.target ?? "$subject") === "subject"));
|
|
399
422
|
if (usesSubject)
|
|
400
423
|
args.set(SUBJECT_ARG, { schema: refTo(subjectKinds.length > 0 ? subjectKinds : "*"), required: true });
|
|
401
424
|
const declared = act.args ?? {};
|
|
402
425
|
const writesOnlyOne = act.writes?.length === 1;
|
|
403
|
-
|
|
426
|
+
/*
|
|
427
|
+
* A declared argument that fills a number field and says no range of its
|
|
428
|
+
* own is asked for within the field's (FR-114): the form will not take
|
|
429
|
+
* what the record would refuse.
|
|
430
|
+
*/
|
|
431
|
+
const withRangeOf = (d, fed) => fed && d.type === fed.type && d.min === undefined && d.max === undefined && d.step === undefined ? { ...d, ...(fed.min === undefined ? {} : { min: fed.min }), ...(fed.max === undefined ? {} : { max: fed.max }), ...(fed.step === undefined ? {} : { step: fed.step }) } : d;
|
|
432
|
+
const note = (arg, schema, fed) => {
|
|
404
433
|
if (arg === SUBJECT_ARG || BUILTIN_REFS.has(arg) || created.has(arg) || args.has(arg))
|
|
405
434
|
return;
|
|
406
|
-
const d = declared[arg];
|
|
435
|
+
const d = declared[arg] ? withRangeOf(declared[arg], fed) : undefined;
|
|
407
436
|
args.set(arg, d ? { schema: fieldSchema(d, !d.required), required: Boolean(d.required) } : schema());
|
|
408
437
|
};
|
|
409
438
|
for (const effect of effects) {
|
|
@@ -414,7 +443,7 @@ function argsOf(name, act, effects, document, edges) {
|
|
|
414
443
|
const spec = kind?.fields[field];
|
|
415
444
|
if (arg && spec) {
|
|
416
445
|
const required = Boolean(spec.required) && spec.default === undefined;
|
|
417
|
-
note(arg, () => ({ schema: fieldSchema(spec, !required), required }));
|
|
446
|
+
note(arg, () => ({ schema: fieldSchema(spec, !required), required }), spec);
|
|
418
447
|
}
|
|
419
448
|
}
|
|
420
449
|
if (effect.as)
|
|
@@ -427,12 +456,14 @@ function argsOf(name, act, effects, document, edges) {
|
|
|
427
456
|
if (!arg)
|
|
428
457
|
continue;
|
|
429
458
|
const kinds = end === "to" ? edge?.to ?? "*" : edge?.from ?? "*";
|
|
459
|
+
if (kinds !== "*" && !named.has(arg))
|
|
460
|
+
named.set(arg, kinds);
|
|
430
461
|
note(arg, () => ({ schema: refTo(kinds === "*" ? "*" : kinds), required: true }));
|
|
431
462
|
}
|
|
432
463
|
}
|
|
433
464
|
else if ("set" in effect) {
|
|
434
465
|
const target = refName(effect.target ?? "$subject");
|
|
435
|
-
const targetKind = target === "subject" ? subjectKinds[0] : created.get(target ?? "");
|
|
466
|
+
const targetKind = target === "subject" ? subjectKinds[0] : (created.get(target ?? "") ?? named.get(target ?? "")?.[0]);
|
|
436
467
|
if (target && target !== "subject" && !created.has(target))
|
|
437
468
|
note(target, () => ({ schema: refTo("*"), required: true }));
|
|
438
469
|
for (const [field, value] of Object.entries(effect.set)) {
|
|
@@ -440,7 +471,7 @@ function argsOf(name, act, effects, document, edges) {
|
|
|
440
471
|
if (!arg)
|
|
441
472
|
continue;
|
|
442
473
|
const spec = targetKind ? document.kinds[targetKind]?.fields[field] : undefined;
|
|
443
|
-
note(arg, () => (spec ? { schema: fieldSchema(spec, !writesOnlyOne), required: writesOnlyOne } : { schema: z.optional(z.unknown()), required: false }));
|
|
474
|
+
note(arg, () => (spec ? { schema: fieldSchema(spec, !writesOnlyOne), required: writesOnlyOne } : { schema: z.optional(z.unknown()), required: false }), spec);
|
|
444
475
|
}
|
|
445
476
|
}
|
|
446
477
|
else if ("remove" in effect) {
|
|
@@ -455,8 +486,8 @@ function argsOf(name, act, effects, document, edges) {
|
|
|
455
486
|
void name;
|
|
456
487
|
return args;
|
|
457
488
|
}
|
|
458
|
-
|
|
459
|
-
|
|
489
|
+
/** An act's own refusal: the framework's typed one (FR-110), which a host shows rather than calling it a failure. */
|
|
490
|
+
const Refused = ActRefusal;
|
|
460
491
|
/**
|
|
461
492
|
* A DOCUMENT COMPILED WITHOUT THE FRAMEWORK'S CHECKER: its own sentences
|
|
462
493
|
* still judged, `checkApp` not asked. For a page drawing a document its host
|
|
@@ -532,12 +563,50 @@ export function compileDocumentWithoutCheck(raw, options = {}) {
|
|
|
532
563
|
const title = act.title ?? name.replace(/-/g, " ");
|
|
533
564
|
const guard = act.allowedWhen ? parseExpr(act.allowedWhen) : undefined;
|
|
534
565
|
const refusal = act.refusal ? parseTemplate(act.refusal) : undefined;
|
|
535
|
-
const destructive = act.destructive ?? effects.some((e) => "remove" in e || "sever" in e);
|
|
566
|
+
const destructive = act.destructive ?? effects.some((e) => "remove" in e || "sever" in e || "replace" in e);
|
|
536
567
|
const creates = [...new Set(effects.flatMap((e) => ("create" in e ? [e.create] : [])))];
|
|
537
568
|
const connects = [...new Set(effects.flatMap((e) => ("connect" in e ? [e.connect] : [])))];
|
|
538
|
-
|
|
569
|
+
// What it may sever: what it says it severs, and what it replaces (FR-115).
|
|
570
|
+
const severs = [...new Set(effects.flatMap((e) => ("sever" in e ? [e.sever] : "replace" in e ? e.replace : [])))];
|
|
539
571
|
// An act WRITES only what it sets on its subject; setting fields on a record it just made is part of making it.
|
|
540
572
|
const writes = [...new Set(effects.flatMap((e) => ("set" in e && !("create" in e) && (refName(e.target ?? "$subject") === "subject") ? Object.keys(e.set) : [])))];
|
|
573
|
+
/*
|
|
574
|
+
* And what it sets on the record at an end of a link it makes or breaks
|
|
575
|
+
* (FR-115's `setsOther`), by that end's kinds: not the subject's, but a
|
|
576
|
+
* field another act sets, so no derived edit offers it freely.
|
|
577
|
+
*/
|
|
578
|
+
const ends = new Map();
|
|
579
|
+
for (const e of effects) {
|
|
580
|
+
if (!("connect" in e) && !("sever" in e))
|
|
581
|
+
continue;
|
|
582
|
+
const edge = edges.get("connect" in e ? e.connect : e.sever);
|
|
583
|
+
for (const [end, value] of [["from", e.from], ["to", e.to]]) {
|
|
584
|
+
const ref = refName(value);
|
|
585
|
+
const kinds = end === "to" ? edge?.to : edge?.from;
|
|
586
|
+
if (ref && ref !== "subject" && kinds && kinds !== "*")
|
|
587
|
+
ends.set(ref, [...new Set([...(ends.get(ref) ?? []), ...kinds])]);
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
const writesOther = {};
|
|
591
|
+
for (const e of effects) {
|
|
592
|
+
if (!("set" in e) || "create" in e)
|
|
593
|
+
continue;
|
|
594
|
+
const target = refName(e.target ?? "$subject");
|
|
595
|
+
for (const kind of (target && target !== "subject" && ends.get(target)) || [])
|
|
596
|
+
writesOther[kind] = [...new Set([...(writesOther[kind] ?? []), ...Object.keys(e.set)])];
|
|
597
|
+
}
|
|
598
|
+
// What it sets on its subject to a fixed value, whatever it is told — a named step (FR-108), resolved as `apply` resolves a literal.
|
|
599
|
+
const sets = {};
|
|
600
|
+
for (const e of effects) {
|
|
601
|
+
if (!("set" in e) || "create" in e || refName(e.target ?? "$subject") !== "subject")
|
|
602
|
+
continue;
|
|
603
|
+
for (const [field, v] of Object.entries(e.set ?? {})) {
|
|
604
|
+
if ((typeof v === "string" && refName(v) === undefined) || typeof v === "number" || typeof v === "boolean")
|
|
605
|
+
sets[field] = typeof v === "string" && v.startsWith("$$") ? v.slice(1) : v;
|
|
606
|
+
else
|
|
607
|
+
delete sets[field];
|
|
608
|
+
}
|
|
609
|
+
}
|
|
541
610
|
/*
|
|
542
611
|
* Twice is once when nothing is made and every value set is given
|
|
543
612
|
* (a literal or an argument), never computed from what is there.
|
|
@@ -563,7 +632,10 @@ export function compileDocumentWithoutCheck(raw, options = {}) {
|
|
|
563
632
|
...(creates.length > 0 ? { creates } : {}),
|
|
564
633
|
...(connects.length > 0 ? { connects } : {}),
|
|
565
634
|
...(severs.length > 0 ? { severs } : {}),
|
|
566
|
-
|
|
635
|
+
// Said even when empty (FR-110): a document act's writes are read off it, so nothing guesses them from its arguments' names.
|
|
636
|
+
writes,
|
|
637
|
+
...(Object.keys(writesOther).length > 0 ? { writesOther } : {}),
|
|
638
|
+
...(Object.keys(sets).length > 0 ? { sets } : {}),
|
|
567
639
|
describe: (input, graph) => {
|
|
568
640
|
const subject = typeof input[SUBJECT_ARG] === "string" ? graph.getNode(input[SUBJECT_ARG]) : undefined;
|
|
569
641
|
const what = subject ? labelFor(subject) : Object.values(input).find((v) => typeof v === "string");
|
|
@@ -678,6 +750,18 @@ export function compileDocumentWithoutCheck(raw, options = {}) {
|
|
|
678
750
|
throw new Refused(`there is no record "${id}"`);
|
|
679
751
|
context.removeNode(id);
|
|
680
752
|
}
|
|
753
|
+
else if ("replace" in effect && subject) {
|
|
754
|
+
// The subject's links of each relation, at its own end, severed — all but the one being made (FR-115).
|
|
755
|
+
const kept = input["to"];
|
|
756
|
+
for (const relation of effect.replace) {
|
|
757
|
+
const fromSubject = edges.get(relation)?.from.includes(subject.kind) ?? true;
|
|
758
|
+
for (const other of fromSubject ? graph.out(subject.id, relation) : graph.in(subject.id, relation)) {
|
|
759
|
+
if (relation === effect.keep && other.id === kept)
|
|
760
|
+
continue;
|
|
761
|
+
context.removeEdge(fromSubject ? { kind: relation, from: subject.id, to: other.id } : { kind: relation, from: other.id, to: subject.id });
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
681
765
|
}
|
|
682
766
|
},
|
|
683
767
|
}));
|
|
@@ -829,7 +913,7 @@ export function inDocumentWords(finding, where, document) {
|
|
|
829
913
|
const first = Object.keys(spec.fields).filter((field) => field !== "label").slice(0, 3);
|
|
830
914
|
return { ...finding, path: `kinds.${kind}.glance`, fix: `Say which: "glance": [${first.map((field) => `"${field}"`).join(", ")}] on kinds.${kind} — the facts a person compares one by, at a glance.` };
|
|
831
915
|
}
|
|
832
|
-
export {
|
|
916
|
+
export { ActRefusal };
|
|
833
917
|
/** Every `renamedFrom` that names nothing in the version before: the values it was meant to carry would be lost. */
|
|
834
918
|
function renamesFromNothing(document, previous) {
|
|
835
919
|
const out = [];
|