solve-engine 1.2.0 → 2.0.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 (384) hide show
  1. package/README.md +12 -17
  2. package/dist/{BytecodeBuilder-Bp9xeTmX.d.cts → BytecodeBuilder-DGGeByAP.d.cts} +18 -0
  3. package/dist/{BytecodeBuilder-Bp9xeTmX.d.ts → BytecodeBuilder-DGGeByAP.d.ts} +18 -0
  4. package/dist/{Configuration-C9W8tJv_.d.cts → Configuration-B6W0-T67.d.cts} +17 -4
  5. package/dist/{Configuration-C9W8tJv_.d.ts → Configuration-B6W0-T67.d.ts} +17 -4
  6. package/dist/{EngineError-CNA_rHY-.d.cts → EngineError-Ce1lPkjZ.d.cts} +2 -0
  7. package/dist/{EngineError-CNA_rHY-.d.ts → EngineError-Ce1lPkjZ.d.ts} +2 -0
  8. package/dist/{PackageCompatibility-B6NX9IaN.d.cts → PackageCompatibility-Bn5jnBtA.d.cts} +2 -2
  9. package/dist/{PackageCompatibility-Ceg5XdAp.d.ts → PackageCompatibility-CIvq2MP5.d.ts} +2 -2
  10. package/dist/{PackageRegistry-DrCPQNyy.d.ts → PackageRegistry-DzeiWcv4.d.ts} +93 -172
  11. package/dist/{PackageRegistry-DnJYVw9G.d.cts → PackageRegistry-dpdurBVO.d.cts} +93 -172
  12. package/dist/{Parselet-Bhf7d0_W.d.ts → Parselet-B-zoPrTa.d.ts} +8 -5
  13. package/dist/{Parselet-Cv7S7KRt.d.cts → Parselet-C4Wu055_.d.cts} +8 -5
  14. package/dist/{ScopeManager-Bzq87GfA.d.ts → ScopeManager-C2LDOrDx.d.ts} +7 -16
  15. package/dist/{ScopeManager-DRDBVfan.d.cts → ScopeManager-D7uMXbhS.d.cts} +7 -16
  16. package/dist/{VMCheckpoints-C6c17Hbo.d.ts → VMCheckpoints-CGyFhivM.d.ts} +3 -3
  17. package/dist/{VMCheckpoints-dZxSMGHG.d.cts → VMCheckpoints-I9jg3jWR.d.cts} +3 -3
  18. package/dist/{Value-DZNQ_PU7.d.cts → Value-CCi_Eecs.d.cts} +40 -0
  19. package/dist/{Value-DZNQ_PU7.d.ts → Value-CCi_Eecs.d.ts} +40 -0
  20. package/dist/{WorkerError-Djd7GGGa.d.cts → WorkerError-B4p6PNfx.d.cts} +1 -1
  21. package/dist/{WorkerError-B7t7R2-m.d.ts → WorkerError-Dhj9BQ_A.d.ts} +1 -1
  22. package/dist/chunk-2JMFUQZH.js +2 -0
  23. package/dist/chunk-2JMFUQZH.js.map +1 -0
  24. package/dist/chunk-2RWAXT6O.js +0 -1
  25. package/dist/chunk-4BZIYU7S.cjs +3 -0
  26. package/dist/chunk-4BZIYU7S.cjs.map +1 -0
  27. package/dist/chunk-4J7XZSZJ.cjs +5 -0
  28. package/dist/chunk-4J7XZSZJ.cjs.map +1 -0
  29. package/dist/chunk-4QVBSG6B.cjs +2 -0
  30. package/dist/chunk-4QVBSG6B.cjs.map +1 -0
  31. package/dist/chunk-5IJD5L3O.cjs +2 -0
  32. package/dist/chunk-5IJD5L3O.cjs.map +1 -0
  33. package/dist/chunk-62LMTO4F.js +2 -0
  34. package/dist/chunk-62LMTO4F.js.map +1 -0
  35. package/dist/chunk-6CY44ZPG.js +2 -0
  36. package/dist/chunk-6CY44ZPG.js.map +1 -0
  37. package/dist/chunk-6G3PMEPA.js +2 -0
  38. package/dist/chunk-6G3PMEPA.js.map +1 -0
  39. package/dist/chunk-6INX773F.cjs +2 -0
  40. package/dist/chunk-6INX773F.cjs.map +1 -0
  41. package/dist/chunk-6KFVG6UY.cjs +2 -0
  42. package/dist/{chunk-YJHY7CMN.cjs.map → chunk-6KFVG6UY.cjs.map} +1 -1
  43. package/dist/chunk-76F3LCIL.js +4 -0
  44. package/dist/chunk-76F3LCIL.js.map +1 -0
  45. package/dist/chunk-7GK3XEZF.js +2 -0
  46. package/dist/chunk-7GK3XEZF.js.map +1 -0
  47. package/dist/chunk-APN442VD.cjs +2 -0
  48. package/dist/chunk-APN442VD.cjs.map +1 -0
  49. package/dist/chunk-AXMQG5TS.cjs +2 -0
  50. package/dist/chunk-AXMQG5TS.cjs.map +1 -0
  51. package/dist/chunk-CIQOK7Q4.cjs +2 -0
  52. package/dist/chunk-CIQOK7Q4.cjs.map +1 -0
  53. package/dist/chunk-E6Z4NQAS.js +2 -0
  54. package/dist/chunk-E6Z4NQAS.js.map +1 -0
  55. package/dist/chunk-EFJCC6FJ.cjs +2 -0
  56. package/dist/chunk-EFJCC6FJ.cjs.map +1 -0
  57. package/dist/chunk-ESUN2THE.cjs +2 -0
  58. package/dist/chunk-ESUN2THE.cjs.map +1 -0
  59. package/dist/chunk-EVAOPEO4.js +2 -0
  60. package/dist/chunk-EVAOPEO4.js.map +1 -0
  61. package/dist/chunk-EYRBENHC.js +3 -0
  62. package/dist/chunk-EYRBENHC.js.map +1 -0
  63. package/dist/chunk-FDE5HWDI.cjs +2 -0
  64. package/dist/chunk-FDE5HWDI.cjs.map +1 -0
  65. package/dist/chunk-FWW3M36J.cjs +2 -0
  66. package/dist/chunk-FWW3M36J.cjs.map +1 -0
  67. package/dist/chunk-GOIQYUWV.js +2 -0
  68. package/dist/chunk-GOIQYUWV.js.map +1 -0
  69. package/dist/chunk-HFKDWQUL.js +2 -0
  70. package/dist/chunk-HFKDWQUL.js.map +1 -0
  71. package/dist/chunk-HLBYHXQD.cjs +3 -0
  72. package/dist/chunk-HLBYHXQD.cjs.map +1 -0
  73. package/dist/chunk-IANAMBJQ.cjs +2 -0
  74. package/dist/chunk-IANAMBJQ.cjs.map +1 -0
  75. package/dist/chunk-IJMNVBIS.js +2 -0
  76. package/dist/chunk-IJMNVBIS.js.map +1 -0
  77. package/dist/chunk-J4LZD4ZY.js +3 -0
  78. package/dist/chunk-J4LZD4ZY.js.map +1 -0
  79. package/dist/chunk-JAK3RAFA.cjs +2 -0
  80. package/dist/chunk-JAK3RAFA.cjs.map +1 -0
  81. package/dist/chunk-JFAJN3C2.cjs +2 -0
  82. package/dist/chunk-JFAJN3C2.cjs.map +1 -0
  83. package/dist/chunk-JPFCXLJV.js +2 -0
  84. package/dist/chunk-JPFCXLJV.js.map +1 -0
  85. package/dist/chunk-JSPKKNPQ.js +3 -0
  86. package/dist/chunk-JSPKKNPQ.js.map +1 -0
  87. package/dist/chunk-L3FPQSGN.js +2 -0
  88. package/dist/chunk-L3FPQSGN.js.map +1 -0
  89. package/dist/chunk-LR4E4A4W.cjs +2 -0
  90. package/dist/chunk-LR4E4A4W.cjs.map +1 -0
  91. package/dist/chunk-MIQBJGGR.js +2 -0
  92. package/dist/chunk-MIQBJGGR.js.map +1 -0
  93. package/dist/chunk-MPB7KUN5.js +3 -0
  94. package/dist/chunk-MPB7KUN5.js.map +1 -0
  95. package/dist/chunk-MSYX32PF.cjs +2 -0
  96. package/dist/chunk-MSYX32PF.cjs.map +1 -0
  97. package/dist/chunk-MVZUTETT.js +2 -0
  98. package/dist/chunk-MVZUTETT.js.map +1 -0
  99. package/dist/chunk-N7N7MPMK.cjs +2 -0
  100. package/dist/chunk-N7N7MPMK.cjs.map +1 -0
  101. package/dist/chunk-NGBBNL4K.cjs +1 -3
  102. package/dist/chunk-P6WPEUAJ.cjs +2 -0
  103. package/dist/chunk-P6WPEUAJ.cjs.map +1 -0
  104. package/dist/chunk-PS272DZJ.cjs +2 -0
  105. package/dist/chunk-PS272DZJ.cjs.map +1 -0
  106. package/dist/chunk-QXQE7X4S.js +2 -0
  107. package/dist/chunk-QXQE7X4S.js.map +1 -0
  108. package/dist/chunk-R2ENWQ76.js +2 -0
  109. package/dist/chunk-R2ENWQ76.js.map +1 -0
  110. package/dist/chunk-R2SZFJTT.cjs +2 -0
  111. package/dist/chunk-R2SZFJTT.cjs.map +1 -0
  112. package/dist/chunk-RAF57WYO.js +2 -0
  113. package/dist/chunk-RAF57WYO.js.map +1 -0
  114. package/dist/chunk-RSF25YSJ.js +2 -0
  115. package/dist/chunk-RSF25YSJ.js.map +1 -0
  116. package/dist/chunk-SOMGSIO4.cjs +3 -0
  117. package/dist/chunk-SOMGSIO4.cjs.map +1 -0
  118. package/dist/chunk-SUXRZWH2.cjs +3 -0
  119. package/dist/chunk-SUXRZWH2.cjs.map +1 -0
  120. package/dist/chunk-SYYE3QAX.cjs +2 -0
  121. package/dist/chunk-SYYE3QAX.cjs.map +1 -0
  122. package/dist/chunk-SZGK6RIP.cjs +2 -0
  123. package/dist/chunk-SZGK6RIP.cjs.map +1 -0
  124. package/dist/chunk-TCZSPH4A.js +2 -0
  125. package/dist/chunk-TCZSPH4A.js.map +1 -0
  126. package/dist/chunk-TLG7VZRX.cjs +2 -0
  127. package/dist/chunk-TLG7VZRX.cjs.map +1 -0
  128. package/dist/chunk-TRBXW6HW.js +2 -0
  129. package/dist/{chunk-AQNHHJMJ.cjs.map → chunk-TRBXW6HW.js.map} +1 -1
  130. package/dist/chunk-TTFO4YDP.cjs +2 -0
  131. package/dist/chunk-TTFO4YDP.cjs.map +1 -0
  132. package/dist/chunk-TWC7K3ZX.js +2 -0
  133. package/dist/chunk-TWC7K3ZX.js.map +1 -0
  134. package/dist/chunk-UDQ57ZRX.cjs +2 -0
  135. package/dist/chunk-UDQ57ZRX.cjs.map +1 -0
  136. package/dist/chunk-UI6IFGBT.js +2 -0
  137. package/dist/chunk-UI6IFGBT.js.map +1 -0
  138. package/dist/chunk-UURM7P3P.cjs +4 -0
  139. package/dist/chunk-UURM7P3P.cjs.map +1 -0
  140. package/dist/chunk-W2JAR233.js +2 -0
  141. package/dist/chunk-W2JAR233.js.map +1 -0
  142. package/dist/chunk-WGZ3FNHI.js +2 -0
  143. package/dist/chunk-WGZ3FNHI.js.map +1 -0
  144. package/dist/chunk-WN5CMP4T.cjs +3 -0
  145. package/dist/chunk-WN5CMP4T.cjs.map +1 -0
  146. package/dist/chunk-XEIDV5JP.js +2 -0
  147. package/dist/chunk-XEIDV5JP.js.map +1 -0
  148. package/dist/chunk-XNIWQHXY.js +2 -0
  149. package/dist/chunk-XNIWQHXY.js.map +1 -0
  150. package/dist/chunk-XR7HEC7B.js +5 -0
  151. package/dist/chunk-XR7HEC7B.js.map +1 -0
  152. package/dist/chunk-Y7O4D3BJ.cjs +2 -0
  153. package/dist/chunk-Y7O4D3BJ.cjs.map +1 -0
  154. package/dist/chunk-YAYBVVG2.js +3 -0
  155. package/dist/chunk-YAYBVVG2.js.map +1 -0
  156. package/dist/chunk-YJ2OPULK.js +2 -0
  157. package/dist/chunk-YJ2OPULK.js.map +1 -0
  158. package/dist/chunk-YVKHEAFT.js +2 -0
  159. package/dist/chunk-YVKHEAFT.js.map +1 -0
  160. package/dist/chunk-ZCNBT44X.cjs +2 -0
  161. package/dist/chunk-ZCNBT44X.cjs.map +1 -0
  162. package/dist/chunk-ZLRJ7TDP.cjs +2 -0
  163. package/dist/chunk-ZLRJ7TDP.cjs.map +1 -0
  164. package/dist/constants.cjs +1 -21
  165. package/dist/constants.d.cts +1 -1
  166. package/dist/constants.d.ts +1 -1
  167. package/dist/constants.js +1 -4
  168. package/dist/engine.cjs +1 -94
  169. package/dist/engine.d.cts +10 -11
  170. package/dist/engine.d.ts +10 -11
  171. package/dist/engine.js +1 -37
  172. package/dist/errors.cjs +1 -105
  173. package/dist/errors.d.cts +3 -3
  174. package/dist/errors.d.ts +3 -3
  175. package/dist/errors.js +1 -4
  176. package/dist/format.cjs +1 -26
  177. package/dist/format.d.cts +2 -2
  178. package/dist/format.d.ts +2 -2
  179. package/dist/format.js +1 -9
  180. package/dist/index.cjs +1 -314
  181. package/dist/index.cjs.map +1 -1
  182. package/dist/index.d.cts +52 -20
  183. package/dist/index.d.ts +52 -20
  184. package/dist/index.js +1 -278
  185. package/dist/index.js.map +1 -1
  186. package/dist/language.cjs +1 -369
  187. package/dist/language.cjs.map +1 -1
  188. package/dist/language.d.cts +9 -10
  189. package/dist/language.d.ts +9 -10
  190. package/dist/language.js +1 -348
  191. package/dist/language.js.map +1 -1
  192. package/dist/lexer.cjs +1 -63
  193. package/dist/lexer.js +1 -10
  194. package/dist/normalizer.cjs +1 -39
  195. package/dist/normalizer.js +1 -10
  196. package/dist/packages.cjs +1 -132
  197. package/dist/packages.d.cts +8 -9
  198. package/dist/packages.d.ts +8 -9
  199. package/dist/packages.js +1 -23
  200. package/dist/parser.cjs +1 -54
  201. package/dist/parser.d.cts +8 -8
  202. package/dist/parser.d.ts +8 -8
  203. package/dist/parser.js +1 -9
  204. package/dist/{pipeline-D-PS9gVw.d.ts → pipeline-72QmQlGx.d.ts} +1 -1
  205. package/dist/{pipeline-DtSBJ8TS.d.cts → pipeline-DCQicwWX.d.cts} +1 -1
  206. package/dist/resolvers.cjs +1 -12
  207. package/dist/resolvers.d.cts +2 -2
  208. package/dist/resolvers.d.ts +2 -2
  209. package/dist/resolvers.js +1 -3
  210. package/dist/services.cjs +1 -20
  211. package/dist/services.js +1 -3
  212. package/dist/testing.cjs +3 -477
  213. package/dist/testing.cjs.map +1 -1
  214. package/dist/testing.d.cts +9 -10
  215. package/dist/testing.d.ts +9 -10
  216. package/dist/testing.js +3 -469
  217. package/dist/testing.js.map +1 -1
  218. package/dist/uom.cjs +1 -55
  219. package/dist/uom.d.cts +2 -2
  220. package/dist/uom.d.ts +2 -2
  221. package/dist/uom.js +1 -10
  222. package/dist/utilities.cjs +1 -36
  223. package/dist/utilities.js +1 -7
  224. package/dist/vm.cjs +1 -295
  225. package/dist/vm.cjs.map +1 -1
  226. package/dist/vm.d.cts +22 -10
  227. package/dist/vm.d.ts +22 -10
  228. package/dist/vm.js +1 -193
  229. package/dist/vm.js.map +1 -1
  230. package/dist/worker.cjs +2 -492
  231. package/dist/worker.cjs.map +1 -1
  232. package/dist/worker.d.cts +16 -17
  233. package/dist/worker.d.ts +16 -17
  234. package/dist/worker.js +2 -483
  235. package/dist/worker.js.map +1 -1
  236. package/package.json +1 -13
  237. package/dist/chunk-3BOK2LDK.js +0 -17
  238. package/dist/chunk-3BOK2LDK.js.map +0 -1
  239. package/dist/chunk-3VGDNEE3.js +0 -84
  240. package/dist/chunk-3VGDNEE3.js.map +0 -1
  241. package/dist/chunk-4K5W7EH2.cjs +0 -112
  242. package/dist/chunk-4K5W7EH2.cjs.map +0 -1
  243. package/dist/chunk-5EFKSKMA.js +0 -413
  244. package/dist/chunk-5EFKSKMA.js.map +0 -1
  245. package/dist/chunk-5HRB36DK.js +0 -405
  246. package/dist/chunk-5HRB36DK.js.map +0 -1
  247. package/dist/chunk-5ON7PUAZ.js +0 -12
  248. package/dist/chunk-5ON7PUAZ.js.map +0 -1
  249. package/dist/chunk-7AXJNQMF.cjs +0 -297
  250. package/dist/chunk-7AXJNQMF.cjs.map +0 -1
  251. package/dist/chunk-7JM3F4KL.js +0 -1795
  252. package/dist/chunk-7JM3F4KL.js.map +0 -1
  253. package/dist/chunk-7USV76HV.cjs +0 -341
  254. package/dist/chunk-7USV76HV.cjs.map +0 -1
  255. package/dist/chunk-A2DZ5BEJ.cjs +0 -1930
  256. package/dist/chunk-A2DZ5BEJ.cjs.map +0 -1
  257. package/dist/chunk-ADBA3XBE.cjs +0 -20
  258. package/dist/chunk-ADBA3XBE.cjs.map +0 -1
  259. package/dist/chunk-AKNGX4TZ.cjs +0 -236
  260. package/dist/chunk-AKNGX4TZ.cjs.map +0 -1
  261. package/dist/chunk-ALYRJ72W.cjs +0 -434
  262. package/dist/chunk-ALYRJ72W.cjs.map +0 -1
  263. package/dist/chunk-AMOJYLG2.cjs +0 -1692
  264. package/dist/chunk-AMOJYLG2.cjs.map +0 -1
  265. package/dist/chunk-AOH6UR2L.js +0 -825
  266. package/dist/chunk-AOH6UR2L.js.map +0 -1
  267. package/dist/chunk-AQNHHJMJ.cjs +0 -261
  268. package/dist/chunk-B7LXJ6LC.cjs +0 -36
  269. package/dist/chunk-B7LXJ6LC.cjs.map +0 -1
  270. package/dist/chunk-BESTLPRK.cjs +0 -6919
  271. package/dist/chunk-BESTLPRK.cjs.map +0 -1
  272. package/dist/chunk-BLI4NIQY.js +0 -98
  273. package/dist/chunk-BLI4NIQY.js.map +0 -1
  274. package/dist/chunk-BSPXMGIS.js +0 -455
  275. package/dist/chunk-BSPXMGIS.js.map +0 -1
  276. package/dist/chunk-C2OMO3WN.cjs +0 -2806
  277. package/dist/chunk-C2OMO3WN.cjs.map +0 -1
  278. package/dist/chunk-CSDQMDU2.js +0 -204
  279. package/dist/chunk-CSDQMDU2.js.map +0 -1
  280. package/dist/chunk-EJ3ILXX6.cjs +0 -223
  281. package/dist/chunk-EJ3ILXX6.cjs.map +0 -1
  282. package/dist/chunk-ENRIK36Q.cjs +0 -94
  283. package/dist/chunk-ENRIK36Q.cjs.map +0 -1
  284. package/dist/chunk-F4UB4XIL.js +0 -109
  285. package/dist/chunk-F4UB4XIL.js.map +0 -1
  286. package/dist/chunk-FD5ZZHEU.js +0 -92
  287. package/dist/chunk-FD5ZZHEU.js.map +0 -1
  288. package/dist/chunk-FE4RC37D.js +0 -2801
  289. package/dist/chunk-FE4RC37D.js.map +0 -1
  290. package/dist/chunk-FEAIOR7N.cjs +0 -91
  291. package/dist/chunk-FEAIOR7N.cjs.map +0 -1
  292. package/dist/chunk-FR7RNOPT.cjs +0 -3303
  293. package/dist/chunk-FR7RNOPT.cjs.map +0 -1
  294. package/dist/chunk-G2YPPLGX.cjs +0 -484
  295. package/dist/chunk-G2YPPLGX.cjs.map +0 -1
  296. package/dist/chunk-GCM5JHMX.js +0 -88
  297. package/dist/chunk-GCM5JHMX.js.map +0 -1
  298. package/dist/chunk-GDEU72RG.cjs +0 -829
  299. package/dist/chunk-GDEU72RG.cjs.map +0 -1
  300. package/dist/chunk-HKTQCQ4Z.cjs +0 -8383
  301. package/dist/chunk-HKTQCQ4Z.cjs.map +0 -1
  302. package/dist/chunk-HWHU642X.cjs +0 -316
  303. package/dist/chunk-HWHU642X.cjs.map +0 -1
  304. package/dist/chunk-ICEKS6YC.cjs +0 -507
  305. package/dist/chunk-ICEKS6YC.cjs.map +0 -1
  306. package/dist/chunk-IJGOFP2J.js +0 -6904
  307. package/dist/chunk-IJGOFP2J.js.map +0 -1
  308. package/dist/chunk-IQJGDZOP.js +0 -333
  309. package/dist/chunk-IQJGDZOP.js.map +0 -1
  310. package/dist/chunk-IT74O4BE.cjs +0 -456
  311. package/dist/chunk-IT74O4BE.cjs.map +0 -1
  312. package/dist/chunk-KXDQKVNX.cjs +0 -459
  313. package/dist/chunk-KXDQKVNX.cjs.map +0 -1
  314. package/dist/chunk-L2TE7PMO.cjs +0 -14
  315. package/dist/chunk-L2TE7PMO.cjs.map +0 -1
  316. package/dist/chunk-L5YHV6BQ.js +0 -499
  317. package/dist/chunk-L5YHV6BQ.js.map +0 -1
  318. package/dist/chunk-LO7HU5WB.cjs +0 -209
  319. package/dist/chunk-LO7HU5WB.cjs.map +0 -1
  320. package/dist/chunk-LSALB3IN.js +0 -292
  321. package/dist/chunk-LSALB3IN.js.map +0 -1
  322. package/dist/chunk-MI7OTUHL.cjs +0 -339
  323. package/dist/chunk-MI7OTUHL.cjs.map +0 -1
  324. package/dist/chunk-MIGXCBXT.cjs +0 -381
  325. package/dist/chunk-MIGXCBXT.cjs.map +0 -1
  326. package/dist/chunk-MVTOCRV2.js +0 -213
  327. package/dist/chunk-MVTOCRV2.js.map +0 -1
  328. package/dist/chunk-N7FNVFXW.cjs +0 -32
  329. package/dist/chunk-N7FNVFXW.cjs.map +0 -1
  330. package/dist/chunk-N7OA4WPJ.js +0 -362
  331. package/dist/chunk-N7OA4WPJ.js.map +0 -1
  332. package/dist/chunk-NAWZATKT.js +0 -478
  333. package/dist/chunk-NAWZATKT.js.map +0 -1
  334. package/dist/chunk-NLNDMWZC.js +0 -31
  335. package/dist/chunk-NLNDMWZC.js.map +0 -1
  336. package/dist/chunk-ORM7CHYZ.js +0 -1531
  337. package/dist/chunk-ORM7CHYZ.js.map +0 -1
  338. package/dist/chunk-OUHT5Z36.cjs +0 -393
  339. package/dist/chunk-OUHT5Z36.cjs.map +0 -1
  340. package/dist/chunk-PCZVMMWU.cjs +0 -74
  341. package/dist/chunk-PCZVMMWU.cjs.map +0 -1
  342. package/dist/chunk-RNKDIXDV.js +0 -336
  343. package/dist/chunk-RNKDIXDV.js.map +0 -1
  344. package/dist/chunk-SBUFNJVE.js +0 -258
  345. package/dist/chunk-SBUFNJVE.js.map +0 -1
  346. package/dist/chunk-TC6BTUSU.cjs +0 -1799
  347. package/dist/chunk-TC6BTUSU.cjs.map +0 -1
  348. package/dist/chunk-TPOK3UNI.js +0 -8355
  349. package/dist/chunk-TPOK3UNI.js.map +0 -1
  350. package/dist/chunk-UF6JG5SG.js +0 -312
  351. package/dist/chunk-UF6JG5SG.js.map +0 -1
  352. package/dist/chunk-UKQHXPGW.js +0 -30
  353. package/dist/chunk-UKQHXPGW.js.map +0 -1
  354. package/dist/chunk-V4XG5QF6.js +0 -1685
  355. package/dist/chunk-V4XG5QF6.js.map +0 -1
  356. package/dist/chunk-VEKIWQ3F.cjs +0 -39
  357. package/dist/chunk-VEKIWQ3F.cjs.map +0 -1
  358. package/dist/chunk-WMQRJTAO.js +0 -3266
  359. package/dist/chunk-WMQRJTAO.js.map +0 -1
  360. package/dist/chunk-X6K3HUOY.cjs +0 -86
  361. package/dist/chunk-X6K3HUOY.cjs.map +0 -1
  362. package/dist/chunk-XBTEO4OB.js +0 -391
  363. package/dist/chunk-XBTEO4OB.js.map +0 -1
  364. package/dist/chunk-XIYYHA65.cjs +0 -101
  365. package/dist/chunk-XIYYHA65.cjs.map +0 -1
  366. package/dist/chunk-YJHY7CMN.cjs +0 -1534
  367. package/dist/chunk-YLJ4XMA6.js +0 -33
  368. package/dist/chunk-YLJ4XMA6.js.map +0 -1
  369. package/dist/chunk-YNIWOYW6.js +0 -232
  370. package/dist/chunk-YNIWOYW6.js.map +0 -1
  371. package/dist/chunk-Z2XP767T.cjs +0 -35
  372. package/dist/chunk-Z2XP767T.cjs.map +0 -1
  373. package/dist/chunk-Z4X2RWOF.js +0 -37
  374. package/dist/chunk-Z4X2RWOF.js.map +0 -1
  375. package/dist/chunk-ZN6YYPIW.js +0 -67
  376. package/dist/chunk-ZN6YYPIW.js.map +0 -1
  377. package/dist/chunk-ZNFFTYWH.js +0 -1854
  378. package/dist/chunk-ZNFFTYWH.js.map +0 -1
  379. package/dist/variables.cjs +0 -17
  380. package/dist/variables.cjs.map +0 -1
  381. package/dist/variables.d.cts +0 -87
  382. package/dist/variables.d.ts +0 -87
  383. package/dist/variables.js +0 -4
  384. package/dist/variables.js.map +0 -1
package/dist/index.d.ts CHANGED
@@ -1,20 +1,19 @@
1
- import { I as IEnginePackage } from './PackageRegistry-DrCPQNyy.js';
2
- export { a as EngineRestoreOptions, b as EngineSnapshot, c as EvalResults, d as Explanation, e as ExplanationStep, E as ExpressionEngine, f as IPackageRegistry, L as LineEvaluation, P as PackageRegistry, S as SNAPSHOT_FORMAT, g as SNAPSHOT_VERSION, h as SerializedAnonymousBody, i as SerializedBytecode, j as SerializedDecimal, k as SerializedLineCacheEntry, l as SerializedNumber, m as SerializedRational, n as SerializedUserFunction, o as SerializedValue, p as SnapshotErrorCodes, q as packageRegistry } from './PackageRegistry-DrCPQNyy.js';
3
- export { a as CompatibilityConflict, b as CompatibilityConflictKind, C as CompatibilityReport, c as CompatibilitySeverity, d as checkPackageCompatibility } from './PackageCompatibility-Ceg5XdAp.js';
1
+ import { I as IEnginePackage, a as EngineOptions, E as ExpressionEngine } from './PackageRegistry-DzeiWcv4.js';
2
+ export { b as EngineRestoreOptions, c as EngineSnapshot, d as Explanation, e as ExplanationStep, S as SNAPSHOT_FORMAT, f as SNAPSHOT_VERSION, g as SerializedAnonymousBody, h as SerializedBytecode, i as SerializedDecimal, j as SerializedLineCacheEntry, k as SerializedNumber, l as SerializedRational, m as SerializedUserFunction, n as SerializedValue, o as SnapshotErrorCodes } from './PackageRegistry-DzeiWcv4.js';
3
+ export { a as CompatibilityConflict, b as CompatibilityConflictKind, C as CompatibilityReport, c as CompatibilitySeverity, d as checkPackageCompatibility } from './PackageCompatibility-CIvq2MP5.js';
4
+ export { E as EngineConfigOverride } from './Configuration-B6W0-T67.js';
4
5
  export { ENGINE_VERSION } from './constants.js';
5
- import './Parselet-Bhf7d0_W.js';
6
- import './BytecodeBuilder-Bp9xeTmX.js';
6
+ import './Parselet-B-zoPrTa.js';
7
+ import './BytecodeBuilder-DGGeByAP.js';
7
8
  import './Token-CbP_OutD.js';
8
- import './pipeline-D-PS9gVw.js';
9
- import './Value-DZNQ_PU7.js';
10
- import './variables.js';
9
+ import './pipeline-72QmQlGx.js';
10
+ import './Value-CCi_Eecs.js';
11
11
  import './Lexer-DKMlj7Sy.js';
12
12
  import './resolvers.js';
13
13
  import '@tanstack/query-core';
14
14
  import './TokenNormalizer-DCWdZjGz.js';
15
- import './ScopeManager-Bzq87GfA.js';
16
- import './EngineError-CNA_rHY-.js';
17
- import './Configuration-C9W8tJv_.js';
15
+ import './ScopeManager-C2LDOrDx.js';
16
+ import './EngineError-Ce1lPkjZ.js';
18
17
 
19
18
  /**
20
19
  * A higher-level, declarative way to contribute a single `name(args)`
@@ -88,16 +87,16 @@ declare const DefineFunctionErrorCodes: {
88
87
  *
89
88
  * This is the higher-level API from issue #102. It derives, from the
90
89
  * declaration alone, everything the low-level contract asks an author to write
91
- * by hand: a plugin function index ({@link allocatePluginFunctionIndex}), a
92
- * lexer keyword so the name tokenises, a call-syntax parselet emitting
93
- * `CALL_PLUGIN`, and a handler that checks arity and argument types (yielding
90
+ * by hand: a named plugin function (the engine assigns its `CALL_PLUGIN`
91
+ * index), a lexer keyword so the name tokenises, a call-syntax parselet emitting
92
+ * that call by name, and a handler that checks arity and argument types (yielding
94
93
  * the engine's own structured errors) before invoking `call` and wrapping its
95
94
  * result. Anything needing custom parsing keeps writing a raw parselet exactly
96
95
  * as before, this sits on top of that contract and does not change it.
97
96
  *
98
97
  * @example
99
98
  * ```ts
100
- * const engine = new ExpressionEngine("en", false, undefined, undefined, [
99
+ * const engine = new ExpressionEngine({ packages: [
101
100
  * ...BUILTIN_PACKAGES,
102
101
  * defineFunction({
103
102
  * name: "vat",
@@ -105,7 +104,7 @@ declare const DefineFunctionErrorCodes: {
105
104
  * returns: "number",
106
105
  * call: (amount) => amount * 1.2,
107
106
  * }),
108
- * ]);
107
+ * ] });
109
108
  * engine.evaluateExpression("vat(100)"); // 120
110
109
  * ```
111
110
  *
@@ -148,9 +147,9 @@ declare function defineFunction<const A extends readonly FunctionArg[], R extend
148
147
  * `checkPackageCompatibility()`'s "return a result, caller decides" shape,
149
148
  * and this codebase's own testing convention of asserting against plain
150
149
  * result objects rather than `toThrow()` for a pure function).
151
- * `assertEngineVersionCompatible()` is the thin throwing wrapper both
152
- * `ExpressionEngine.registerPackage()` and the `PackageRegistry` singleton
153
- * call as the very first thing they do. See `ARCHITECTURE.md` §5.3.
150
+ * `assertEngineVersionCompatible()` is the thin throwing wrapper
151
+ * `ExpressionEngine.registerPackage()` calls as the very first thing it
152
+ * does. See `ARCHITECTURE.md` §5.3.
154
153
  */
155
154
  type EngineVersionCheckResult = {
156
155
  compatible: true;
@@ -185,4 +184,37 @@ declare function checkEngineVersionCompatibility(pkg: IEnginePackage, engineVers
185
184
  */
186
185
  declare function assertEngineVersionCompatible(pkg: IEnginePackage, engineVersion?: string): void;
187
186
 
188
- export { DefineFunctionErrorCodes, type EngineVersionCheckResult, type FunctionArg, type FunctionSpec, type FunctionValueType, IEnginePackage, assertEngineVersionCompatible, checkEngineVersionCompatibility, defineFunction };
187
+ /** Options for {@link createEngine}: the engine options, minus `packages` (the
188
+ * built-in set is always registered), plus `extraPackages` to add your own. */
189
+ interface CreateEngineOptions extends Omit<EngineOptions, "packages"> {
190
+ /** Packages to register ON TOP of the built-in set (e.g. an OSRS or stocks package). */
191
+ extraPackages?: IEnginePackage[];
192
+ }
193
+ /**
194
+ * A batteries-included {@link ExpressionEngine} with every built-in package
195
+ * registered.
196
+ *
197
+ * The constructor registers only the packages it is given, so a consumer's
198
+ * bundler can tree-shake away the built-ins they never use: an engine built
199
+ * with `new ExpressionEngine({ packages: [ARITHMETIC_PACKAGE] })` carries no
200
+ * finance, colour or weather code. This convenience is the opposite trade: it
201
+ * pulls the FULL built-in set (`BUILTIN_PACKAGES`) for the common "I want
202
+ * everything" case, so importing it defeats that tree-shaking. Reach for the
203
+ * constructor with an explicit package list when bundle size matters, and for
204
+ * `createEngine` when it does not.
205
+ *
206
+ * @param options - Engine options ({@link EngineOptions}) minus `packages`, plus
207
+ * an optional `extraPackages` to register alongside the built-in set.
208
+ * @returns An engine with the built-in packages (and any extras) registered.
209
+ *
210
+ * @example
211
+ * ```typescript
212
+ * import { createEngine } from "solve-engine";
213
+ * const engine = createEngine();
214
+ * const value = engine.evaluateExpression("2 + 2 * 10");
215
+ * console.log(value.toNumber()); // 22
216
+ * ```
217
+ */
218
+ declare function createEngine(options?: CreateEngineOptions): ExpressionEngine;
219
+
220
+ export { type CreateEngineOptions, DefineFunctionErrorCodes, EngineOptions, type EngineVersionCheckResult, ExpressionEngine, type FunctionArg, type FunctionSpec, type FunctionValueType, IEnginePackage, assertEngineVersionCompatible, checkEngineVersionCompatibility, createEngine, defineFunction };
package/dist/index.js CHANGED
@@ -1,279 +1,2 @@
1
- import './chunk-7JM3F4KL.js';
2
- import { assertEngineVersionCompatible } from './chunk-IJGOFP2J.js';
3
- export { ExpressionEngine, SNAPSHOT_FORMAT, SNAPSHOT_VERSION, SnapshotErrorCodes, assertEngineVersionCompatible, checkEngineVersionCompatibility, checkPackageCompatibility } from './chunk-IJGOFP2J.js';
4
- import { sharedParseletRegistry } from './chunk-AOH6UR2L.js';
5
- import './chunk-2RWAXT6O.js';
6
- import './chunk-3VGDNEE3.js';
7
- import './chunk-5ON7PUAZ.js';
8
- import './chunk-FD5ZZHEU.js';
9
- import './chunk-FE4RC37D.js';
10
- import './chunk-UF6JG5SG.js';
11
- import './chunk-YNIWOYW6.js';
12
- import './chunk-UKQHXPGW.js';
13
- import './chunk-TPOK3UNI.js';
14
- import { BindingPower } from './chunk-IQJGDZOP.js';
15
- import './chunk-L5YHV6BQ.js';
16
- import './chunk-3BOK2LDK.js';
17
- import './chunk-F4UB4XIL.js';
18
- import './chunk-NLNDMWZC.js';
19
- import { allocatePluginFunctionIndex } from './chunk-WMQRJTAO.js';
20
- import { sharedVariableResolver } from './chunk-GCM5JHMX.js';
21
- import './chunk-BSPXMGIS.js';
22
- import './chunk-BLI4NIQY.js';
23
- import './chunk-Z4X2RWOF.js';
24
- import './chunk-5HRB36DK.js';
25
- import './chunk-ZNFFTYWH.js';
26
- import { Value, boolValue, stringValue, numberValue } from './chunk-5EFKSKMA.js';
27
- import './chunk-MVTOCRV2.js';
28
- export { ENGINE_VERSION } from './chunk-CSDQMDU2.js';
29
- import { sharedLexer } from './chunk-RNKDIXDV.js';
30
- import './chunk-LSALB3IN.js';
31
- import './chunk-ORM7CHYZ.js';
32
- import './chunk-NAWZATKT.js';
33
- import './chunk-XBTEO4OB.js';
34
- import './chunk-SBUFNJVE.js';
35
- import './chunk-V4XG5QF6.js';
36
- import { ErrorFactory } from './chunk-N7OA4WPJ.js';
37
- import './chunk-YLJ4XMA6.js';
38
-
39
- // src/api/PackageRegistry.ts
40
- var PackageRegistry = class {
41
- constructor() {
42
- this.Value = Value;
43
- }
44
- registerPrefixParselet(tokenType, parselet) {
45
- sharedParseletRegistry.registerPrefix(tokenType, parselet);
46
- }
47
- registerInfixParselet(tokenType, parselet) {
48
- sharedParseletRegistry.registerInfix(tokenType, parselet);
49
- }
50
- registerVariableSource(source) {
51
- sharedVariableResolver.registerSource(source);
52
- }
53
- registerPackage(pkg) {
54
- assertEngineVersionCompatible(pkg);
55
- if (pkg.lexerVocabulary) {
56
- sharedLexer.registerVocabulary(pkg.lexerVocabulary);
57
- }
58
- if (pkg.prefixParselets) {
59
- for (const pp of pkg.prefixParselets) {
60
- this.registerPrefixParselet(pp.tokenType, pp.parselet);
61
- }
62
- }
63
- if (pkg.infixParselets) {
64
- for (const ip of pkg.infixParselets) {
65
- this.registerInfixParselet(ip.tokenType, ip.parselet);
66
- }
67
- }
68
- if (pkg.variableSources) {
69
- for (const vs of pkg.variableSources) {
70
- this.registerVariableSource(vs);
71
- }
72
- }
73
- }
74
- };
75
- var packageRegistry = new PackageRegistry();
76
-
77
- // src/api/defineFunction.ts
78
- var DefineFunctionErrorCodes = {
79
- /** The spec's `name` is not a single identifier. Thrown by `defineFunction`, before any engine sees it. */
80
- DEFINE_FUNCTION_INVALID_NAME: "DEFINE_FUNCTION_INVALID_NAME",
81
- /** The spec is otherwise malformed (bad `args`, unsupported type, missing `call`). Thrown by `defineFunction`. */
82
- DEFINE_FUNCTION_INVALID_SPEC: "DEFINE_FUNCTION_INVALID_SPEC",
83
- /** The call site passed the wrong number of arguments. Raised at evaluation time. */
84
- DEFINE_FUNCTION_ARITY_MISMATCH: "DEFINE_FUNCTION_ARITY_MISMATCH",
85
- /** An argument was the wrong value type. Raised at evaluation time. */
86
- DEFINE_FUNCTION_ARGUMENT_TYPE: "DEFINE_FUNCTION_ARGUMENT_TYPE",
87
- /** The `call` implementation returned a value that did not match `returns`. Raised at evaluation time, an authoring bug rather than a user one. */
88
- DEFINE_FUNCTION_RETURN_TYPE: "DEFINE_FUNCTION_RETURN_TYPE"
89
- };
90
- var NAME_PATTERN = /^[a-z_][a-z0-9_]*$/i;
91
- var SUPPORTED_TYPES = /* @__PURE__ */ new Set(["number", "string", "boolean"]);
92
- function plural(count) {
93
- return count === 1 ? "1 argument" : `${count} arguments`;
94
- }
95
- function describeValueType(v) {
96
- switch (v.type) {
97
- case 0 /* Number */:
98
- case 1 /* Hex */:
99
- return "a number";
100
- case 3 /* String */:
101
- return "a string";
102
- case 10 /* Boolean */:
103
- return "a boolean";
104
- case 2 /* BigInt */:
105
- return "a big integer";
106
- case 5 /* Percentage */:
107
- return "a percentage";
108
- case 6 /* Uom */:
109
- return "a value with a unit";
110
- case 4 /* Datetime */:
111
- return "a date";
112
- case 7 /* Matrix */:
113
- return "a matrix";
114
- case 8 /* Range */:
115
- return "a range";
116
- case 9 /* Symbolic */:
117
- return "a symbolic expression";
118
- default:
119
- return "an unsupported value";
120
- }
121
- }
122
- function coerceArgument(value, arg, fnName) {
123
- switch (arg.type) {
124
- case "number":
125
- if (value.type === 0 /* Number */ || value.type === 1 /* Hex */) {
126
- return value.toNumber();
127
- }
128
- break;
129
- case "string":
130
- if (value.type === 3 /* String */) return value.value;
131
- break;
132
- case "boolean":
133
- if (value.type === 10 /* Boolean */) return value.value;
134
- break;
135
- }
136
- throw ErrorFactory.execution({
137
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARGUMENT_TYPE,
138
- message: `${fnName}() expects "${arg.name}" to be a ${arg.type}, but was given ${describeValueType(value)}`,
139
- expected: `a ${arg.type}`,
140
- found: describeValueType(value),
141
- context: { functionName: fnName, argName: arg.name, expectedType: arg.type }
142
- });
143
- }
144
- function wrapReturn(result, returns, fnName) {
145
- switch (returns) {
146
- case "number":
147
- if (typeof result === "number") return numberValue(result);
148
- break;
149
- case "string":
150
- if (typeof result === "string") return stringValue(result);
151
- break;
152
- case "boolean":
153
- if (typeof result === "boolean") return boolValue(result);
154
- break;
155
- }
156
- throw ErrorFactory.internal({
157
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_RETURN_TYPE,
158
- message: `${fnName}() is declared to return a ${returns}, but its implementation returned ${typeof result}`,
159
- expected: `a ${returns}`,
160
- found: typeof result,
161
- context: { functionName: fnName, expectedType: returns }
162
- });
163
- }
164
- var DefinedFunctionParselet = class {
165
- constructor(fnIndex, fnName) {
166
- this.fnIndex = fnIndex;
167
- this.fnName = fnName;
168
- this.category = "Function";
169
- }
170
- parse(parser, _token, builder) {
171
- parser.consume("LPAREN");
172
- let argCount = 0;
173
- if (parser.peek()?.type !== "RPAREN") {
174
- parser.parseExpression(BindingPower.Lowest, builder);
175
- argCount++;
176
- while (parser.match("COMMA")) {
177
- parser.parseExpression(BindingPower.Lowest, builder);
178
- argCount++;
179
- }
180
- }
181
- parser.consume("RPAREN");
182
- builder.emitOpcode(50 /* CALL_PLUGIN */);
183
- builder.emitIndex(this.fnIndex);
184
- builder.emitIndex(argCount);
185
- }
186
- };
187
- function makeHandler(spec) {
188
- const arity = spec.args.length;
189
- return (args) => {
190
- if (args.length !== arity) {
191
- throw ErrorFactory.execution({
192
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARITY_MISMATCH,
193
- message: `${spec.name}() takes ${plural(arity)}, but was given ${args.length === 0 ? "none" : plural(args.length)}`,
194
- expected: plural(arity),
195
- found: args.length === 0 ? "none" : plural(args.length),
196
- context: { functionName: spec.name, expected: arity, actual: args.length }
197
- });
198
- }
199
- const jsArgs = new Array(arity);
200
- for (let i = 0; i < arity; i++) {
201
- jsArgs[i] = coerceArgument(args[i], spec.args[i], spec.name);
202
- }
203
- const result = spec.call(...jsArgs);
204
- return wrapReturn(result, spec.returns, spec.name);
205
- };
206
- }
207
- function validateSpec(spec) {
208
- if (typeof spec?.name !== "string" || !NAME_PATTERN.test(spec.name)) {
209
- throw ErrorFactory.config({
210
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_NAME,
211
- message: `defineFunction: name must be a single identifier, got ${JSON.stringify(spec?.name)}`,
212
- suggestion: 'e.g. "vat" or "net_price"',
213
- context: { name: spec?.name }
214
- });
215
- }
216
- if (!Array.isArray(spec.args)) {
217
- throw ErrorFactory.config({
218
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,
219
- message: `defineFunction: "${spec.name}" args must be an array`,
220
- context: { name: spec.name }
221
- });
222
- }
223
- for (const arg of spec.args) {
224
- if (typeof arg?.name !== "string" || arg.name.length === 0) {
225
- throw ErrorFactory.config({
226
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,
227
- message: `defineFunction: "${spec.name}" has an argument with no name`,
228
- context: { name: spec.name }
229
- });
230
- }
231
- if (!SUPPORTED_TYPES.has(arg.type)) {
232
- throw ErrorFactory.config({
233
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,
234
- message: `defineFunction: "${spec.name}" argument "${arg.name}" has unsupported type ${JSON.stringify(arg.type)}`,
235
- suggestion: "supported argument types are number, string, boolean",
236
- context: { name: spec.name, argName: arg.name, type: arg.type }
237
- });
238
- }
239
- }
240
- if (!SUPPORTED_TYPES.has(spec.returns)) {
241
- throw ErrorFactory.config({
242
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,
243
- message: `defineFunction: "${spec.name}" has unsupported return type ${JSON.stringify(spec.returns)}`,
244
- suggestion: "supported return types are number, string, boolean",
245
- context: { name: spec.name, returns: spec.returns }
246
- });
247
- }
248
- if (typeof spec.call !== "function") {
249
- throw ErrorFactory.config({
250
- code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,
251
- message: `defineFunction: "${spec.name}" is missing a call implementation`,
252
- context: { name: spec.name }
253
- });
254
- }
255
- }
256
- function defineFunction(spec) {
257
- validateSpec(spec);
258
- const name = spec.name;
259
- const tokenType = `DEFINE_FN_${name.toUpperCase()}`;
260
- const index = allocatePluginFunctionIndex();
261
- return {
262
- name: `solve-fn-${name}`,
263
- lexerVocabulary: {
264
- // Lowercased because the lexer lowercases input before lookup, so the
265
- // call is matched case-insensitively.
266
- keywords: { [name.toLowerCase()]: tokenType }
267
- },
268
- prefixParselets: [
269
- { tokenType, parselet: new DefinedFunctionParselet(index, name) }
270
- ],
271
- pluginFunctions: [
272
- { index, handler: makeHandler(spec) }
273
- ]
274
- };
275
- }
276
-
277
- export { DefineFunctionErrorCodes, PackageRegistry, defineFunction, packageRegistry };
278
- //# sourceMappingURL=index.js.map
1
+ import'./chunk-JSPKKNPQ.js';import'./chunk-RAF57WYO.js';import {n}from'./chunk-XR7HEC7B.js';export{n as ExpressionEngine,d as SNAPSHOT_FORMAT,e as SNAPSHOT_VERSION,f as SnapshotErrorCodes,c as assertEngineVersionCompatible,b as checkEngineVersionCompatibility,a as checkPackageCompatibility}from'./chunk-XR7HEC7B.js';import'./chunk-XNIWQHXY.js';import'./chunk-2RWAXT6O.js';import'./chunk-7GK3XEZF.js';import'./chunk-MIQBJGGR.js';import'./chunk-YJ2OPULK.js';import'./chunk-TWC7K3ZX.js';import'./chunk-J4LZD4ZY.js';import'./chunk-XEIDV5JP.js';import {y as y$1}from'./chunk-EYRBENHC.js';import'./chunk-6G3PMEPA.js';import'./chunk-6CY44ZPG.js';import {a}from'./chunk-YVKHEAFT.js';import'./chunk-QXQE7X4S.js';import'./chunk-76F3LCIL.js';import'./chunk-TCZSPH4A.js';import'./chunk-W2JAR233.js';import'./chunk-YAYBVVG2.js';import'./chunk-E6Z4NQAS.js';import'./chunk-HFKDWQUL.js';import'./chunk-R2ENWQ76.js';import'./chunk-RSF25YSJ.js';import {J,t,n as n$1}from'./chunk-EVAOPEO4.js';import'./chunk-WGZ3FNHI.js';export{a as ENGINE_VERSION}from'./chunk-L3FPQSGN.js';import'./chunk-GOIQYUWV.js';import'./chunk-JPFCXLJV.js';import'./chunk-UI6IFGBT.js';import'./chunk-IJMNVBIS.js';import'./chunk-62LMTO4F.js';import'./chunk-TRBXW6HW.js';import'./chunk-2JMFUQZH.js';import {c}from'./chunk-MPB7KUN5.js';var r={DEFINE_FUNCTION_INVALID_NAME:"DEFINE_FUNCTION_INVALID_NAME",DEFINE_FUNCTION_INVALID_SPEC:"DEFINE_FUNCTION_INVALID_SPEC",DEFINE_FUNCTION_ARITY_MISMATCH:"DEFINE_FUNCTION_ARITY_MISMATCH",DEFINE_FUNCTION_ARGUMENT_TYPE:"DEFINE_FUNCTION_ARGUMENT_TYPE",DEFINE_FUNCTION_RETURN_TYPE:"DEFINE_FUNCTION_RETURN_TYPE"},b=/^[a-z_][a-z0-9_]*$/i,y=new Set(["number","string","boolean"]);function u(e){return e===1?"1 argument":`${e} arguments`}function f(e){switch(e.type){case 0:case 1:return "a number";case 3:return "a string";case 10:return "a boolean";case 2:return "a big integer";case 5:return "a percentage";case 6:return "a value with a unit";case 4:return "a date";case 7:return "a matrix";case 8:return "a range";case 9:return "a symbolic expression";default:return "an unsupported value"}}function A(e,n,t){switch(n.type){case "number":if(e.type===0||e.type===1)return e.toNumber();break;case "string":if(e.type===3)return e.value;break;case "boolean":if(e.type===10)return e.value;break}throw c.execution({code:r.DEFINE_FUNCTION_ARGUMENT_TYPE,message:`${t}() expects "${n.name}" to be a ${n.type}, but was given ${f(e)}`,expected:`a ${n.type}`,found:f(e),context:{functionName:t,argName:n.name,expectedType:n.type}})}function S(e,n,t$1){switch(n){case "number":if(typeof e=="number")return n$1(e);break;case "string":if(typeof e=="string")return t(e);break;case "boolean":if(typeof e=="boolean")return J(e);break}throw c.internal({code:r.DEFINE_FUNCTION_RETURN_TYPE,message:`${t$1}() is declared to return a ${n}, but its implementation returned ${typeof e}`,expected:`a ${n}`,found:typeof e,context:{functionName:t$1,expectedType:n}})}var p=class{constructor(n){this.fnName=n;this.category="Function";}parse(n,t,i){n.consume("LPAREN");let a$1=0;if(n.peek()?.type!=="RPAREN")for(n.parseExpression(a.Lowest,i),a$1++;n.match("COMMA");)n.parseExpression(a.Lowest,i),a$1++;n.consume("RPAREN"),i.emitPluginCall(this.fnName,a$1);}};function P(e){let n=e.args.length;return t=>{if(t.length!==n)throw c.execution({code:r.DEFINE_FUNCTION_ARITY_MISMATCH,message:`${e.name}() takes ${u(n)}, but was given ${t.length===0?"none":u(t.length)}`,expected:u(n),found:t.length===0?"none":u(t.length),context:{functionName:e.name,expected:n,actual:t.length}});let i=new Array(n);for(let s=0;s<n;s++)i[s]=A(t[s],e.args[s],e.name);let a=e.call(...i);return S(a,e.returns,e.name)}}function V(e){if(typeof e?.name!="string"||!b.test(e.name))throw c.config({code:r.DEFINE_FUNCTION_INVALID_NAME,message:`defineFunction: name must be a single identifier, got ${JSON.stringify(e?.name)}`,suggestion:'e.g. "vat" or "net_price"',context:{name:e?.name}});if(!Array.isArray(e.args))throw c.config({code:r.DEFINE_FUNCTION_INVALID_SPEC,message:`defineFunction: "${e.name}" args must be an array`,context:{name:e.name}});for(let n of e.args){if(typeof n?.name!="string"||n.name.length===0)throw c.config({code:r.DEFINE_FUNCTION_INVALID_SPEC,message:`defineFunction: "${e.name}" has an argument with no name`,context:{name:e.name}});if(!y.has(n.type))throw c.config({code:r.DEFINE_FUNCTION_INVALID_SPEC,message:`defineFunction: "${e.name}" argument "${n.name}" has unsupported type ${JSON.stringify(n.type)}`,suggestion:"supported argument types are number, string, boolean",context:{name:e.name,argName:n.name,type:n.type}})}if(!y.has(e.returns))throw c.config({code:r.DEFINE_FUNCTION_INVALID_SPEC,message:`defineFunction: "${e.name}" has unsupported return type ${JSON.stringify(e.returns)}`,suggestion:"supported return types are number, string, boolean",context:{name:e.name,returns:e.returns}});if(typeof e.call!="function")throw c.config({code:r.DEFINE_FUNCTION_INVALID_SPEC,message:`defineFunction: "${e.name}" is missing a call implementation`,context:{name:e.name}})}function O(e){V(e);let n=e.name,t=`DEFINE_FN_${n.toUpperCase()}`;return {name:`solve-fn-${n}`,lexerVocabulary:{keywords:{[n.toLowerCase()]:t}},prefixParselets:{[t]:new p(n)},pluginFunctions:{[n]:P(e)}}}function h(e={}){let{extraPackages:n$1=[],...t}=e;return new n({...t,packages:n$1.length>0?[...y$1,...n$1]:y$1})}export{r as DefineFunctionErrorCodes,h as createEngine,O as defineFunction};//# sourceMappingURL=index.js.map
279
2
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/PackageRegistry.ts","../src/api/defineFunction.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { sharedParseletRegistry } from \"@solve-js/parser/registry/ParseletRegistry\";\nimport { PrefixParselet, InfixParselet } from \"@solve-js/parser/Parselet\";\nimport { Value } from \"@solve-js/vm/Value\";\nimport { IVariableSource } from \"@solve-js/variables/IVariableSource\";\nimport { sharedVariableResolver } from \"@solve-js/variables/VariableResolver\";\nimport { sharedLexer } from \"@solve-js/lexer/Lexer\";\nimport type { LexerVocabulary } from \"@solve-js/lexer/ExpressionLexer\";\nimport type { IAsyncResolver } from \"@solve-js/resolvers/ResolverRegistry\";\nimport type { NormalizerRule } from \"@solve-js/normalizer/NormalizerRule\";\nimport type { TokenCategory } from \"@solve-js/language/TokenCategory\";\nimport type { CompletionItem } from \"@solve-js/language/LanguageService\";\nimport type { LineExecutionContext } from \"@solve-js/vm/VM\";\nimport { assertEngineVersionCompatible } from \"./EngineVersionCompatibility\";\n\n/**\n * Public API for registering plugins with the solve-js engine.\n *\n * All registration goes through this interface, parselets, variable\n * sources, and full packages. The default implementation is\n * {@link PackageRegistry} (singleton via {@link packageRegistry}).\n *\n * @example\n * ```typescript\n * import { packageRegistry } from \"solve-engine\";\n * packageRegistry.registerPackage(myCustomPackage);\n * ```\n */\nexport interface IPackageRegistry {\n /** Register a prefix parselet (e.g., `GE`, `NOW`, `floor`). */\n registerPrefixParselet(tokenType: string, parselet: PrefixParselet): void;\n /** Register an infix parselet (e.g., `+`, `in`, `to`). */\n registerInfixParselet(tokenType: string, parselet: InfixParselet): void;\n /** @deprecated Has no effect. See {@link IEnginePackage.variableSources}. */\n registerVariableSource(source: IVariableSource): void;\n /** Register a complete package (parselets + variable sources). */\n registerPackage(pkg: IEnginePackage): void;\n /** Convenience reference to the Value class for creating typed values. */\n Value: typeof Value;\n}\n\n/**\n * Package descriptor for registering a complete provider with the engine.\n *\n * A package bundles all the pieces needed for a domain-specific provider:\n * lexer plugins for custom token recognition, parselets for Pratt parsing,\n * plugin functions dispatched via CALL_PLUGIN bytecode, variable sources,\n * and optional async resolvers for data that loads asynchronously (e.g.,\n * exchange rates, game prices).\n *\n * @example\n * ```typescript\n * const myPackage: IEnginePackage = {\n * name: \"MyProvider\",\n * lexerVocabulary: myLexerVocabulary,\n * prefixParselets: [{ tokenType: \"MY_FUNC\", parselet: new MyParselet() }],\n * pluginFunctions: [{ index: MY_FN_IDX, handler: myHandler }],\n * asyncResolvers: [myAsyncResolver],\n * };\n * packageRegistry.registerPackage(myPackage);\n * ```\n */\nexport interface IEnginePackage {\n /** Human-readable name for debugging and error attribution. */\n name: string;\n /**\n * Semver range of `solve-engine` versions this package is compatible with\n * (e.g. `\"^0.1.0\"`, `\">=0.1.0 <0.3.0\"`), checked against the engine's own\n * running version ({@link ENGINE_VERSION}, `@solve-js/constants/version`)\n * via `checkEngineVersionCompatibility()`/`assertEngineVersionCompatible()`\n * (`@solve-js/api/EngineVersionCompatibility`) at registration time.\n *\n * Optional, omitted means \"no declared constraint,\" so every package\n * that predates this field (all built-ins, `examples/osrs`) keeps\n * registering exactly as before.\n *\n * Unlike every other compatibility signal in this codebase (e.g.\n * `checkPackageCompatibility()`'s sibling-package collision warnings,\n * which always log and proceed. See `api/PackageCompatibility.ts`), a\n * declared `engineVersion` range the running engine does NOT satisfy is\n * a deliberate, hard REJECTION: `registerPackage()` throws rather than\n * warning. See `ARCHITECTURE.md` §5.3.\n */\n engineVersion?: string;\n /** Optional lexer vocabulary (keywords/operators/units) for recognizing custom tokens (e.g., `GE`, `£`). */\n lexerVocabulary?: LexerVocabulary;\n /** Prefix parselets for this package's custom functions/operators. */\n prefixParselets?: Array<{ tokenType: string; parselet: PrefixParselet }>;\n /** Infix parselets for this package's custom binary operators. */\n infixParselets?: Array<{ tokenType: string; parselet: InfixParselet }>;\n /**\n * Functions dispatched via CALL_PLUGIN bytecode (emitted by this package's\n * parselets with `builder.emitIndex(index)`).\n *\n * Each entry's `index` MUST come from {@link allocatePluginFunctionIndex}\n * (`@solve-js/vm/VMBuiltins`), never hardcode a number. Two packages\n * independently picking the same index would silently overwrite each\n * other's handler in the shared registry.\n *\n * The handler's optional second parameter, `context`, carries the\n * current line's {@link LineExecutionContext} (line number, and, only\n * inside a real document, never `evaluateExpression()`'s single-shot\n * path, closures for reading another line's cached result). Every\n * handler that doesn't need cross-line data can ignore it entirely.\n *\n * @example\n * ```ts\n * const MY_FN_IDX = allocatePluginFunctionIndex();\n * // In a parselet's parse(): builder.emitOpcode(OpCode.CALL_PLUGIN); builder.emitIndex(MY_FN_IDX); builder.emitIndex(argCount);\n * pluginFunctions: [{ index: MY_FN_IDX, handler: myHandler }]\n * ```\n */\n pluginFunctions?: Array<{ index: number; handler: (args: Value[], context?: LineExecutionContext) => Value | Promise<Value> }>;\n /**\n * Named-variable sources.\n *\n * @deprecated Currently has no effect. Sources declared here are registered\n * into the engine's {@link EngineContext} and unregistered again on package\n * removal, but no evaluation path ever calls `VariableResolver.resolve()`, so\n * a variable a source provides is never found. Verified by searching every\n * use of `IVariableSource` outside its own declaration: they are all\n * registration bookkeeping.\n *\n * Declared here rather than deleted because removing a public field is a\n * breaking change and the intended behaviour is worth keeping. Documented as\n * dead so a package author does not spend an afternoon working out why their\n * variables resolve to nothing. To expose a value today, contribute a plugin\n * function through {@link IEnginePackage.pluginFunctions}.\n */\n variableSources?: IVariableSource[];\n /**\n * Async resolvers for this package's domain.\n * When set, the ExpressionEngine runs preflight() before VM execution\n * for each resolver. If async data is needed, a Pending result is\n * returned immediately and the line re-evaluates when the data resolves.\n *\n * Each resolver must have a unique `namespace`, the ResolverRegistry\n * is keyed by namespace. Multiple resolvers let a package handle\n * distinct async operations (e.g., `fetch`, `wait`, `poll`) in\n * separate, focused classes rather than one monolithic preflight().\n */\n asyncResolvers?: IAsyncResolver[];\n /**\n * Multi-word phrases to fuse into single compound tokens.\n * Each key is a space-separated phrase (e.g., \"to the power of\"),\n * each value is the target token type after fusion (e.g., \"CARET\").\n *\n * Registered into the engine's {@link PhraseTrie} for single-pass\n * O(depth) matching, no separate rule scanning per phrase.\n *\n * @example\n * ```ts\n * phrases: {\n * \"to the power of\": \"CARET\",\n * \"abyssal whip\": \"ITEM\",\n * }\n * ```\n */\n phrases?: Record<string, string>;\n /**\n * Normalizer rules for post-lexer token transformation.\n * Applied by the TokenNormalizer between lexing and parsing.\n * For phrase fusion, prefer the declarative {@link phrases} field\n * which uses the faster PhraseTrie. Use this for non-phrase rules\n * like implicit operator insertion.\n */\n normalizerRules?: NormalizerRule[];\n /**\n * Semantic highlight categories for this package's custom token types\n * (introduced via {@link lexerVocabulary} or {@link normalizerRules}), the\n * plugin-facing half of solve-js's editor-agnostic language service (see\n * `language/TokenCategoryMap.ts`). Without an entry here, a package's\n * custom tokens (e.g. a game-item name fused from several identifiers)\n * are still lexed and parsed correctly, but render with no highlight\n * category in any editor integration.\n *\n * @example\n * ```ts\n * tokenCategories: { MY_KEYWORD: \"keyword\", MY_ITEM: \"my-plugin-item\" }\n * ```\n */\n tokenCategories?: Record<string, TokenCategory>;\n /**\n * Completion candidates for this package, the plugin-facing half of\n * solve-js's editor-agnostic completions API\n * (`LanguageService.getCompletions()`). A package's single-word\n * keywords (via {@link lexerVocabulary}) already flow into completions\n * automatically; this field is for candidates that AREN'T lexer\n * keywords, such as a vocabulary of item/entity names. A plain,\n * pre-built list, not a callback, completion candidate lists are\n * meant to be cheap and static within one engine configuration.\n *\n * @example\n * ```ts\n * completionItems: [{ label: \"Abyssal whip\", category: \"my-plugin-item\", detail: \"Item\" }]\n * ```\n */\n completionItems?: CompletionItem[];\n /**\n * Custom `as <name>` converters, the extension point for the\n * Converters package's general `<expr> as <type>` grammar (e.g.\n * `50% as decimal`, `255 as hex`). The built-in converter names\n * (`percent`, `decimal`, `hex`, `fraction`, `multiplier`, `sci`,\n * `binary`, `octal`, ...) dispatch to dedicated fast opcodes; anything\n * else, including any name a third-party package registers here\n * resolves through `OpCode.CALL_AS_CONVERTER` against\n * `vm/VMBuiltins.ts`'s `asConverterRegistry` at runtime. No lexer\n * keyword registration is needed for a custom name: the AS parselet\n * accepts any bare-word token after \"as\" and reads its raw text.\n *\n * Each handler is a pure, synchronous `(value: Value) => Value`, for\n * async conversions (e.g. a live currency-style lookup), use\n * {@link asyncResolvers} instead.\n *\n * @example\n * ```ts\n * asConverters: { roman: (v) => stringValue(toRomanNumeral(v.toNumber())) }\n * ```\n */\n asConverters?: Record<string, (value: Value) => Value>;\n}\n\n/**\n * Default implementation of {@link IPackageRegistry}, the plugin registration API.\n *\n * All registrations delegate to shared singletons (parselet registry,\n * variable resolver, lexer). This ensures that packages registered through\n * any PackageRegistry instance are visible engine-wide.\n *\n * @example\n * ```typescript\n * import { packageRegistry } from \"solve-engine\";\n *\n * // Register a complete provider package\n * packageRegistry.registerPackage({\n * name: \"MyProvider\",\n * prefixParselets: [{ tokenType: \"MY_FUNC\", parselet: new MyParselet() }],\n * });\n * ```\n *\n * @deprecated Register on an engine instead:\n * `engine.registerPackage(pkg)`.\n *\n * This class writes into process-wide singletons, which is incompatible with an\n * engine owning its own registries. Since the introduction of\n * {@link EngineContext}, an engine reads plugin functions, opcode handlers and\n * variable sources from its own context, so a package registered here is not\n * visible to any engine. Parselets and lexer vocabulary registered here reach\n * the shared registries, which an engine also does not read: it builds its own\n * `ParseletRegistry` and its own `Lexer`.\n *\n * In other words this path registers into state nothing evaluates against. It\n * remains exported because removing it is a breaking change, and it is where\n * the singletons that survive are still written from, but it should not be used\n * in new code and will be removed before 1.0 proper.\n */\nexport class PackageRegistry implements IPackageRegistry {\n Value = Value;\n\n registerPrefixParselet(tokenType: string, parselet: PrefixParselet): void {\n sharedParseletRegistry.registerPrefix(tokenType, parselet);\n }\n\n registerInfixParselet(tokenType: string, parselet: InfixParselet): void {\n sharedParseletRegistry.registerInfix(tokenType, parselet);\n }\n\n registerVariableSource(source: IVariableSource): void {\n sharedVariableResolver.registerSource(source);\n }\n\n registerPackage(pkg: IEnginePackage): void {\n // Same hard engine-version gate ExpressionEngine.registerPackage() uses\n // (see its own comment and ARCHITECTURE.md §5.3). This weaker\n // shared-singleton path had no compatibility checking of any kind\n // before this, so without this call the version gate would be\n // trivially bypassable through this entry point.\n assertEngineVersionCompatible(pkg);\n\n if (pkg.lexerVocabulary) {\n sharedLexer.registerVocabulary(pkg.lexerVocabulary);\n }\n if (pkg.prefixParselets) {\n for (const pp of pkg.prefixParselets) {\n this.registerPrefixParselet(pp.tokenType, pp.parselet);\n }\n }\n if (pkg.infixParselets) {\n for (const ip of pkg.infixParselets) {\n this.registerInfixParselet(ip.tokenType, ip.parselet);\n }\n }\n if (pkg.variableSources) {\n for (const vs of pkg.variableSources) {\n this.registerVariableSource(vs);\n }\n }\n // Note: asyncResolvers are NOT registered here, the shared PackageRegistry singleton\n // doesn't have a ResolverRegistry (that lives inside ExpressionEngine).\n // Use ExpressionEngine.registerPackage() directly if you need async resolvers.\n }\n}\n\n/**\n * Singleton PackageRegistry instance, the default plugin registration API.\n *\n * All packages should register through this instance. The underlying registries\n * are shared singletons, so multiple PackageRegistry instances would be redundant.\n */\nexport const packageRegistry = new PackageRegistry();\n","import type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport type { PrefixParselet } from \"@solve-js/parser/Parselet\";\nimport type { Parser } from \"@solve-js/parser/Parser\";\nimport type { Token } from \"@solve-js/lexer/Token\";\nimport type { BytecodeBuilder } from \"@solve-js/parser/BytecodeBuilder\";\nimport { OpCode } from \"@solve-js/parser/OpCode\";\nimport { BindingPower } from \"@solve-js/parser/BindingPower\";\nimport { allocatePluginFunctionIndex } from \"@solve-js/vm/VMBuiltins\";\nimport {\n Value,\n ValueType,\n numberValue,\n stringValue,\n boolValue,\n} from \"@solve-js/vm/Value\";\nimport { ErrorFactory } from \"@solve-js/errors/UnifiedErrorFramework\";\n\n/**\n * A higher-level, declarative way to contribute a single `name(args)`\n * function, sitting ON TOP OF the package contract rather than replacing it.\n *\n * The low-level contract (allocate a plugin function index, write a parselet,\n * emit `CALL_PLUGIN`) stays exactly as it was and remains the way to add\n * anything that needs custom parsing. This module derives that same wiring\n * from a declaration for the common case, a function called with parenthesised\n * arguments, so adding `vat(x)` costs a spec object rather than an\n * understanding of the parser and the VM. See `defineFunction`.\n */\n\n/** The value types a declared argument or return may take. */\nexport type FunctionValueType = \"number\" | \"string\" | \"boolean\";\n\n/** The JavaScript type a {@link FunctionValueType} maps to at the `call` boundary. */\ntype JsValue<T extends FunctionValueType> = T extends \"number\"\n ? number\n : T extends \"string\"\n ? string\n : boolean;\n\n/** One declared parameter: a name (for error messages) and a value type. */\nexport interface FunctionArg {\n /** Parameter name, used only in the generated type-mismatch messages. */\n name: string;\n /** The value type this parameter accepts. */\n type: FunctionValueType;\n}\n\n/** Map a tuple of {@link FunctionArg} specs to the tuple of JS values `call` receives. */\ntype CallArgs<A extends readonly FunctionArg[]> = {\n [K in keyof A]: JsValue<A[K][\"type\"]>;\n};\n\n/**\n * A declarative function definition.\n *\n * `A` and `R` are inferred from the literal `args`/`returns` (via\n * `defineFunction`'s `const` type parameter), so `call`'s parameters and\n * return are typed from the declaration with no annotations: an\n * `{ type: \"number\" }` argument arrives as a `number`, and a `returns:\n * \"string\"` demands a `string` back.\n */\nexport interface FunctionSpec<\n A extends readonly FunctionArg[] = readonly FunctionArg[],\n R extends FunctionValueType = FunctionValueType,\n> {\n /**\n * The call name, a single identifier (`/^[a-z_][a-z0-9_]*$/i`). Registered\n * as a lexer keyword, so it is matched case-insensitively and cannot collide\n * with a built-in keyword (that collision throws at registration time).\n */\n name: string;\n /** The parameters, in order. A fixed-length list: variadic and optional args are out of scope (see {@link defineFunction}). */\n args: A;\n /** The value type the function returns. */\n returns: R;\n /** The implementation, receiving plain JS values and returning one. Must be synchronous (see {@link defineFunction}). */\n call: (...args: CallArgs<A>) => JsValue<R>;\n}\n\n/**\n * Error codes the declarative function API raises. Kept as a co-located const\n * (the convention `errors/ErrorCode.ts` documents for a domain's own codes) so\n * the strings have one source of truth.\n */\nexport const DefineFunctionErrorCodes = {\n /** The spec's `name` is not a single identifier. Thrown by `defineFunction`, before any engine sees it. */\n DEFINE_FUNCTION_INVALID_NAME: \"DEFINE_FUNCTION_INVALID_NAME\",\n /** The spec is otherwise malformed (bad `args`, unsupported type, missing `call`). Thrown by `defineFunction`. */\n DEFINE_FUNCTION_INVALID_SPEC: \"DEFINE_FUNCTION_INVALID_SPEC\",\n /** The call site passed the wrong number of arguments. Raised at evaluation time. */\n DEFINE_FUNCTION_ARITY_MISMATCH: \"DEFINE_FUNCTION_ARITY_MISMATCH\",\n /** An argument was the wrong value type. Raised at evaluation time. */\n DEFINE_FUNCTION_ARGUMENT_TYPE: \"DEFINE_FUNCTION_ARGUMENT_TYPE\",\n /** The `call` implementation returned a value that did not match `returns`. Raised at evaluation time, an authoring bug rather than a user one. */\n DEFINE_FUNCTION_RETURN_TYPE: \"DEFINE_FUNCTION_RETURN_TYPE\",\n} as const;\n\n/** A single identifier: a letter or underscore, then letters, digits, or underscores. */\nconst NAME_PATTERN = /^[a-z_][a-z0-9_]*$/i;\n\nconst SUPPORTED_TYPES: ReadonlySet<string> = new Set([\"number\", \"string\", \"boolean\"]);\n\n/** \"1 argument\" / \"2 arguments\", so a count reads as English either way. Mirrors `VMBuiltinArity.ts`. */\nfunction plural(count: number): string {\n return count === 1 ? \"1 argument\" : `${count} arguments`;\n}\n\n/**\n * A human noun for the type a Value actually carries, for the \"was given ...\"\n * half of a mismatch message. Covers the three declarable types by their own\n * names and everything else by a readable category, so the message never reads\n * \"given a 6\".\n */\nfunction describeValueType(v: Value): string {\n switch (v.type) {\n case ValueType.Number:\n case ValueType.Hex:\n return \"a number\";\n case ValueType.String:\n return \"a string\";\n case ValueType.Boolean:\n return \"a boolean\";\n case ValueType.BigInt:\n return \"a big integer\";\n case ValueType.Percentage:\n return \"a percentage\";\n case ValueType.Uom:\n return \"a value with a unit\";\n case ValueType.Datetime:\n return \"a date\";\n case ValueType.Matrix:\n return \"a matrix\";\n case ValueType.Range:\n return \"a range\";\n case ValueType.Symbolic:\n return \"a symbolic expression\";\n default:\n return \"an unsupported value\";\n }\n}\n\n/**\n * Read one runtime Value as the JS primitive its declared type promises, or\n * raise the engine's structured type error.\n *\n * A \"number\" accepts a plain number or a based literal (`0xFF`), both of which\n * ARE numbers written differently, and reads it with `toNumber()`. Nothing\n * else is coerced: a percentage, a unit-bearing value or a string is a\n * genuinely different kind of value, and silently reinterpreting it is the\n * class of wrong-answer this API exists to avoid.\n */\nfunction coerceArgument(\n value: Value,\n arg: FunctionArg,\n fnName: string,\n): number | string | boolean {\n switch (arg.type) {\n case \"number\":\n // Hex is a number in another base (see `hexValue`), so it reads as one here.\n if (value.type === ValueType.Number || value.type === ValueType.Hex) {\n return value.toNumber();\n }\n break;\n case \"string\":\n if (value.type === ValueType.String) return value.value as string;\n break;\n case \"boolean\":\n if (value.type === ValueType.Boolean) return value.value as boolean;\n break;\n }\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARGUMENT_TYPE,\n message: `${fnName}() expects \"${arg.name}\" to be a ${arg.type}, but was given ${describeValueType(value)}`,\n expected: `a ${arg.type}`,\n found: describeValueType(value),\n context: { functionName: fnName, argName: arg.name, expectedType: arg.type },\n });\n}\n\n/**\n * Wrap the `call` result back into a Value of the declared return type, or\n * raise a structured error if the implementation handed back something else.\n *\n * The type check here catches an authoring mistake (a function declared to\n * return a number that returns `undefined`, or a Promise from an accidental\n * `async`), turning it into a named error rather than a Value that lies about\n * its own type downstream.\n */\nfunction wrapReturn(result: unknown, returns: FunctionValueType, fnName: string): Value {\n switch (returns) {\n case \"number\":\n if (typeof result === \"number\") return numberValue(result);\n break;\n case \"string\":\n if (typeof result === \"string\") return stringValue(result);\n break;\n case \"boolean\":\n if (typeof result === \"boolean\") return boolValue(result);\n break;\n }\n throw ErrorFactory.internal({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_RETURN_TYPE,\n message: `${fnName}() is declared to return a ${returns}, but its implementation returned ${typeof result}`,\n expected: `a ${returns}`,\n found: typeof result,\n context: { functionName: fnName, expectedType: returns },\n });\n}\n\n/**\n * The call-syntax parselet generated for one declared function.\n *\n * Identical in shape to the built-in `FunctionCallParselet`: consume the open\n * paren, parse a comma-separated argument list, then emit `CALL_PLUGIN` with\n * the function's index and the argument count. The count is whatever was\n * written, arity is checked at the dispatch point (see {@link makeHandler}),\n * the same place the built-in arity check lives.\n */\nclass DefinedFunctionParselet implements PrefixParselet {\n readonly category = \"Function\";\n\n constructor(\n private readonly fnIndex: number,\n private readonly fnName: string,\n ) {}\n\n parse(parser: Parser, _token: Token, builder: BytecodeBuilder): void {\n parser.consume(\"LPAREN\");\n\n let argCount = 0;\n if (parser.peek()?.type !== \"RPAREN\") {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n while (parser.match(\"COMMA\")) {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n }\n }\n\n parser.consume(\"RPAREN\");\n\n builder.emitOpcode(OpCode.CALL_PLUGIN);\n builder.emitIndex(this.fnIndex);\n builder.emitIndex(argCount);\n }\n}\n\n/**\n * Build the plugin function that checks arity and argument types, calls the\n * host implementation, and wraps the result.\n *\n * The VM has already screened out faulted arguments (an errored or still\n * pending operand short-circuits before the handler runs, see\n * `VM.ts`'s `CALL_PLUGIN` case), so every Value reaching here carries a real\n * result. Arity is checked first, before any argument is read, so a wrong\n * count is reported as a wrong count rather than as a type error on a missing\n * argument.\n */\nfunction makeHandler(spec: FunctionSpec): (args: Value[]) => Value {\n const arity = spec.args.length;\n return (args: Value[]): Value => {\n if (args.length !== arity) {\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARITY_MISMATCH,\n message: `${spec.name}() takes ${plural(arity)}, but was given ${args.length === 0 ? \"none\" : plural(args.length)}`,\n expected: plural(arity),\n found: args.length === 0 ? \"none\" : plural(args.length),\n context: { functionName: spec.name, expected: arity, actual: args.length },\n });\n }\n\n const jsArgs: (number | string | boolean)[] = new Array(arity);\n for (let i = 0; i < arity; i++) {\n jsArgs[i] = coerceArgument(args[i], spec.args[i], spec.name);\n }\n\n const result = (spec.call as (...a: (number | string | boolean)[]) => unknown)(...jsArgs);\n return wrapReturn(result, spec.returns, spec.name);\n };\n}\n\n/** Reject a spec that could not produce a working function, before any engine sees it. */\nfunction validateSpec(spec: FunctionSpec): void {\n if (typeof spec?.name !== \"string\" || !NAME_PATTERN.test(spec.name)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_NAME,\n message: `defineFunction: name must be a single identifier, got ${JSON.stringify(spec?.name)}`,\n suggestion: 'e.g. \"vat\" or \"net_price\"',\n context: { name: spec?.name },\n });\n }\n if (!Array.isArray(spec.args)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" args must be an array`,\n context: { name: spec.name },\n });\n }\n for (const arg of spec.args) {\n if (typeof arg?.name !== \"string\" || arg.name.length === 0) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has an argument with no name`,\n context: { name: spec.name },\n });\n }\n if (!SUPPORTED_TYPES.has(arg.type)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" argument \"${arg.name}\" has unsupported type ${JSON.stringify(arg.type)}`,\n suggestion: \"supported argument types are number, string, boolean\",\n context: { name: spec.name, argName: arg.name, type: arg.type },\n });\n }\n }\n if (!SUPPORTED_TYPES.has(spec.returns)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has unsupported return type ${JSON.stringify(spec.returns)}`,\n suggestion: \"supported return types are number, string, boolean\",\n context: { name: spec.name, returns: spec.returns },\n });\n }\n if (typeof spec.call !== \"function\") {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" is missing a call implementation`,\n context: { name: spec.name },\n });\n }\n}\n\n/**\n * Turn a declarative {@link FunctionSpec} into a ready-to-register\n * {@link IEnginePackage}.\n *\n * This is the higher-level API from issue #102. It derives, from the\n * declaration alone, everything the low-level contract asks an author to write\n * by hand: a plugin function index ({@link allocatePluginFunctionIndex}), a\n * lexer keyword so the name tokenises, a call-syntax parselet emitting\n * `CALL_PLUGIN`, and a handler that checks arity and argument types (yielding\n * the engine's own structured errors) before invoking `call` and wrapping its\n * result. Anything needing custom parsing keeps writing a raw parselet exactly\n * as before, this sits on top of that contract and does not change it.\n *\n * @example\n * ```ts\n * const engine = new ExpressionEngine(\"en\", false, undefined, undefined, [\n * ...BUILTIN_PACKAGES,\n * defineFunction({\n * name: \"vat\",\n * args: [{ name: \"amount\", type: \"number\" }],\n * returns: \"number\",\n * call: (amount) => amount * 1.2,\n * }),\n * ]);\n * engine.evaluateExpression(\"vat(100)\"); // 120\n * ```\n *\n * The returned package is self-contained and composes with any others through\n * the engine's `packages` array; register several functions by passing several\n * packages. Its name is `solve-fn-<name>`.\n *\n * Scope: arguments are a fixed-length list of `number`/`string`/`boolean`, and\n * `call` is synchronous. Variadic and optional arguments, other value types\n * (units, percentages, dates, matrices), and async work are deliberately out\n * of scope, a function needing any of those keeps using the low-level\n * contract, whose parselets and async resolvers are unchanged.\n *\n * @throws {EngineError} (category CONFIG) if the spec is malformed, at the\n * point `defineFunction` is called, before the package reaches an engine.\n */\nexport function defineFunction<\n const A extends readonly FunctionArg[],\n R extends FunctionValueType,\n>(spec: FunctionSpec<A, R>): IEnginePackage {\n validateSpec(spec as FunctionSpec);\n\n const name = spec.name;\n // Uppercased so the generated type is a valid, collision-resistant token\n // type; the name pattern guarantees it forms one. Distinct from the\n // built-in FUNC type, so this never routes through the builtin name map.\n const tokenType = `DEFINE_FN_${name.toUpperCase()}`;\n // Allocated at definition time (not module load), so importing this module\n // consumes no index and the export stays side-effect free.\n const index = allocatePluginFunctionIndex();\n\n return {\n name: `solve-fn-${name}`,\n lexerVocabulary: {\n // Lowercased because the lexer lowercases input before lookup, so the\n // call is matched case-insensitively.\n keywords: { [name.toLowerCase()]: tokenType },\n },\n prefixParselets: [\n { tokenType, parselet: new DefinedFunctionParselet(index, name) },\n ],\n pluginFunctions: [\n { index, handler: makeHandler(spec as FunctionSpec) },\n ],\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/api/defineFunction.ts","../src/api/createEngine.ts"],"names":["DefineFunctionErrorCodes","NAME_PATTERN","SUPPORTED_TYPES","plural","count","describeValueType","v","coerceArgument","value","arg","fnName","ErrorFactory","wrapReturn","result","returns","numberValue","stringValue","boolValue","DefinedFunctionParselet","parser","_token","builder","argCount","BindingPower","makeHandler","spec","arity","args","jsArgs","i","validateSpec","defineFunction","name","tokenType","createEngine","options","extraPackages","engineOptions","ExpressionEngine","BUILTIN_PACKAGES"],"mappings":"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","file":"index.js","sourcesContent":["import type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport type { PrefixParselet } from \"@solve-js/parser/Parselet\";\nimport type { Parser } from \"@solve-js/parser/Parser\";\nimport type { Token } from \"@solve-js/lexer/Token\";\nimport type { BytecodeBuilder } from \"@solve-js/parser/BytecodeBuilder\";\nimport { BindingPower } from \"@solve-js/parser/BindingPower\";\nimport {\n Value,\n ValueType,\n numberValue,\n stringValue,\n boolValue,\n} from \"@solve-js/vm/Value\";\nimport { ErrorFactory } from \"@solve-js/errors/UnifiedErrorFramework\";\n\n/**\n * A higher-level, declarative way to contribute a single `name(args)`\n * function, sitting ON TOP OF the package contract rather than replacing it.\n *\n * The low-level contract (allocate a plugin function index, write a parselet,\n * emit `CALL_PLUGIN`) stays exactly as it was and remains the way to add\n * anything that needs custom parsing. This module derives that same wiring\n * from a declaration for the common case, a function called with parenthesised\n * arguments, so adding `vat(x)` costs a spec object rather than an\n * understanding of the parser and the VM. See `defineFunction`.\n */\n\n/** The value types a declared argument or return may take. */\nexport type FunctionValueType = \"number\" | \"string\" | \"boolean\";\n\n/** The JavaScript type a {@link FunctionValueType} maps to at the `call` boundary. */\ntype JsValue<T extends FunctionValueType> = T extends \"number\"\n ? number\n : T extends \"string\"\n ? string\n : boolean;\n\n/** One declared parameter: a name (for error messages) and a value type. */\nexport interface FunctionArg {\n /** Parameter name, used only in the generated type-mismatch messages. */\n name: string;\n /** The value type this parameter accepts. */\n type: FunctionValueType;\n}\n\n/** Map a tuple of {@link FunctionArg} specs to the tuple of JS values `call` receives. */\ntype CallArgs<A extends readonly FunctionArg[]> = {\n [K in keyof A]: JsValue<A[K][\"type\"]>;\n};\n\n/**\n * A declarative function definition.\n *\n * `A` and `R` are inferred from the literal `args`/`returns` (via\n * `defineFunction`'s `const` type parameter), so `call`'s parameters and\n * return are typed from the declaration with no annotations: an\n * `{ type: \"number\" }` argument arrives as a `number`, and a `returns:\n * \"string\"` demands a `string` back.\n */\nexport interface FunctionSpec<\n A extends readonly FunctionArg[] = readonly FunctionArg[],\n R extends FunctionValueType = FunctionValueType,\n> {\n /**\n * The call name, a single identifier (`/^[a-z_][a-z0-9_]*$/i`). Registered\n * as a lexer keyword, so it is matched case-insensitively and cannot collide\n * with a built-in keyword (that collision throws at registration time).\n */\n name: string;\n /** The parameters, in order. A fixed-length list: variadic and optional args are out of scope (see {@link defineFunction}). */\n args: A;\n /** The value type the function returns. */\n returns: R;\n /** The implementation, receiving plain JS values and returning one. Must be synchronous (see {@link defineFunction}). */\n call: (...args: CallArgs<A>) => JsValue<R>;\n}\n\n/**\n * Error codes the declarative function API raises. Kept as a co-located const\n * (the convention `errors/ErrorCode.ts` documents for a domain's own codes) so\n * the strings have one source of truth.\n */\nexport const DefineFunctionErrorCodes = {\n /** The spec's `name` is not a single identifier. Thrown by `defineFunction`, before any engine sees it. */\n DEFINE_FUNCTION_INVALID_NAME: \"DEFINE_FUNCTION_INVALID_NAME\",\n /** The spec is otherwise malformed (bad `args`, unsupported type, missing `call`). Thrown by `defineFunction`. */\n DEFINE_FUNCTION_INVALID_SPEC: \"DEFINE_FUNCTION_INVALID_SPEC\",\n /** The call site passed the wrong number of arguments. Raised at evaluation time. */\n DEFINE_FUNCTION_ARITY_MISMATCH: \"DEFINE_FUNCTION_ARITY_MISMATCH\",\n /** An argument was the wrong value type. Raised at evaluation time. */\n DEFINE_FUNCTION_ARGUMENT_TYPE: \"DEFINE_FUNCTION_ARGUMENT_TYPE\",\n /** The `call` implementation returned a value that did not match `returns`. Raised at evaluation time, an authoring bug rather than a user one. */\n DEFINE_FUNCTION_RETURN_TYPE: \"DEFINE_FUNCTION_RETURN_TYPE\",\n} as const;\n\n/** A single identifier: a letter or underscore, then letters, digits, or underscores. */\nconst NAME_PATTERN = /^[a-z_][a-z0-9_]*$/i;\n\nconst SUPPORTED_TYPES: ReadonlySet<string> = new Set([\"number\", \"string\", \"boolean\"]);\n\n/** \"1 argument\" / \"2 arguments\", so a count reads as English either way. Mirrors `VMBuiltinArity.ts`. */\nfunction plural(count: number): string {\n return count === 1 ? \"1 argument\" : `${count} arguments`;\n}\n\n/**\n * A human noun for the type a Value actually carries, for the \"was given ...\"\n * half of a mismatch message. Covers the three declarable types by their own\n * names and everything else by a readable category, so the message never reads\n * \"given a 6\".\n */\nfunction describeValueType(v: Value): string {\n switch (v.type) {\n case ValueType.Number:\n case ValueType.Hex:\n return \"a number\";\n case ValueType.String:\n return \"a string\";\n case ValueType.Boolean:\n return \"a boolean\";\n case ValueType.BigInt:\n return \"a big integer\";\n case ValueType.Percentage:\n return \"a percentage\";\n case ValueType.Uom:\n return \"a value with a unit\";\n case ValueType.Datetime:\n return \"a date\";\n case ValueType.Matrix:\n return \"a matrix\";\n case ValueType.Range:\n return \"a range\";\n case ValueType.Symbolic:\n return \"a symbolic expression\";\n default:\n return \"an unsupported value\";\n }\n}\n\n/**\n * Read one runtime Value as the JS primitive its declared type promises, or\n * raise the engine's structured type error.\n *\n * A \"number\" accepts a plain number or a based literal (`0xFF`), both of which\n * ARE numbers written differently, and reads it with `toNumber()`. Nothing\n * else is coerced: a percentage, a unit-bearing value or a string is a\n * genuinely different kind of value, and silently reinterpreting it is the\n * class of wrong-answer this API exists to avoid.\n */\nfunction coerceArgument(\n value: Value,\n arg: FunctionArg,\n fnName: string,\n): number | string | boolean {\n switch (arg.type) {\n case \"number\":\n // Hex is a number in another base (see `hexValue`), so it reads as one here.\n if (value.type === ValueType.Number || value.type === ValueType.Hex) {\n return value.toNumber();\n }\n break;\n case \"string\":\n if (value.type === ValueType.String) return value.value as string;\n break;\n case \"boolean\":\n if (value.type === ValueType.Boolean) return value.value as boolean;\n break;\n }\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARGUMENT_TYPE,\n message: `${fnName}() expects \"${arg.name}\" to be a ${arg.type}, but was given ${describeValueType(value)}`,\n expected: `a ${arg.type}`,\n found: describeValueType(value),\n context: { functionName: fnName, argName: arg.name, expectedType: arg.type },\n });\n}\n\n/**\n * Wrap the `call` result back into a Value of the declared return type, or\n * raise a structured error if the implementation handed back something else.\n *\n * The type check here catches an authoring mistake (a function declared to\n * return a number that returns `undefined`, or a Promise from an accidental\n * `async`), turning it into a named error rather than a Value that lies about\n * its own type downstream.\n */\nfunction wrapReturn(result: unknown, returns: FunctionValueType, fnName: string): Value {\n switch (returns) {\n case \"number\":\n if (typeof result === \"number\") return numberValue(result);\n break;\n case \"string\":\n if (typeof result === \"string\") return stringValue(result);\n break;\n case \"boolean\":\n if (typeof result === \"boolean\") return boolValue(result);\n break;\n }\n throw ErrorFactory.internal({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_RETURN_TYPE,\n message: `${fnName}() is declared to return a ${returns}, but its implementation returned ${typeof result}`,\n expected: `a ${returns}`,\n found: typeof result,\n context: { functionName: fnName, expectedType: returns },\n });\n}\n\n/**\n * The call-syntax parselet generated for one declared function.\n *\n * Identical in shape to the built-in `FunctionCallParselet`: consume the open\n * paren, parse a comma-separated argument list, then emit `CALL_PLUGIN` with\n * the function's index and the argument count. The count is whatever was\n * written, arity is checked at the dispatch point (see {@link makeHandler}),\n * the same place the built-in arity check lives.\n */\nclass DefinedFunctionParselet implements PrefixParselet {\n readonly category = \"Function\";\n\n constructor(\n private readonly fnName: string,\n ) {}\n\n parse(parser: Parser, _token: Token, builder: BytecodeBuilder): void {\n parser.consume(\"LPAREN\");\n\n let argCount = 0;\n if (parser.peek()?.type !== \"RPAREN\") {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n while (parser.match(\"COMMA\")) {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n }\n }\n\n parser.consume(\"RPAREN\");\n\n builder.emitPluginCall(this.fnName, argCount);\n }\n}\n\n/**\n * Build the plugin function that checks arity and argument types, calls the\n * host implementation, and wraps the result.\n *\n * The VM has already screened out faulted arguments (an errored or still\n * pending operand short-circuits before the handler runs, see\n * `VM.ts`'s `CALL_PLUGIN` case), so every Value reaching here carries a real\n * result. Arity is checked first, before any argument is read, so a wrong\n * count is reported as a wrong count rather than as a type error on a missing\n * argument.\n */\nfunction makeHandler(spec: FunctionSpec): (args: Value[]) => Value {\n const arity = spec.args.length;\n return (args: Value[]): Value => {\n if (args.length !== arity) {\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARITY_MISMATCH,\n message: `${spec.name}() takes ${plural(arity)}, but was given ${args.length === 0 ? \"none\" : plural(args.length)}`,\n expected: plural(arity),\n found: args.length === 0 ? \"none\" : plural(args.length),\n context: { functionName: spec.name, expected: arity, actual: args.length },\n });\n }\n\n const jsArgs: (number | string | boolean)[] = new Array(arity);\n for (let i = 0; i < arity; i++) {\n jsArgs[i] = coerceArgument(args[i], spec.args[i], spec.name);\n }\n\n const result = (spec.call as (...a: (number | string | boolean)[]) => unknown)(...jsArgs);\n return wrapReturn(result, spec.returns, spec.name);\n };\n}\n\n/** Reject a spec that could not produce a working function, before any engine sees it. */\nfunction validateSpec(spec: FunctionSpec): void {\n if (typeof spec?.name !== \"string\" || !NAME_PATTERN.test(spec.name)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_NAME,\n message: `defineFunction: name must be a single identifier, got ${JSON.stringify(spec?.name)}`,\n suggestion: 'e.g. \"vat\" or \"net_price\"',\n context: { name: spec?.name },\n });\n }\n if (!Array.isArray(spec.args)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" args must be an array`,\n context: { name: spec.name },\n });\n }\n for (const arg of spec.args) {\n if (typeof arg?.name !== \"string\" || arg.name.length === 0) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has an argument with no name`,\n context: { name: spec.name },\n });\n }\n if (!SUPPORTED_TYPES.has(arg.type)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" argument \"${arg.name}\" has unsupported type ${JSON.stringify(arg.type)}`,\n suggestion: \"supported argument types are number, string, boolean\",\n context: { name: spec.name, argName: arg.name, type: arg.type },\n });\n }\n }\n if (!SUPPORTED_TYPES.has(spec.returns)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has unsupported return type ${JSON.stringify(spec.returns)}`,\n suggestion: \"supported return types are number, string, boolean\",\n context: { name: spec.name, returns: spec.returns },\n });\n }\n if (typeof spec.call !== \"function\") {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" is missing a call implementation`,\n context: { name: spec.name },\n });\n }\n}\n\n/**\n * Turn a declarative {@link FunctionSpec} into a ready-to-register\n * {@link IEnginePackage}.\n *\n * This is the higher-level API from issue #102. It derives, from the\n * declaration alone, everything the low-level contract asks an author to write\n * by hand: a named plugin function (the engine assigns its `CALL_PLUGIN`\n * index), a lexer keyword so the name tokenises, a call-syntax parselet emitting\n * that call by name, and a handler that checks arity and argument types (yielding\n * the engine's own structured errors) before invoking `call` and wrapping its\n * result. Anything needing custom parsing keeps writing a raw parselet exactly\n * as before, this sits on top of that contract and does not change it.\n *\n * @example\n * ```ts\n * const engine = new ExpressionEngine({ packages: [\n * ...BUILTIN_PACKAGES,\n * defineFunction({\n * name: \"vat\",\n * args: [{ name: \"amount\", type: \"number\" }],\n * returns: \"number\",\n * call: (amount) => amount * 1.2,\n * }),\n * ] });\n * engine.evaluateExpression(\"vat(100)\"); // 120\n * ```\n *\n * The returned package is self-contained and composes with any others through\n * the engine's `packages` array; register several functions by passing several\n * packages. Its name is `solve-fn-<name>`.\n *\n * Scope: arguments are a fixed-length list of `number`/`string`/`boolean`, and\n * `call` is synchronous. Variadic and optional arguments, other value types\n * (units, percentages, dates, matrices), and async work are deliberately out\n * of scope, a function needing any of those keeps using the low-level\n * contract, whose parselets and async resolvers are unchanged.\n *\n * @throws {EngineError} (category CONFIG) if the spec is malformed, at the\n * point `defineFunction` is called, before the package reaches an engine.\n */\nexport function defineFunction<\n const A extends readonly FunctionArg[],\n R extends FunctionValueType,\n>(spec: FunctionSpec<A, R>): IEnginePackage {\n validateSpec(spec as FunctionSpec);\n\n const name = spec.name;\n // Uppercased so the generated type is a valid, collision-resistant token\n // type; the name pattern guarantees it forms one. Distinct from the\n // built-in FUNC type, so this never routes through the builtin name map.\n const tokenType = `DEFINE_FN_${name.toUpperCase()}`;\n\n return {\n name: `solve-fn-${name}`,\n lexerVocabulary: {\n // Lowercased because the lexer lowercases input before lookup, so the\n // call is matched case-insensitively.\n keywords: { [name.toLowerCase()]: tokenType },\n },\n prefixParselets: {\n [tokenType]: new DefinedFunctionParselet(name),\n },\n pluginFunctions: {\n [name]: makeHandler(spec as FunctionSpec),\n },\n };\n}\n","import { ExpressionEngine, type EngineOptions } from \"@solve-js/engine/ExpressionEngine\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\n\n/** Options for {@link createEngine}: the engine options, minus `packages` (the\n * built-in set is always registered), plus `extraPackages` to add your own. */\nexport interface CreateEngineOptions extends Omit<EngineOptions, \"packages\"> {\n\t/** Packages to register ON TOP of the built-in set (e.g. an OSRS or stocks package). */\n\textraPackages?: IEnginePackage[];\n}\n\n/**\n * A batteries-included {@link ExpressionEngine} with every built-in package\n * registered.\n *\n * The constructor registers only the packages it is given, so a consumer's\n * bundler can tree-shake away the built-ins they never use: an engine built\n * with `new ExpressionEngine({ packages: [ARITHMETIC_PACKAGE] })` carries no\n * finance, colour or weather code. This convenience is the opposite trade: it\n * pulls the FULL built-in set (`BUILTIN_PACKAGES`) for the common \"I want\n * everything\" case, so importing it defeats that tree-shaking. Reach for the\n * constructor with an explicit package list when bundle size matters, and for\n * `createEngine` when it does not.\n *\n * @param options - Engine options ({@link EngineOptions}) minus `packages`, plus\n * an optional `extraPackages` to register alongside the built-in set.\n * @returns An engine with the built-in packages (and any extras) registered.\n *\n * @example\n * ```typescript\n * import { createEngine } from \"solve-engine\";\n * const engine = createEngine();\n * const value = engine.evaluateExpression(\"2 + 2 * 10\");\n * console.log(value.toNumber()); // 22\n * ```\n */\nexport function createEngine(options: CreateEngineOptions = {}): ExpressionEngine {\n\tconst { extraPackages = [], ...engineOptions } = options;\n\treturn new ExpressionEngine({\n\t\t...engineOptions,\n\t\tpackages: extraPackages.length > 0 ? [...BUILTIN_PACKAGES, ...extraPackages] : BUILTIN_PACKAGES,\n\t});\n}\n"]}