@astrale-os/kernel-dsl 1.0.0-beta.2 → 1.0.0-beta.20

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 (307) hide show
  1. package/dist/v1/addressing/class-key.js +3 -3
  2. package/dist/v1/addressing/definition-ref.js +21 -37
  3. package/dist/v1/addressing/domain-dependency.d.ts +0 -6
  4. package/dist/v1/addressing/domain-dependency.js +1 -6
  5. package/dist/v1/addressing/key.d.ts +4 -1
  6. package/dist/v1/addressing/key.js +23 -3
  7. package/dist/v1/addressing/ordering.d.ts +2 -0
  8. package/dist/v1/addressing/ordering.js +4 -0
  9. package/dist/v1/addressing/patterns.d.ts +1 -1
  10. package/dist/v1/addressing/patterns.js +2 -6
  11. package/dist/v1/builder/callable/authoring.d.ts +11 -5
  12. package/dist/v1/builder/callable/authoring.js +2 -0
  13. package/dist/v1/builder/class/authoring.d.ts +94 -224
  14. package/dist/v1/builder/class/authoring.js +31 -33
  15. package/dist/v1/builder/class/handle.d.ts +27 -0
  16. package/dist/v1/builder/class/handle.js +1 -0
  17. package/dist/v1/builder/class/input.d.ts +159 -0
  18. package/dist/v1/builder/class/projection.d.ts +129 -0
  19. package/dist/v1/builder/class/projection.js +1 -0
  20. package/dist/v1/builder/class/property.d.ts +3 -9
  21. package/dist/v1/builder/class/property.js +1 -0
  22. package/dist/v1/builder/core/authoring.d.ts +1 -1
  23. package/dist/v1/builder/index.d.ts +5 -2
  24. package/dist/v1/builder/lowering/callable.js +1 -0
  25. package/dist/v1/builder/lowering/class.d.ts +9 -1
  26. package/dist/v1/builder/lowering/class.js +62 -17
  27. package/dist/v1/builder/lowering/policy.js +2 -0
  28. package/dist/v1/builder/lowering/property-keys.d.ts +27 -0
  29. package/dist/v1/builder/lowering/property-keys.js +108 -0
  30. package/dist/v1/builder/lowering/schema/compile.js +11 -6
  31. package/dist/v1/builder/lowering/schema/context.d.ts +9 -1
  32. package/dist/v1/builder/lowering/schema/context.js +36 -4
  33. package/dist/v1/builder/lowering/schema/lifetime.d.ts +11 -0
  34. package/dist/v1/builder/lowering/schema/lifetime.js +55 -0
  35. package/dist/v1/builder/lowering/value/path.d.ts +1 -1
  36. package/dist/v1/builder/lowering/value/path.js +2 -4
  37. package/dist/v1/builder/lowering/value/zod.js +1 -3
  38. package/dist/v1/builder/policy/authoring.d.ts +85 -5
  39. package/dist/v1/builder/policy/authoring.js +107 -68
  40. package/dist/v1/builder/schema/define.d.ts +0 -1
  41. package/dist/v1/builder/schema/diagnostic.d.ts +3 -2
  42. package/dist/v1/builder/schema/diagnostic.js +5 -10
  43. package/dist/v1/builder/schema/input.d.ts +1 -1
  44. package/dist/v1/builder/schema/projection/callable.d.ts +7 -5
  45. package/dist/v1/builder/schema/projection/class.d.ts +118 -15
  46. package/dist/v1/builder/schema/projection/core-input.d.ts +2 -1
  47. package/dist/v1/builder/schema/projection/identity.d.ts +2 -1
  48. package/dist/v1/builder/schema/projection/model.d.ts +4 -2
  49. package/dist/v1/builder/schema/projection/property.d.ts +1 -1
  50. package/dist/v1/builder/schema/projection/resolved-class.d.ts +2 -1
  51. package/dist/v1/builder/schema/projection.d.ts +1 -1
  52. package/dist/v1/builder/value/full-match.d.ts +0 -1
  53. package/dist/v1/builder/value/full-match.js +0 -1
  54. package/dist/v1/builder/value/path-metadata.d.ts +1 -1
  55. package/dist/v1/builder/value/path.d.ts +1 -1
  56. package/dist/v1/bundle/codec.js +11 -13
  57. package/dist/v1/bundle/diagnostic.d.ts +2 -0
  58. package/dist/v1/bundle/diagnostic.js +9 -7
  59. package/dist/v1/bundle/model.js +1 -1
  60. package/dist/v1/bundle/structure.js +4 -6
  61. package/dist/v1/compiled/admission/accept.js +4 -10
  62. package/dist/v1/compiled/admission/closure.js +2 -2
  63. package/dist/v1/compiled/admission/diagnostic.d.ts +1 -1
  64. package/dist/v1/compiled/admission/diagnostic.js +1 -3
  65. package/dist/v1/compiled/admission/revision.d.ts +9 -1
  66. package/dist/v1/compiled/admission/revision.js +6 -3
  67. package/dist/v1/compiled/admission/semantics/class.d.ts +4 -1
  68. package/dist/v1/compiled/admission/semantics/class.js +37 -12
  69. package/dist/v1/compiled/admission/semantics/core.d.ts +1 -24
  70. package/dist/v1/compiled/admission/semantics/core.js +56 -24
  71. package/dist/v1/compiled/admission/semantics/edge.d.ts +2 -4
  72. package/dist/v1/compiled/admission/semantics/edge.js +6 -65
  73. package/dist/v1/compiled/admission/semantics/policy/callable.js +0 -2
  74. package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +5 -20
  75. package/dist/v1/compiled/admission/semantics/policy/contracts.js +8 -21
  76. package/dist/v1/compiled/admission/semantics/policy/parity.js +40 -43
  77. package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +4 -1
  78. package/dist/v1/compiled/admission/semantics/policy/pattern.js +4 -16
  79. package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +2 -24
  80. package/dist/v1/compiled/admission/semantics/policy/typing.js +19 -201
  81. package/dist/v1/compiled/admission/wire/callable.js +11 -1
  82. package/dist/v1/compiled/admission/wire/class.js +73 -21
  83. package/dist/v1/compiled/admission/wire/policy.d.ts +4 -3
  84. package/dist/v1/compiled/admission/wire/policy.js +8 -7
  85. package/dist/v1/compiled/compiler/compile.js +8 -8
  86. package/dist/v1/compiled/diagnostic.js +2 -3
  87. package/dist/v1/compiled/loader/load.d.ts +3 -2
  88. package/dist/v1/compiled/loader/load.js +11 -45
  89. package/dist/v1/domain/create.js +5 -6
  90. package/dist/v1/domain/model/domain.d.ts +2 -7
  91. package/dist/v1/domain/model/input.d.ts +2 -1
  92. package/dist/v1/domain/namespace/member-collection.js +4 -6
  93. package/dist/v1/domain/projection/classes.js +4 -1
  94. package/dist/v1/domain/validation/create.d.ts +6 -3
  95. package/dist/v1/domain/validation/create.js +21 -69
  96. package/dist/v1/index.d.ts +2 -1
  97. package/dist/v1/language/.spec/schemas/draft-2020-12.schema.json +462 -0
  98. package/dist/v1/language/.spec/schemas/value-schema.schema.json +22 -0
  99. package/dist/v1/language/callable/admission.d.ts +15 -0
  100. package/dist/v1/language/callable/admission.js +43 -0
  101. package/dist/v1/language/callable/model/callable.d.ts +10 -0
  102. package/dist/v1/language/callable/resolved.d.ts +16 -3
  103. package/dist/v1/language/class/inheritance.d.ts +36 -5
  104. package/dist/v1/language/class/inheritance.js +87 -1
  105. package/dist/v1/language/class/lifetime.d.ts +50 -11
  106. package/dist/v1/language/class/lifetime.js +89 -20
  107. package/dist/v1/language/class/model/class.d.ts +45 -9
  108. package/dist/v1/language/class/model/edge.d.ts +31 -2
  109. package/dist/v1/language/class/model/property.d.ts +16 -7
  110. package/dist/v1/language/class/property-values.js +2 -4
  111. package/dist/v1/language/class/unique.d.ts +143 -0
  112. package/dist/v1/language/class/unique.js +264 -0
  113. package/dist/v1/language/core/facts.d.ts +85 -0
  114. package/dist/v1/language/core/facts.js +116 -0
  115. package/dist/v1/language/definition/metadata.d.ts +5 -0
  116. package/dist/v1/language/definition/metadata.js +7 -0
  117. package/dist/v1/language/freeze.d.ts +5 -0
  118. package/dist/v1/{schema/canonical → language}/freeze.js +4 -0
  119. package/dist/v1/language/index.d.ts +7 -2
  120. package/dist/v1/language/index.js +5 -1
  121. package/dist/v1/language/limits.d.ts +64 -0
  122. package/dist/v1/language/limits.js +60 -0
  123. package/dist/v1/language/policy/analysis/branches.d.ts +8 -0
  124. package/dist/v1/language/policy/analysis/branches.js +2 -1
  125. package/dist/v1/language/policy/analysis/budgets.d.ts +45 -12
  126. package/dist/v1/language/policy/analysis/budgets.js +133 -19
  127. package/dist/v1/language/policy/analysis/checks.js +3 -2
  128. package/dist/v1/language/policy/analysis/typing.d.ts +51 -0
  129. package/dist/v1/language/policy/analysis/typing.js +455 -0
  130. package/dist/v1/language/policy/model/policy.d.ts +49 -9
  131. package/dist/v1/language/policy/model/policy.js +14 -0
  132. package/dist/v1/language/policy/normalization/normalize.d.ts +6 -6
  133. package/dist/v1/language/policy/normalization/normalize.js +22 -21
  134. package/dist/v1/language/validation/diagnostic.d.ts +15 -1
  135. package/dist/v1/language/validation/diagnostic.js +21 -0
  136. package/dist/v1/language/validation/rule.d.ts +45 -0
  137. package/dist/v1/language/validation/rule.js +109 -0
  138. package/dist/v1/language/value/compile/fields.js +4 -8
  139. package/dist/v1/language/value/evaluate/program.d.ts +2 -1
  140. package/dist/v1/language/value/evaluate/program.js +2 -2
  141. package/dist/v1/language/value/evaluate/validate.d.ts +2 -2
  142. package/dist/v1/language/value/evaluate/validate.js +6 -2
  143. package/dist/v1/language/value/evaluate/validity.optimization.d.ts +14 -0
  144. package/dist/v1/language/value/evaluate/validity.optimization.js +342 -0
  145. package/dist/v1/language/value/inclusion/arrays.d.ts +3 -0
  146. package/dist/v1/language/value/inclusion/arrays.js +85 -0
  147. package/dist/v1/language/value/inclusion/assertions.d.ts +18 -0
  148. package/dist/v1/language/value/inclusion/assertions.js +29 -0
  149. package/dist/v1/language/value/inclusion/combinators.d.ts +3 -0
  150. package/dist/v1/language/value/inclusion/combinators.js +67 -0
  151. package/dist/v1/language/value/inclusion/equivalence.d.ts +4 -0
  152. package/dist/v1/language/value/inclusion/equivalence.js +74 -0
  153. package/dist/v1/language/value/inclusion/evidence.d.ts +34 -0
  154. package/dist/v1/language/value/inclusion/evidence.js +138 -0
  155. package/dist/v1/language/value/inclusion/includes.d.ts +17 -0
  156. package/dist/v1/language/value/inclusion/includes.js +25 -719
  157. package/dist/v1/language/value/inclusion/keywords.d.ts +5 -0
  158. package/dist/v1/language/value/inclusion/keywords.js +31 -0
  159. package/dist/v1/language/value/inclusion/kinds.d.ts +17 -0
  160. package/dist/v1/language/value/inclusion/kinds.js +57 -0
  161. package/dist/v1/language/value/inclusion/location.d.ts +24 -0
  162. package/dist/v1/language/value/inclusion/location.js +63 -0
  163. package/dist/v1/language/value/inclusion/numbers.d.ts +3 -0
  164. package/dist/v1/language/value/inclusion/numbers.js +41 -0
  165. package/dist/v1/language/value/inclusion/objects.d.ts +3 -0
  166. package/dist/v1/language/value/inclusion/objects.js +190 -0
  167. package/dist/v1/language/value/inclusion/strings.d.ts +3 -0
  168. package/dist/v1/language/value/inclusion/strings.js +29 -0
  169. package/dist/v1/language/value/inclusion/types.d.ts +3 -0
  170. package/dist/v1/language/value/inclusion/types.js +11 -0
  171. package/dist/v1/language/value/ordering.d.ts +14 -0
  172. package/dist/v1/language/value/ordering.js +86 -9
  173. package/dist/v1/language/value/profile/canonicalize.js +6 -5
  174. package/dist/v1/language/value/profile/json.validate.d.ts +3 -1
  175. package/dist/v1/language/value/profile/json.validate.js +3 -2
  176. package/dist/v1/language/value/profile/meta-schema.compiled.js +4 -1
  177. package/dist/v1/language/value/profile/rules.js +17 -43
  178. package/dist/v1/language/value/profile/validate.js +1 -10
  179. package/dist/v1/language/value/profile/vocabulary.d.ts +35 -2
  180. package/dist/v1/language/value/profile/vocabulary.js +52 -5
  181. package/dist/v1/language/value/reference/closure.js +3 -4
  182. package/dist/v1/language/value/reference/recursion.js +2 -22
  183. package/dist/v1/language/value/reference/registry.index.d.ts +2 -0
  184. package/dist/v1/language/value/reference/registry.index.js +33 -16
  185. package/dist/v1/language/value/regexp/ast.js +6 -7
  186. package/dist/v1/language/value/regexp/compile.d.ts +5 -11
  187. package/dist/v1/language/value/regexp/compile.js +14 -12
  188. package/dist/v1/language/value/regexp/syntax.js +3 -2
  189. package/dist/v1/language/value/syntax/keywords.d.ts +3 -3
  190. package/dist/v1/language/value/syntax/keywords.js +4 -20
  191. package/dist/v1/language/value/syntax/node-path/validate.js +2 -3
  192. package/dist/v1/language/value/syntax/pointer.d.ts +2 -0
  193. package/dist/v1/language/value/syntax/pointer.js +5 -2
  194. package/dist/v1/language/value/syntax/walk.d.ts +2 -0
  195. package/dist/v1/language/value/syntax/walk.js +19 -20
  196. package/dist/v1/schema/.spec/schemas/domain-schema.schema.json +2519 -0
  197. package/dist/v1/schema/admission/accept.js +3 -14
  198. package/dist/v1/schema/admission/callable.d.ts +21 -0
  199. package/dist/v1/schema/admission/callable.js +96 -0
  200. package/dist/v1/schema/analysis/class.js +33 -15
  201. package/dist/v1/schema/canonical/revision.js +4 -4
  202. package/dist/v1/schema/compatibility/api.d.ts +2 -1
  203. package/dist/v1/schema/compatibility/api.js +1 -0
  204. package/dist/v1/schema/compatibility/comparators/callables.js +1 -1
  205. package/dist/v1/schema/compatibility/comparators/classes.d.ts +9 -4
  206. package/dist/v1/schema/compatibility/comparators/classes.js +29 -8
  207. package/dist/v1/schema/compatibility/comparators/index.d.ts +1 -1
  208. package/dist/v1/schema/compatibility/comparators/members.js +1 -1
  209. package/dist/v1/schema/compatibility/comparators/values.js +2 -2
  210. package/dist/v1/schema/compatibility/coordinate.js +3 -3
  211. package/dist/v1/schema/compatibility/diff.js +2 -4
  212. package/dist/v1/schema/compatibility/extension.d.ts +11 -0
  213. package/dist/v1/schema/compatibility/extension.js +22 -0
  214. package/dist/v1/schema/compatibility/fields.d.ts +20 -4
  215. package/dist/v1/schema/compatibility/fields.js +13 -3
  216. package/dist/v1/schema/compatibility/meaning/footprint.js +16 -50
  217. package/dist/v1/schema/compatibility/model.d.ts +17 -5
  218. package/dist/v1/schema/compatibility/report.js +1 -1
  219. package/dist/v1/schema/compatibility/scope.d.ts +2 -0
  220. package/dist/v1/schema/compatibility/scope.js +4 -1
  221. package/dist/v1/schema/compatibility/structure/index.js +6 -4
  222. package/dist/v1/schema/compatibility/structure/requirements.js +57 -58
  223. package/dist/v1/schema/compatibility/versioning/index.js +1 -1
  224. package/dist/v1/schema/compatibility/versioning/surface.d.ts +1 -1
  225. package/dist/v1/schema/compatibility/versioning/surface.js +30 -2
  226. package/dist/v1/schema/compatibility/walk.d.ts +17 -0
  227. package/dist/v1/schema/compatibility/walk.js +41 -0
  228. package/dist/v1/schema/diagnostic.d.ts +17 -3
  229. package/dist/v1/schema/diagnostic.js +14 -11
  230. package/dist/v1/schema/index.d.ts +10 -1
  231. package/dist/v1/schema/index.js +4 -0
  232. package/dist/v1/schema/model/schema.d.ts +20 -1
  233. package/dist/v1/schema/model/schema.js +1 -1
  234. package/dist/v1/schema/normalization/domain.d.ts +2 -0
  235. package/dist/v1/schema/normalization/domain.js +29 -9
  236. package/dist/v1/schema/resolution/closure.js +2 -1
  237. package/dist/v1/schema/resolution/context.js +13 -13
  238. package/dist/v1/schema/resolution/domain.d.ts +5 -0
  239. package/dist/v1/schema/resolution/domain.js +2 -2
  240. package/dist/v1/schema/resolution/origins.js +3 -2
  241. package/dist/v1/schema/rule.d.ts +26 -0
  242. package/dist/v1/schema/rule.js +440 -0
  243. package/dist/v1/schema/validation/callable.d.ts +35 -2
  244. package/dist/v1/schema/validation/callable.js +65 -9
  245. package/dist/v1/schema/validation/class.d.ts +6 -2
  246. package/dist/v1/schema/validation/class.js +127 -104
  247. package/dist/v1/schema/validation/core.js +90 -168
  248. package/dist/v1/schema/validation/domain.js +4 -13
  249. package/dist/v1/schema/validation/domain.json-schema.d.ts +15 -0
  250. package/dist/v1/schema/validation/domain.json-schema.js +197 -0
  251. package/dist/v1/schema/validation/domain.route.d.ts +6 -1
  252. package/dist/v1/schema/validation/domain.route.js +18 -0
  253. package/dist/v1/schema/validation/domain.structure.d.ts +7780 -0
  254. package/dist/v1/schema/validation/domain.structure.js +398 -147
  255. package/dist/v1/schema/validation/json.json-schema.d.ts +40 -0
  256. package/dist/v1/schema/validation/json.json-schema.js +46 -0
  257. package/dist/v1/schema/validation/policy/budgets.d.ts +33 -2
  258. package/dist/v1/schema/validation/policy/budgets.js +87 -121
  259. package/dist/v1/schema/validation/policy/context.d.ts +6 -5
  260. package/dist/v1/schema/validation/policy/context.js +7 -10
  261. package/dist/v1/schema/validation/policy/objects.d.ts +1 -1
  262. package/dist/v1/schema/validation/policy/objects.js +6 -14
  263. package/dist/v1/schema/validation/policy/references.js +11 -27
  264. package/dist/v1/schema/validation/policy/typing.d.ts +3 -18
  265. package/dist/v1/schema/validation/policy/typing.js +22 -356
  266. package/dist/v1/schema/validation/policy/uses.d.ts +40 -3
  267. package/dist/v1/schema/validation/policy/uses.js +66 -89
  268. package/dist/v1/schema/validation/policy/validate.js +5 -5
  269. package/dist/v1/schema/validation/value-api.d.ts +22 -0
  270. package/dist/v1/schema/validation/value-api.js +34 -1
  271. package/dist/v1/schema/validation/value.d.ts +3 -0
  272. package/dist/v1/schema/validation/value.js +9 -17
  273. package/dist/v1/schema/validation/value.json-schema.d.ts +49 -0
  274. package/dist/v1/schema/validation/value.json-schema.js +137 -0
  275. package/dist/v1/schema/validation/view.js +4 -8
  276. package/dist/value/canonical.d.ts +6 -0
  277. package/dist/value/canonical.js +36 -0
  278. package/dist/value/decode.d.ts +7 -0
  279. package/dist/value/decode.js +159 -9
  280. package/dist/value/index.d.ts +1 -1
  281. package/dist/value/json.d.ts +2 -2
  282. package/dist/value/json.js +2 -2
  283. package/dist/value/types.d.ts +6 -0
  284. package/dist/value/unicode.d.ts +2 -1
  285. package/dist/value/unicode.js +2 -0
  286. package/package.json +8 -1
  287. package/dist/v1/builder/lowering/core-properties.d.ts +0 -10
  288. package/dist/v1/builder/lowering/core-properties.js +0 -76
  289. package/dist/v1/compiled/admission/semantics/cardinality.d.ts +0 -5
  290. package/dist/v1/compiled/admission/semantics/cardinality.js +0 -113
  291. package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +0 -8
  292. package/dist/v1/compiled/admission/semantics/policy/equality.js +0 -27
  293. package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +0 -9
  294. package/dist/v1/compiled/admission/semantics/policy/measure.js +0 -81
  295. package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +0 -10
  296. package/dist/v1/compiled/admission/semantics/policy/variants.js +0 -65
  297. package/dist/v1/language/class/index.d.ts +0 -8
  298. package/dist/v1/language/class/index.js +0 -1
  299. package/dist/v1/language/core/index.d.ts +0 -2
  300. package/dist/v1/language/value/index.d.ts +0 -11
  301. package/dist/v1/language/value/index.js +0 -8
  302. package/dist/v1/schema/canonical/domain.d.ts +0 -3
  303. package/dist/v1/schema/canonical/domain.digest.d.ts +0 -3
  304. package/dist/v1/schema/canonical/domain.digest.js +0 -5
  305. package/dist/v1/schema/canonical/domain.js +0 -5
  306. package/dist/v1/schema/canonical/freeze.d.ts +0 -1
  307. /package/dist/v1/{language/core/index.js → builder/class/input.js} +0 -0
@@ -0,0 +1,108 @@
1
+ import { PropertyKey as admitPropertyKey } from '../../addressing/index.js';
2
+ import { definitionRefIndex } from '../../addressing/ordering.js';
3
+ import { createPropertyValues } from '../../language/class/property-values.js';
4
+ import { analyzeDefinitions } from '../../schema/analysis/class.js';
5
+ import { buildDomainResolutionContext } from '../../schema/resolution/context.js';
6
+ import { escapeToken, fail } from '../schema/diagnostic.js';
7
+ /**
8
+ * Analyze the already-canonical Definition surface of `candidate` once, so Property shorthand
9
+ * resolves against each Class's own and inherited Properties. Core values and key tuples take no
10
+ * part in Class composition, so they are left out of the analysis.
11
+ */
12
+ export function analyzePropertyOwners(candidate, lookup) {
13
+ const analysisCandidate = {
14
+ ...candidate,
15
+ core: { nodes: {}, edges: [] },
16
+ };
17
+ return analyzeDefinitions(buildDomainResolutionContext(analysisCandidate, lookup)).definitions;
18
+ }
19
+ /** Lower rich builder shorthand to the canonical full-key Core representation. */
20
+ export function canonicalizeCorePropertyKeys(core, owners) {
21
+ const nodes = Object.fromEntries(Object.entries(core.nodes).map(([slug, node]) => {
22
+ const definition = owners.get(definitionRefIndex(node.class));
23
+ if (definition === undefined) {
24
+ fail('BUILDER_CORE_PROPERTY', `/core/nodes/${escapeToken(slug)}/class`, 'Core property shorthand requires a resolvable concrete Class.');
25
+ }
26
+ return [
27
+ slug,
28
+ {
29
+ ...node,
30
+ properties: qualify(node.properties, definition, `/core/nodes/${escapeToken(slug)}/properties`),
31
+ },
32
+ ];
33
+ }));
34
+ const edges = core.edges.map((edge, index) => {
35
+ const definition = owners.get(definitionRefIndex(edge.class));
36
+ if (definition === undefined) {
37
+ fail('BUILDER_CORE_PROPERTY', `/core/edges/${index}/class`, 'Core property shorthand requires a resolvable concrete Class.');
38
+ }
39
+ return {
40
+ ...edge,
41
+ properties: qualify(edge.properties, definition, `/core/edges/${index}/properties`),
42
+ };
43
+ });
44
+ return { nodes, edges };
45
+ }
46
+ /**
47
+ * Lower each Property a key tuple names by its name to its full key among the Class's own and
48
+ * inherited Properties; a full key stays as authored. Ambiguity and absence are refused here, so a
49
+ * tuple never names a Property the author did not mean. A Node tuple names Properties only; an Edge
50
+ * tuple names them as `{ property }` beside its structural fields.
51
+ */
52
+ export function canonicalizeUniquePropertyKeys(classes, origin, owners) {
53
+ return Object.fromEntries(Object.entries(classes).map(([name, declaration]) => {
54
+ if (declaration.kind === 'edge' && declaration.orientation !== 'directed') {
55
+ return [name, declaration];
56
+ }
57
+ if (declaration.unique === undefined)
58
+ return [name, declaration];
59
+ const ref = { origin, kind: 'class', name };
60
+ const definition = owners.get(definitionRefIndex(ref));
61
+ const pointer = `/classes/${escapeToken(name)}/unique`;
62
+ const resolve = (input, at) => {
63
+ if (definition === undefined) {
64
+ fail('BUILDER_UNIQUE_PROPERTY', at, 'A key Property requires a resolvable Class.');
65
+ }
66
+ return resolveInputKey(input, definition, 'BUILDER_UNIQUE_PROPERTY', at);
67
+ };
68
+ if (declaration.kind === 'node') {
69
+ const unique = declaration.unique.map((tuple, t) => tuple.map((key, f) => resolve(key, `${pointer}/${t}/${f}`)));
70
+ return [name, { ...declaration, unique }];
71
+ }
72
+ const unique = declaration.unique.map((tuple, t) => tuple.map((field, f) => typeof field === 'string'
73
+ ? field
74
+ : { property: resolve(field.property, `${pointer}/${t}/${f}/property`) }));
75
+ return [name, { ...declaration, unique }];
76
+ }));
77
+ }
78
+ function qualify(input, definition, pointer) {
79
+ const result = {};
80
+ const sourceByKey = new Map();
81
+ for (const [inputKey, value] of Object.entries(input)) {
82
+ const key = resolveInputKey(inputKey, definition, 'BUILDER_CORE_PROPERTY', `${pointer}/${escapeToken(inputKey)}`);
83
+ const previous = sourceByKey.get(key);
84
+ if (previous !== undefined) {
85
+ fail('BUILDER_CORE_PROPERTY', `${pointer}/${escapeToken(inputKey)}`, `Property is supplied twice through ${JSON.stringify(previous)} and ${JSON.stringify(inputKey)}.`);
86
+ }
87
+ sourceByKey.set(key, inputKey);
88
+ result[key] = value;
89
+ }
90
+ return createPropertyValues(Object.entries(result).map(([key, value]) => [admitPropertyKey(key), value]));
91
+ }
92
+ /** The full key of the Property `input` names on `definition`: its full key, or its unique name. */
93
+ function resolveInputKey(input, definition, code, pointer) {
94
+ if (admitPropertyKey.is(input)) {
95
+ const key = admitPropertyKey(input);
96
+ if (!definition.properties.has(key)) {
97
+ fail(code, pointer, `Property ${input} is not present on the Class.`);
98
+ }
99
+ return key;
100
+ }
101
+ const candidates = [...definition.properties].flatMap(([key, field]) => field.name === input ? [key] : []);
102
+ if (candidates.length === 1)
103
+ return candidates[0];
104
+ if (candidates.length === 0) {
105
+ fail(code, pointer, `Property ${JSON.stringify(input)} does not exist.`);
106
+ }
107
+ fail(code, pointer, `Property ${JSON.stringify(input)} is ambiguous; use one of: ${candidates.join(', ')}.`);
108
+ }
@@ -1,19 +1,20 @@
1
+ import { deepFreeze } from '../../../language/freeze.js';
1
2
  import { acceptDomainSchema } from '../../../schema/admission/accept.js';
2
- import { canonicalizeDomainSchema } from '../../../schema/canonical/domain.js';
3
- import { deepFreeze } from '../../../schema/canonical/freeze.js';
4
3
  import { MemoryDomainSchemaLookup } from '../../../schema/dependency/lookup.js';
4
+ import { normalizeDomainSchema } from '../../../schema/normalization/domain.js';
5
5
  import { lookupEntriesForDependencies } from '../../../schema/resolution/closure.js';
6
6
  import { parseDomainSchemaStructure } from '../../../schema/validation/domain.structure.js';
7
7
  import { assertKnownKeys, escapeToken } from '../../schema/diagnostic.js';
8
8
  import { V1CallableCompiler } from '../callable.js';
9
9
  import { V1DefinitionCompiler } from '../class.js';
10
- import { canonicalizeCorePropertyKeys } from '../core-properties.js';
11
10
  import { compileCore } from '../core.js';
12
11
  import { assertPolicyCompositionAcyclic, V1PolicyCompiler } from '../policy.js';
12
+ import { analyzePropertyOwners, canonicalizeCorePropertyKeys, canonicalizeUniquePropertyKeys, } from '../property-keys.js';
13
13
  import { BuilderValueSchemas } from '../value/compile.js';
14
14
  import { V1ViewCompiler } from '../view.js';
15
15
  import { captureSchema, commitSchemaOwnership } from './capture.js';
16
16
  import { BuilderContext } from './context.js';
17
+ import { assertAuthoredLifetimes } from './lifetime.js';
17
18
  /**
18
19
  * Compile the V1 TypeScript builder graph through the same semantic acceptance
19
20
  * path used for untrusted decoded schemas.
@@ -21,9 +22,11 @@ import { BuilderContext } from './context.js';
21
22
  * This is the private implementation behind defineSchema.
22
23
  */
23
24
  export function compileSchema(origin, input) {
24
- const lookup = new MemoryDomainSchemaLookup(lookupEntriesForDependencies(input.dependencies ?? {}));
25
+ const dependencies = lookupEntriesForDependencies(input.dependencies ?? {});
26
+ const lookup = new MemoryDomainSchemaLookup(dependencies);
25
27
  const candidate = assembleDomainSchema(origin, input, lookup);
26
28
  const accepted = acceptDomainSchema(candidate, lookup);
29
+ assertAuthoredLifetimes(accepted, dependencies);
27
30
  commitSchemaOwnership(input, origin);
28
31
  return accepted;
29
32
  }
@@ -75,9 +78,11 @@ function assembleDomainSchema(origin, input, lookup) {
75
78
  views,
76
79
  core,
77
80
  };
81
+ const owners = analyzePropertyOwners(semanticContent, lookup);
78
82
  const qualifiedContent = {
79
83
  ...semanticContent,
80
- core: canonicalizeCorePropertyKeys(semanticContent, lookup),
84
+ classes: canonicalizeUniquePropertyKeys(classes, origin, owners),
85
+ core: canonicalizeCorePropertyKeys(core, owners),
81
86
  };
82
87
  context.noteDomainEndpointReferences(qualifiedContent);
83
88
  const candidate = {
@@ -85,7 +90,7 @@ function assembleDomainSchema(origin, input, lookup) {
85
90
  dependencies: context.dependencies(),
86
91
  };
87
92
  const structured = parseDomainSchemaStructure(candidate);
88
- const canonical = parseDomainSchemaStructure(canonicalizeDomainSchema(structured));
93
+ const canonical = parseDomainSchemaStructure(normalizeDomainSchema(structured));
89
94
  return deepFreeze(canonical);
90
95
  }
91
96
  function mapRecord(record, map) {
@@ -6,7 +6,8 @@ import type { PolicyObjectRef } from '../../../language/index.js';
6
6
  import type { ValueSchemaRegistry } from '../../../language/value/reference/registry.js';
7
7
  import type { DomainSchema, DomainSchemaIR } from '../../../schema/model/schema.js';
8
8
  import type { Function, PolicyObjectInput } from '../../callable/authoring.js';
9
- import type { Class, ClassReferenceInput } from '../../class/authoring.js';
9
+ import type { Class } from '../../class/handle.js';
10
+ import type { ClassReferenceInput } from '../../class/input.js';
10
11
  import type { CoreEndpoint, CoreNode } from '../../core/authoring.js';
11
12
  import type { Policy } from '../../policy/authoring.js';
12
13
  import type { View } from '../../view/authoring.js';
@@ -29,8 +30,15 @@ export declare class BuilderContext {
29
30
  captureFunction(value: Function, ref: FunctionRef, pointer: string): void;
30
31
  captureView(value: View, ref: ViewRef, pointer: string): void;
31
32
  resolveClass(input: ClassReferenceInput, kind: ClassKind, pointer: string): ClassRef;
33
+ /** A parent of another Domain must be open to it in the dependency revision authored against. */
34
+ resolveParent(input: ClassReferenceInput, kind: ClassKind, pointer: string): ClassRef;
32
35
  resolveNodeClass(input: ClassReferenceInput, pointer: string): ClassRef;
33
36
  resolveEdgeClass(input: ClassReferenceInput, pointer: string): ClassRef;
37
+ /**
38
+ * The roles of a resolved Edge Class's source and target, or of an undirected Class's two
39
+ * endpoints in their stored order, which is the authored one.
40
+ */
41
+ edgeRoles(ref: ClassRef): readonly [source: string, target: string];
34
42
  resolvePolicy(input: Lazy<unknown>, pointer: string): PolicyRef;
35
43
  resolvePolicyObject(input: PolicyObjectInput | PolicyObjectRef, pointer: string): PolicyObjectRef;
36
44
  /** A Core fact belongs to the Domain that declares it, so a dependency endpoint never resolves. */
@@ -1,11 +1,14 @@
1
1
  import { compareDefinitionRefs, compareUnicode, definitionRefIndex, } from '../../../addressing/ordering.js';
2
2
  import { DEPENDENCY_ALIAS_PATTERN } from '../../../addressing/patterns.js';
3
3
  import { isMethodExecutable } from '../../../language/callable/executable.js';
4
+ import { admitsForeignSubclass, inheritanceOf } from '../../../language/class/inheritance.js';
4
5
  import { policyObjectKey, policyObjectOrigin } from '../../../language/index.js';
5
6
  import { graphNodePathSchema } from '../../../language/value/syntax/node-path/schema.js';
7
+ import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
6
8
  import { revisionOfDomainSchema } from '../../../schema/canonical/revision.js';
7
9
  import { requireDomainClosure } from '../../../schema/resolution/closure.js';
8
10
  import { collectUsedForeignOrigins } from '../../../schema/resolution/origins.js';
11
+ import { classConfiguration } from '../../class/authoring.js';
9
12
  import { fail } from '../../schema/diagnostic.js';
10
13
  import { resolveLazy } from '../../schema/lazy.js';
11
14
  import { OwnershipCapture } from './ownership.js';
@@ -14,6 +17,7 @@ export class BuilderContext {
14
17
  ownership = new OwnershipCapture();
15
18
  localDefinitions = new Map();
16
19
  localClassKinds = new Map();
20
+ #localClasses = new Map();
17
21
  policies = new Map();
18
22
  policyObjects = new Map();
19
23
  policyObjectRefs = new Set();
@@ -22,7 +26,7 @@ export class BuilderContext {
22
26
  constructor(origin, dependencies) {
23
27
  this.origin = origin;
24
28
  for (const [alias, schema] of Object.entries(dependencies)) {
25
- const pointer = `/dependencies/${escapePointer(alias)}`;
29
+ const pointer = `/dependencies/${escapePointerToken(alias)}`;
26
30
  if (!DEPENDENCY_ALIAS_PATTERN.test(alias)) {
27
31
  fail('BUILDER_DEPENDENCY_ALIAS', pointer, `Dependency alias ${JSON.stringify(alias)} must be an ASCII lower-camel identifier.`);
28
32
  }
@@ -47,6 +51,7 @@ export class BuilderContext {
47
51
  }
48
52
  this.localDefinitions.set(key, ref);
49
53
  this.localClassKinds.set(key, value.kind);
54
+ this.#localClasses.set(key, value);
50
55
  this.ownership.captureDefinition(value, ref, pointer);
51
56
  this.capturePolicyObject(value, ref);
52
57
  }
@@ -90,12 +95,42 @@ export class BuilderContext {
90
95
  }
91
96
  return { ...ref };
92
97
  }
98
+ /** A parent of another Domain must be open to it in the dependency revision authored against. */
99
+ resolveParent(input, kind, pointer) {
100
+ const ref = this.resolveClass(input, kind, pointer);
101
+ if (ref.origin === this.origin)
102
+ return ref;
103
+ const parent = this.#dependencies.get(ref.origin).schema.classes[ref.name];
104
+ if (!admitsForeignSubclass(parent)) {
105
+ fail('BUILDER_CLASS_INHERITANCE', pointer, `Class ${ref.origin}:class.${ref.name} is ${inheritanceOf(parent)}: only an open Class admits a subclass of another Domain.`);
106
+ }
107
+ return ref;
108
+ }
93
109
  resolveNodeClass(input, pointer) {
94
110
  return this.resolveClass(input, 'node', pointer);
95
111
  }
96
112
  resolveEdgeClass(input, pointer) {
97
113
  return this.resolveClass(input, 'edge', pointer);
98
114
  }
115
+ /**
116
+ * The roles of a resolved Edge Class's source and target, or of an undirected Class's two
117
+ * endpoints in their stored order, which is the authored one.
118
+ */
119
+ edgeRoles(ref) {
120
+ if (ref.origin === this.origin) {
121
+ const value = this.#localClasses.get(definitionRefIndex(ref));
122
+ if (value.orientation === 'directed') {
123
+ const input = classConfiguration(value);
124
+ return [input.source.as, input.target.as];
125
+ }
126
+ const input = classConfiguration(value);
127
+ return [input.endpoints[0].as, input.endpoints[1].as];
128
+ }
129
+ const definition = this.#dependencies.get(ref.origin).schema.classes[ref.name];
130
+ return definition.orientation === 'directed'
131
+ ? [definition.endpoints.source.role, definition.endpoints.target.role]
132
+ : [definition.endpoints[0].role, definition.endpoints[1].role];
133
+ }
99
134
  resolvePolicy(input, pointer) {
100
135
  const value = resolveLazy(input, pointer);
101
136
  if (typeof value !== 'object' || value === null) {
@@ -211,9 +246,6 @@ export class BuilderContext {
211
246
  this.policyObjectRefs.add(policyObjectKey(ref));
212
247
  }
213
248
  }
214
- function escapePointer(value) {
215
- return value.replaceAll('~', '~0').replaceAll('/', '~1');
216
- }
217
249
  function isResolvedClass(value) {
218
250
  if (typeof value !== 'object' || value === null)
219
251
  return false;
@@ -0,0 +1,11 @@
1
+ import type { DomainSchemaEntry } from '../../../schema/dependency/lookup.js';
2
+ import type { DomainSchema } from '../../../schema/model/schema.js';
3
+ /**
4
+ * Authoring refuses two Edge Classes that acceptance keeps, because a stored Schema must decode
5
+ * again with the lifetimes it derives (BUILDER-EDGE-LIFETIMES):
6
+ * - one with an endpoint that can hold a Node of another Domain while an endpoint requires an Edge.
7
+ * It can neither restrict that Domain's deletions nor detach below the required count, so the
8
+ * required endpoint must become optional;
9
+ * - one whose lifetimes differ from those of an Edge Class it extends, the root Edge aside.
10
+ */
11
+ export declare function assertAuthoredLifetimes(schema: DomainSchema, dependencies: readonly DomainSchemaEntry[]): void;
@@ -0,0 +1,55 @@
1
+ import { Key } from '../../../addressing/key.js';
2
+ import { definitionRefIndex } from '../../../addressing/ordering.js';
3
+ import { isGraphRoot } from '../../../language/class/inheritance.js';
4
+ import { contractEndpoints, edgeLifetimes, lifetimeScope, reachesAnotherDomain, requiredEndpoint, } from '../../../language/class/lifetime.js';
5
+ import { BuilderError, diagnostic, escapeToken } from '../../schema/diagnostic.js';
6
+ /**
7
+ * Authoring refuses two Edge Classes that acceptance keeps, because a stored Schema must decode
8
+ * again with the lifetimes it derives (BUILDER-EDGE-LIFETIMES):
9
+ * - one with an endpoint that can hold a Node of another Domain while an endpoint requires an Edge.
10
+ * It can neither restrict that Domain's deletions nor detach below the required count, so the
11
+ * required endpoint must become optional;
12
+ * - one whose lifetimes differ from those of an Edge Class it extends, the root Edge aside.
13
+ */
14
+ export function assertAuthoredLifetimes(schema, dependencies) {
15
+ const classes = [
16
+ ...Object.values(schema.classes),
17
+ ...dependencies.flatMap((entry) => Object.values(entry.schema.classes)),
18
+ ];
19
+ const scope = lifetimeScope(classes);
20
+ const declarations = new Map(classes.map((declaration) => [definitionRefIndex(declaration.ref), declaration]));
21
+ const diagnostics = Object.entries(schema.classes).flatMap(([name, declaration]) => {
22
+ if (declaration.kind !== 'edge')
23
+ return [];
24
+ const pointer = `/classes/${escapeToken(name)}`;
25
+ const endpoints = contractEndpoints(declaration);
26
+ const keys = declaration.orientation === 'directed' ? ['source', 'target'] : ['0', '1'];
27
+ const counts = declaration.orientation === 'directed' ? ['outgoing', 'incoming'] : ['incident', 'incident'];
28
+ const found = [];
29
+ const required = requiredEndpoint(declaration);
30
+ const reaching = endpoints.find(({ endpoint }) => reachesAnotherDomain(schema.origin, endpoint, scope));
31
+ if (required !== undefined && reaching !== undefined)
32
+ found.push(diagnostic('BUILDER_EDGE_LIFETIME', `${pointer}/endpoints/${keys[required.index]}/${counts[required.index]}`, `${Key.of(declaration.ref)} endpoint ${reaching.endpoint.role} can hold Nodes of another ` +
33
+ `Domain, so it cannot restrict their deletion, and endpoint ${required.endpoint.role} ` +
34
+ `requires ${required.count} Edges, so it cannot detach: make ${required.endpoint.role} optional.`));
35
+ const lifetimes = edgeLifetimes(declaration, scope);
36
+ declaration.extends.forEach((ref, index) => {
37
+ const parent = declarations.get(definitionRefIndex(ref));
38
+ if (parent?.kind !== 'edge' || isGraphRoot(parent))
39
+ return;
40
+ const inherited = edgeLifetimes(parent, scope);
41
+ const same = (order) => order.every((at, position) => lifetimes[position] === inherited[at]);
42
+ if (same([0, 1]) || (declaration.orientation === 'undirected' && same([1, 0])))
43
+ return;
44
+ found.push(diagnostic('BUILDER_EDGE_LIFETIME', `${pointer}/extends/${index}`, `${Key.of(declaration.ref)} has lifetimes ${spell(endpoints, lifetimes)}, and ` +
45
+ `${Key.of(parent.ref)} it extends has ${spell(contractEndpoints(parent), inherited)}: ` +
46
+ `an Edge Class keeps the lifetimes of the Classes it extends.`));
47
+ });
48
+ return found;
49
+ });
50
+ if (diagnostics.length > 0)
51
+ throw new BuilderError(diagnostics);
52
+ }
53
+ function spell(endpoints, lifetimes) {
54
+ return `${endpoints[0].endpoint.role} ${lifetimes[0]} and ${endpoints[1].endpoint.role} ${lifetimes[1]}`;
55
+ }
@@ -1,3 +1,3 @@
1
- import type { NodeClassReferenceInput } from '../../class/authoring.js';
1
+ import type { NodeClassReferenceInput } from '../../class/input.js';
2
2
  import type { ZodValueSchemaOverrideContext } from './zod.js';
3
3
  export declare function lowerPathSchema(context: ZodValueSchemaOverrideContext, resolveAccepts: (inputs: readonly NodeClassReferenceInput[], pointer: string) => readonly unknown[], pointer: string): void;
@@ -1,9 +1,10 @@
1
+ import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
1
2
  import { pathAccepts } from '../../value/path-metadata.js';
2
3
  export function lowerPathSchema(context, resolveAccepts, pointer) {
3
4
  const inputs = pathAccepts(context.zodSchema);
4
5
  if (inputs === undefined)
5
6
  return;
6
- const location = context.path.reduce((current, segment) => `${current}/${escapeToken(String(segment))}`, pointer);
7
+ const location = context.path.reduce((current, segment) => `${current}/${escapePointerToken(String(segment))}`, pointer);
7
8
  for (const key of Object.keys(context.jsonSchema))
8
9
  delete context.jsonSchema[key];
9
10
  Object.assign(context.jsonSchema, {
@@ -15,6 +16,3 @@ export function lowerPathSchema(context, resolveAccepts, pointer) {
15
16
  },
16
17
  });
17
18
  }
18
- function escapeToken(value) {
19
- return value.replaceAll('~', '~0').replaceAll('/', '~1');
20
- }
@@ -4,6 +4,7 @@ import { canonicalizeValueSchema } from '../../../language/value/profile/canonic
4
4
  import { validateValueSchema } from '../../../language/value/profile/validate.js';
5
5
  import { isIRegexp } from '../../../language/value/regexp/syntax.js';
6
6
  import { fullMatchSource } from '../../../language/value/syntax/full-match.js';
7
+ import { escapePointerToken } from '../../../language/value/syntax/pointer.js';
7
8
  import { diagnostic } from '../../schema/diagnostic.js';
8
9
  /**
9
10
  * Converts only Zod contracts whose JSON-value acceptance is represented
@@ -289,9 +290,6 @@ function getCheckDefinition(value) {
289
290
  function isZodType(value) {
290
291
  return value instanceof ZodType;
291
292
  }
292
- function escapePointerToken(value) {
293
- return value.replaceAll('~', '~0').replaceAll('/', '~1');
294
- }
295
293
  function isPlainRecord(value) {
296
294
  return value !== null && typeof value === 'object' && !Array.isArray(value);
297
295
  }
@@ -1,18 +1,79 @@
1
1
  import type { ClassRef } from '../../addressing/index.js';
2
+ import type { ResolvedClass } from '../../language/class/resolved.js';
2
3
  import type { PolicyCheckExpression, PolicyPatternExpression, PolicyPatternTerm as CanonicalPolicyPatternTerm, PolicyObjectRef } from '../../language/policy/model/policy.js';
3
4
  import type { PolicyObjectInput } from '../callable/authoring.js';
4
- import type { EdgeClassReferenceInput, NodeClassReferenceInput } from '../class/authoring.js';
5
+ import type { DirectedEdgeClass, EdgeClass, UndirectedEdgeClass } from '../class/handle.js';
6
+ import type { EdgeClassReferenceInput, NodeClassReferenceInput } from '../class/input.js';
5
7
  import type { AuthoringValue } from '../schema/handle.js';
6
8
  import type { Lazy } from '../schema/lazy.js';
9
+ import type { ResolveLazy } from '../schema/projection/identity.js';
10
+ /**
11
+ * @deprecated Name the ends by their roles: `edge(classValue, { [role]: term }, { repeat })`
12
+ * lowers to this same pattern.
13
+ */
7
14
  export interface PolicyEdgeInput {
8
15
  readonly source: CanonicalPolicyPatternTerm;
9
16
  readonly class: EdgeClassReferenceInput;
10
17
  readonly target: CanonicalPolicyPatternTerm;
11
- readonly repeat?: {
12
- readonly min: number;
13
- readonly max: number;
14
- };
18
+ readonly repeat?: PolicyEdgeRepeat;
19
+ }
20
+ /** How many Edges of the Class a path between the two terms crosses, both bounds included. */
21
+ export interface PolicyEdgeRepeat {
22
+ readonly min: number;
23
+ readonly max: number;
24
+ }
25
+ export interface PolicyEdgeOptions {
26
+ readonly repeat?: PolicyEdgeRepeat;
15
27
  }
28
+ /** An Edge Class whose ends a Policy names by role: authored, resolved, or either lazily. */
29
+ export type PolicyEdgeClassInput = Lazy<EdgeClass | ResolvedClass<'edge'>>;
30
+ /**
31
+ * The roles of an Edge Class's two ends, as literal types: the `as` of an authored Class's ends,
32
+ * the `role` of a resolved Class's, read through a lazy reference.
33
+ */
34
+ export type EdgeRolesOf<Value> = ResolveLazy<Value> extends infer Resolved ? Resolved extends DirectedEdgeClass<infer Config> ? Config extends {
35
+ readonly source: {
36
+ readonly as: infer Source;
37
+ };
38
+ readonly target: {
39
+ readonly as: infer Target;
40
+ };
41
+ } ? Source | Target : never : Resolved extends UndirectedEdgeClass<infer Config> ? Config extends {
42
+ readonly endpoints: readonly [
43
+ {
44
+ readonly as: infer First;
45
+ },
46
+ {
47
+ readonly as: infer Second;
48
+ }
49
+ ];
50
+ } ? First | Second : never : Resolved extends {
51
+ readonly kind: 'edge';
52
+ readonly definition: {
53
+ readonly endpoints: infer Endpoints;
54
+ };
55
+ } ? Endpoints extends {
56
+ readonly source: {
57
+ readonly role: infer Source;
58
+ };
59
+ readonly target: {
60
+ readonly role: infer Target;
61
+ };
62
+ } ? Source | Target : Endpoints extends readonly [
63
+ {
64
+ readonly role: infer First;
65
+ },
66
+ {
67
+ readonly role: infer Second;
68
+ }
69
+ ] ? First | Second : never : never : never;
70
+ /**
71
+ * The two ends of an Edge, keyed by exactly the Class's two roles, both required. A Class whose
72
+ * roles the types do not know names no ends.
73
+ */
74
+ export type PolicyEdgeEnds<Value> = [EdgeRolesOf<Value>] extends [never] ? never : string extends EdgeRolesOf<Value> ? never : {
75
+ readonly [Role in EdgeRolesOf<Value> & string]: CanonicalPolicyPatternTerm;
76
+ };
16
77
  export interface PolicyNodeBinder {
17
78
  (): CanonicalPolicyPatternTerm;
18
79
  (definition: NodeClassReferenceInput): CanonicalPolicyPatternTerm;
@@ -36,6 +97,23 @@ export interface PolicyPatternContext {
36
97
  readonly object: CanonicalPolicyPatternTerm;
37
98
  readonly source: CanonicalPolicyPatternTerm;
38
99
  readonly target: CanonicalPolicyPatternTerm;
100
+ /**
101
+ * An Edge of `classValue` between two terms, each keyed by the role of its end: `{ [role]: term }`,
102
+ * the source's role written first by convention. It lowers to the pattern whose source is the
103
+ * term of the source's role and whose target is the term of the target's role. For an undirected
104
+ * Class, the first endpoint's role lowers to the source, and the roles only order the two terms:
105
+ * the pattern still matches an Edge between the two Nodes whichever end each Node holds.
106
+ *
107
+ * ```ts
108
+ * edge(project_owned_by, { owner: subject, project })
109
+ * edge(() => subtask_of, { child: a, parent: b }, { repeat: { min: 1, max: 3 } })
110
+ * ```
111
+ */
112
+ edge<ClassValue extends PolicyEdgeClassInput>(classValue: ClassValue, ends: PolicyEdgeEnds<ClassValue>, options?: PolicyEdgeOptions): PolicyPatternExpression;
113
+ /**
114
+ * @deprecated Name the ends by their roles: `edge(classValue, { [role]: term }, { repeat })`
115
+ * lowers to this same pattern.
116
+ */
39
117
  edge(input: PolicyEdgeInput): PolicyPatternExpression;
40
118
  exists(build: (context: PolicyExistsContext) => PolicyPatternExpression): PolicyPatternExpression;
41
119
  allOf(first: PolicyPatternExpression, ...rest: readonly PolicyPatternExpression[]): PolicyPatternExpression;
@@ -63,6 +141,8 @@ export declare const policy: PolicyBuilder;
63
141
  export declare function createPatternContext(options: {
64
142
  readonly resolveObject: (value: PolicyObjectInput, pointer: string) => PolicyObjectRef;
65
143
  readonly resolveEdgeClass: (value: EdgeClassReferenceInput, pointer: string) => ClassRef;
144
+ /** The roles of an Edge Class's source and target, or of an undirected Class's two endpoints. */
145
+ readonly edgeRoles: (ref: ClassRef) => readonly [source: string, target: string];
66
146
  readonly resolveNodeClass: (value: NodeClassReferenceInput, pointer: string) => ClassRef;
67
147
  readonly pointer: string;
68
148
  }): PolicyPatternContext;