@astrale-os/kernel-dsl 0.2.0-beta.8 → 0.2.0

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 (321) hide show
  1. package/dist/v1/addressing/class-key.js +5 -4
  2. package/dist/v1/addressing/method-key.js +3 -2
  3. package/dist/v1/addressing/patterns.d.ts +0 -5
  4. package/dist/v1/addressing/patterns.js +5 -5
  5. package/dist/v1/builder/callable/authoring.d.ts +87 -41
  6. package/dist/v1/builder/callable/authoring.js +29 -14
  7. package/dist/v1/builder/class/authoring.d.ts +311 -36
  8. package/dist/v1/builder/class/authoring.js +3 -4
  9. package/dist/v1/builder/class/property.d.ts +16 -8
  10. package/dist/v1/builder/class/property.js +21 -5
  11. package/dist/v1/builder/core/authoring.d.ts +28 -13
  12. package/dist/v1/builder/core/authoring.js +22 -2
  13. package/dist/v1/builder/index.d.ts +9 -8
  14. package/dist/v1/builder/index.js +2 -2
  15. package/dist/v1/builder/lowering/callable.d.ts +3 -1
  16. package/dist/v1/builder/lowering/callable.js +43 -51
  17. package/dist/v1/builder/lowering/class.d.ts +7 -0
  18. package/dist/v1/builder/lowering/class.js +79 -29
  19. package/dist/v1/builder/lowering/core.d.ts +3 -2
  20. package/dist/v1/builder/lowering/core.js +9 -6
  21. package/dist/v1/builder/lowering/policy.d.ts +8 -1
  22. package/dist/v1/builder/lowering/policy.js +35 -0
  23. package/dist/v1/builder/lowering/schema/capture.js +9 -4
  24. package/dist/v1/builder/lowering/schema/compile.d.ts +2 -2
  25. package/dist/v1/builder/lowering/schema/compile.js +15 -2
  26. package/dist/v1/builder/lowering/schema/context.d.ts +11 -8
  27. package/dist/v1/builder/lowering/schema/context.js +59 -29
  28. package/dist/v1/builder/lowering/schema/ownership.d.ts +3 -3
  29. package/dist/v1/builder/lowering/schema/ownership.js +2 -1
  30. package/dist/v1/builder/lowering/value/compile.js +14 -4
  31. package/dist/v1/builder/lowering/value/zod.d.ts +7 -6
  32. package/dist/v1/builder/lowering/value/zod.js +16 -7
  33. package/dist/v1/builder/lowering/view.d.ts +4 -3
  34. package/dist/v1/builder/lowering/view.js +2 -14
  35. package/dist/v1/builder/policy/authoring.d.ts +23 -6
  36. package/dist/v1/builder/policy/authoring.js +35 -8
  37. package/dist/v1/builder/schema/define.d.ts +8 -5
  38. package/dist/v1/builder/schema/diagnostic.d.ts +1 -1
  39. package/dist/v1/builder/schema/handle.d.ts +2 -1
  40. package/dist/v1/builder/schema/input.d.ts +9 -1
  41. package/dist/v1/builder/schema/projection/callable.d.ts +51 -0
  42. package/dist/v1/builder/schema/projection/callable.js +1 -0
  43. package/dist/v1/builder/schema/projection/class.d.ts +89 -0
  44. package/dist/v1/builder/schema/projection/class.js +1 -0
  45. package/dist/v1/builder/schema/projection/core-input.d.ts +32 -0
  46. package/dist/v1/builder/schema/projection/core-input.js +1 -0
  47. package/dist/v1/builder/schema/projection/domain.d.ts +59 -0
  48. package/dist/v1/builder/schema/projection/domain.js +1 -0
  49. package/dist/v1/builder/schema/projection/identity.d.ts +39 -0
  50. package/dist/v1/builder/schema/projection/identity.js +1 -0
  51. package/dist/v1/builder/schema/projection/model.d.ts +59 -0
  52. package/dist/v1/builder/schema/projection/model.js +1 -0
  53. package/dist/v1/builder/schema/projection/property.d.ts +32 -0
  54. package/dist/v1/builder/schema/projection/property.js +1 -0
  55. package/dist/v1/builder/schema/projection/resolved-class.d.ts +76 -0
  56. package/dist/v1/builder/schema/projection/resolved-class.js +1 -0
  57. package/dist/v1/builder/schema/projection.d.ts +4 -258
  58. package/dist/v1/builder/value/full-match.js +6 -3
  59. package/dist/v1/builder/value/path.d.ts +2 -2
  60. package/dist/v1/builder/value/path.js +2 -2
  61. package/dist/v1/builder/view/authoring.d.ts +6 -14
  62. package/dist/v1/builder/view/authoring.js +13 -5
  63. package/dist/v1/bundle/structure.d.ts +2 -1
  64. package/dist/v1/compiled/admission/accept.d.ts +1 -1
  65. package/dist/v1/compiled/admission/accept.js +11 -814
  66. package/dist/v1/compiled/admission/closure.d.ts +3 -0
  67. package/dist/v1/compiled/admission/closure.js +173 -0
  68. package/dist/v1/compiled/admission/diagnostic.d.ts +7 -0
  69. package/dist/v1/compiled/admission/diagnostic.js +13 -0
  70. package/dist/v1/compiled/admission/revision.js +9 -1
  71. package/dist/v1/compiled/admission/semantics/cardinality.d.ts +5 -0
  72. package/dist/v1/compiled/admission/semantics/cardinality.js +113 -0
  73. package/dist/v1/compiled/admission/semantics/class.d.ts +5 -0
  74. package/dist/v1/compiled/admission/semantics/class.js +125 -0
  75. package/dist/v1/compiled/admission/semantics/context.d.ts +60 -0
  76. package/dist/v1/compiled/admission/semantics/context.js +81 -0
  77. package/dist/v1/compiled/admission/semantics/core.d.ts +35 -0
  78. package/dist/v1/compiled/admission/semantics/core.js +123 -0
  79. package/dist/v1/compiled/admission/semantics/edge.d.ts +8 -0
  80. package/dist/v1/compiled/admission/semantics/edge.js +89 -0
  81. package/dist/v1/compiled/admission/semantics/policy/admit.d.ts +4 -0
  82. package/dist/v1/compiled/admission/semantics/policy/admit.js +63 -0
  83. package/dist/v1/compiled/admission/semantics/policy/callable.d.ts +5 -0
  84. package/dist/v1/compiled/admission/semantics/policy/callable.js +72 -0
  85. package/dist/v1/compiled/admission/semantics/policy/contracts.d.ts +24 -0
  86. package/dist/v1/compiled/admission/semantics/policy/contracts.js +45 -0
  87. package/dist/v1/compiled/admission/semantics/policy/equality.d.ts +8 -0
  88. package/dist/v1/compiled/admission/semantics/policy/equality.js +27 -0
  89. package/dist/v1/compiled/admission/semantics/policy/measure.d.ts +9 -0
  90. package/dist/v1/compiled/admission/semantics/policy/measure.js +81 -0
  91. package/dist/v1/compiled/admission/semantics/policy/parity.d.ts +4 -0
  92. package/dist/v1/compiled/admission/semantics/policy/parity.js +139 -0
  93. package/dist/v1/compiled/admission/semantics/policy/pattern.d.ts +8 -0
  94. package/dist/v1/compiled/admission/semantics/policy/pattern.js +78 -0
  95. package/dist/v1/compiled/admission/semantics/policy/typing.d.ts +28 -0
  96. package/dist/v1/compiled/admission/semantics/policy/typing.js +206 -0
  97. package/dist/v1/compiled/admission/semantics/policy/variants.d.ts +10 -0
  98. package/dist/v1/compiled/admission/semantics/policy/variants.js +65 -0
  99. package/dist/v1/compiled/admission/semantics.d.ts +1 -1
  100. package/dist/v1/compiled/admission/semantics.js +8 -1078
  101. package/dist/v1/compiled/admission/wire/callable.d.ts +6 -0
  102. package/dist/v1/compiled/admission/wire/callable.js +90 -0
  103. package/dist/v1/compiled/admission/wire/class.d.ts +4 -0
  104. package/dist/v1/compiled/admission/wire/class.js +133 -0
  105. package/dist/v1/compiled/admission/wire/core.d.ts +5 -0
  106. package/dist/v1/compiled/admission/wire/core.js +32 -0
  107. package/dist/v1/compiled/admission/wire/dependency.d.ts +14 -0
  108. package/dist/v1/compiled/admission/wire/dependency.js +43 -0
  109. package/dist/v1/compiled/admission/wire/entry.d.ts +5 -0
  110. package/dist/v1/compiled/admission/wire/entry.js +100 -0
  111. package/dist/v1/compiled/admission/wire/pattern.d.ts +12 -0
  112. package/dist/v1/compiled/admission/wire/pattern.js +111 -0
  113. package/dist/v1/compiled/admission/wire/policy.d.ts +10 -0
  114. package/dist/v1/compiled/admission/wire/policy.js +189 -0
  115. package/dist/v1/compiled/admission/wire/program.d.ts +4 -0
  116. package/dist/v1/compiled/admission/wire/program.js +52 -0
  117. package/dist/v1/compiled/admission/wire/property.d.ts +4 -0
  118. package/dist/v1/compiled/admission/wire/property.js +74 -0
  119. package/dist/v1/compiled/admission/wire/reference.d.ts +8 -0
  120. package/dist/v1/compiled/admission/wire/reference.js +33 -0
  121. package/dist/v1/compiled/admission/wire/value.d.ts +29 -0
  122. package/dist/v1/compiled/admission/wire/value.js +98 -0
  123. package/dist/v1/compiled/admission/wire/view.d.ts +3 -0
  124. package/dist/v1/compiled/admission/wire/view.js +17 -0
  125. package/dist/v1/compiled/compiler/compile.js +43 -11
  126. package/dist/v1/compiled/generated.d.ts +10 -0
  127. package/dist/v1/compiled/generated.js +15 -0
  128. package/dist/v1/compiled/loader/load.d.ts +5 -0
  129. package/dist/v1/compiled/loader/load.js +18 -4
  130. package/dist/v1/compiled/model/schema.d.ts +16 -7
  131. package/dist/v1/domain/create.js +18 -28
  132. package/dist/v1/domain/model/domain.d.ts +0 -1
  133. package/dist/v1/domain/model/input.d.ts +3 -0
  134. package/dist/v1/domain/projection/classes.js +13 -41
  135. package/dist/v1/domain/validation/create.d.ts +2 -0
  136. package/dist/v1/domain/validation/create.js +12 -0
  137. package/dist/v1/index.d.ts +5 -2
  138. package/dist/v1/index.js +3 -1
  139. package/dist/v1/language/callable/composition.d.ts +27 -0
  140. package/dist/v1/language/callable/composition.js +52 -0
  141. package/dist/v1/language/callable/executable.d.ts +6 -0
  142. package/dist/v1/language/callable/executable.js +4 -0
  143. package/dist/v1/language/callable/model/callable.d.ts +34 -9
  144. package/dist/v1/language/callable/model/callable.js +3 -1
  145. package/dist/v1/language/callable/resolved.d.ts +23 -8
  146. package/dist/v1/language/class/facets.d.ts +5 -2
  147. package/dist/v1/language/class/inheritance.d.ts +12 -0
  148. package/dist/v1/language/class/inheritance.js +25 -0
  149. package/dist/v1/language/class/lifetime.d.ts +17 -0
  150. package/dist/v1/language/class/lifetime.js +26 -0
  151. package/dist/v1/language/class/model/class.d.ts +8 -4
  152. package/dist/v1/language/class/model/property.d.ts +4 -2
  153. package/dist/v1/language/class/property-values.js +5 -2
  154. package/dist/v1/language/class/resolved.d.ts +25 -15
  155. package/dist/v1/language/core/model/core.d.ts +7 -1
  156. package/dist/v1/language/core/resolved.d.ts +6 -2
  157. package/dist/v1/language/definition/metadata.d.ts +8 -0
  158. package/dist/v1/language/definition/metadata.js +12 -0
  159. package/dist/v1/language/index.d.ts +9 -0
  160. package/dist/v1/language/index.js +6 -0
  161. package/dist/v1/language/policy/analysis/branches.d.ts +4 -3
  162. package/dist/v1/language/policy/analysis/branches.js +54 -12
  163. package/dist/v1/language/policy/analysis/budgets.js +1 -1
  164. package/dist/v1/language/policy/analysis/checks.d.ts +28 -0
  165. package/dist/v1/language/policy/analysis/checks.js +80 -0
  166. package/dist/v1/language/policy/index.d.ts +1 -0
  167. package/dist/v1/language/policy/index.js +1 -0
  168. package/dist/v1/language/policy/model/policy.d.ts +71 -5
  169. package/dist/v1/language/policy/model/policy.js +52 -1
  170. package/dist/v1/language/policy/normalization/normalize.d.ts +12 -1
  171. package/dist/v1/language/policy/normalization/normalize.js +178 -44
  172. package/dist/v1/language/state/index.d.ts +3 -0
  173. package/dist/v1/language/state/index.js +1 -0
  174. package/dist/v1/language/state/machine.d.ts +28 -0
  175. package/dist/v1/language/state/machine.js +40 -0
  176. package/dist/v1/language/state/topology.d.ts +14 -0
  177. package/dist/v1/language/state/topology.js +69 -0
  178. package/dist/v1/language/value/compile/fields.d.ts +1 -1
  179. package/dist/v1/language/value/compile/load.d.ts +4 -2
  180. package/dist/v1/language/value/compile/load.js +22 -1
  181. package/dist/v1/language/value/compile/model.d.ts +16 -1
  182. package/dist/v1/language/value/evaluate/assertions.d.ts +2 -0
  183. package/dist/v1/language/value/evaluate/assertions.js +13 -0
  184. package/dist/v1/language/value/evaluate/evaluator.js +111 -28
  185. package/dist/v1/language/value/evaluate/preparation.d.ts +10 -1
  186. package/dist/v1/language/value/evaluate/preparation.js +17 -26
  187. package/dist/v1/language/value/evaluate/program.js +1 -1
  188. package/dist/v1/language/value/evaluate/validate.d.ts +6 -2
  189. package/dist/v1/language/value/evaluate/validate.js +18 -11
  190. package/dist/v1/language/value/inclusion/includes.d.ts +9 -0
  191. package/dist/v1/language/value/inclusion/includes.js +777 -0
  192. package/dist/v1/language/value/model/blob.d.ts +31 -0
  193. package/dist/v1/language/value/model/blob.js +90 -0
  194. package/dist/v1/language/value/model/instant.d.ts +0 -2
  195. package/dist/v1/language/value/model/instant.js +1 -1
  196. package/dist/v1/language/value/model/schema.d.ts +2 -1
  197. package/dist/v1/language/value/model/schema.js +1 -5
  198. package/dist/v1/language/value/ordering.d.ts +2 -0
  199. package/dist/v1/language/value/ordering.js +4 -8
  200. package/dist/v1/language/value/profile/json.validate.js +1 -1
  201. package/dist/v1/language/value/profile/rules.js +48 -12
  202. package/dist/v1/language/value/reference/registry.d.ts +2 -1
  203. package/dist/v1/language/value/regexp/ast.js +3 -64
  204. package/dist/v1/language/value/regexp/compile.d.ts +32 -3
  205. package/dist/v1/language/value/regexp/compile.js +117 -21
  206. package/dist/v1/language/value/regexp/matcher.d.ts +6 -3
  207. package/dist/v1/language/value/regexp/matcher.js +185 -28
  208. package/dist/v1/language/value/regexp/syntax.d.ts +12 -1
  209. package/dist/v1/language/value/regexp/syntax.js +14 -2
  210. package/dist/v1/language/value/regexp/unicode.d.ts +32 -0
  211. package/dist/v1/language/value/regexp/unicode.js +139 -0
  212. package/dist/v1/language/value/syntax/full-match.js +8 -5
  213. package/dist/v1/language/value/syntax/node-path/validate.js +4 -6
  214. package/dist/v1/language/view/model/view.d.ts +2 -4
  215. package/dist/v1/language/view/resolved.d.ts +2 -2
  216. package/dist/v1/schema/analysis/class.d.ts +36 -6
  217. package/dist/v1/schema/analysis/class.js +31 -66
  218. package/dist/v1/schema/canonical/revision.d.ts +2 -1
  219. package/dist/v1/schema/canonical/revision.js +4 -1
  220. package/dist/v1/schema/compatibility/api.d.ts +3 -0
  221. package/dist/v1/schema/compatibility/api.js +2 -0
  222. package/dist/v1/schema/compatibility/comparators/callables.d.ts +39 -0
  223. package/dist/v1/schema/compatibility/comparators/callables.js +101 -0
  224. package/dist/v1/schema/compatibility/comparators/classes.d.ts +47 -0
  225. package/dist/v1/schema/compatibility/comparators/classes.js +160 -0
  226. package/dist/v1/schema/compatibility/comparators/index.d.ts +12 -0
  227. package/dist/v1/schema/compatibility/comparators/index.js +53 -0
  228. package/dist/v1/schema/compatibility/comparators/members.d.ts +4 -0
  229. package/dist/v1/schema/compatibility/comparators/members.js +49 -0
  230. package/dist/v1/schema/compatibility/comparators/values.d.ts +5 -0
  231. package/dist/v1/schema/compatibility/comparators/values.js +37 -0
  232. package/dist/v1/schema/compatibility/compare.d.ts +5 -0
  233. package/dist/v1/schema/compatibility/compare.js +23 -0
  234. package/dist/v1/schema/compatibility/context.d.ts +19 -0
  235. package/dist/v1/schema/compatibility/context.js +49 -0
  236. package/dist/v1/schema/compatibility/coordinate.d.ts +40 -0
  237. package/dist/v1/schema/compatibility/coordinate.js +38 -0
  238. package/dist/v1/schema/compatibility/diff.d.ts +12 -0
  239. package/dist/v1/schema/compatibility/diff.js +39 -0
  240. package/dist/v1/schema/compatibility/evidence.d.ts +16 -0
  241. package/dist/v1/schema/compatibility/evidence.js +62 -0
  242. package/dist/v1/schema/compatibility/fields.d.ts +194 -0
  243. package/dist/v1/schema/compatibility/fields.js +94 -0
  244. package/dist/v1/schema/compatibility/index.d.ts +6 -0
  245. package/dist/v1/schema/compatibility/index.js +3 -0
  246. package/dist/v1/schema/compatibility/meaning/footprint.d.ts +7 -0
  247. package/dist/v1/schema/compatibility/meaning/footprint.js +59 -0
  248. package/dist/v1/schema/compatibility/meaning/index.d.ts +3 -0
  249. package/dist/v1/schema/compatibility/meaning/index.js +16 -0
  250. package/dist/v1/schema/compatibility/model.d.ts +131 -0
  251. package/dist/v1/schema/compatibility/model.js +1 -0
  252. package/dist/v1/schema/compatibility/references.d.ts +38 -0
  253. package/dist/v1/schema/compatibility/references.js +149 -0
  254. package/dist/v1/schema/compatibility/report.d.ts +27 -0
  255. package/dist/v1/schema/compatibility/report.js +100 -0
  256. package/dist/v1/schema/compatibility/scope.d.ts +36 -0
  257. package/dist/v1/schema/compatibility/scope.js +110 -0
  258. package/dist/v1/schema/compatibility/structure/index.d.ts +3 -0
  259. package/dist/v1/schema/compatibility/structure/index.js +40 -0
  260. package/dist/v1/schema/compatibility/structure/inheritance.d.ts +7 -0
  261. package/dist/v1/schema/compatibility/structure/inheritance.js +68 -0
  262. package/dist/v1/schema/compatibility/structure/requirements.d.ts +7 -0
  263. package/dist/v1/schema/compatibility/structure/requirements.js +97 -0
  264. package/dist/v1/schema/compatibility/subjects.d.ts +39 -0
  265. package/dist/v1/schema/compatibility/subjects.js +143 -0
  266. package/dist/v1/schema/compatibility/versioning/index.d.ts +8 -0
  267. package/dist/v1/schema/compatibility/versioning/index.js +50 -0
  268. package/dist/v1/schema/compatibility/versioning/members.d.ts +12 -0
  269. package/dist/v1/schema/compatibility/versioning/members.js +47 -0
  270. package/dist/v1/schema/compatibility/versioning/surface.d.ts +11 -0
  271. package/dist/v1/schema/compatibility/versioning/surface.js +61 -0
  272. package/dist/v1/schema/diagnostic.d.ts +1 -1
  273. package/dist/v1/schema/fingerprint.d.ts +2 -0
  274. package/dist/v1/schema/fingerprint.js +1 -0
  275. package/dist/v1/schema/index.d.ts +4 -3
  276. package/dist/v1/schema/index.js +2 -1
  277. package/dist/v1/schema/model/schema.d.ts +8 -11
  278. package/dist/v1/schema/normalization/domain.js +57 -13
  279. package/dist/v1/schema/resolution/definition.index.d.ts +1 -2
  280. package/dist/v1/schema/resolution/definition.index.js +0 -3
  281. package/dist/v1/schema/resolution/domain.d.ts +4 -1
  282. package/dist/v1/schema/resolution/domain.js +26 -18
  283. package/dist/v1/schema/resolution/origins.d.ts +28 -5
  284. package/dist/v1/schema/resolution/origins.js +68 -31
  285. package/dist/v1/schema/validation/callable.d.ts +4 -0
  286. package/dist/v1/schema/validation/callable.js +39 -0
  287. package/dist/v1/schema/validation/class.d.ts +10 -0
  288. package/dist/v1/schema/validation/class.js +79 -60
  289. package/dist/v1/schema/validation/core.js +83 -55
  290. package/dist/v1/schema/validation/domain.d.ts +2 -1
  291. package/dist/v1/schema/validation/domain.js +2 -0
  292. package/dist/v1/schema/validation/domain.structure.d.ts +0 -2
  293. package/dist/v1/schema/validation/domain.structure.js +214 -171
  294. package/dist/v1/schema/validation/policy/budgets.js +36 -6
  295. package/dist/v1/schema/validation/policy/context.js +5 -16
  296. package/dist/v1/schema/validation/policy/objects.d.ts +4 -0
  297. package/dist/v1/schema/validation/policy/objects.js +71 -0
  298. package/dist/v1/schema/validation/policy/references.js +16 -4
  299. package/dist/v1/schema/validation/policy/typing.d.ts +2 -0
  300. package/dist/v1/schema/validation/policy/typing.js +55 -7
  301. package/dist/v1/schema/validation/policy/uses.js +73 -99
  302. package/dist/v1/schema/validation/value-api.d.ts +2 -0
  303. package/dist/v1/schema/validation/value-api.js +1 -0
  304. package/dist/v1/schema/validation/value.js +7 -1
  305. package/dist/v1/schema/validation/view.js +14 -9
  306. package/dist/value/accept.d.ts +9 -0
  307. package/dist/value/accept.js +106 -7
  308. package/dist/value/canonical.d.ts +3 -0
  309. package/dist/value/canonical.js +22 -6
  310. package/dist/value/immutable.optimization.d.ts +15 -0
  311. package/dist/value/immutable.optimization.js +34 -0
  312. package/dist/value/index.d.ts +1 -1
  313. package/dist/value/index.js +1 -1
  314. package/dist/value/json.d.ts +1 -1
  315. package/dist/value/json.js +1 -1
  316. package/dist/value/limits.d.ts +1 -1
  317. package/dist/value/unicode.d.ts +4 -1
  318. package/dist/value/unicode.js +28 -0
  319. package/package.json +20 -5
  320. package/dist/v1/schema/compatibility/meaning.d.ts +0 -29
  321. package/dist/v1/schema/compatibility/meaning.js +0 -605
@@ -0,0 +1,28 @@
1
+ import { type ZodType } from 'zod';
2
+ import type { EventName, StateName, StateTopology, TransitionRelation, ValidTransitionRelation } from './topology.js';
3
+ export interface StateMachine<Transitions extends TransitionRelation = any, Initial extends StateName<Transitions> = StateName<Transitions>> extends StateTopology<Transitions, Initial> {
4
+ readonly stateSchema: ZodType<StateName<Transitions>, StateName<Transitions>>;
5
+ readonly eventSchema: ZodType<EventName<Transitions>, EventName<Transitions>>;
6
+ eventsFrom<State extends StateName<Transitions>>(state: State): readonly EventName<Transitions, State>[];
7
+ decide<State extends StateName<Transitions>, Event extends EventName<Transitions>>(state: State, event: Event): TransitionDecision<Transitions, State, Event>;
8
+ }
9
+ export type StateOf<Machine extends StateMachine> = StateName<Machine['transitions']>;
10
+ export type EventOf<Machine extends StateMachine, State extends StateOf<Machine> = StateOf<Machine>> = EventName<Machine['transitions'], State>;
11
+ type TransitionDecision<Transitions extends TransitionRelation, State extends StateName<Transitions>, Event extends EventName<Transitions>> = State extends StateName<Transitions> ? Event extends EventName<Transitions> ? Event extends keyof Transitions[State] ? Readonly<{
12
+ kind: 'allowed';
13
+ transition: Readonly<{
14
+ from: State;
15
+ event: Event;
16
+ to: Transitions[State][Event];
17
+ }>;
18
+ }> : Readonly<{
19
+ kind: 'rejected';
20
+ code: 'STATE_TRANSITION_ILLEGAL';
21
+ from: State;
22
+ event: Event;
23
+ }> : never : never;
24
+ export declare function stateMachine<const Transitions extends TransitionRelation, const Initial extends StateName<Transitions>>(input: Readonly<{
25
+ initial: Initial;
26
+ transitions: Transitions & ValidTransitionRelation<Transitions>;
27
+ }>): StateMachine<Transitions, Initial>;
28
+ export {};
@@ -0,0 +1,40 @@
1
+ import { enum as enumeration } from 'zod';
2
+ import { compareUnicode } from '../../addressing/ordering.js';
3
+ import { admitStateTopology } from './topology.js';
4
+ export function stateMachine(input) {
5
+ const topology = admitStateTopology(input);
6
+ const states = Object.keys(topology.transitions);
7
+ const events = [
8
+ ...new Set(states.flatMap((state) => Object.keys(topology.transitions[state]))),
9
+ ].sort(compareUnicode);
10
+ const stateSet = new Set(states);
11
+ const eventSet = new Set(events);
12
+ return Object.freeze({
13
+ ...topology,
14
+ stateSchema: enumeration(states),
15
+ eventSchema: enumeration(events),
16
+ eventsFrom(state) {
17
+ admitState(state, stateSet);
18
+ return Object.freeze(Object.keys(topology.transitions[state]));
19
+ },
20
+ decide(state, event) {
21
+ admitState(state, stateSet);
22
+ admitEvent(event, eventSet);
23
+ const target = topology.transitions[state][event];
24
+ return target === undefined
25
+ ? Object.freeze({ kind: 'rejected', code: 'STATE_TRANSITION_ILLEGAL', from: state, event })
26
+ : Object.freeze({
27
+ kind: 'allowed',
28
+ transition: Object.freeze({ from: state, event, to: target }),
29
+ });
30
+ },
31
+ });
32
+ }
33
+ function admitState(state, states) {
34
+ if (!states.has(state))
35
+ throw new TypeError(`State machine does not declare state "${state}".`);
36
+ }
37
+ function admitEvent(event, events) {
38
+ if (!events.has(event))
39
+ throw new TypeError(`State machine does not declare event "${event}".`);
40
+ }
@@ -0,0 +1,14 @@
1
+ export type TransitionRelation = Readonly<Record<string, Readonly<Record<string, string>>>>;
2
+ export type StateName<Transitions extends TransitionRelation> = Extract<keyof Transitions, string>;
3
+ export type EventName<Transitions extends TransitionRelation, State extends StateName<Transitions> = StateName<Transitions>> = State extends StateName<Transitions> ? Extract<keyof Transitions[State], string> : never;
4
+ export type ValidTransitionRelation<Transitions extends TransitionRelation> = Readonly<{
5
+ [State in StateName<Transitions>]: Readonly<{
6
+ [Event in keyof Transitions[State]]: string extends StateName<Transitions> ? string : Exclude<StateName<Transitions>, State>;
7
+ }>;
8
+ }>;
9
+ export interface StateTopology<Transitions extends TransitionRelation = TransitionRelation, Initial extends StateName<Transitions> = StateName<Transitions>> {
10
+ readonly initial: Initial;
11
+ readonly transitions: Transitions;
12
+ }
13
+ export type StateTopologyOf<Value> = Value extends StateTopology<infer Transitions, infer Initial> ? StateTopology<Transitions, Initial> : undefined;
14
+ export declare function admitStateTopology(input: unknown): StateTopology;
@@ -0,0 +1,69 @@
1
+ import { compareUnicode } from '../../addressing/ordering.js';
2
+ export function admitStateTopology(input) {
3
+ if (!isRecord(input) || !exactKeys(input, ['initial', 'transitions']))
4
+ invalidInput();
5
+ const initial = input.initial;
6
+ const authored = input.transitions;
7
+ if (typeof initial !== 'string' || initial.length === 0 || !isRecord(authored))
8
+ invalidInput();
9
+ const states = Object.keys(authored);
10
+ if (states.length === 0)
11
+ throw new TypeError('State topology requires at least one state.');
12
+ if (states.includes(''))
13
+ throw new TypeError('State topology has an empty state name.');
14
+ if (!states.includes(initial)) {
15
+ throw new TypeError(`State topology initial state "${initial}" is not declared.`);
16
+ }
17
+ const declared = new Set(states);
18
+ const transitions = Object.create(null);
19
+ let transitionCount = 0;
20
+ for (const state of states.sort(compareUnicode)) {
21
+ const outgoing = authored[state];
22
+ if (!isRecord(outgoing))
23
+ throw new TypeError(`State "${state}" transitions must be an object.`);
24
+ const accepted = Object.create(null);
25
+ for (const event of Object.keys(outgoing).sort(compareUnicode)) {
26
+ const target = outgoing[event];
27
+ if (event.length === 0)
28
+ throw new TypeError(`State "${state}" has an empty event name.`);
29
+ if (typeof target !== 'string' || !declared.has(target)) {
30
+ throw new TypeError(`State "${state}" event "${event}" targets undeclared state "${String(target)}".`);
31
+ }
32
+ if (target === state) {
33
+ throw new TypeError(`State "${state}" event "${event}" is a self-transition.`);
34
+ }
35
+ accepted[event] = target;
36
+ transitionCount += 1;
37
+ }
38
+ transitions[state] = Object.freeze(accepted);
39
+ }
40
+ if (transitionCount === 0)
41
+ throw new TypeError('State topology requires at least one transition.');
42
+ const reachable = new Set([initial]);
43
+ const pending = [initial];
44
+ while (pending.length > 0) {
45
+ const state = pending.shift();
46
+ for (const target of Object.values(transitions[state])) {
47
+ if (reachable.has(target))
48
+ continue;
49
+ reachable.add(target);
50
+ pending.push(target);
51
+ }
52
+ }
53
+ for (const state of states) {
54
+ if (!reachable.has(state)) {
55
+ throw new TypeError(`State "${state}" is unreachable from initial "${initial}".`);
56
+ }
57
+ }
58
+ return Object.freeze({ initial, transitions: Object.freeze(transitions) });
59
+ }
60
+ function invalidInput() {
61
+ throw new TypeError('State topology must contain exactly initial and transitions.');
62
+ }
63
+ function isRecord(input) {
64
+ return input !== null && typeof input === 'object' && !Array.isArray(input);
65
+ }
66
+ function exactKeys(input, expected) {
67
+ const keys = Reflect.ownKeys(input);
68
+ return keys.length === expected.length && keys.every((key) => expected.includes(String(key)));
69
+ }
@@ -1,3 +1,3 @@
1
1
  import type { ValueProgram } from './model.js';
2
2
  /** Exact field constraints available for independent scalar route validation. */
3
- export declare function inputFieldNodes(program: ValueProgram): Readonly<Record<string, readonly number[]>> | undefined;
3
+ export declare function inputFieldNodes(program: Pick<ValueProgram, 'root' | 'nodes'>): Readonly<Record<string, readonly number[]>> | undefined;
@@ -1,4 +1,6 @@
1
1
  import type { CompiledInstanceSchema } from '../evaluate/types.js';
2
- import type { ValueProgram } from './model.js';
2
+ import type { IndexedValueProgram, ValueProgram } from './model.js';
3
+ /** Bind already-admitted entry-local indices without copying any pattern machine. */
4
+ export declare function bindValueProgram(program: IndexedValueProgram, patterns: ValueProgram['patterns']): ValueProgram;
3
5
  /** Bind admitted portable indices to the canonical instance evaluator. */
4
- export declare function loadValueProgram(program: ValueProgram): CompiledInstanceSchema;
6
+ export declare function loadValueProgram(program: ValueProgram, rootIndex?: number): CompiledInstanceSchema;
@@ -1,7 +1,28 @@
1
1
  import { loadPattern } from '../regexp/matcher.js';
2
2
  import { appendPointer } from '../syntax/pointer.js';
3
+ const loadedPrograms = new WeakMap();
4
+ /** Bind already-admitted entry-local indices without copying any pattern machine. */
5
+ export function bindValueProgram(program, patterns) {
6
+ return Object.freeze({
7
+ ...program,
8
+ patterns: Object.freeze(program.patterns.map((index) => patterns[index])),
9
+ });
10
+ }
3
11
  /** Bind admitted portable indices to the canonical instance evaluator. */
4
- export function loadValueProgram(program) {
12
+ export function loadValueProgram(program, rootIndex = program.root) {
13
+ let compiled = loadedPrograms.get(program);
14
+ if (compiled === undefined) {
15
+ compiled = createValueProgram(program);
16
+ loadedPrograms.set(program, compiled);
17
+ }
18
+ if (rootIndex === program.root)
19
+ return compiled;
20
+ const root = compiled.locations.get(String(rootIndex));
21
+ if (root === undefined)
22
+ throw new TypeError('Compiled value program root is absent.');
23
+ return { ...compiled, root };
24
+ }
25
+ function createValueProgram(program) {
5
26
  const resource = { key: 'compiled', schema: true, ownerOrigin: 'compiled' };
6
27
  const locations = program.nodes.map((node, index) => ({
7
28
  key: String(index),
@@ -14,6 +14,17 @@ export interface Pattern {
14
14
  readonly start: number;
15
15
  readonly states: readonly PatternState[];
16
16
  }
17
+ /** A scalar run counts Unicode scalars, never UTF-16 code units. */
18
+ export interface ScalarRun {
19
+ readonly ranges: readonly ScalarRange[];
20
+ readonly minimum: number;
21
+ readonly maximum?: number;
22
+ }
23
+ /** All runs except the last have an exact finite length. */
24
+ export interface RunPattern {
25
+ readonly source: string;
26
+ readonly runs: readonly ScalarRun[];
27
+ }
17
28
  export interface ValueNode {
18
29
  readonly schema: JsonValue;
19
30
  readonly children: Readonly<Record<string, number>>;
@@ -23,5 +34,9 @@ export interface ValueNode {
23
34
  export interface ValueProgram {
24
35
  readonly root: number;
25
36
  readonly nodes: readonly ValueNode[];
26
- readonly patterns: readonly Pattern[];
37
+ readonly patterns: readonly (Pattern | RunPattern)[];
38
+ }
39
+ /** Pattern indices belong to the enclosing compiled entry's table. */
40
+ export interface IndexedValueProgram extends Omit<ValueProgram, 'patterns'> {
41
+ readonly patterns: readonly number[];
27
42
  }
@@ -1,6 +1,8 @@
1
1
  import type { Value as JsonValue } from '@astrale-os/kernel-dsl/value';
2
2
  export declare function matchesType(input: string, value: JsonValue): boolean;
3
3
  export declare function jsonEqual(left: JsonValue, right: JsonValue): boolean;
4
+ /** Count Unicode code points with string-iterator semantics, without a character array. */
5
+ export declare function codePointLength(input: string): number;
4
6
  export declare function unique(values: readonly JsonValue[]): boolean;
5
7
  /** Compare finite JSON numbers as their exact ECMAScript decimal spellings. */
6
8
  export declare function isMultipleOf(value: number, divisor: number): boolean;
@@ -21,6 +21,19 @@ export function matchesType(input, value) {
21
21
  export function jsonEqual(left, right) {
22
22
  return equal(left, right);
23
23
  }
24
+ /** Count Unicode code points with string-iterator semantics, without a character array. */
25
+ export function codePointLength(input) {
26
+ let length = 0;
27
+ for (let index = 0; index < input.length; index++, length++) {
28
+ const first = input.charCodeAt(index);
29
+ if (first >= 0xd800 && first <= 0xdbff && index + 1 < input.length) {
30
+ const second = input.charCodeAt(index + 1);
31
+ if (second >= 0xdc00 && second <= 0xdfff)
32
+ index++;
33
+ }
34
+ }
35
+ return length;
36
+ }
24
37
  export function unique(values) {
25
38
  const seen = new Set();
26
39
  for (const value of values) {
@@ -1,36 +1,61 @@
1
+ import { isCanonicalBlobRef } from '../model/blob.js';
1
2
  import { isInstantValue } from '../model/instant.js';
2
3
  import { isValueObject as isJsonObject } from '../model/object.js';
3
4
  import { appendPointer } from '../syntax/pointer.js';
4
- import { isMultipleOf, jsonEqual, matchesType, unique } from './assertions.js';
5
+ import { codePointLength, isMultipleOf, jsonEqual, matchesType, unique } from './assertions.js';
5
6
  import { evaluation, mergeAnnotations } from './types.js';
6
7
  /** Evaluate complete Draft 2020-12 acceptance without dynamic source generation. */
7
8
  export function evaluateInstance(compiled, input) {
8
9
  return new InstanceEvaluator(compiled).evaluate(compiled.root, input, '');
9
10
  }
11
+ /** Bound per-call retention independently of the size or diversity of an input value. */
12
+ const MAX_CACHED_PATTERN_RESULTS = 256;
13
+ const MAX_CACHED_PATTERN_INPUT_LENGTH = 128;
10
14
  class InstanceEvaluator {
11
15
  compiled;
12
- active = new Set();
16
+ resultCache = new Map();
17
+ searchResults = new Map();
18
+ fullMatchResults = new Map();
19
+ patternResultCount = 0;
13
20
  constructor(compiled) {
14
21
  this.compiled = compiled;
15
22
  }
16
23
  evaluate(location, input, instancePointer) {
17
- const activeKey = `${location.key}\u0000${instancePointer}`;
18
- if (this.active.has(activeKey)) {
24
+ const key = `${location.key}\u0000${instancePointer}`;
25
+ // propertyNames evaluates the name at the property's value pointer. Cache by the actual
26
+ // input too, retaining one result per repeated sub-problem within this call. A null entry
27
+ // marks an active evaluation; completed results and their annotations are only read.
28
+ let byLocation = this.resultCache.get(input);
29
+ const memoized = byLocation?.get(key);
30
+ if (memoized === null) {
19
31
  throw new TypeError('Admitted value schema entered a non-productive evaluation cycle.');
20
32
  }
21
- this.active.add(activeKey);
33
+ if (memoized !== undefined)
34
+ return memoized;
35
+ if (byLocation === undefined) {
36
+ byLocation = new Map();
37
+ this.resultCache.set(input, byLocation);
38
+ }
39
+ byLocation.set(key, null);
22
40
  try {
23
- if (location.schema === true)
24
- return evaluation();
25
- if (location.schema === false) {
26
- return evaluation([
41
+ let result;
42
+ if (location.schema === true) {
43
+ result = evaluation();
44
+ }
45
+ else if (location.schema === false) {
46
+ result = evaluation([
27
47
  invalid(instancePointer, 'false', 'The false schema rejects every value.'),
28
48
  ]);
29
49
  }
30
- return this.evaluateObjectSchema(location, location.schema, input, instancePointer);
50
+ else {
51
+ result = this.evaluateObjectSchema(location, location.schema, input, instancePointer);
52
+ }
53
+ byLocation.set(key, result);
54
+ return result;
31
55
  }
32
- finally {
33
- this.active.delete(activeKey);
56
+ catch (error) {
57
+ byLocation.delete(key);
58
+ throw error;
34
59
  }
35
60
  }
36
61
  evaluateObjectSchema(location, schema, input, instancePointer) {
@@ -79,14 +104,20 @@ class InstanceEvaluator {
79
104
  });
80
105
  const anyOf = schemaList(schema.anyOf);
81
106
  if (anyOf !== undefined) {
82
- const results = anyOf.map((_, index) => this.evaluate(this.child(location, 'anyOf', index), input, instancePointer));
83
- const admitted = results.filter(({ valid }) => valid);
84
- if (admitted.length === 0) {
107
+ let admitted = 0;
108
+ anyOf.forEach((_, index) => {
109
+ const branch = this.child(location, 'anyOf', index);
110
+ if (contradictsRequiredConst(branch.schema, input))
111
+ return;
112
+ const result = this.evaluate(branch, input, instancePointer);
113
+ if (!result.valid)
114
+ return;
115
+ admitted += 1;
116
+ mergeAnnotations(properties, items, result);
117
+ });
118
+ if (admitted === 0) {
85
119
  failures.push(invalid(instancePointer, 'anyOf', 'Value satisfies no anyOf branch.'));
86
120
  }
87
- else {
88
- admitted.forEach((result) => mergeAnnotations(properties, items, result));
89
- }
90
121
  }
91
122
  const oneOf = schemaList(schema.oneOf);
92
123
  if (oneOf !== undefined) {
@@ -119,6 +150,9 @@ class InstanceEvaluator {
119
150
  if (schema['x-astrale-value-kind'] === 'instant' && !isInstantValue(input)) {
120
151
  failures.push(invalid(instancePointer, 'x-astrale-value-kind', 'Value is not an exact UTC millisecond Instant.'));
121
152
  }
153
+ if (schema['x-astrale-value-kind'] === 'blob' && !isCanonicalBlobRef(input)) {
154
+ failures.push(invalid(instancePointer, 'x-astrale-value-kind', 'Value is not a canonical blob Ref.'));
155
+ }
122
156
  if (typeof schema.type === 'string') {
123
157
  if (!matchesType(schema.type, input)) {
124
158
  failures.push(invalid(instancePointer, 'type', `Value is not of type ${schema.type}.`));
@@ -154,18 +188,23 @@ class InstanceEvaluator {
154
188
  }
155
189
  }
156
190
  evaluateStringAssertions(schema, input, instancePointer, failures) {
157
- const length = Array.from(input).length;
158
- if (typeof schema.maxLength === 'number' && length > schema.maxLength) {
159
- failures.push(invalid(instancePointer, 'maxLength', 'String exceeds maxLength.'));
160
- }
161
- if (typeof schema.minLength === 'number' && length < schema.minLength) {
162
- failures.push(invalid(instancePointer, 'minLength', 'String is below minLength.'));
191
+ // For n UTF-16 units, ceil(n / 2) <= code points <= n. Count only if those
192
+ // bounds cannot already prove both length assertions; other assertions still run.
193
+ if ((typeof schema.maxLength === 'number' && input.length > schema.maxLength) ||
194
+ (typeof schema.minLength === 'number' && Math.ceil(input.length / 2) < schema.minLength)) {
195
+ const length = codePointLength(input);
196
+ if (typeof schema.maxLength === 'number' && length > schema.maxLength) {
197
+ failures.push(invalid(instancePointer, 'maxLength', 'String exceeds maxLength.'));
198
+ }
199
+ if (typeof schema.minLength === 'number' && length < schema.minLength) {
200
+ failures.push(invalid(instancePointer, 'minLength', 'String is below minLength.'));
201
+ }
163
202
  }
164
- if (typeof schema.pattern === 'string' && !this.compiled.matcher(schema.pattern).test(input)) {
203
+ if (typeof schema.pattern === 'string' && !this.matchesPattern(schema.pattern, input, false)) {
165
204
  failures.push(invalid(instancePointer, 'pattern', 'String does not match pattern.'));
166
205
  }
167
206
  if (typeof schema.fullMatch === 'string' &&
168
- !this.compiled.matcher(schema.fullMatch).matches(input)) {
207
+ !this.matchesPattern(schema.fullMatch, input, true)) {
169
208
  failures.push(invalid(instancePointer, 'fullMatch', 'String does not match fullMatch.'));
170
209
  }
171
210
  }
@@ -284,9 +323,8 @@ class InstanceEvaluator {
284
323
  const patternMatched = new Set();
285
324
  let patternsValid = true;
286
325
  for (const pattern of Object.keys(patterns)) {
287
- const matcher = this.compiled.matcher(pattern);
288
326
  for (const name of names) {
289
- if (!matcher.test(name))
327
+ if (!this.matchesPattern(pattern, name, false))
290
328
  continue;
291
329
  patternMatched.add(name);
292
330
  const result = this.evaluate(this.child(location, 'patternProperties', pattern), input[name], appendPointer(instancePointer, name));
@@ -349,6 +387,51 @@ class InstanceEvaluator {
349
387
  child(parent, keyword, member) {
350
388
  return this.compiled.child(parent, keyword, member);
351
389
  }
390
+ matchesPattern(source, input, whole) {
391
+ const cacheable = input.length <= MAX_CACHED_PATTERN_INPUT_LENGTH;
392
+ const cache = whole ? this.fullMatchResults : this.searchResults;
393
+ if (cacheable) {
394
+ const found = cache.get(source)?.get(input);
395
+ if (found !== undefined)
396
+ return found;
397
+ }
398
+ const matcher = this.compiled.matcher(source);
399
+ const result = whole ? matcher.matches(input) : matcher.test(input);
400
+ if (cacheable && this.patternResultCount < MAX_CACHED_PATTERN_RESULTS) {
401
+ let values = cache.get(source);
402
+ if (values === undefined) {
403
+ values = new Map();
404
+ cache.set(source, values);
405
+ }
406
+ values.set(input, result);
407
+ this.patternResultCount++;
408
+ }
409
+ return result;
410
+ }
411
+ }
412
+ /** A required property with a different primitive const makes the entire branch impossible. */
413
+ function contradictsRequiredConst(schema, input) {
414
+ if (!isJsonObject(schema) || !isJsonObject(input) || !Array.isArray(schema.required)) {
415
+ return false;
416
+ }
417
+ if (!isJsonObject(schema.properties))
418
+ return false;
419
+ for (const key of schema.required) {
420
+ if (typeof key !== 'string' || !Object.hasOwn(input, key))
421
+ continue;
422
+ const property = schema.properties[key];
423
+ if (!isJsonObject(property) || !Object.hasOwn(property, 'const'))
424
+ continue;
425
+ const expected = property.const;
426
+ if ((expected === null ||
427
+ typeof expected === 'string' ||
428
+ typeof expected === 'number' ||
429
+ typeof expected === 'boolean') &&
430
+ input[key] !== expected) {
431
+ return true;
432
+ }
433
+ }
434
+ return false;
352
435
  }
353
436
  function schemaList(input) {
354
437
  return Array.isArray(input) ? input : undefined;
@@ -1,6 +1,8 @@
1
1
  import type { JsonSchema } from '../model/schema.js';
2
2
  import type { ValueSchemaRegistry } from '../reference/registry.js';
3
+ import type { IRegexpMatcher } from '../regexp/matcher.js';
3
4
  import type { CompiledInstanceSchema } from './types.js';
5
+ import { compilePattern } from '../regexp/compile.js';
4
6
  export type InstanceSchemaCompilation = {
5
7
  readonly compiled: true;
6
8
  readonly value: CompiledInstanceSchema;
@@ -8,6 +10,13 @@ export type InstanceSchemaCompilation = {
8
10
  readonly compiled: false;
9
11
  readonly message: string;
10
12
  };
13
+ /** Owned by one compilation or source-resolution closure, not retained process-globally. */
14
+ interface PreparedPattern {
15
+ readonly pattern: ReturnType<typeof compilePattern>;
16
+ readonly matcher: IRegexpMatcher;
17
+ }
18
+ export type PatternPool = Map<string, PreparedPattern>;
11
19
  /** Prepare reference and linear-regexp state without generating executable source. */
12
- export declare function prepareValueSchema(schema: JsonSchema, registry: ValueSchemaRegistry, pointer: string): InstanceSchemaCompilation;
20
+ export declare function prepareValueSchema(schema: JsonSchema, registry: ValueSchemaRegistry, pointer: string, pool?: PatternPool): InstanceSchemaCompilation;
13
21
  export declare function childKey(pointer: string): string;
22
+ export {};
@@ -6,7 +6,7 @@ import { loadPattern } from '../regexp/matcher.js';
6
6
  import { appendPointer } from '../syntax/pointer.js';
7
7
  import { walkSchema } from '../syntax/walk.js';
8
8
  /** Prepare reference and linear-regexp state without generating executable source. */
9
- export function prepareValueSchema(schema, registry, pointer) {
9
+ export function prepareValueSchema(schema, registry, pointer, pool = new Map()) {
10
10
  const indexed = indexRegistry(registry, pointer);
11
11
  if (indexed.diagnostics.length > 0)
12
12
  return failed(indexed.diagnostics);
@@ -26,11 +26,11 @@ export function prepareValueSchema(schema, registry, pointer) {
26
26
  });
27
27
  if (!isJsonObject(location.schema))
28
28
  return;
29
- rememberMatcher(matchers, location.schema.pattern);
30
- rememberMatcher(matchers, location.schema.fullMatch);
29
+ rememberMatcher(matchers, pool, location.schema.pattern);
30
+ rememberMatcher(matchers, pool, location.schema.fullMatch);
31
31
  if (isJsonObject(location.schema.patternProperties)) {
32
32
  for (const pattern of Object.keys(location.schema.patternProperties)) {
33
- rememberMatcher(matchers, pattern);
33
+ rememberMatcher(matchers, pool, pattern);
34
34
  }
35
35
  }
36
36
  });
@@ -40,13 +40,14 @@ export function prepareValueSchema(schema, registry, pointer) {
40
40
  if (root === undefined) {
41
41
  return { compiled: false, message: 'The root value schema is absent from its closure.' };
42
42
  }
43
+ let program;
43
44
  return {
44
45
  compiled: true,
45
46
  value: {
46
47
  root,
47
48
  locations,
48
49
  resolutions: closure.resolutions,
49
- program: () => portableProgram(root, locations, closure.resolutions),
50
+ program: () => (program ??= portableProgram(root, locations, closure.resolutions, matchers)),
50
51
  child(location, keyword, member) {
51
52
  const keywordPointer = appendPointer(location.pointer, keyword);
52
53
  const pointer = member === undefined ? keywordPointer : appendPointer(keywordPointer, member);
@@ -67,15 +68,14 @@ export function prepareValueSchema(schema, registry, pointer) {
67
68
  if (matcher === undefined) {
68
69
  throw new TypeError('Value schema uses an unprepared I-Regexp source.');
69
70
  }
70
- return matcher;
71
+ return matcher.matcher;
71
72
  },
72
73
  },
73
74
  };
74
75
  }
75
- function portableProgram(root, locations, resolutions) {
76
+ function portableProgram(root, locations, resolutions, patterns) {
76
77
  const ordered = [...locations.values()];
77
78
  const indices = new Map(ordered.map((location, index) => [location.key, index]));
78
- const patterns = new Map();
79
79
  const nodes = ordered.map((location) => {
80
80
  const children = {};
81
81
  walkSchema(location.schema, (child) => {
@@ -85,7 +85,6 @@ function portableProgram(root, locations, resolutions) {
85
85
  if (target !== undefined)
86
86
  children[childKey(child.pointer)] = target;
87
87
  });
88
- rememberPattern(patterns, location.schema);
89
88
  const resolved = resolutions.get(location.key);
90
89
  const reference = resolved === undefined
91
90
  ? undefined
@@ -102,29 +101,21 @@ function portableProgram(root, locations, resolutions) {
102
101
  return Object.freeze({
103
102
  root: indices.get(root.key),
104
103
  nodes: Object.freeze(nodes),
105
- patterns: Object.freeze([...patterns.values()]),
104
+ patterns: Object.freeze([...patterns.values()].map(({ pattern }) => pattern)),
106
105
  });
107
106
  }
108
- function rememberPattern(patterns, schema) {
109
- if (!isJsonObject(schema))
110
- return;
111
- for (const source of [schema.pattern, schema.fullMatch]) {
112
- if (typeof source === 'string' && !patterns.has(source))
113
- patterns.set(source, compilePattern(source));
114
- }
115
- if (isJsonObject(schema.patternProperties)) {
116
- for (const source of Object.keys(schema.patternProperties)) {
117
- if (!patterns.has(source))
118
- patterns.set(source, compilePattern(source));
119
- }
120
- }
121
- }
122
107
  export function childKey(pointer) {
123
108
  return pointer.slice(1);
124
109
  }
125
- function rememberMatcher(matchers, input) {
110
+ function rememberMatcher(matchers, pool, input) {
126
111
  if (typeof input === 'string' && !matchers.has(input)) {
127
- matchers.set(input, loadPattern(compilePattern(input)));
112
+ let prepared = pool.get(input);
113
+ if (prepared === undefined) {
114
+ const pattern = compilePattern(input);
115
+ prepared = { pattern, matcher: loadPattern(pattern) };
116
+ pool.set(input, prepared);
117
+ }
118
+ matchers.set(input, prepared);
128
119
  }
129
120
  }
130
121
  function failed(diagnostics) {
@@ -6,7 +6,7 @@ export function validateValueProgram(program, input, roots = [program.root]) {
6
6
  if (canonical.length > 0)
7
7
  return canonical;
8
8
  return roots.flatMap((root) => {
9
- const result = evaluateInstance(loadValueProgram({ ...program, root }), input);
9
+ const result = evaluateInstance(loadValueProgram(program, root), input);
10
10
  return result.failures.map((failure) => ({
11
11
  code: 'VALUE_SCHEMA_INSTANCE_INVALID',
12
12
  pointer: failure.instancePointer,
@@ -2,11 +2,15 @@ import type { Value as JsonValue } from '@astrale-os/kernel-dsl/value';
2
2
  import type { Diagnostic } from '../../validation/diagnostic.js';
3
3
  import type { JsonSchema } from '../model/schema.js';
4
4
  import type { ValueSchemaRegistry } from '../reference/registry.js';
5
+ import type { CompiledInstanceSchema } from './types.js';
6
+ import { type PatternPool } from './preparation.js';
5
7
  /**
6
8
  * Validate one complete portable value with the admitted V1 Draft 2020-12 profile.
7
9
  *
8
10
  * Evaluation is an interpreter over the exact local resource closure. It never performs network
9
- * resolution or dynamic source generation, and every admitted I-Regexp executes through RE2JS.
11
+ * resolution or dynamic source generation; patterns use the portable executor.
10
12
  * `format` remains annotation-only; the graph NodePath codec performs its separate locator check.
11
13
  */
12
- export declare function validateJsonInstance(schema: JsonSchema, value: JsonValue, registry: ValueSchemaRegistry, pointer?: string): Diagnostic[];
14
+ export declare function validateJsonInstance(schema: JsonSchema, value: JsonValue, registry: ValueSchemaRegistry, pointer?: string, patterns?: PatternPool): Diagnostic[];
15
+ /** Validate with the exact preparation already retained by a source-resolved Property or Callable. */
16
+ export declare function validatePreparedInstance(compiled: CompiledInstanceSchema, value: unknown): Diagnostic[];