@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.
Files changed (139) hide show
  1. package/README.md +23 -2
  2. package/dist/address.d.ts +31 -0
  3. package/dist/address.d.ts.map +1 -0
  4. package/dist/address.js +53 -0
  5. package/dist/address.js.map +1 -0
  6. package/dist/app.d.ts +1 -1
  7. package/dist/app.d.ts.map +1 -1
  8. package/dist/arrange.d.ts +13 -183
  9. package/dist/arrange.d.ts.map +1 -1
  10. package/dist/arrange.js +12 -470
  11. package/dist/arrange.js.map +1 -1
  12. package/dist/arrangement.d.ts +169 -0
  13. package/dist/arrangement.d.ts.map +1 -0
  14. package/dist/arrangement.js +220 -0
  15. package/dist/arrangement.js.map +1 -0
  16. package/dist/arranging.d.ts +28 -0
  17. package/dist/arranging.d.ts.map +1 -0
  18. package/dist/arranging.js +264 -0
  19. package/dist/arranging.js.map +1 -0
  20. package/dist/capabilities.js +1 -1
  21. package/dist/capabilities.js.map +1 -1
  22. package/dist/cli/check/hidden-reads.d.ts.map +1 -1
  23. package/dist/cli/check/hidden-reads.js +31 -0
  24. package/dist/cli/check/hidden-reads.js.map +1 -1
  25. package/dist/cli/check/lenses.d.ts.map +1 -1
  26. package/dist/cli/check/lenses.js +29 -1
  27. package/dist/cli/check/lenses.js.map +1 -1
  28. package/dist/cli/describe.d.ts.map +1 -1
  29. package/dist/cli/describe.js +16 -6
  30. package/dist/cli/describe.js.map +1 -1
  31. package/dist/cli/docs.js +1 -1
  32. package/dist/cli/docs.js.map +1 -1
  33. package/dist/columns.d.ts +48 -16
  34. package/dist/columns.d.ts.map +1 -1
  35. package/dist/columns.js +65 -22
  36. package/dist/columns.js.map +1 -1
  37. package/dist/conformance/fixtures.d.ts.map +1 -1
  38. package/dist/conformance/fixtures.js +19 -1
  39. package/dist/conformance/fixtures.js.map +1 -1
  40. package/dist/describe.d.ts +2 -2
  41. package/dist/describe.d.ts.map +1 -1
  42. package/dist/describe.js +1 -1
  43. package/dist/describe.js.map +1 -1
  44. package/dist/document/act-findings.d.ts +5 -0
  45. package/dist/document/act-findings.d.ts.map +1 -0
  46. package/dist/document/act-findings.js +84 -0
  47. package/dist/document/act-findings.js.map +1 -0
  48. package/dist/document/compile-checked.d.ts.map +1 -1
  49. package/dist/document/compile-checked.js +11 -4
  50. package/dist/document/compile-checked.js.map +1 -1
  51. package/dist/document/compile.d.ts +15 -4
  52. package/dist/document/compile.d.ts.map +1 -1
  53. package/dist/document/compile.js +102 -18
  54. package/dist/document/compile.js.map +1 -1
  55. package/dist/document/describe-coverage.d.ts +37 -0
  56. package/dist/document/describe-coverage.d.ts.map +1 -0
  57. package/dist/document/describe-coverage.js +162 -0
  58. package/dist/document/describe-coverage.js.map +1 -0
  59. package/dist/document/describe-place.d.ts.map +1 -1
  60. package/dist/document/describe-place.js +14 -1
  61. package/dist/document/describe-place.js.map +1 -1
  62. package/dist/document/diff.d.ts +5 -0
  63. package/dist/document/diff.d.ts.map +1 -1
  64. package/dist/document/diff.js +12 -3
  65. package/dist/document/diff.js.map +1 -1
  66. package/dist/document/edit.d.ts +1 -1
  67. package/dist/document/edit.d.ts.map +1 -1
  68. package/dist/document/edit.js +63 -6
  69. package/dist/document/edit.js.map +1 -1
  70. package/dist/document/far-end.d.ts +15 -0
  71. package/dist/document/far-end.d.ts.map +1 -0
  72. package/dist/document/far-end.js +26 -0
  73. package/dist/document/far-end.js.map +1 -0
  74. package/dist/document/index.d.ts +1 -1
  75. package/dist/document/index.d.ts.map +1 -1
  76. package/dist/document/migrate.d.ts.map +1 -1
  77. package/dist/document/migrate.js +7 -5
  78. package/dist/document/migrate.js.map +1 -1
  79. package/dist/document/range.d.ts +17 -0
  80. package/dist/document/range.d.ts.map +1 -0
  81. package/dist/document/range.js +46 -0
  82. package/dist/document/range.js.map +1 -0
  83. package/dist/document/schema.d.ts +23 -0
  84. package/dist/document/schema.d.ts.map +1 -1
  85. package/dist/document/schema.js +16 -0
  86. package/dist/document/schema.js.map +1 -1
  87. package/dist/document/thumbnail.d.ts +21 -0
  88. package/dist/document/thumbnail.d.ts.map +1 -1
  89. package/dist/document/thumbnail.js +139 -32
  90. package/dist/document/thumbnail.js.map +1 -1
  91. package/dist/document/to-document.d.ts.map +1 -1
  92. package/dist/document/to-document.js +16 -2
  93. package/dist/document/to-document.js.map +1 -1
  94. package/dist/index.d.ts +3 -2
  95. package/dist/index.d.ts.map +1 -1
  96. package/dist/index.js +3 -2
  97. package/dist/index.js.map +1 -1
  98. package/dist/mutations/define-mutation.d.ts.map +1 -1
  99. package/dist/mutations/define-mutation.js +9 -1
  100. package/dist/mutations/define-mutation.js.map +1 -1
  101. package/dist/mutations/derive-edits.d.ts +8 -0
  102. package/dist/mutations/derive-edits.d.ts.map +1 -1
  103. package/dist/mutations/derive-edits.js +30 -7
  104. package/dist/mutations/derive-edits.js.map +1 -1
  105. package/dist/mutations/form.d.ts +2 -0
  106. package/dist/mutations/form.d.ts.map +1 -1
  107. package/dist/mutations/form.js +1 -0
  108. package/dist/mutations/form.js.map +1 -1
  109. package/dist/mutations/node-ref.d.ts +4 -1
  110. package/dist/mutations/node-ref.d.ts.map +1 -1
  111. package/dist/mutations/node-ref.js +6 -0
  112. package/dist/mutations/node-ref.js.map +1 -1
  113. package/dist/mutations/types.d.ts +16 -0
  114. package/dist/mutations/types.d.ts.map +1 -1
  115. package/dist/places.js +1 -1
  116. package/dist/places.js.map +1 -1
  117. package/dist/refusal.d.ts.map +1 -1
  118. package/dist/refusal.js +4 -0
  119. package/dist/refusal.js.map +1 -1
  120. package/dist/refused.d.ts +20 -0
  121. package/dist/refused.d.ts.map +1 -0
  122. package/dist/refused.js +24 -0
  123. package/dist/refused.js.map +1 -0
  124. package/dist/scaffold/project.d.ts.map +1 -1
  125. package/dist/scaffold/project.js +3 -0
  126. package/dist/scaffold/project.js.map +1 -1
  127. package/dist/search.d.ts +1 -1
  128. package/dist/search.d.ts.map +1 -1
  129. package/dist/search.js +1 -1
  130. package/dist/search.js.map +1 -1
  131. package/dist/theme/derive.d.ts.map +1 -1
  132. package/dist/theme/derive.js +5 -4
  133. package/dist/theme/derive.js.map +1 -1
  134. package/dist/theme/types.d.ts.map +1 -1
  135. package/dist/theme/types.js +5 -0
  136. package/dist/theme/types.js.map +1 -1
  137. package/dist/version.d.ts +1 -1
  138. package/dist/version.js +1 -1
  139. 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":"AACA,OAAO,EAA+D,KAAK,gBAAgB,EAAE,KAAK,cAAc,EAAE,KAAK,eAAe,EAAE,MAAM,cAAc,CAAC;AAW7J;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,gBAAgB,GAAG,eAAe,CAe9G"}
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 { compileDocumentWithoutCheck, frameworkPath, inDocumentWords } from "./compile.js";
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
- return compiled;
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;AAC7J,OAAO,EAAE,SAAS,EAAgB,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;GAMG;AACH;;;;GAIG;AACH,MAAM,UAAU,eAAe,CAAC,GAAY,EAAE,UAA0B,EAAE;IACxE,MAAM,QAAQ,GAAG,2BAA2B,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;IAC3D,IAAI,CAAC,QAAQ,CAAC,EAAE;QAAE,OAAO,QAAQ,CAAC;IAClC,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,QAAQ,CAAC;IACnC,qHAAqH;IACrH,MAAM,QAAQ,GAAc,CAAC,GAAG,QAAQ,CAAC,QAAQ,EAAE,GAAG,UAAU,CAAC,QAAQ,CAAC,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;IACvH,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC/B,MAAM,OAAO,GAAG,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,aAAa,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,CAAC,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAW,CAAC;QAC/O,2GAA2G;QAC3G,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC;YAAE,SAAS;QACnG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,KAAK,iBAAiB,CAAC,CAAC,CAAC,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC;IACtG,CAAC;IACD,IAAI,SAAS,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;IACxD,OAAO,EAAE,GAAG,QAAQ,EAAE,QAAQ,EAAE,CAAC;AACnC,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
- /** The effects an act's shorthands mean, in order. */
36
- export declare function effectsOf(act: ActSpec, document: GraviewDocument): readonly EffectSpec[];
37
- declare class Refused extends Error {
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 { Refused as ActRefusal };
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;AAKrB,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;AAkBrB,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,sDAAsD;AACtD,wBAAgB,SAAS,CAAC,GAAG,EAAE,OAAO,EAAE,QAAQ,EAAE,eAAe,GAAG,SAAS,UAAU,EAAE,CAmBxF;AAySD,cAAM,OAAQ,SAAQ,KAAK;CAAG;AAE9B;;;;;;;GAOG;AACH,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,GAAE,cAAmB,GAAG,gBAAgB,GAAG,eAAe,CAmT1H;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,OAAO,IAAI,UAAU,EAAE,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"}
@@ -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
- effects.push({ connect: act.connects, from: "$subject", to: "$to" });
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({ sever: act.severs, from: "$subject", to: "$to" });
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
- schema = z.number();
356
- break;
357
- case "integer":
358
- schema = z.number().check(z.int());
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
- const note = (arg, schema) => {
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
- class Refused extends Error {
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
- const severs = [...new Set(effects.flatMap((e) => ("sever" in e ? [e.sever] : [])))];
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
- ...(writes.length > 0 ? { writes } : {}),
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 { Refused as ActRefusal };
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 = [];