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.
- package/README.md +12 -17
- package/dist/{BytecodeBuilder-Bp9xeTmX.d.cts → BytecodeBuilder-DGGeByAP.d.cts} +18 -0
- package/dist/{BytecodeBuilder-Bp9xeTmX.d.ts → BytecodeBuilder-DGGeByAP.d.ts} +18 -0
- package/dist/{Configuration-C9W8tJv_.d.cts → Configuration-B6W0-T67.d.cts} +17 -4
- package/dist/{Configuration-C9W8tJv_.d.ts → Configuration-B6W0-T67.d.ts} +17 -4
- package/dist/{EngineError-CNA_rHY-.d.cts → EngineError-Ce1lPkjZ.d.cts} +2 -0
- package/dist/{EngineError-CNA_rHY-.d.ts → EngineError-Ce1lPkjZ.d.ts} +2 -0
- package/dist/{PackageCompatibility-B6NX9IaN.d.cts → PackageCompatibility-Bn5jnBtA.d.cts} +2 -2
- package/dist/{PackageCompatibility-Ceg5XdAp.d.ts → PackageCompatibility-CIvq2MP5.d.ts} +2 -2
- package/dist/{PackageRegistry-DrCPQNyy.d.ts → PackageRegistry-DzeiWcv4.d.ts} +93 -172
- package/dist/{PackageRegistry-DnJYVw9G.d.cts → PackageRegistry-dpdurBVO.d.cts} +93 -172
- package/dist/{Parselet-Bhf7d0_W.d.ts → Parselet-B-zoPrTa.d.ts} +8 -5
- package/dist/{Parselet-Cv7S7KRt.d.cts → Parselet-C4Wu055_.d.cts} +8 -5
- package/dist/{ScopeManager-Bzq87GfA.d.ts → ScopeManager-C2LDOrDx.d.ts} +7 -16
- package/dist/{ScopeManager-DRDBVfan.d.cts → ScopeManager-D7uMXbhS.d.cts} +7 -16
- package/dist/{VMCheckpoints-C6c17Hbo.d.ts → VMCheckpoints-CGyFhivM.d.ts} +3 -3
- package/dist/{VMCheckpoints-dZxSMGHG.d.cts → VMCheckpoints-I9jg3jWR.d.cts} +3 -3
- package/dist/{Value-DZNQ_PU7.d.cts → Value-CCi_Eecs.d.cts} +40 -0
- package/dist/{Value-DZNQ_PU7.d.ts → Value-CCi_Eecs.d.ts} +40 -0
- package/dist/{WorkerError-Djd7GGGa.d.cts → WorkerError-B4p6PNfx.d.cts} +1 -1
- package/dist/{WorkerError-B7t7R2-m.d.ts → WorkerError-Dhj9BQ_A.d.ts} +1 -1
- package/dist/chunk-2JMFUQZH.js +2 -0
- package/dist/chunk-2JMFUQZH.js.map +1 -0
- package/dist/chunk-2RWAXT6O.js +0 -1
- package/dist/chunk-4BZIYU7S.cjs +3 -0
- package/dist/chunk-4BZIYU7S.cjs.map +1 -0
- package/dist/chunk-4J7XZSZJ.cjs +5 -0
- package/dist/chunk-4J7XZSZJ.cjs.map +1 -0
- package/dist/chunk-4QVBSG6B.cjs +2 -0
- package/dist/chunk-4QVBSG6B.cjs.map +1 -0
- package/dist/chunk-5IJD5L3O.cjs +2 -0
- package/dist/chunk-5IJD5L3O.cjs.map +1 -0
- package/dist/chunk-62LMTO4F.js +2 -0
- package/dist/chunk-62LMTO4F.js.map +1 -0
- package/dist/chunk-6CY44ZPG.js +2 -0
- package/dist/chunk-6CY44ZPG.js.map +1 -0
- package/dist/chunk-6G3PMEPA.js +2 -0
- package/dist/chunk-6G3PMEPA.js.map +1 -0
- package/dist/chunk-6INX773F.cjs +2 -0
- package/dist/chunk-6INX773F.cjs.map +1 -0
- package/dist/chunk-6KFVG6UY.cjs +2 -0
- package/dist/{chunk-YJHY7CMN.cjs.map → chunk-6KFVG6UY.cjs.map} +1 -1
- package/dist/chunk-76F3LCIL.js +4 -0
- package/dist/chunk-76F3LCIL.js.map +1 -0
- package/dist/chunk-7GK3XEZF.js +2 -0
- package/dist/chunk-7GK3XEZF.js.map +1 -0
- package/dist/chunk-APN442VD.cjs +2 -0
- package/dist/chunk-APN442VD.cjs.map +1 -0
- package/dist/chunk-AXMQG5TS.cjs +2 -0
- package/dist/chunk-AXMQG5TS.cjs.map +1 -0
- package/dist/chunk-CIQOK7Q4.cjs +2 -0
- package/dist/chunk-CIQOK7Q4.cjs.map +1 -0
- package/dist/chunk-E6Z4NQAS.js +2 -0
- package/dist/chunk-E6Z4NQAS.js.map +1 -0
- package/dist/chunk-EFJCC6FJ.cjs +2 -0
- package/dist/chunk-EFJCC6FJ.cjs.map +1 -0
- package/dist/chunk-ESUN2THE.cjs +2 -0
- package/dist/chunk-ESUN2THE.cjs.map +1 -0
- package/dist/chunk-EVAOPEO4.js +2 -0
- package/dist/chunk-EVAOPEO4.js.map +1 -0
- package/dist/chunk-EYRBENHC.js +3 -0
- package/dist/chunk-EYRBENHC.js.map +1 -0
- package/dist/chunk-FDE5HWDI.cjs +2 -0
- package/dist/chunk-FDE5HWDI.cjs.map +1 -0
- package/dist/chunk-FWW3M36J.cjs +2 -0
- package/dist/chunk-FWW3M36J.cjs.map +1 -0
- package/dist/chunk-GOIQYUWV.js +2 -0
- package/dist/chunk-GOIQYUWV.js.map +1 -0
- package/dist/chunk-HFKDWQUL.js +2 -0
- package/dist/chunk-HFKDWQUL.js.map +1 -0
- package/dist/chunk-HLBYHXQD.cjs +3 -0
- package/dist/chunk-HLBYHXQD.cjs.map +1 -0
- package/dist/chunk-IANAMBJQ.cjs +2 -0
- package/dist/chunk-IANAMBJQ.cjs.map +1 -0
- package/dist/chunk-IJMNVBIS.js +2 -0
- package/dist/chunk-IJMNVBIS.js.map +1 -0
- package/dist/chunk-J4LZD4ZY.js +3 -0
- package/dist/chunk-J4LZD4ZY.js.map +1 -0
- package/dist/chunk-JAK3RAFA.cjs +2 -0
- package/dist/chunk-JAK3RAFA.cjs.map +1 -0
- package/dist/chunk-JFAJN3C2.cjs +2 -0
- package/dist/chunk-JFAJN3C2.cjs.map +1 -0
- package/dist/chunk-JPFCXLJV.js +2 -0
- package/dist/chunk-JPFCXLJV.js.map +1 -0
- package/dist/chunk-JSPKKNPQ.js +3 -0
- package/dist/chunk-JSPKKNPQ.js.map +1 -0
- package/dist/chunk-L3FPQSGN.js +2 -0
- package/dist/chunk-L3FPQSGN.js.map +1 -0
- package/dist/chunk-LR4E4A4W.cjs +2 -0
- package/dist/chunk-LR4E4A4W.cjs.map +1 -0
- package/dist/chunk-MIQBJGGR.js +2 -0
- package/dist/chunk-MIQBJGGR.js.map +1 -0
- package/dist/chunk-MPB7KUN5.js +3 -0
- package/dist/chunk-MPB7KUN5.js.map +1 -0
- package/dist/chunk-MSYX32PF.cjs +2 -0
- package/dist/chunk-MSYX32PF.cjs.map +1 -0
- package/dist/chunk-MVZUTETT.js +2 -0
- package/dist/chunk-MVZUTETT.js.map +1 -0
- package/dist/chunk-N7N7MPMK.cjs +2 -0
- package/dist/chunk-N7N7MPMK.cjs.map +1 -0
- package/dist/chunk-NGBBNL4K.cjs +1 -3
- package/dist/chunk-P6WPEUAJ.cjs +2 -0
- package/dist/chunk-P6WPEUAJ.cjs.map +1 -0
- package/dist/chunk-PS272DZJ.cjs +2 -0
- package/dist/chunk-PS272DZJ.cjs.map +1 -0
- package/dist/chunk-QXQE7X4S.js +2 -0
- package/dist/chunk-QXQE7X4S.js.map +1 -0
- package/dist/chunk-R2ENWQ76.js +2 -0
- package/dist/chunk-R2ENWQ76.js.map +1 -0
- package/dist/chunk-R2SZFJTT.cjs +2 -0
- package/dist/chunk-R2SZFJTT.cjs.map +1 -0
- package/dist/chunk-RAF57WYO.js +2 -0
- package/dist/chunk-RAF57WYO.js.map +1 -0
- package/dist/chunk-RSF25YSJ.js +2 -0
- package/dist/chunk-RSF25YSJ.js.map +1 -0
- package/dist/chunk-SOMGSIO4.cjs +3 -0
- package/dist/chunk-SOMGSIO4.cjs.map +1 -0
- package/dist/chunk-SUXRZWH2.cjs +3 -0
- package/dist/chunk-SUXRZWH2.cjs.map +1 -0
- package/dist/chunk-SYYE3QAX.cjs +2 -0
- package/dist/chunk-SYYE3QAX.cjs.map +1 -0
- package/dist/chunk-SZGK6RIP.cjs +2 -0
- package/dist/chunk-SZGK6RIP.cjs.map +1 -0
- package/dist/chunk-TCZSPH4A.js +2 -0
- package/dist/chunk-TCZSPH4A.js.map +1 -0
- package/dist/chunk-TLG7VZRX.cjs +2 -0
- package/dist/chunk-TLG7VZRX.cjs.map +1 -0
- package/dist/chunk-TRBXW6HW.js +2 -0
- package/dist/{chunk-AQNHHJMJ.cjs.map → chunk-TRBXW6HW.js.map} +1 -1
- package/dist/chunk-TTFO4YDP.cjs +2 -0
- package/dist/chunk-TTFO4YDP.cjs.map +1 -0
- package/dist/chunk-TWC7K3ZX.js +2 -0
- package/dist/chunk-TWC7K3ZX.js.map +1 -0
- package/dist/chunk-UDQ57ZRX.cjs +2 -0
- package/dist/chunk-UDQ57ZRX.cjs.map +1 -0
- package/dist/chunk-UI6IFGBT.js +2 -0
- package/dist/chunk-UI6IFGBT.js.map +1 -0
- package/dist/chunk-UURM7P3P.cjs +4 -0
- package/dist/chunk-UURM7P3P.cjs.map +1 -0
- package/dist/chunk-W2JAR233.js +2 -0
- package/dist/chunk-W2JAR233.js.map +1 -0
- package/dist/chunk-WGZ3FNHI.js +2 -0
- package/dist/chunk-WGZ3FNHI.js.map +1 -0
- package/dist/chunk-WN5CMP4T.cjs +3 -0
- package/dist/chunk-WN5CMP4T.cjs.map +1 -0
- package/dist/chunk-XEIDV5JP.js +2 -0
- package/dist/chunk-XEIDV5JP.js.map +1 -0
- package/dist/chunk-XNIWQHXY.js +2 -0
- package/dist/chunk-XNIWQHXY.js.map +1 -0
- package/dist/chunk-XR7HEC7B.js +5 -0
- package/dist/chunk-XR7HEC7B.js.map +1 -0
- package/dist/chunk-Y7O4D3BJ.cjs +2 -0
- package/dist/chunk-Y7O4D3BJ.cjs.map +1 -0
- package/dist/chunk-YAYBVVG2.js +3 -0
- package/dist/chunk-YAYBVVG2.js.map +1 -0
- package/dist/chunk-YJ2OPULK.js +2 -0
- package/dist/chunk-YJ2OPULK.js.map +1 -0
- package/dist/chunk-YVKHEAFT.js +2 -0
- package/dist/chunk-YVKHEAFT.js.map +1 -0
- package/dist/chunk-ZCNBT44X.cjs +2 -0
- package/dist/chunk-ZCNBT44X.cjs.map +1 -0
- package/dist/chunk-ZLRJ7TDP.cjs +2 -0
- package/dist/chunk-ZLRJ7TDP.cjs.map +1 -0
- package/dist/constants.cjs +1 -21
- package/dist/constants.d.cts +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +1 -4
- package/dist/engine.cjs +1 -94
- package/dist/engine.d.cts +10 -11
- package/dist/engine.d.ts +10 -11
- package/dist/engine.js +1 -37
- package/dist/errors.cjs +1 -105
- package/dist/errors.d.cts +3 -3
- package/dist/errors.d.ts +3 -3
- package/dist/errors.js +1 -4
- package/dist/format.cjs +1 -26
- package/dist/format.d.cts +2 -2
- package/dist/format.d.ts +2 -2
- package/dist/format.js +1 -9
- package/dist/index.cjs +1 -314
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +52 -20
- package/dist/index.d.ts +52 -20
- package/dist/index.js +1 -278
- package/dist/index.js.map +1 -1
- package/dist/language.cjs +1 -369
- package/dist/language.cjs.map +1 -1
- package/dist/language.d.cts +9 -10
- package/dist/language.d.ts +9 -10
- package/dist/language.js +1 -348
- package/dist/language.js.map +1 -1
- package/dist/lexer.cjs +1 -63
- package/dist/lexer.js +1 -10
- package/dist/normalizer.cjs +1 -39
- package/dist/normalizer.js +1 -10
- package/dist/packages.cjs +1 -132
- package/dist/packages.d.cts +8 -9
- package/dist/packages.d.ts +8 -9
- package/dist/packages.js +1 -23
- package/dist/parser.cjs +1 -54
- package/dist/parser.d.cts +8 -8
- package/dist/parser.d.ts +8 -8
- package/dist/parser.js +1 -9
- package/dist/{pipeline-D-PS9gVw.d.ts → pipeline-72QmQlGx.d.ts} +1 -1
- package/dist/{pipeline-DtSBJ8TS.d.cts → pipeline-DCQicwWX.d.cts} +1 -1
- package/dist/resolvers.cjs +1 -12
- package/dist/resolvers.d.cts +2 -2
- package/dist/resolvers.d.ts +2 -2
- package/dist/resolvers.js +1 -3
- package/dist/services.cjs +1 -20
- package/dist/services.js +1 -3
- package/dist/testing.cjs +3 -477
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +9 -10
- package/dist/testing.d.ts +9 -10
- package/dist/testing.js +3 -469
- package/dist/testing.js.map +1 -1
- package/dist/uom.cjs +1 -55
- package/dist/uom.d.cts +2 -2
- package/dist/uom.d.ts +2 -2
- package/dist/uom.js +1 -10
- package/dist/utilities.cjs +1 -36
- package/dist/utilities.js +1 -7
- package/dist/vm.cjs +1 -295
- package/dist/vm.cjs.map +1 -1
- package/dist/vm.d.cts +22 -10
- package/dist/vm.d.ts +22 -10
- package/dist/vm.js +1 -193
- package/dist/vm.js.map +1 -1
- package/dist/worker.cjs +2 -492
- package/dist/worker.cjs.map +1 -1
- package/dist/worker.d.cts +16 -17
- package/dist/worker.d.ts +16 -17
- package/dist/worker.js +2 -483
- package/dist/worker.js.map +1 -1
- package/package.json +1 -13
- package/dist/chunk-3BOK2LDK.js +0 -17
- package/dist/chunk-3BOK2LDK.js.map +0 -1
- package/dist/chunk-3VGDNEE3.js +0 -84
- package/dist/chunk-3VGDNEE3.js.map +0 -1
- package/dist/chunk-4K5W7EH2.cjs +0 -112
- package/dist/chunk-4K5W7EH2.cjs.map +0 -1
- package/dist/chunk-5EFKSKMA.js +0 -413
- package/dist/chunk-5EFKSKMA.js.map +0 -1
- package/dist/chunk-5HRB36DK.js +0 -405
- package/dist/chunk-5HRB36DK.js.map +0 -1
- package/dist/chunk-5ON7PUAZ.js +0 -12
- package/dist/chunk-5ON7PUAZ.js.map +0 -1
- package/dist/chunk-7AXJNQMF.cjs +0 -297
- package/dist/chunk-7AXJNQMF.cjs.map +0 -1
- package/dist/chunk-7JM3F4KL.js +0 -1795
- package/dist/chunk-7JM3F4KL.js.map +0 -1
- package/dist/chunk-7USV76HV.cjs +0 -341
- package/dist/chunk-7USV76HV.cjs.map +0 -1
- package/dist/chunk-A2DZ5BEJ.cjs +0 -1930
- package/dist/chunk-A2DZ5BEJ.cjs.map +0 -1
- package/dist/chunk-ADBA3XBE.cjs +0 -20
- package/dist/chunk-ADBA3XBE.cjs.map +0 -1
- package/dist/chunk-AKNGX4TZ.cjs +0 -236
- package/dist/chunk-AKNGX4TZ.cjs.map +0 -1
- package/dist/chunk-ALYRJ72W.cjs +0 -434
- package/dist/chunk-ALYRJ72W.cjs.map +0 -1
- package/dist/chunk-AMOJYLG2.cjs +0 -1692
- package/dist/chunk-AMOJYLG2.cjs.map +0 -1
- package/dist/chunk-AOH6UR2L.js +0 -825
- package/dist/chunk-AOH6UR2L.js.map +0 -1
- package/dist/chunk-AQNHHJMJ.cjs +0 -261
- package/dist/chunk-B7LXJ6LC.cjs +0 -36
- package/dist/chunk-B7LXJ6LC.cjs.map +0 -1
- package/dist/chunk-BESTLPRK.cjs +0 -6919
- package/dist/chunk-BESTLPRK.cjs.map +0 -1
- package/dist/chunk-BLI4NIQY.js +0 -98
- package/dist/chunk-BLI4NIQY.js.map +0 -1
- package/dist/chunk-BSPXMGIS.js +0 -455
- package/dist/chunk-BSPXMGIS.js.map +0 -1
- package/dist/chunk-C2OMO3WN.cjs +0 -2806
- package/dist/chunk-C2OMO3WN.cjs.map +0 -1
- package/dist/chunk-CSDQMDU2.js +0 -204
- package/dist/chunk-CSDQMDU2.js.map +0 -1
- package/dist/chunk-EJ3ILXX6.cjs +0 -223
- package/dist/chunk-EJ3ILXX6.cjs.map +0 -1
- package/dist/chunk-ENRIK36Q.cjs +0 -94
- package/dist/chunk-ENRIK36Q.cjs.map +0 -1
- package/dist/chunk-F4UB4XIL.js +0 -109
- package/dist/chunk-F4UB4XIL.js.map +0 -1
- package/dist/chunk-FD5ZZHEU.js +0 -92
- package/dist/chunk-FD5ZZHEU.js.map +0 -1
- package/dist/chunk-FE4RC37D.js +0 -2801
- package/dist/chunk-FE4RC37D.js.map +0 -1
- package/dist/chunk-FEAIOR7N.cjs +0 -91
- package/dist/chunk-FEAIOR7N.cjs.map +0 -1
- package/dist/chunk-FR7RNOPT.cjs +0 -3303
- package/dist/chunk-FR7RNOPT.cjs.map +0 -1
- package/dist/chunk-G2YPPLGX.cjs +0 -484
- package/dist/chunk-G2YPPLGX.cjs.map +0 -1
- package/dist/chunk-GCM5JHMX.js +0 -88
- package/dist/chunk-GCM5JHMX.js.map +0 -1
- package/dist/chunk-GDEU72RG.cjs +0 -829
- package/dist/chunk-GDEU72RG.cjs.map +0 -1
- package/dist/chunk-HKTQCQ4Z.cjs +0 -8383
- package/dist/chunk-HKTQCQ4Z.cjs.map +0 -1
- package/dist/chunk-HWHU642X.cjs +0 -316
- package/dist/chunk-HWHU642X.cjs.map +0 -1
- package/dist/chunk-ICEKS6YC.cjs +0 -507
- package/dist/chunk-ICEKS6YC.cjs.map +0 -1
- package/dist/chunk-IJGOFP2J.js +0 -6904
- package/dist/chunk-IJGOFP2J.js.map +0 -1
- package/dist/chunk-IQJGDZOP.js +0 -333
- package/dist/chunk-IQJGDZOP.js.map +0 -1
- package/dist/chunk-IT74O4BE.cjs +0 -456
- package/dist/chunk-IT74O4BE.cjs.map +0 -1
- package/dist/chunk-KXDQKVNX.cjs +0 -459
- package/dist/chunk-KXDQKVNX.cjs.map +0 -1
- package/dist/chunk-L2TE7PMO.cjs +0 -14
- package/dist/chunk-L2TE7PMO.cjs.map +0 -1
- package/dist/chunk-L5YHV6BQ.js +0 -499
- package/dist/chunk-L5YHV6BQ.js.map +0 -1
- package/dist/chunk-LO7HU5WB.cjs +0 -209
- package/dist/chunk-LO7HU5WB.cjs.map +0 -1
- package/dist/chunk-LSALB3IN.js +0 -292
- package/dist/chunk-LSALB3IN.js.map +0 -1
- package/dist/chunk-MI7OTUHL.cjs +0 -339
- package/dist/chunk-MI7OTUHL.cjs.map +0 -1
- package/dist/chunk-MIGXCBXT.cjs +0 -381
- package/dist/chunk-MIGXCBXT.cjs.map +0 -1
- package/dist/chunk-MVTOCRV2.js +0 -213
- package/dist/chunk-MVTOCRV2.js.map +0 -1
- package/dist/chunk-N7FNVFXW.cjs +0 -32
- package/dist/chunk-N7FNVFXW.cjs.map +0 -1
- package/dist/chunk-N7OA4WPJ.js +0 -362
- package/dist/chunk-N7OA4WPJ.js.map +0 -1
- package/dist/chunk-NAWZATKT.js +0 -478
- package/dist/chunk-NAWZATKT.js.map +0 -1
- package/dist/chunk-NLNDMWZC.js +0 -31
- package/dist/chunk-NLNDMWZC.js.map +0 -1
- package/dist/chunk-ORM7CHYZ.js +0 -1531
- package/dist/chunk-ORM7CHYZ.js.map +0 -1
- package/dist/chunk-OUHT5Z36.cjs +0 -393
- package/dist/chunk-OUHT5Z36.cjs.map +0 -1
- package/dist/chunk-PCZVMMWU.cjs +0 -74
- package/dist/chunk-PCZVMMWU.cjs.map +0 -1
- package/dist/chunk-RNKDIXDV.js +0 -336
- package/dist/chunk-RNKDIXDV.js.map +0 -1
- package/dist/chunk-SBUFNJVE.js +0 -258
- package/dist/chunk-SBUFNJVE.js.map +0 -1
- package/dist/chunk-TC6BTUSU.cjs +0 -1799
- package/dist/chunk-TC6BTUSU.cjs.map +0 -1
- package/dist/chunk-TPOK3UNI.js +0 -8355
- package/dist/chunk-TPOK3UNI.js.map +0 -1
- package/dist/chunk-UF6JG5SG.js +0 -312
- package/dist/chunk-UF6JG5SG.js.map +0 -1
- package/dist/chunk-UKQHXPGW.js +0 -30
- package/dist/chunk-UKQHXPGW.js.map +0 -1
- package/dist/chunk-V4XG5QF6.js +0 -1685
- package/dist/chunk-V4XG5QF6.js.map +0 -1
- package/dist/chunk-VEKIWQ3F.cjs +0 -39
- package/dist/chunk-VEKIWQ3F.cjs.map +0 -1
- package/dist/chunk-WMQRJTAO.js +0 -3266
- package/dist/chunk-WMQRJTAO.js.map +0 -1
- package/dist/chunk-X6K3HUOY.cjs +0 -86
- package/dist/chunk-X6K3HUOY.cjs.map +0 -1
- package/dist/chunk-XBTEO4OB.js +0 -391
- package/dist/chunk-XBTEO4OB.js.map +0 -1
- package/dist/chunk-XIYYHA65.cjs +0 -101
- package/dist/chunk-XIYYHA65.cjs.map +0 -1
- package/dist/chunk-YJHY7CMN.cjs +0 -1534
- package/dist/chunk-YLJ4XMA6.js +0 -33
- package/dist/chunk-YLJ4XMA6.js.map +0 -1
- package/dist/chunk-YNIWOYW6.js +0 -232
- package/dist/chunk-YNIWOYW6.js.map +0 -1
- package/dist/chunk-Z2XP767T.cjs +0 -35
- package/dist/chunk-Z2XP767T.cjs.map +0 -1
- package/dist/chunk-Z4X2RWOF.js +0 -37
- package/dist/chunk-Z4X2RWOF.js.map +0 -1
- package/dist/chunk-ZN6YYPIW.js +0 -67
- package/dist/chunk-ZN6YYPIW.js.map +0 -1
- package/dist/chunk-ZNFFTYWH.js +0 -1854
- package/dist/chunk-ZNFFTYWH.js.map +0 -1
- package/dist/variables.cjs +0 -17
- package/dist/variables.cjs.map +0 -1
- package/dist/variables.d.cts +0 -87
- package/dist/variables.d.ts +0 -87
- package/dist/variables.js +0 -4
- package/dist/variables.js.map +0 -1
package/dist/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/worker/client.ts","../src/worker/serialize.ts","../src/worker/runtime.ts","../src/worker/transport.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA8HA,IAAM,qBAAN,MAAiD;AAAA,EAWhD,YAAY,SAAA,EAA4B;AATxC,IAAA,IAAA,CAAQ,MAAA,GAAS,CAAA;AACjB,IAAA,IAAA,CAAiB,OAAA,uBAAc,GAAA,EAA4B;AAI3D;AAAA;AAAA;AAAA,IAAA,IAAA,CAAiB,iBAAA,uBAAwB,GAAA,EAA0C;AACnF,IAAA,IAAA,CAAiB,mBAAA,uBAA0B,GAAA,EAAuC;AAClF,IAAA,IAAA,CAAQ,UAAA,GAAa,KAAA;AAGpB,IAAA,IAAA,CAAK,SAAA,GAAY,SAAA;AACjB,IAAA,IAAA,CAAK,UAAU,SAAA,CAAU,CAAC,QAAQ,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA;AAAA,EACtD;AAAA;AAAA,EAGA,KAAK,OAAA,EAA6C;AACjD,IAAA,MAAM,KAAK,IAAA,CAAK,MAAA,EAAA;AAChB,IAAA,OAAO,IAAI,OAAA,CAAc,CAAC,OAAA,EAAS,MAAA,KAAW;AAC7C,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,EAAA,EAAI,EAAE,SAAS,MAAM,OAAA,EAAQ,EAAG,MAAA,EAAQ,CAAA;AACzD,MAAA,IAAA,CAAK,UAAU,WAAA,CAAY;AAAA,QAC1B,IAAA,EAAM,MAAA;AAAA,QACN,EAAA;AAAA,QACA,YAAY,OAAA,CAAQ,UAAA;AAAA,QACpB,gBAAgB,OAAA,CAAQ,cAAA;AAAA,QACxB,QAAQ,OAAA,CAAQ,MAAA;AAAA,QAChB,UAAU,OAAA,CAAQ,QAAA;AAAA,QAClB,YAAY,OAAA,CAAQ;AAAA,OACpB,CAAA;AAAA,IACF,CAAC,CAAA;AAAA,EACF;AAAA,EAEA,aAAA,CACC,OACA,OAAA,EACmC;AAGnC,IAAA,MAAM,EAAE,MAAA,EAAQ,GAAG,OAAA,EAAQ,GAAI,WAAW,EAAC;AAC3C,IAAA,MAAM,eAAe,MAAA,CAAO,IAAA,CAAK,OAAO,CAAA,CAAE,MAAA,GAAS,IAAK,OAAA,GAAoC,MAAA;AAC5F,IAAA,OAAO,KAAK,IAAA,CAA8B,eAAA,EAAiB,CAAC,KAAA,EAAO,YAAY,GAAG,MAAM,CAAA;AAAA,EACzF;AAAA,EAEA,aAAA,CAAc,OAAiB,OAAA,EAA8D;AAC5F,IAAA,OAAO,KAAK,IAAA,CAA6B,eAAA,EAAiB,CAAC,KAAK,CAAA,EAAG,SAAS,MAAM,CAAA;AAAA,EACnF;AAAA,EAEA,kBAAA,CAAmB,YAAoB,OAAA,EAAyD;AAC/F,IAAA,OAAO,KAAK,IAAA,CAAwB,oBAAA,EAAsB,CAAC,UAAU,CAAA,EAAG,SAAS,MAAM,CAAA;AAAA,EACxF;AAAA,EAEA,WAAW,QAAA,EAA4D;AACtE,IAAA,IAAA,CAAK,iBAAA,CAAkB,IAAI,QAAQ,CAAA;AACnC,IAAA,OAAO,MAAM,IAAA,CAAK,iBAAA,CAAkB,MAAA,CAAO,QAAQ,CAAA;AAAA,EACpD;AAAA,EAEA,aAAa,QAAA,EAAyD;AACrE,IAAA,IAAA,CAAK,mBAAA,CAAoB,IAAI,QAAQ,CAAA;AACrC,IAAA,OAAO,MAAM,IAAA,CAAK,mBAAA,CAAoB,MAAA,CAAO,QAAQ,CAAA;AAAA,EACtD;AAAA,EAEA,SAAA,GAAkB;AACjB,IAAA,IAAI,KAAK,UAAA,EAAY;AACrB,IAAA,IAAA,CAAK,UAAA,GAAa,IAAA;AAClB,IAAA,MAAM,QAAQ,qBAAA,EAAsB;AACpC,IAAA,KAAA,MAAW,KAAA,IAAS,IAAA,CAAK,OAAA,CAAQ,MAAA,EAAO,EAAG;AAC1C,MAAA,IAAA,CAAK,OAAO,KAAK,CAAA;AACjB,MAAA,KAAA,CAAM,OAAO,KAAK,CAAA;AAAA,IACnB;AACA,IAAA,IAAA,CAAK,QAAQ,KAAA,EAAM;AAGnB,IAAA,IAAA,CAAK,kBAAkB,KAAA,EAAM;AAC7B,IAAA,IAAA,CAAK,oBAAoB,KAAA,EAAM;AAC/B,IAAA,IAAA,CAAK,UAAU,SAAA,EAAU;AAAA,EAC1B;AAAA;AAAA,EAGQ,IAAA,CAAQ,MAAA,EAAsB,IAAA,EAAyB,MAAA,EAAkC;AAChG,IAAA,IAAI,KAAK,UAAA,EAAY,OAAO,OAAA,CAAQ,MAAA,CAAO,uBAAuB,CAAA;AAClE,IAAA,IAAI,QAAQ,OAAA,EAAS,OAAO,QAAQ,MAAA,CAAO,oBAAA,CAAqB,MAAM,CAAC,CAAA;AAEvE,IAAA,MAAM,KAAK,IAAA,CAAK,MAAA,EAAA;AAChB,IAAA,OAAO,IAAI,OAAA,CAAW,CAAC,OAAA,EAAS,MAAA,KAAW;AAC1C,MAAA,MAAM,KAAA,GAAwB,EAAE,OAAA,EAA8C,MAAA,EAAO;AAErF,MAAA,IAAI,MAAA,EAAQ;AACX,QAAA,MAAM,UAAU,MAAY;AAE3B,UAAA,IAAI,CAAC,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA,EAAG;AAC3B,UAAA,IAAA,CAAK,OAAA,CAAQ,OAAO,EAAE,CAAA;AACtB,UAAA,IAAA,CAAK,UAAU,WAAA,CAAY,EAAE,IAAA,EAAM,QAAA,EAAU,IAAI,CAAA;AACjD,UAAA,MAAA,CAAO,oBAAA,CAAqB,MAAM,CAAC,CAAA;AAAA,QACpC,CAAA;AACA,QAAA,KAAA,CAAM,MAAA,GAAS,MAAA;AACf,QAAA,KAAA,CAAM,OAAA,GAAU,OAAA;AAChB,QAAA,MAAA,CAAO,iBAAiB,OAAA,EAAS,OAAA,EAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,MACzD;AAEA,MAAA,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAA,EAAI,KAAK,CAAA;AAC1B,MAAA,IAAA,CAAK,SAAA,CAAU,YAAY,EAAE,IAAA,EAAM,WAAW,EAAA,EAAI,MAAA,EAAQ,MAAM,CAAA;AAAA,IACjE,CAAC,CAAA;AAAA,EACF;AAAA;AAAA,EAGQ,UAAU,GAAA,EAAoB;AACrC,IAAA,MAAM,OAAA,GAAU,GAAA;AAChB,IAAA,QAAQ,QAAQ,IAAA;AAAM,MACrB,KAAK,OAAA;AAAA,MACL,KAAK,QAAA,EAAU;AACd,QAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,IAAA,KAAS,QAAA,GAAW,QAAQ,KAAA,GAAQ,MAAA;AAC1D,QAAA,IAAA,CAAK,MAAA,CAAO,QAAQ,EAAA,EAAI,CAAC,UAAU,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAC,CAAA;AACvD,QAAA;AAAA,MACD;AAAA,MACA,KAAK,OAAA;AACJ,QAAA,IAAA,CAAK,MAAA,CAAO,OAAA,CAAQ,EAAA,EAAI,CAAC,KAAA,KAAU,KAAA,CAAM,MAAA,CAAO,sBAAA,CAAuB,OAAA,CAAQ,KAAK,CAAC,CAAC,CAAA;AACtF,QAAA;AAAA,MACD,KAAK,cAAA;AAIJ,QAAA,KAAA,MAAW,QAAA,IAAY,CAAC,GAAG,IAAA,CAAK,iBAAiB,CAAA,EAAG,QAAA,CAAS,QAAQ,KAAK,CAAA;AAC1E,QAAA;AAAA,MACD,KAAK,aAAA;AACJ,QAAA,KAAA,MAAW,QAAA,IAAY,CAAC,GAAG,IAAA,CAAK,mBAAmB,CAAA,EAAG;AACrD,UAAA,QAAA,CAAS;AAAA,YACR,UAAU,OAAA,CAAQ,QAAA;AAAA,YAClB,WAAW,OAAA,CAAQ,SAAA;AAAA,YACnB,KAAA,EAAO,sBAAA,CAAuB,OAAA,CAAQ,KAAK;AAAA,WAC3C,CAAA;AAAA,QACF;AACA,QAAA;AAAA;AACF,EACD;AAAA;AAAA,EAGQ,MAAA,CAAO,IAAY,KAAA,EAA8C;AACxE,IAAA,MAAM,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,EAAE,CAAA;AACjC,IAAA,IAAI,CAAC,KAAA,EAAO;AACZ,IAAA,IAAA,CAAK,OAAA,CAAQ,OAAO,EAAE,CAAA;AACtB,IAAA,IAAA,CAAK,OAAO,KAAK,CAAA;AACjB,IAAA,KAAA,CAAM,KAAK,CAAA;AAAA,EACZ;AAAA;AAAA,EAGQ,OAAO,KAAA,EAA6B;AAC3C,IAAA,IAAI,KAAA,CAAM,UAAU,KAAA,CAAM,OAAA,QAAe,MAAA,CAAO,mBAAA,CAAoB,OAAA,EAAS,KAAA,CAAM,OAAO,CAAA;AAAA,EAC3F;AACD,CAAA;AAeA,eAAsB,mBAAmB,OAAA,EAAqD;AAC7F,EAAA,MAAM,MAAA,GAAS,IAAI,kBAAA,CAAmB,OAAA,CAAQ,SAAS,CAAA;AACvD,EAAA,MAAM,MAAA,CAAO,KAAK,OAAO,CAAA;AACzB,EAAA,OAAO,MAAA;AACR;;;ACxQA,SAAS,aAAa,CAAA,EAA6C;AAClE,EAAA,OAAO,CAAA,GAAI,CAAA,GAAI,UAAA,GAAa,CAAA,GAAI,IAAI,WAAA,GAAc,KAAA;AACnD;AAGA,SAAS,gBAAgB,CAAA,EAAiC;AACzD,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,IAAA,CAAK,GAAA,CAAI,CAAC,IAAA,KAAiD;AAO1E,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,SAAS,IAAA,EAAM,OAAO,eAAe,IAAI,CAAA;AACzE,IAAA,IAAI,OAAO,IAAA,KAAS,QAAA,IAAY,CAAC,MAAA,CAAO,SAAS,IAAI,CAAA,EAAG,OAAO,YAAA,CAAa,IAAI,CAAA;AAChF,IAAA,OAAO,IAAA;AAAA,EACR,CAAC,CAAA;AACD,EAAA,OAAO,EAAE,IAAA,EAAM,CAAA,CAAE,IAAA,EAAM,IAAA,EAAM,EAAE,IAAA,EAAM,KAAA,EAAO,WAAA,EAAa,CAAA,CAAE,WAAA,EAAY;AACxE;AAUO,SAAS,cAAA,CAAe,OAAc,QAAA,EAAgD;AAC5F,EAAA,MAAM,OAAA,GAAU,MAAM,QAAA,EAAS;AAC/B,EAAA,MAAM,GAAA,GAAuB;AAAA,IAC5B,MAAM,KAAA,CAAM,IAAA;AAAA,IACZ,IAAA,EAAM,WAAA,CAAY,KAAA,EAAO,QAAQ,CAAA;AAAA;AAAA;AAAA;AAAA,IAIjC,MAAA,EAAQ,MAAA,CAAO,QAAA,CAAS,OAAO,IAAI,OAAA,GAAU;AAAA,GAC9C;AACA,EAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,OAAO,CAAA,EAAG;AAC9B,IAAA,GAAA,CAAI,SAAA,GAAY,aAAa,OAAO,CAAA;AAAA,EACrC;AAEA,EAAA,IAAI,KAAA,CAAM,IAAA,KAAS,MAAA,EAAW,GAAA,CAAI,OAAO,KAAA,CAAM,IAAA;AAC/C,EAAA,IAAI,KAAA,CAAM,QAAA,KAAa,MAAA,EAAW,GAAA,CAAI,WAAW,KAAA,CAAM,QAAA;AAEvD,EAAA,MAAM,MAAM,KAAA,CAAM,KAAA;AAClB,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAI5B,IAAA,GAAA,CAAI,MAAA,GAAS,IAAI,QAAA,EAAS;AAAA,EAC3B,CAAA,MAAA,IAAW,MAAM,IAAA,KAAA,CAAA,eAA2B;AAC3C,IAAA,GAAA,CAAI,MAAA,GAAS,gBAAgB,GAAiB,CAAA;AAAA,EAC/C,CAAA,MAAA,IAAW,MAAM,IAAA,KAAA,CAAA,cAA0B;AAC1C,IAAA,MAAM,CAAA,GAAI,GAAA;AACV,IAAA,GAAA,CAAI,QAAQ,EAAE,GAAA,EAAK,EAAE,GAAA,EAAK,GAAA,EAAK,EAAE,GAAA,EAAI;AAAA,EACtC,CAAA,MAAA,IAAW,MAAM,IAAA,KAAA,EAAA,eAA2B;AAC3C,IAAA,MAAM,CAAA,GAAI,GAAA;AACV,IAAA,GAAA,CAAI,MAAA,GAAS,EAAE,GAAA,EAAK,WAAA,CAAY,CAAC,GAAG,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,GAAG,CAAA,CAAE,CAAA,EAAG,CAAA,EAAG,CAAA,CAAE,CAAA,EAAG,MAAA,EAAQ,EAAE,MAAA,EAAQ,GAAA,EAAK,YAAA,CAAa,CAAC,CAAA,EAAE;AAAA,EAC5G;AAEA,EAAA,OAAO,GAAA;AACR;AAGA,SAAS,cAAA,CAAe,OAAiC,QAAA,EAAuD;AAC/G,EAAA,OAAO,KAAA,GAAQ,cAAA,CAAe,KAAA,EAAO,QAAQ,CAAA,GAAI,IAAA;AAClD;AAGA,SAAS,oBAAA,CAAqB,OAA4B,QAAA,EAAsD;AAC/G,EAAA,OAAO;AAAA,IACN,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,KAAK,KAAA,CAAM,GAAA;AAAA,IACX,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,YAAY,KAAA,CAAM,UAAA;AAAA,IAClB,cAAc,KAAA,CAAM,YAAA;AAAA,IACpB,MAAA,EAAQ,cAAA,CAAe,KAAA,CAAM,MAAA,EAAQ,QAAQ,CAAA;AAAA,IAC7C,KAAA,EAAO,MAAM,KAAA,IAAS;AAAA,GACvB;AACD;AAGO,SAAS,mBAAA,CAAoB,MAAkB,QAAA,EAAqD;AAC1G,EAAA,OAAO;AAAA,IACN,YAAY,IAAA,CAAK,UAAA;AAAA,IACjB,MAAM,IAAA,CAAK,IAAA;AAAA,IACX,eAAe,IAAA,CAAK,aAAA;AAAA,IACpB,aAAa,IAAA,CAAK,WAAA;AAAA,IAClB,SAAS,IAAA,CAAK,OAAA;AAAA,IACd,iBAAiB,IAAA,CAAK,eAAA;AAAA,IACtB,YAAA,EAAc,KAAK,YAAA,CAAa,GAAA,CAAI,CAAC,KAAA,KAAU,oBAAA,CAAqB,KAAA,EAAO,QAAQ,CAAC,CAAA;AAAA,IACpF,YAAY,IAAA,CAAK,UAAA;AAAA,IACjB,MAAA,EAAQ,cAAA,CAAe,IAAA,CAAK,MAAA,EAAQ,QAAQ,CAAA;AAAA,IAC5C,OAAO,IAAA,CAAK;AAAA,GACb;AACD;AAGO,SAAS,sBAAA,CAAuB,QAAuB,QAAA,EAAwD;AACrH,EAAA,MAAM,GAAA,GAA+B;AAAA,IACpC,KAAA,EAAO,OAAO,KAAA,CAAM,GAAA,CAAI,CAAC,IAAA,KAAS,mBAAA,CAAoB,IAAA,EAAM,QAAQ,CAAC,CAAA;AAAA,IACrE,YAAY,MAAA,CAAO,UAAA;AAAA,IACnB,MAAA,EAAQ,CAAC,GAAG,MAAA,CAAO,MAAM;AAAA,GAC1B;AAGA,EAAA,IAAI,MAAA,CAAO,WAAA,KAAgB,MAAA,EAAW,GAAA,CAAI,cAAc,MAAA,CAAO,WAAA;AAC/D,EAAA,OAAO,GAAA;AACR;;;ACpFA,SAAS,eAAA,CAAgB,WAA6B,KAAA,EAA+C;AACpG,EAAA,IAAI,KAAA,KAAU,QAAW,OAAO,SAAA;AAChC,EAAA,MAAM,MAAA,GAAS,IAAI,GAAA,CAAI,SAAA,CAAU,GAAA,CAAI,CAAC,GAAA,KAAQ,CAAC,GAAA,CAAI,IAAA,EAAM,GAAG,CAAC,CAAC,CAAA;AAC9D,EAAA,MAAM,WAA6B,EAAC;AACpC,EAAA,KAAA,MAAW,QAAQ,KAAA,EAAO;AACzB,IAAA,MAAM,GAAA,GAAM,MAAA,CAAO,GAAA,CAAI,IAAI,CAAA;AAC3B,IAAA,IAAI,CAAC,GAAA,EAAK;AACT,MAAA,MAAM,YAAA,CAAa,MAAA;AAAA,QAClB,gBAAA,CAAiB,sBAAA;AAAA,QACjB,qBAAqB,IAAI,CAAA,qCAAA,CAAA;AAAA,QACzB,EAAE,MAAM,SAAA,EAAW,CAAC,GAAG,MAAA,CAAO,IAAA,EAAM,CAAA;AAAE,OACvC;AAAA,IACD;AACA,IAAA,QAAA,CAAS,KAAK,GAAG,CAAA;AAAA,EAClB;AACA,EAAA,OAAO,QAAA;AACR;AAQO,SAAS,kBAAA,CAAmB,SAAA,EAA4B,OAAA,GAAgC,EAAC,EAAe;AAC9G,EAAA,MAAM,SAAA,GAAY,QAAQ,QAAA,IAAY,gBAAA;AAEtC,EAAA,IAAI,MAAA,GAAkC,IAAA;AACtC,EAAA,IAAI,UAAA;AAGJ,EAAA,MAAM,QAAA,uBAAe,GAAA,EAA6B;AAMlD,EAAA,IAAI,aAAA,uBAAoB,GAAA,EAAoB;AAQ5C,EAAA,IAAI,kBAAA,GAA6C,IAAA;AAGjD,EAAA,IAAI,aAAA,GAAqC,IAAA;AAEzC,EAAA,MAAM,IAAA,GAAO,CAAC,OAAA,KAAuC,SAAA,CAAU,YAAY,OAAO,CAAA;AAElF,EAAA,MAAM,IAAA,GAAO,CAAC,EAAA,EAAY,KAAA,KAAyB;AAClD,IAAA,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,EAAA,EAAI,KAAA,EAAO,qBAAqB,qBAAA,CAAsB,KAAK,CAAC,CAAA,EAAG,CAAA;AAAA,EACtF,CAAA;AAQA,EAAA,MAAM,WAAA,GAAc,CAAC,OAAA,KAAiD;AACrE,IAAA,MAAM,GAAA,uBAAU,GAAA,EAAoB;AACpC,IAAA,IAAI,OAAA,CAAQ,WAAW,eAAA,EAAiB;AACvC,MAAC,QAAQ,IAAA,CAAK,CAAC,CAAA,CAAa,KAAA,CAAM,IAAI,CAAA,CAAE,OAAA,CAAQ,CAAC,IAAA,EAAM,UAAU,GAAA,CAAI,GAAA,CAAI,KAAA,GAAQ,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,IAC1F,CAAA,MAAA,IAAW,OAAA,CAAQ,MAAA,KAAW,eAAA,EAAiB;AAC9C,MAAC,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAA,CAAe,OAAA,CAAQ,CAAC,IAAA,EAAM,KAAA,KAAU,GAAA,CAAI,GAAA,CAAI,KAAA,GAAQ,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,IAChF,CAAA,MAAO;AACN,MAAA,GAAA,CAAI,GAAA,CAAI,EAAA,EAAI,OAAA,CAAQ,IAAA,CAAK,CAAC,CAAW,CAAA;AAAA,IACtC;AACA,IAAA,OAAO,GAAA;AAAA,EACR,CAAA;AAYA,EAAA,MAAM,gBAAA,GAAmB,CAAC,GAAA,EAAuB,KAAA,KAAsC;AACtF,IAAA,IAAI,KAAA,CAAM,SAAS,OAAA,EAAS;AAC3B,MAAA,IAAA,CAAK;AAAA,QACJ,IAAA,EAAM,aAAA;AAAA,QACN,UAAU,KAAA,CAAM,QAAA;AAAA,QAChB,WAAW,KAAA,CAAM,SAAA;AAAA,QACjB,KAAA,EAAO,oBAAA,CAAqB,qBAAA,CAAsB,KAAA,CAAM,KAAK,CAAC;AAAA,OAC9D,CAAA;AACD,MAAA;AAAA,IACD;AAEA,IAAA,MAAM,QAA6B,EAAC;AACpC,IAAA,KAAA,MAAW,UAAA,IAAc,MAAM,WAAA,EAAa;AAC3C,MAAA,MAAM,IAAA,GAAO,aAAA,CAAc,GAAA,CAAI,UAAU,CAAA;AACzC,MAAA,IAAI,SAAS,MAAA,EAAW;AACxB,MAAA,IAAI;AACH,QAAA,MAAM,QAAQ,GAAA,CAAI,YAAA,CAAa,UAAA,EAAY,IAAI,EAAE,CAAC,CAAA;AAClD,QAAA,IAAI,KAAA,EAAO,KAAA,CAAM,IAAA,CAAK,EAAE,UAAA,EAAY,OAAO,cAAA,CAAe,KAAA,EAAO,UAAU,CAAA,EAAG,CAAA;AAAA,MAC/E,CAAA,CAAA,MAAQ;AAAA,MAKR;AAAA,IACD;AACA,IAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG,IAAA,CAAK,EAAE,IAAA,EAAM,cAAA,EAAgB,OAAO,CAAA;AAAA,EAC3D,CAAA;AAQA,EAAA,MAAM,cAAA,GAAiB,CAAC,GAAA,KAAgC;AACvD,IAAA,aAAA,IAAgB;AAChB,IAAA,MAAM,MAAA,GAAS,GAAA,CAAI,cAAA,EAAe,CAAE,SAAA,EAAU;AAC9C,IAAA,aAAA,GAAgB,MAAM,KAAK,MAAA,CAAO,MAAA,EAAO;AACzC,IAAA,KAAA,CAAM,YAAY;AACjB,MAAA,IAAI;AACH,QAAA,WAAS;AACR,UAAA,MAAM,EAAE,IAAA,EAAM,KAAA,EAAM,GAAI,MAAM,OAAO,IAAA,EAAK;AAC1C,UAAA,IAAI,IAAA,EAAM;AACV,UAAA,gBAAA,CAAiB,KAAK,KAAK,CAAA;AAAA,QAC5B;AAAA,MACD,CAAA,CAAA,MAAQ;AAAA,MAER;AAAA,IACD,CAAA,GAAG;AAAA,EACJ,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,CAAC,OAAA,KAA+B;AAClD,IAAA,IAAI;AACH,MAAA,MAAM,QAAA,GAAW,eAAA,CAAgB,SAAA,EAAW,OAAA,CAAQ,QAAQ,CAAA;AAC5D,MAAA,MAAA,GAAS,IAAI,gBAAA;AAAA,QACZ,QAAQ,UAAA,IAAc,IAAA;AAAA,QACtB,QAAQ,cAAA,IAAkB,KAAA;AAAA,QAC1B,OAAA,CAAQ,MAAA;AAAA,QACR,KAAA,CAAA;AAAA,QACA;AAAA,OACD;AACA,MAAA,UAAA,GAAa,OAAA,CAAQ,UAAA;AAIrB,MAAA,cAAA,CAAe,MAAM,CAAA;AACrB,MAAA,IAAA,CAAK,EAAE,IAAA,EAAM,OAAA,EAAS,EAAA,EAAI,OAAA,CAAQ,IAAI,CAAA;AAAA,IACvC,SAAS,KAAA,EAAO;AAIf,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,KAAK,CAAA;AAAA,IACvB;AAAA,EACD,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,GAAA,EAAuB,OAAA,KAAqC;AAC9E,IAAA,MAAM,EAAE,MAAA,EAAQ,IAAA,EAAK,GAAI,OAAA;AACzB,IAAA,QAAQ,MAAA;AAAQ,MACf,KAAK,eAAA;AACJ,QAAA,OAAO,sBAAA,CAAuB,GAAA,CAAI,aAAA,CAAc,IAAA,CAAK,CAAC,GAAa,IAAA,CAAK,CAAC,CAAU,CAAA,EAAG,UAAU,CAAA;AAAA,MACjG,KAAK,eAAA;AACJ,QAAA,OAAO,GAAA,CAAI,aAAA,CAAc,IAAA,CAAK,CAAC,CAAa,CAAA,CAAE,GAAA,CAAI,CAAC,IAAA,KAAS,mBAAA,CAAoB,IAAA,EAAM,UAAU,CAAC,CAAA;AAAA,MAClG,KAAK,oBAAA;AACJ,QAAA,OAAO,GAAA,CAAI,kBAAA,CAAmB,IAAA,CAAK,CAAC,CAAW,CAAA,CAAE,GAAA,CAAI,CAAC,KAAA,KAAU,cAAA,CAAe,KAAA,EAAO,UAAU,CAAC,CAAA;AAAA,MAClG;AACC,QAAA,MAAM,YAAA,CAAa,SAAA;AAAA,UAClB,gBAAA,CAAiB,qBAAA;AAAA,UACjB,CAAA,wCAAA,EAA2C,MAAA,CAAO,MAAM,CAAC,CAAA,CAAA,CAAA;AAAA,UACzD,EAAE,MAAA;AAAO,SACV;AAAA;AACF,EACD,CAAA;AAEA,EAAA,MAAM,aAAA,GAAgB,CAAC,OAAA,KAAkC;AACxD,IAAA,MAAM,GAAA,GAAM,MAAA;AACZ,IAAA,IAAI,CAAC,GAAA,EAAK;AACT,MAAA,IAAA;AAAA,QACC,OAAA,CAAQ,EAAA;AAAA,QACR,YAAA,CAAa,SAAA;AAAA,UACZ,gBAAA,CAAiB,sBAAA;AAAA,UACjB;AAAA;AACD,OACD;AACA,MAAA;AAAA,IACD;AAOA,IAAA,kBAAA,EAAoB,KAAA,EAAM;AAO1B,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,kBAAA,GAAqB,UAAA;AACrB,IAAA,aAAA,GAAgB,YAAY,OAAO,CAAA;AACnC,IAAA,QAAA,CAAS,GAAA,CAAI,OAAA,CAAQ,EAAA,EAAI,UAAU,CAAA;AACnC,IAAA,GAAA,CAAI,kBAAA,CAAmB,WAAW,MAAM,CAAA;AAExC,IAAA,IAAI;AACH,MAAA,MAAM,KAAA,GAAQ,SAAA,CAAU,GAAA,EAAK,OAAO,CAAA;AACpC,MAAA,IAAA,CAAK,EAAE,IAAA,EAAM,QAAA,EAAU,IAAI,OAAA,CAAQ,EAAA,EAAI,OAAO,CAAA;AAAA,IAC/C,SAAS,KAAA,EAAO;AACf,MAAA,IAAA,CAAK,OAAA,CAAQ,IAAI,KAAK,CAAA;AAAA,IACvB,CAAA,SAAE;AACD,MAAA,QAAA,CAAS,MAAA,CAAO,QAAQ,EAAE,CAAA;AAC1B,MAAA,GAAA,CAAI,mBAAmB,IAAI,CAAA;AAAA,IAC5B;AAAA,EACD,CAAA;AAEA,EAAA,SAAA,CAAU,SAAA,CAAU,CAAC,GAAA,KAAQ;AAC5B,IAAA,MAAM,OAAA,GAAU,GAAA;AAChB,IAAA,QAAQ,QAAQ,IAAA;AAAM,MACrB,KAAK,MAAA;AACJ,QAAA,UAAA,CAAW,OAAO,CAAA;AAClB,QAAA;AAAA,MACD,KAAK,SAAA;AACJ,QAAA,aAAA,CAAc,OAAO,CAAA;AACrB,QAAA;AAAA,MACD,KAAK,QAAA;AAIJ,QAAA,QAAA,CAAS,GAAA,CAAI,OAAA,CAAQ,EAAE,CAAA,EAAG,KAAA,EAAM;AAChC,QAAA;AAAA;AACF,EACD,CAAC,CAAA;AAED,EAAA,OAAO,MAAM;AACZ,IAAA,aAAA,IAAgB;AAChB,IAAA,aAAA,GAAgB,IAAA;AAChB,IAAA,kBAAA,EAAoB,KAAA,EAAM;AAC1B,IAAA,kBAAA,GAAqB,IAAA;AACrB,IAAA,aAAA,uBAAoB,GAAA,EAAI;AACxB,IAAA,KAAA,MAAW,UAAA,IAAc,QAAA,CAAS,MAAA,EAAO,aAAc,KAAA,EAAM;AAC7D,IAAA,QAAA,CAAS,KAAA,EAAM;AACf,IAAA,MAAA,EAAQ,KAAA,EAAM;AACd,IAAA,MAAA,GAAS,IAAA;AACT,IAAA,SAAA,CAAU,SAAA,EAAU;AAAA,EACrB,CAAA;AACD;;;ACvQA,SAAS,aAAgB,KAAA,EAAa;AACrC,EAAA,OAAO,OAAO,UAAA,CAAW,eAAA,KAAoB,UAAA,GAC1C,UAAA,CAAW,eAAA,CAAgB,KAAK,CAAA,GAChC,IAAA,CAAK,KAAA,CAAM,IAAA,CAAK,SAAA,CAAU,KAAK,CAAC,CAAA;AACpC;AAaO,SAAS,sBAAA,GAA6E;AAC5F,EAAA,IAAI,aAAA,GAAqD,IAAA;AACzD,EAAA,IAAI,WAAA,GAAmD,IAAA;AACvD,EAAA,IAAI,KAAA,GAAQ,IAAA;AAIZ,EAAA,MAAM,OAAA,GAAU,CAAC,MAAA,EAAmD,OAAA,KAA2B;AAC9F,IAAA,MAAM,MAAA,GAAS,aAAa,OAAO,CAAA;AACnC,IAAA,cAAA,CAAe,MAAM;AACpB,MAAA,IAAI,CAAC,KAAA,EAAO;AACZ,MAAA,MAAA,KAAW,MAAM,CAAA;AAAA,IAClB,CAAC,CAAA;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,MAAA,GAA0B;AAAA,IAC/B,aAAa,CAAC,OAAA,KAAY,OAAA,CAAQ,MAAM,aAAa,OAAO,CAAA;AAAA,IAC5D,SAAA,EAAW,CAAC,OAAA,KAAY;AACvB,MAAA,aAAA,GAAgB,OAAA;AAAA,IACjB,CAAA;AAAA,IACA,WAAW,MAAM;AAChB,MAAA,KAAA,GAAQ,KAAA;AAAA,IACT;AAAA,GACD;AAEA,EAAA,MAAM,IAAA,GAAwB;AAAA,IAC7B,aAAa,CAAC,OAAA,KAAY,OAAA,CAAQ,MAAM,eAAe,OAAO,CAAA;AAAA,IAC9D,SAAA,EAAW,CAAC,OAAA,KAAY;AACvB,MAAA,WAAA,GAAc,OAAA;AAAA,IACf,CAAA;AAAA,IACA,WAAW,MAAM;AAChB,MAAA,KAAA,GAAQ,KAAA;AAAA,IACT;AAAA,GACD;AAEA,EAAA,OAAO,EAAE,QAAQ,IAAA,EAAK;AACvB;AAqBO,SAAS,qBAAqB,MAAA,EAA0C;AAC9E,EAAA,OAAO;AAAA,IACN,WAAA,EAAa,CAAC,OAAA,KAAY,MAAA,CAAO,YAAY,OAAO,CAAA;AAAA,IACpD,SAAA,EAAW,CAAC,OAAA,KAAY;AACvB,MAAA,MAAM,QAAA,GAAW,CAAC,KAAA,KAAmC,OAAA,CAAQ,MAAM,IAAI,CAAA;AACvE,MAAA,IAAI,OAAO,MAAA,CAAO,gBAAA,KAAqB,UAAA,EAAY;AAClD,QAAA,MAAA,CAAO,gBAAA,CAAiB,WAAW,QAAQ,CAAA;AAAA,MAC5C,CAAA,MAAO;AACN,QAAA,MAAA,CAAO,SAAA,GAAY,QAAA;AAAA,MACpB;AACA,MAAA,MAAA,CAAO,KAAA,IAAQ;AAAA,IAChB,CAAA;AAAA;AAAA;AAAA,IAGA,WAAW,MAAM;AAChB,MAAA,MAAA,CAAO,SAAA,IAAY;AACnB,MAAA,MAAA,CAAO,KAAA,IAAQ;AAAA,IAChB;AAAA,GACD;AACD;AAmBO,SAAS,qBAAqB,IAAA,EAAwC;AAC5E,EAAA,OAAO;AAAA,IACN,WAAA,EAAa,CAAC,OAAA,KAAY,IAAA,CAAK,YAAY,OAAO,CAAA;AAAA,IAClD,SAAA,EAAW,CAAC,OAAA,KAAY;AACvB,MAAA,IAAA,CAAK,GAAG,SAAA,EAAW,CAAC,OAAA,KAAY,OAAA,CAAQ,OAAO,CAAC,CAAA;AAAA,IACjD,CAAA;AAAA,IACA,WAAW,MAAM;AAChB,MAAA,IAAA,CAAK,SAAA,IAAY;AACjB,MAAA,IAAA,CAAK,KAAA,IAAQ;AAAA,IACd;AAAA,GACD;AACD","file":"worker.js","sourcesContent":["/**\n * The main-side half of the harness: an async proxy of the core evaluate\n * methods.\n *\n * {@link createWorkerEngine} performs the init handshake and resolves once the\n * worker's engine is built, so the returned {@link WorkerEngine} is ready to\n * call. Each call stamps a request id, tracks the pending promise, and settles\n * it when the matching answer arrives, so several requests can be outstanding at\n * once. An `AbortSignal` rejects the local promise and posts a `cancel` for the\n * same id, mapping keystroke-level cancellation onto the boundary rather than\n * re-inventing it.\n */\n\nimport type { EngineConfig } from \"@solve-js/constants/Configuration\";\nimport type { UnifiedParsingOptions } from \"@solve-js/types/ParsingResult\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport type { EngineError } from \"@solve-js/errors\";\nimport {\n\tdeserializeEngineError,\n\tworkerCancelledError,\n\tworkerTerminatedError,\n} from \"@solve-js/errors\";\nimport type { WorkerTransport } from \"./transport\";\nimport type {\n\tWorkerMethod,\n\tWorkerRequestArgs,\n\tWorkerToMainMessage,\n} from \"./protocol\";\nimport type {\n\tSerializedValue,\n\tSerializedParsedLine,\n\tSerializedParsingResult,\n} from \"./dto\";\n\n/** Configuration for {@link createWorkerEngine}. */\nexport interface WorkerEngineOptions {\n\t/** The channel to the worker runtime. See `worker/transport.ts` for adapters. */\n\ttransport: WorkerTransport;\n\t/** Locale for keywords and number formatting; defaults to English worker-side. */\n\tlocaleCode?: string;\n\t/** Whether the worker builds its engine with diagnostics enabled. */\n\tdiagnosticMode?: boolean;\n\t/** Partial engine configuration, merged with the defaults worker-side. */\n\tconfig?: Partial<EngineConfig>;\n\t/**\n\t * Names of built-in packages the worker should register. Omitted registers\n\t * them all. Names rather than the packages themselves, since a package\n\t * carries functions that cannot cross a `postMessage` boundary; a host with\n\t * a custom package bakes it into its own worker entry and selects it here by\n\t * name.\n\t */\n\tpackages?: string[];\n\t/** Formatting settings the worker uses when it renders a DTO's display text. */\n\tformatting?: FormattingSettings;\n}\n\n/** Per-call options common to every proxied method. */\nexport interface WorkerCallOptions {\n\t/** Abort the request. Rejects the returned promise and cancels the work worker-side. */\n\tsignal?: AbortSignal;\n}\n\n/**\n * One line whose result changed after a live value resolved worker-side, carried\n * as its freshly re-evaluated {@link SerializedValue}. The value the host renders\n * against `lineNumber`, recovered worker-side so the main thread needs no further\n * round-trip to display it.\n */\nexport interface WorkerAsyncUpdate {\n\tlineNumber: number;\n\tvalue: SerializedValue;\n}\n\n/**\n * A live-data resolution that failed worker-side. `error` is the same structured\n * {@link EngineError} an in-process resolver failure would surface, rebuilt from\n * its transported form, so a host branches on `code`/`category` as it always has.\n */\nexport interface WorkerAsyncError {\n\tqueryKey: string;\n\tpackageId: string;\n\terror: EngineError;\n}\n\n/**\n * An async proxy of {@link ExpressionEngine}'s core evaluate methods.\n *\n * Each method mirrors its synchronous counterpart but returns a Promise of the\n * serialisable DTO rather than a live `Value`, and accepts an `AbortSignal`.\n */\nexport interface WorkerEngine {\n\t/** Parse a whole document off-thread. Mirrors `ExpressionEngine.parseDocument`. */\n\tparseDocument(input: string, options?: UnifiedParsingOptions & WorkerCallOptions): Promise<SerializedParsingResult>;\n\t/** Evaluate an array of lines off-thread. Mirrors `ExpressionEngine.evaluateLines`. */\n\tevaluateLines(lines: string[], options?: WorkerCallOptions): Promise<SerializedParsedLine[]>;\n\t/** Evaluate a single expression off-thread. Mirrors `ExpressionEngine.evaluateExpression`. */\n\tevaluateExpression(expression: string, options?: WorkerCallOptions): Promise<SerializedValue[]>;\n\t/**\n\t * Subscribe to live-data resolutions that land after a request already\n\t * answered.\n\t *\n\t * A currency, weather or historical-rate value resolves inside the worker some\n\t * time after `parseDocument` returned its pending result. When it does, the\n\t * affected lines are re-evaluated worker-side and their fresh values arrive\n\t * here as one batch. This is a subscription rather than a per-request promise\n\t * because a resolution is tied to no single request: it belongs to whichever\n\t * document is current when the value lands. Returns an unsubscribe function.\n\t */\n\tonResolved(listener: (lines: WorkerAsyncUpdate[]) => void): () => void;\n\t/**\n\t * Subscribe to live-data resolutions that failed. Returns an unsubscribe\n\t * function. See {@link onResolved}; this is its failure channel.\n\t */\n\tonAsyncError(listener: (error: WorkerAsyncError) => void): () => void;\n\t/** Reject every in-flight request and tear the transport down. Idempotent. */\n\tterminate(): void;\n}\n\n/** A promise awaiting one worker answer, plus the abort wiring to unhook when it settles. */\ninterface PendingRequest {\n\tresolve: (value: unknown) => void;\n\treject: (error: unknown) => void;\n\tsignal?: AbortSignal;\n\tonAbort?: () => void;\n}\n\nclass WorkerEngineClient implements WorkerEngine {\n\tprivate readonly transport: WorkerTransport;\n\tprivate nextId = 1;\n\tprivate readonly pending = new Map<number, PendingRequest>();\n\t// Broadcast subscribers for async resolutions. Sets, not one callback each, so\n\t// several views can watch the same worker; a resolution is not tied to a\n\t// request id, so these live outside `pending`.\n\tprivate readonly resolvedListeners = new Set<(lines: WorkerAsyncUpdate[]) => void>();\n\tprivate readonly asyncErrorListeners = new Set<(error: WorkerAsyncError) => void>();\n\tprivate terminated = false;\n\n\tconstructor(transport: WorkerTransport) {\n\t\tthis.transport = transport;\n\t\tthis.transport.onMessage((raw) => this.onMessage(raw));\n\t}\n\n\t/** Perform the init handshake, resolving once the worker posts `ready`. */\n\tinit(options: WorkerEngineOptions): Promise<void> {\n\t\tconst id = this.nextId++;\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve: () => resolve(), reject });\n\t\t\tthis.transport.postMessage({\n\t\t\t\tkind: \"init\",\n\t\t\t\tid,\n\t\t\t\tlocaleCode: options.localeCode,\n\t\t\t\tdiagnosticMode: options.diagnosticMode,\n\t\t\t\tconfig: options.config,\n\t\t\t\tpackages: options.packages,\n\t\t\t\tformatting: options.formatting,\n\t\t\t});\n\t\t});\n\t}\n\n\tparseDocument(\n\t\tinput: string,\n\t\toptions?: UnifiedParsingOptions & WorkerCallOptions,\n\t): Promise<SerializedParsingResult> {\n\t\t// The signal stays main-side and drives a `cancel`; only the parsing\n\t\t// options cross, so an AbortSignal never reaches `postMessage`.\n\t\tconst { signal, ...parsing } = options ?? {};\n\t\tconst parseOptions = Object.keys(parsing).length > 0 ? (parsing as UnifiedParsingOptions) : undefined;\n\t\treturn this.call<SerializedParsingResult>(\"parseDocument\", [input, parseOptions], signal);\n\t}\n\n\tevaluateLines(lines: string[], options?: WorkerCallOptions): Promise<SerializedParsedLine[]> {\n\t\treturn this.call<SerializedParsedLine[]>(\"evaluateLines\", [lines], options?.signal);\n\t}\n\n\tevaluateExpression(expression: string, options?: WorkerCallOptions): Promise<SerializedValue[]> {\n\t\treturn this.call<SerializedValue[]>(\"evaluateExpression\", [expression], options?.signal);\n\t}\n\n\tonResolved(listener: (lines: WorkerAsyncUpdate[]) => void): () => void {\n\t\tthis.resolvedListeners.add(listener);\n\t\treturn () => this.resolvedListeners.delete(listener);\n\t}\n\n\tonAsyncError(listener: (error: WorkerAsyncError) => void): () => void {\n\t\tthis.asyncErrorListeners.add(listener);\n\t\treturn () => this.asyncErrorListeners.delete(listener);\n\t}\n\n\tterminate(): void {\n\t\tif (this.terminated) return;\n\t\tthis.terminated = true;\n\t\tconst error = workerTerminatedError();\n\t\tfor (const entry of this.pending.values()) {\n\t\t\tthis.unhook(entry);\n\t\t\tentry.reject(error);\n\t\t}\n\t\tthis.pending.clear();\n\t\t// No more resolutions can arrive across a torn-down transport, so drop the\n\t\t// subscribers rather than leaving them referenced for the client's lifetime.\n\t\tthis.resolvedListeners.clear();\n\t\tthis.asyncErrorListeners.clear();\n\t\tthis.transport.terminate();\n\t}\n\n\t/** Dispatch one request and return the promise that settles on its answer. */\n\tprivate call<T>(method: WorkerMethod, args: WorkerRequestArgs, signal?: AbortSignal): Promise<T> {\n\t\tif (this.terminated) return Promise.reject(workerTerminatedError());\n\t\tif (signal?.aborted) return Promise.reject(workerCancelledError(method));\n\n\t\tconst id = this.nextId++;\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst entry: PendingRequest = { resolve: resolve as (value: unknown) => void, reject };\n\n\t\t\tif (signal) {\n\t\t\t\tconst onAbort = (): void => {\n\t\t\t\t\t// Nothing to do if the answer already arrived and settled this id.\n\t\t\t\t\tif (!this.pending.has(id)) return;\n\t\t\t\t\tthis.pending.delete(id);\n\t\t\t\t\tthis.transport.postMessage({ kind: \"cancel\", id });\n\t\t\t\t\treject(workerCancelledError(method));\n\t\t\t\t};\n\t\t\t\tentry.signal = signal;\n\t\t\t\tentry.onAbort = onAbort;\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t}\n\n\t\t\tthis.pending.set(id, entry);\n\t\t\tthis.transport.postMessage({ kind: \"request\", id, method, args });\n\t\t});\n\t}\n\n\t/** Route one incoming message to the request that is waiting on its id. */\n\tprivate onMessage(raw: unknown): void {\n\t\tconst message = raw as WorkerToMainMessage;\n\t\tswitch (message.kind) {\n\t\t\tcase \"ready\":\n\t\t\tcase \"result\": {\n\t\t\t\tconst value = message.kind === \"result\" ? message.value : undefined;\n\t\t\t\tthis.settle(message.id, (entry) => entry.resolve(value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"error\":\n\t\t\t\tthis.settle(message.id, (entry) => entry.reject(deserializeEngineError(message.error)));\n\t\t\t\tbreak;\n\t\t\tcase \"async-update\":\n\t\t\t\t// A broadcast, not an answer to a request: fan it out to every\n\t\t\t\t// subscriber. A copy of the listener set is iterated so a listener\n\t\t\t\t// that unsubscribes itself mid-callback cannot disturb the walk.\n\t\t\t\tfor (const listener of [...this.resolvedListeners]) listener(message.lines);\n\t\t\t\tbreak;\n\t\t\tcase \"async-error\":\n\t\t\t\tfor (const listener of [...this.asyncErrorListeners]) {\n\t\t\t\t\tlistener({\n\t\t\t\t\t\tqueryKey: message.queryKey,\n\t\t\t\t\t\tpackageId: message.packageId,\n\t\t\t\t\t\terror: deserializeEngineError(message.error),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/** Remove a pending request by id and run the settle callback, if it is still pending. */\n\tprivate settle(id: number, apply: (entry: PendingRequest) => void): void {\n\t\tconst entry = this.pending.get(id);\n\t\tif (!entry) return;\n\t\tthis.pending.delete(id);\n\t\tthis.unhook(entry);\n\t\tapply(entry);\n\t}\n\n\t/** Detach an entry's abort listener so a settled request leaves nothing on the signal. */\n\tprivate unhook(entry: PendingRequest): void {\n\t\tif (entry.signal && entry.onAbort) entry.signal.removeEventListener(\"abort\", entry.onAbort);\n\t}\n}\n\n/**\n * Build a worker-backed engine and wait for it to be ready.\n *\n * ```ts\n * const { client, host } = createLinkedTransports();\n * startWorkerRuntime(host);\n * const engine = await createWorkerEngine({ transport: client });\n * const result = await engine.parseDocument(text);\n * ```\n *\n * In production `client` wraps a real `Worker` (see `eventTargetTransport` /\n * `messagePortTransport`), and `startWorkerRuntime` runs inside that worker.\n */\nexport async function createWorkerEngine(options: WorkerEngineOptions): Promise<WorkerEngine> {\n\tconst client = new WorkerEngineClient(options.transport);\n\tawait client.init(options);\n\treturn client;\n}\n","/**\n * Turn live engine results into the clone-safe DTOs the worker harness posts.\n *\n * These functions run on the worker side, just before a result crosses the\n * boundary, and are also what the main side re-runs on a synchronous result to\n * compare the two paths in tests. They are pure and deterministic given the\n * same {@link FormattingSettings}, so a value serialised on either side is\n * byte-for-byte the same DTO.\n */\n\nimport { Value, ValueType, type MatrixData, type MatrixEntry, type RangeData, type ColourData } from \"@solve-js/vm/Value\";\nimport { formatValue } from \"@solve-js/format/FormatEngine\";\nimport { toHexString, formatColour } from \"@solve-js/packages/colour/ColourMath\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport { formatSymbolic } from \"@solve-js/symbolic\";\nimport type { ParsedLine, InlineSolvePosition, ParsingResult } from \"@solve-js/types/ParsingResult\";\nimport type {\n\tSerializedValue,\n\tSerializedMatrix,\n\tSerializedParsedLine,\n\tSerializedInlineSolve,\n\tSerializedParsingResult,\n} from \"./dto\";\n\n/**\n * The JSON-safe string tag for a non-finite reading. `Infinity`/`-Infinity`/`NaN`\n * cannot cross `JSON` (which turns each into `null`), so this one string form is\n * what survives both `structuredClone` and `JSON`, and a host recovers the value\n * with `Number(tag)`. Shared by the scalar `nonFinite` field and matrix cells.\n */\nfunction nonFiniteTag(n: number): \"Infinity\" | \"-Infinity\" | \"NaN\" {\n\treturn n > 0 ? \"Infinity\" : n < 0 ? \"-Infinity\" : \"NaN\";\n}\n\n/** Project a matrix onto clone-safe cells: finite primitives pass through, symbolic cells and non-finite numbers become strings. */\nfunction serializeMatrix(m: MatrixData): SerializedMatrix {\n\tconst cells = m.data.map((cell: MatrixEntry): number | boolean | string => {\n\t\t// A `SymbolicNode` (the object-typed cell variant) flattens to its display\n\t\t// string. A non-finite number (a `[1/0, 2]` cell) cannot cross JSON any\n\t\t// more than a scalar reading can, so it takes the same string tag rather\n\t\t// than being passed through raw and turned into `null` by `JSON.stringify`\n\t\t// (which would diverge from the `structuredClone` path). A finite number\n\t\t// or a boolean is already clone-safe and passes through.\n\t\tif (typeof cell === \"object\" && cell !== null) return formatSymbolic(cell);\n\t\tif (typeof cell === \"number\" && !Number.isFinite(cell)) return nonFiniteTag(cell);\n\t\treturn cell;\n\t});\n\treturn { rows: m.rows, cols: m.cols, cells, hasSymbolic: m.hasSymbolic };\n}\n\n/**\n * Project a {@link Value} onto a {@link SerializedValue}.\n *\n * `text` and `number` are set for every value; the type-specific fields are\n * added only where the payload needs them, so the DTO stays minimal and a\n * deep-equal between the two evaluation paths does not trip on a property one\n * side left `undefined`.\n */\nexport function serializeValue(value: Value, settings?: FormattingSettings): SerializedValue {\n\tconst reading = value.toNumber();\n\tconst dto: SerializedValue = {\n\t\ttype: value.type,\n\t\ttext: formatValue(value, settings),\n\t\t// A non-finite reading (1/0, 0/0, an overflow) cannot cross JSON, which\n\t\t// turns it into null and breaks the round-trip the DTO guarantees. Keep\n\t\t// `number` finite and name the real value in `nonFinite` instead.\n\t\tnumber: Number.isFinite(reading) ? reading : 0,\n\t};\n\tif (!Number.isFinite(reading)) {\n\t\tdto.nonFinite = nonFiniteTag(reading);\n\t}\n\n\tif (value.unit !== undefined) dto.unit = value.unit;\n\tif (value.timedOut !== undefined) dto.timedOut = value.timedOut;\n\n\tconst raw = value.value;\n\tif (typeof raw === \"bigint\") {\n\t\t// Covers BigInt values and a Hex value that carries a bigint magnitude:\n\t\t// a base-ten string is the one representation that neither loses\n\t\t// precision nor breaks JSON.\n\t\tdto.bigint = raw.toString();\n\t} else if (value.type === ValueType.Matrix) {\n\t\tdto.matrix = serializeMatrix(raw as MatrixData);\n\t} else if (value.type === ValueType.Range) {\n\t\tconst r = raw as RangeData;\n\t\tdto.range = { min: r.min, max: r.max };\n\t} else if (value.type === ValueType.Colour) {\n\t\tconst c = raw as ColourData;\n\t\tdto.colour = { hex: toHexString(c), r: c.r, g: c.g, b: c.b, a: c.a, format: c.format, css: formatColour(c) };\n\t}\n\n\treturn dto;\n}\n\n/** Serialise a nullable value, the shape both `result` fields carry. */\nfunction serializeMaybe(value: Value | null | undefined, settings?: FormattingSettings): SerializedValue | null {\n\treturn value ? serializeValue(value, settings) : null;\n}\n\n/** Project an inline solve onto its DTO, serialising its result. */\nfunction serializeInlineSolve(solve: InlineSolvePosition, settings?: FormattingSettings): SerializedInlineSolve {\n\treturn {\n\t\tstart: solve.start,\n\t\tend: solve.end,\n\t\texpression: solve.expression,\n\t\tlineNumber: solve.lineNumber,\n\t\tcolumnNumber: solve.columnNumber,\n\t\tresult: serializeMaybe(solve.result, settings),\n\t\terror: solve.error ?? null,\n\t};\n}\n\n/** Project a parsed line onto its DTO, serialising its result and every inline solve. */\nexport function serializeParsedLine(line: ParsedLine, settings?: FormattingSettings): SerializedParsedLine {\n\treturn {\n\t\tlineNumber: line.lineNumber,\n\t\ttext: line.text,\n\t\tstartPosition: line.startPosition,\n\t\tendPosition: line.endPosition,\n\t\tisEmpty: line.isEmpty,\n\t\thasInlineSolves: line.hasInlineSolves,\n\t\tinlineSolves: line.inlineSolves.map((solve) => serializeInlineSolve(solve, settings)),\n\t\texpression: line.expression,\n\t\tresult: serializeMaybe(line.result, settings),\n\t\terror: line.error,\n\t};\n}\n\n/** Project a whole parsing result onto its DTO. */\nexport function serializeParsingResult(result: ParsingResult, settings?: FormattingSettings): SerializedParsingResult {\n\tconst dto: SerializedParsingResult = {\n\t\tlines: result.lines.map((line) => serializeParsedLine(line, settings)),\n\t\ttotalLines: result.totalLines,\n\t\terrors: [...result.errors],\n\t};\n\t// The diagnostics report is already the engine's own JSON form, so it\n\t// crosses unchanged; present only when the host asked for it.\n\tif (result.diagnostics !== undefined) dto.diagnostics = result.diagnostics;\n\treturn dto;\n}\n","/**\n * The worker-side half of the harness: it owns an {@link ExpressionEngine} and\n * answers the protocol.\n *\n * {@link startWorkerRuntime} is transport-agnostic, so the same function runs\n * behind a browser `Worker`, a Node `worker_threads` port, or an in-process\n * link. A host's worker entry file is two lines: adapt the environment onto a\n * {@link WorkerTransport} and call this.\n *\n * The runtime never posts a raw {@link Value}. Every result is projected onto a\n * DTO first (`worker/serialize.ts`), and every failure is caught and flattened\n * into a structured error, so a worker-side throw reaches the caller as an\n * `EngineError` rather than a lost promise.\n */\n\nimport { ExpressionEngine } from \"@solve-js/engine/ExpressionEngine\";\nimport type { AsyncResolutionEvent } from \"@solve-js/engine/AsyncResolutionBatcher\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport {\n\tErrorFactory,\n\tnormalizeUnknownError,\n\tserializeEngineError,\n\tWorkerErrorCodes,\n} from \"@solve-js/errors\";\nimport { serializeParsingResult, serializeParsedLine, serializeValue } from \"./serialize\";\nimport type { WorkerTransport } from \"./transport\";\nimport type {\n\tMainToWorkerMessage,\n\tInitMessage,\n\tRequestMessage,\n\tWorkerToMainMessage,\n\tAsyncResolvedLine,\n} from \"./protocol\";\n\n/** Options a host bakes into its own worker entry, chiefly its custom packages. */\nexport interface WorkerRuntimeOptions {\n\t/**\n\t * The packages available to register, defaulting to {@link BUILTIN_PACKAGES}.\n\t * A host with its own package authors a worker entry that passes them here,\n\t * then selects among them by name from the main side. This is how a\n\t * function-carrying package reaches the worker: baked into its bundle, never\n\t * posted across the boundary.\n\t */\n\tpackages?: IEnginePackage[];\n}\n\n/**\n * Resolve the requested package names against the available set.\n *\n * Undefined names means \"all of them\". A name with no match is a configuration\n * failure the caller must see, not a silent omission that would leave a feature\n * quietly missing from every result.\n */\nfunction resolvePackages(available: IEnginePackage[], names: string[] | undefined): IEnginePackage[] {\n\tif (names === undefined) return available;\n\tconst byName = new Map(available.map((pkg) => [pkg.name, pkg]));\n\tconst resolved: IEnginePackage[] = [];\n\tfor (const name of names) {\n\t\tconst pkg = byName.get(name);\n\t\tif (!pkg) {\n\t\t\tthrow ErrorFactory.config(\n\t\t\t\tWorkerErrorCodes.WORKER_UNKNOWN_PACKAGE,\n\t\t\t\t`No package named \"${name}\" is available in this worker runtime`,\n\t\t\t\t{ name, available: [...byName.keys()] },\n\t\t\t);\n\t\t}\n\t\tresolved.push(pkg);\n\t}\n\treturn resolved;\n}\n\n/**\n * Attach the runtime to a transport and start serving.\n *\n * Returns a teardown function that clears the engine and detaches, for a host\n * that reuses a transport or shuts a worker down cleanly.\n */\nexport function startWorkerRuntime(transport: WorkerTransport, options: WorkerRuntimeOptions = {}): () => void {\n\tconst available = options.packages ?? BUILTIN_PACKAGES;\n\n\tlet engine: ExpressionEngine | null = null;\n\tlet formatting: FormattingSettings | undefined;\n\t// One AbortController per in-flight request, so a `cancel` can map onto the\n\t// engine's keystroke signal for exactly the request the caller aborted.\n\tconst inFlight = new Map<number, AbortController>();\n\n\t// The line texts of the current document, keyed by the line number the engine\n\t// evaluates them under (1-based for a document, -1 for a lone expression). An\n\t// async resolution names the lines whose result changed but not the new value,\n\t// so this is what the event pump re-reads a line from to recover it.\n\tlet retainedLines = new Map<number, string>();\n\n\t// The current document's abort controller, kept alive past the request that\n\t// created it so this document's async resolutions can still land. Aborted when\n\t// a new document supersedes it: aborting drops the old document's in-flight\n\t// resolutions at the engine's own staleness guard (an aborted signal is\n\t// discarded before it reaches the batcher), so a stale value never reaches the\n\t// host as if it were current. See {@link handleRequest}.\n\tlet documentController: AbortController | null = null;\n\n\t// Cancels the event-stream reader on teardown. Null until the pump starts.\n\tlet stopEventPump: (() => void) | null = null;\n\n\tconst post = (message: WorkerToMainMessage): void => transport.postMessage(message);\n\n\tconst fail = (id: number, error: unknown): void => {\n\t\tpost({ kind: \"error\", id, error: serializeEngineError(normalizeUnknownError(error)) });\n\t};\n\n\t/**\n\t * Record the line texts a request evaluates, so a later async resolution can\n\t * re-read exactly the lines it names. A whole document splits into 1-based\n\t * lines; a lone `evaluateExpression` maps onto the engine's `-1` sentinel, the\n\t * same line number the engine registers and later reports for it.\n\t */\n\tconst retainLines = (message: RequestMessage): Map<number, string> => {\n\t\tconst map = new Map<number, string>();\n\t\tif (message.method === \"parseDocument\") {\n\t\t\t(message.args[0] as string).split(\"\\n\").forEach((text, index) => map.set(index + 1, text));\n\t\t} else if (message.method === \"evaluateLines\") {\n\t\t\t(message.args[0] as string[]).forEach((text, index) => map.set(index + 1, text));\n\t\t} else {\n\t\t\tmap.set(-1, message.args[0] as string);\n\t\t}\n\t\treturn map;\n\t};\n\n\t/**\n\t * Turn one async resolution event into a message home.\n\t *\n\t * A `lines-updated` event names the lines whose result changed; the resolved\n\t * value lives in the engine's cache, so each named line is re-evaluated (which\n\t * now reads the settled value from that cache rather than starting a fresh\n\t * fetch) and serialised. A line the current document no longer retains belongs\n\t * to a superseded document and is skipped. An `error` event carries the failed\n\t * query straight across as a structured error.\n\t */\n\tconst handleAsyncEvent = (eng: ExpressionEngine, event: AsyncResolutionEvent): void => {\n\t\tif (event.type === \"error\") {\n\t\t\tpost({\n\t\t\t\tkind: \"async-error\",\n\t\t\t\tqueryKey: event.queryKey,\n\t\t\t\tpackageId: event.packageId,\n\t\t\t\terror: serializeEngineError(normalizeUnknownError(event.error)),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst lines: AsyncResolvedLine[] = [];\n\t\tfor (const lineNumber of event.lineNumbers) {\n\t\t\tconst text = retainedLines.get(lineNumber);\n\t\t\tif (text === undefined) continue;\n\t\t\ttry {\n\t\t\t\tconst value = eng.evaluateLine(lineNumber, text)[0];\n\t\t\t\tif (value) lines.push({ lineNumber, value: serializeValue(value, formatting) });\n\t\t\t} catch {\n\t\t\t\t// A line that resolved into an error re-throws on re-evaluation; the\n\t\t\t\t// batcher's own `error` event is the channel for that, so this keeps\n\t\t\t\t// the update to the lines that produced a value rather than posting a\n\t\t\t\t// second, half-formed failure here.\n\t\t\t}\n\t\t}\n\t\tif (lines.length > 0) post({ kind: \"async-update\", lines });\n\t};\n\n\t/**\n\t * Drain the engine's async-resolution event stream for the life of the\n\t * runtime, posting each event home. Started once the engine exists; the reader\n\t * loop ends when the stream closes (engine cleared) or the returned canceller\n\t * runs at teardown.\n\t */\n\tconst startEventPump = (eng: ExpressionEngine): void => {\n\t\tstopEventPump?.();\n\t\tconst reader = eng.getEventStream().getReader();\n\t\tstopEventPump = () => void reader.cancel();\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) return;\n\t\t\t\t\thandleAsyncEvent(eng, value);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// The stream errored or was cancelled (teardown); the loop is done.\n\t\t\t}\n\t\t})();\n\t};\n\n\tconst handleInit = (message: InitMessage): void => {\n\t\ttry {\n\t\t\tconst packages = resolvePackages(available, message.packages);\n\t\t\tengine = new ExpressionEngine(\n\t\t\t\tmessage.localeCode ?? \"en\",\n\t\t\t\tmessage.diagnosticMode ?? false,\n\t\t\t\tmessage.config,\n\t\t\t\tundefined,\n\t\t\t\tpackages,\n\t\t\t);\n\t\t\tformatting = message.formatting;\n\t\t\t// Drain live-data resolutions for the engine's whole lifetime, so a\n\t\t\t// value that settles after a request already answered still reaches the\n\t\t\t// host. Started here, after the engine exists, and torn down with it.\n\t\t\tstartEventPump(engine);\n\t\t\tpost({ kind: \"ready\", id: message.id });\n\t\t} catch (error) {\n\t\t\t// A build failure leaves no engine; the caller's `createWorkerEngine`\n\t\t\t// promise rejects with this rather than hanging on a `ready` that\n\t\t\t// never comes.\n\t\t\tfail(message.id, error);\n\t\t}\n\t};\n\n\tconst runMethod = (eng: ExpressionEngine, message: RequestMessage): unknown => {\n\t\tconst { method, args } = message;\n\t\tswitch (method) {\n\t\t\tcase \"parseDocument\":\n\t\t\t\treturn serializeParsingResult(eng.parseDocument(args[0] as string, args[1] as never), formatting);\n\t\t\tcase \"evaluateLines\":\n\t\t\t\treturn eng.evaluateLines(args[0] as string[]).map((line) => serializeParsedLine(line, formatting));\n\t\t\tcase \"evaluateExpression\":\n\t\t\t\treturn eng.evaluateExpression(args[0] as string).map((value) => serializeValue(value, formatting));\n\t\t\tdefault:\n\t\t\t\tthrow ErrorFactory.execution(\n\t\t\t\t\tWorkerErrorCodes.WORKER_UNKNOWN_METHOD,\n\t\t\t\t\t`The worker runtime has no method named \"${String(method)}\"`,\n\t\t\t\t\t{ method },\n\t\t\t\t);\n\t\t}\n\t};\n\n\tconst handleRequest = (message: RequestMessage): void => {\n\t\tconst eng = engine;\n\t\tif (!eng) {\n\t\t\tfail(\n\t\t\t\tmessage.id,\n\t\t\t\tErrorFactory.execution(\n\t\t\t\t\tWorkerErrorCodes.WORKER_NOT_INITIALISED,\n\t\t\t\t\t\"The worker received a request before its engine finished initialising\",\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Supersede the previous document: abort its controller so any resolution\n\t\t// still in flight for it is dropped at the engine's staleness guard rather\n\t\t// than posted home as if it belonged to this request's document. The old\n\t\t// retained lines go with it. Every evaluate call shares one engine and one\n\t\t// document context, so the most recent call is the live one.\n\t\tdocumentController?.abort();\n\n\t\t// This request's controller doubles as the document controller: wired in as\n\t\t// the keystroke signal so a later `cancel` (or the next supersede) aborts\n\t\t// the async work this evaluation fires, the same mechanism a host uses on\n\t\t// the main thread. It is deliberately NOT aborted when the request settles,\n\t\t// so this document's live values can still resolve and stream back.\n\t\tconst controller = new AbortController();\n\t\tdocumentController = controller;\n\t\tretainedLines = retainLines(message);\n\t\tinFlight.set(message.id, controller);\n\t\teng.setKeystrokeSignal(controller.signal);\n\n\t\ttry {\n\t\t\tconst value = runMethod(eng, message);\n\t\t\tpost({ kind: \"result\", id: message.id, value });\n\t\t} catch (error) {\n\t\t\tfail(message.id, error);\n\t\t} finally {\n\t\t\tinFlight.delete(message.id);\n\t\t\teng.setKeystrokeSignal(null);\n\t\t}\n\t};\n\n\ttransport.onMessage((raw) => {\n\t\tconst message = raw as MainToWorkerMessage;\n\t\tswitch (message.kind) {\n\t\t\tcase \"init\":\n\t\t\t\thandleInit(message);\n\t\t\t\tbreak;\n\t\t\tcase \"request\":\n\t\t\t\thandleRequest(message);\n\t\t\t\tbreak;\n\t\t\tcase \"cancel\":\n\t\t\t\t// Abort maps onto the keystroke signal for the named request; a\n\t\t\t\t// cancel that arrives after the request already settled finds no\n\t\t\t\t// controller and is a harmless no-op.\n\t\t\t\tinFlight.get(message.id)?.abort();\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\treturn () => {\n\t\tstopEventPump?.();\n\t\tstopEventPump = null;\n\t\tdocumentController?.abort();\n\t\tdocumentController = null;\n\t\tretainedLines = new Map();\n\t\tfor (const controller of inFlight.values()) controller.abort();\n\t\tinFlight.clear();\n\t\tengine?.clear();\n\t\tengine = null;\n\t\ttransport.terminate();\n\t};\n}\n","/**\n * The seam between the harness and whatever actually carries messages.\n *\n * Both the client (`worker/client.ts`) and the runtime (`worker/runtime.ts`)\n * talk to a {@link WorkerTransport} and nothing more, so the same code drives a\n * browser `Worker`, a Node `worker_threads` port, or an in-process pair. The\n * three factory functions below adapt each of those onto the interface; a host\n * with a transport this file does not cover can implement the three methods\n * directly.\n */\n\n/**\n * A bidirectional message channel with a single receive handler.\n *\n * `onMessage` registers the one handler the harness needs; calling it again\n * replaces the previous handler. `terminate` tears the channel down and is safe\n * to call more than once.\n */\nexport interface WorkerTransport {\n\t/** Send one message to the other end. The message must be clone-safe. */\n\tpostMessage(message: unknown): void;\n\t/** Register the handler that receives messages from the other end. */\n\tonMessage(handler: (message: unknown) => void): void;\n\t/** Tear the channel down. Idempotent. */\n\tterminate(): void;\n}\n\n/**\n * Clone a message the way `postMessage` would, so an in-process transport has\n * the same value semantics as a real one.\n *\n * The harness protocol is clone-safe by construction, so the `JSON` fallback\n * (for a runtime without a global `structuredClone`) is lossless here; the\n * structured-clone path is preferred because it is what a real worker uses and\n * because it throws loudly if a non-clone-safe value ever reaches it, which is\n * exactly the mistake the DTO layer exists to prevent.\n *\n * A function, not a module-level const, so this module does no work at load\n * time and stays deletable under the package's `sideEffects: false` claim; the\n * `typeof` probe runs once per message, which is free next to the clone itself.\n */\nfunction cloneMessage<T>(value: T): T {\n\treturn typeof globalThis.structuredClone === \"function\"\n\t\t? globalThis.structuredClone(value)\n\t\t: JSON.parse(JSON.stringify(value));\n}\n\n/**\n * A pair of linked in-process transports.\n *\n * `client` and `host` are two ends of one channel: a message posted on either\n * is cloned at post time and delivered to the other on a microtask, so delivery\n * is asynchronous (as a real worker's is) but deterministic (no timers, no I/O).\n * Wire `client` into {@link createWorkerEngine} and `host` into\n * {@link startWorkerRuntime} to run the whole protocol, DTO serialisation and\n * cancellation included, without a second thread. This is the transport tests\n * use, and a fit for a host that wants the message-passing shape on one thread.\n */\nexport function createLinkedTransports(): { client: WorkerTransport; host: WorkerTransport } {\n\tlet clientHandler: ((message: unknown) => void) | null = null;\n\tlet hostHandler: ((message: unknown) => void) | null = null;\n\tlet alive = true;\n\n\t// The handler is read at delivery time rather than post time so setup order\n\t// (post before the other end has registered) cannot drop a message.\n\tconst deliver = (target: () => ((message: unknown) => void) | null, message: unknown): void => {\n\t\tconst cloned = cloneMessage(message);\n\t\tqueueMicrotask(() => {\n\t\t\tif (!alive) return;\n\t\t\ttarget()?.(cloned);\n\t\t});\n\t};\n\n\tconst client: WorkerTransport = {\n\t\tpostMessage: (message) => deliver(() => hostHandler, message),\n\t\tonMessage: (handler) => {\n\t\t\tclientHandler = handler;\n\t\t},\n\t\tterminate: () => {\n\t\t\talive = false;\n\t\t},\n\t};\n\n\tconst host: WorkerTransport = {\n\t\tpostMessage: (message) => deliver(() => clientHandler, message),\n\t\tonMessage: (handler) => {\n\t\t\thostHandler = handler;\n\t\t},\n\t\tterminate: () => {\n\t\t\talive = false;\n\t\t},\n\t};\n\n\treturn { client, host };\n}\n\n/** The `postMessage`/`onmessage`/event-listener shape a browser `Worker`, a worker's `self`, or a DOM `MessagePort` presents. */\ninterface EventTargetLike {\n\tpostMessage(message: unknown): void;\n\taddEventListener?(type: \"message\", handler: (event: { data: unknown }) => void): void;\n\tonmessage?: ((event: { data: unknown }) => void) | null;\n\tterminate?(): void;\n\tclose?(): void;\n\tstart?(): void;\n}\n\n/**\n * Adapt a browser-style message target onto a {@link WorkerTransport}.\n *\n * Covers the main-side `Worker`, the worker global `self`, and a DOM\n * `MessagePort`: each posts with `postMessage` and receives a `MessageEvent`\n * whose `data` is the payload. A `MessagePort` is `start`ed here so it begins\n * dispatching. On the main side pass a `Worker`; inside a browser worker pass\n * `self`.\n */\nexport function eventTargetTransport(target: EventTargetLike): WorkerTransport {\n\treturn {\n\t\tpostMessage: (message) => target.postMessage(message),\n\t\tonMessage: (handler) => {\n\t\t\tconst listener = (event: { data: unknown }): void => handler(event.data);\n\t\t\tif (typeof target.addEventListener === \"function\") {\n\t\t\t\ttarget.addEventListener(\"message\", listener);\n\t\t\t} else {\n\t\t\t\ttarget.onmessage = listener;\n\t\t\t}\n\t\t\ttarget.start?.();\n\t\t},\n\t\t// A main-side Worker terminates; a worker's own `self` closes. Calling\n\t\t// whichever exists keeps one adapter usable from both ends.\n\t\tterminate: () => {\n\t\t\ttarget.terminate?.();\n\t\t\ttarget.close?.();\n\t\t},\n\t};\n}\n\n/** The `postMessage`/`on(\"message\")` shape a Node `worker_threads` `Worker`, `parentPort`, or `MessagePort` presents. */\ninterface MessagePortLike {\n\tpostMessage(message: unknown): void;\n\ton(event: \"message\", handler: (message: unknown) => void): void;\n\tterminate?(): void;\n\tclose?(): void;\n}\n\n/**\n * Adapt a Node `worker_threads` port onto a {@link WorkerTransport}.\n *\n * Covers the main-side `Worker`, the worker's `parentPort`, and a\n * `worker_threads` `MessagePort`: each posts with `postMessage` and emits a\n * `\"message\"` event whose argument IS the payload (no `.data` wrapper, unlike\n * the DOM). On the main side pass the `Worker`; inside the worker pass\n * `parentPort`.\n */\nexport function messagePortTransport(port: MessagePortLike): WorkerTransport {\n\treturn {\n\t\tpostMessage: (message) => port.postMessage(message),\n\t\tonMessage: (handler) => {\n\t\t\tport.on(\"message\", (message) => handler(message));\n\t\t},\n\t\tterminate: () => {\n\t\t\tport.terminate?.();\n\t\t\tport.close?.();\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/worker/client.ts","../src/worker/serialize.ts","../src/worker/runtime.ts","../src/worker/transport.ts"],"names":["WorkerEngineClient","transport","raw","options","id","resolve","reject","input","signal","parsing","parseOptions","lines","expression","listener","error","workerTerminatedError","entry","method","args","workerCancelledError","onAbort","message","value","deserializeEngineError","apply","createWorkerEngine","client","nonFiniteTag","n","serializeMatrix","m","cells","cell","formatSymbolic","serializeValue","settings","reading","dto","formatValue","r","c","toHexString","formatColour","serializeMaybe","serializeInlineSolve","solve","serializeParsedLine","line","serializeParsingResult","result","resolvePackages","available","names","byName","pkg","resolved","name","ErrorFactory","WorkerErrorCodes","startWorkerRuntime","BUILTIN_PACKAGES","engine","formatting","inFlight","retainedLines","documentController","stopEventPump","post","fail","serializeEngineError","normalizeUnknownError","retainLines","map","text","index","handleAsyncEvent","eng","event","lineNumber","startEventPump","reader","done","handleInit","packages","ExpressionEngine","runMethod","handleRequest","controller","cloneMessage","createLinkedTransports","clientHandler","hostHandler","alive","deliver","target","cloned","handler","eventTargetTransport","messagePortTransport","port"],"mappings":"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","file":"worker.js","sourcesContent":["/**\n * The main-side half of the harness: an async proxy of the core evaluate\n * methods.\n *\n * {@link createWorkerEngine} performs the init handshake and resolves once the\n * worker's engine is built, so the returned {@link WorkerEngine} is ready to\n * call. Each call stamps a request id, tracks the pending promise, and settles\n * it when the matching answer arrives, so several requests can be outstanding at\n * once. An `AbortSignal` rejects the local promise and posts a `cancel` for the\n * same id, mapping keystroke-level cancellation onto the boundary rather than\n * re-inventing it.\n */\n\nimport type { EngineConfigOverride } from \"@solve-js/constants/Configuration\";\nimport type { UnifiedParsingOptions } from \"@solve-js/types/ParsingResult\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport type { EngineError } from \"@solve-js/errors\";\nimport {\n\tdeserializeEngineError,\n\tworkerCancelledError,\n\tworkerTerminatedError,\n} from \"@solve-js/errors\";\nimport type { WorkerTransport } from \"./transport\";\nimport type {\n\tWorkerMethod,\n\tWorkerRequestArgs,\n\tWorkerToMainMessage,\n} from \"./protocol\";\nimport type {\n\tSerializedValue,\n\tSerializedParsedLine,\n\tSerializedParsingResult,\n} from \"./dto\";\n\n/** Configuration for {@link createWorkerEngine}. */\nexport interface WorkerEngineOptions {\n\t/** The channel to the worker runtime. See `worker/transport.ts` for adapters. */\n\ttransport: WorkerTransport;\n\t/** Locale for keywords and number formatting; defaults to English worker-side. */\n\tlocaleCode?: string;\n\t/** Whether the worker builds its engine with diagnostics enabled. */\n\tdiagnostics?: boolean;\n\t/** Config overrides, merged per section over the defaults worker-side. */\n\tconfig?: EngineConfigOverride;\n\t/**\n\t * Names of built-in packages the worker should register. Omitted registers\n\t * them all. Names rather than the packages themselves, since a package\n\t * carries functions that cannot cross a `postMessage` boundary; a host with\n\t * a custom package bakes it into its own worker entry and selects it here by\n\t * name.\n\t */\n\tpackages?: string[];\n\t/** Formatting settings the worker uses when it renders a DTO's display text. */\n\tformatting?: FormattingSettings;\n}\n\n/** Per-call options common to every proxied method. */\nexport interface WorkerCallOptions {\n\t/** Abort the request. Rejects the returned promise and cancels the work worker-side. */\n\tsignal?: AbortSignal;\n}\n\n/**\n * One line whose result changed after a live value resolved worker-side, carried\n * as its freshly re-evaluated {@link SerializedValue}. The value the host renders\n * against `lineNumber`, recovered worker-side so the main thread needs no further\n * round-trip to display it.\n */\nexport interface WorkerAsyncUpdate {\n\tlineNumber: number;\n\tvalue: SerializedValue;\n}\n\n/**\n * A live-data resolution that failed worker-side. `error` is the same structured\n * {@link EngineError} an in-process resolver failure would surface, rebuilt from\n * its transported form, so a host branches on `code`/`category` as it always has.\n */\nexport interface WorkerAsyncError {\n\tqueryKey: string;\n\tpackageId: string;\n\terror: EngineError;\n}\n\n/**\n * An async proxy of {@link ExpressionEngine}'s core evaluate methods.\n *\n * Each method mirrors its synchronous counterpart but returns a Promise of the\n * serialisable DTO rather than a live `Value`, and accepts an `AbortSignal`.\n */\nexport interface WorkerEngine {\n\t/** Parse a whole document off-thread. Mirrors `ExpressionEngine.parseDocument`. */\n\tparseDocument(input: string, options?: UnifiedParsingOptions & WorkerCallOptions): Promise<SerializedParsingResult>;\n\t/** Evaluate an array of lines off-thread. Mirrors `ExpressionEngine.evaluateLines`. */\n\tevaluateLines(lines: string[], options?: WorkerCallOptions): Promise<SerializedParsedLine[]>;\n\t/** Evaluate a single expression off-thread. Mirrors `ExpressionEngine.evaluateExpression`. */\n\tevaluateExpression(expression: string, options?: WorkerCallOptions): Promise<SerializedValue>;\n\t/**\n\t * Subscribe to live-data resolutions that land after a request already\n\t * answered.\n\t *\n\t * A currency, weather or historical-rate value resolves inside the worker some\n\t * time after `parseDocument` returned its pending result. When it does, the\n\t * affected lines are re-evaluated worker-side and their fresh values arrive\n\t * here as one batch. This is a subscription rather than a per-request promise\n\t * because a resolution is tied to no single request: it belongs to whichever\n\t * document is current when the value lands. Returns an unsubscribe function.\n\t */\n\tonResolved(listener: (lines: WorkerAsyncUpdate[]) => void): () => void;\n\t/**\n\t * Subscribe to live-data resolutions that failed. Returns an unsubscribe\n\t * function. See {@link onResolved}; this is its failure channel.\n\t */\n\tonAsyncError(listener: (error: WorkerAsyncError) => void): () => void;\n\t/** Reject every in-flight request and tear the transport down. Idempotent. */\n\tterminate(): void;\n}\n\n/** A promise awaiting one worker answer, plus the abort wiring to unhook when it settles. */\ninterface PendingRequest {\n\tresolve: (value: unknown) => void;\n\treject: (error: unknown) => void;\n\tsignal?: AbortSignal;\n\tonAbort?: () => void;\n}\n\nclass WorkerEngineClient implements WorkerEngine {\n\tprivate readonly transport: WorkerTransport;\n\tprivate nextId = 1;\n\tprivate readonly pending = new Map<number, PendingRequest>();\n\t// Broadcast subscribers for async resolutions. Sets, not one callback each, so\n\t// several views can watch the same worker; a resolution is not tied to a\n\t// request id, so these live outside `pending`.\n\tprivate readonly resolvedListeners = new Set<(lines: WorkerAsyncUpdate[]) => void>();\n\tprivate readonly asyncErrorListeners = new Set<(error: WorkerAsyncError) => void>();\n\tprivate terminated = false;\n\n\tconstructor(transport: WorkerTransport) {\n\t\tthis.transport = transport;\n\t\tthis.transport.onMessage((raw) => this.onMessage(raw));\n\t}\n\n\t/** Perform the init handshake, resolving once the worker posts `ready`. */\n\tinit(options: WorkerEngineOptions): Promise<void> {\n\t\tconst id = this.nextId++;\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve: () => resolve(), reject });\n\t\t\tthis.transport.postMessage({\n\t\t\t\tkind: \"init\",\n\t\t\t\tid,\n\t\t\t\tlocaleCode: options.localeCode,\n\t\t\t\tdiagnostics: options.diagnostics,\n\t\t\t\tconfig: options.config,\n\t\t\t\tpackages: options.packages,\n\t\t\t\tformatting: options.formatting,\n\t\t\t});\n\t\t});\n\t}\n\n\tparseDocument(\n\t\tinput: string,\n\t\toptions?: UnifiedParsingOptions & WorkerCallOptions,\n\t): Promise<SerializedParsingResult> {\n\t\t// The signal stays main-side and drives a `cancel`; only the parsing\n\t\t// options cross, so an AbortSignal never reaches `postMessage`.\n\t\tconst { signal, ...parsing } = options ?? {};\n\t\tconst parseOptions = Object.keys(parsing).length > 0 ? (parsing as UnifiedParsingOptions) : undefined;\n\t\treturn this.call<SerializedParsingResult>(\"parseDocument\", [input, parseOptions], signal);\n\t}\n\n\tevaluateLines(lines: string[], options?: WorkerCallOptions): Promise<SerializedParsedLine[]> {\n\t\treturn this.call<SerializedParsedLine[]>(\"evaluateLines\", [lines], options?.signal);\n\t}\n\n\tevaluateExpression(expression: string, options?: WorkerCallOptions): Promise<SerializedValue> {\n\t\treturn this.call<SerializedValue>(\"evaluateExpression\", [expression], options?.signal);\n\t}\n\n\tonResolved(listener: (lines: WorkerAsyncUpdate[]) => void): () => void {\n\t\tthis.resolvedListeners.add(listener);\n\t\treturn () => this.resolvedListeners.delete(listener);\n\t}\n\n\tonAsyncError(listener: (error: WorkerAsyncError) => void): () => void {\n\t\tthis.asyncErrorListeners.add(listener);\n\t\treturn () => this.asyncErrorListeners.delete(listener);\n\t}\n\n\tterminate(): void {\n\t\tif (this.terminated) return;\n\t\tthis.terminated = true;\n\t\tconst error = workerTerminatedError();\n\t\tfor (const entry of this.pending.values()) {\n\t\t\tthis.unhook(entry);\n\t\t\tentry.reject(error);\n\t\t}\n\t\tthis.pending.clear();\n\t\t// No more resolutions can arrive across a torn-down transport, so drop the\n\t\t// subscribers rather than leaving them referenced for the client's lifetime.\n\t\tthis.resolvedListeners.clear();\n\t\tthis.asyncErrorListeners.clear();\n\t\tthis.transport.terminate();\n\t}\n\n\t/** Dispatch one request and return the promise that settles on its answer. */\n\tprivate call<T>(method: WorkerMethod, args: WorkerRequestArgs, signal?: AbortSignal): Promise<T> {\n\t\tif (this.terminated) return Promise.reject(workerTerminatedError());\n\t\tif (signal?.aborted) return Promise.reject(workerCancelledError(method));\n\n\t\tconst id = this.nextId++;\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst entry: PendingRequest = { resolve: resolve as (value: unknown) => void, reject };\n\n\t\t\tif (signal) {\n\t\t\t\tconst onAbort = (): void => {\n\t\t\t\t\t// Nothing to do if the answer already arrived and settled this id.\n\t\t\t\t\tif (!this.pending.has(id)) return;\n\t\t\t\t\tthis.pending.delete(id);\n\t\t\t\t\tthis.transport.postMessage({ kind: \"cancel\", id });\n\t\t\t\t\treject(workerCancelledError(method));\n\t\t\t\t};\n\t\t\t\tentry.signal = signal;\n\t\t\t\tentry.onAbort = onAbort;\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t}\n\n\t\t\tthis.pending.set(id, entry);\n\t\t\tthis.transport.postMessage({ kind: \"request\", id, method, args });\n\t\t});\n\t}\n\n\t/** Route one incoming message to the request that is waiting on its id. */\n\tprivate onMessage(raw: unknown): void {\n\t\tconst message = raw as WorkerToMainMessage;\n\t\tswitch (message.kind) {\n\t\t\tcase \"ready\":\n\t\t\tcase \"result\": {\n\t\t\t\tconst value = message.kind === \"result\" ? message.value : undefined;\n\t\t\t\tthis.settle(message.id, (entry) => entry.resolve(value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"error\":\n\t\t\t\tthis.settle(message.id, (entry) => entry.reject(deserializeEngineError(message.error)));\n\t\t\t\tbreak;\n\t\t\tcase \"async-update\":\n\t\t\t\t// A broadcast, not an answer to a request: fan it out to every\n\t\t\t\t// subscriber. A copy of the listener set is iterated so a listener\n\t\t\t\t// that unsubscribes itself mid-callback cannot disturb the walk.\n\t\t\t\tfor (const listener of [...this.resolvedListeners]) listener(message.lines);\n\t\t\t\tbreak;\n\t\t\tcase \"async-error\":\n\t\t\t\tfor (const listener of [...this.asyncErrorListeners]) {\n\t\t\t\t\tlistener({\n\t\t\t\t\t\tqueryKey: message.queryKey,\n\t\t\t\t\t\tpackageId: message.packageId,\n\t\t\t\t\t\terror: deserializeEngineError(message.error),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/** Remove a pending request by id and run the settle callback, if it is still pending. */\n\tprivate settle(id: number, apply: (entry: PendingRequest) => void): void {\n\t\tconst entry = this.pending.get(id);\n\t\tif (!entry) return;\n\t\tthis.pending.delete(id);\n\t\tthis.unhook(entry);\n\t\tapply(entry);\n\t}\n\n\t/** Detach an entry's abort listener so a settled request leaves nothing on the signal. */\n\tprivate unhook(entry: PendingRequest): void {\n\t\tif (entry.signal && entry.onAbort) entry.signal.removeEventListener(\"abort\", entry.onAbort);\n\t}\n}\n\n/**\n * Build a worker-backed engine and wait for it to be ready.\n *\n * ```ts\n * const { client, host } = createLinkedTransports();\n * startWorkerRuntime(host);\n * const engine = await createWorkerEngine({ transport: client });\n * const result = await engine.parseDocument(text);\n * ```\n *\n * In production `client` wraps a real `Worker` (see `eventTargetTransport` /\n * `messagePortTransport`), and `startWorkerRuntime` runs inside that worker.\n */\nexport async function createWorkerEngine(options: WorkerEngineOptions): Promise<WorkerEngine> {\n\tconst client = new WorkerEngineClient(options.transport);\n\tawait client.init(options);\n\treturn client;\n}\n","/**\n * Turn live engine results into the clone-safe DTOs the worker harness posts.\n *\n * These functions run on the worker side, just before a result crosses the\n * boundary, and are also what the main side re-runs on a synchronous result to\n * compare the two paths in tests. They are pure and deterministic given the\n * same {@link FormattingSettings}, so a value serialised on either side is\n * byte-for-byte the same DTO.\n */\n\nimport { Value, ValueType, type MatrixData, type MatrixEntry, type RangeData, type ColourData } from \"@solve-js/vm/Value\";\nimport { formatValue } from \"@solve-js/format/FormatEngine\";\nimport { toHexString, formatColour } from \"@solve-js/packages/colour/ColourMath\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport { formatSymbolic } from \"@solve-js/symbolic\";\nimport type { ParsedLine, InlineSolvePosition, ParsingResult } from \"@solve-js/types/ParsingResult\";\nimport type {\n\tSerializedValue,\n\tSerializedMatrix,\n\tSerializedParsedLine,\n\tSerializedInlineSolve,\n\tSerializedParsingResult,\n} from \"./dto\";\n\n/**\n * The JSON-safe string tag for a non-finite reading. `Infinity`/`-Infinity`/`NaN`\n * cannot cross `JSON` (which turns each into `null`), so this one string form is\n * what survives both `structuredClone` and `JSON`, and a host recovers the value\n * with `Number(tag)`. Shared by the scalar `nonFinite` field and matrix cells.\n */\nfunction nonFiniteTag(n: number): \"Infinity\" | \"-Infinity\" | \"NaN\" {\n\treturn n > 0 ? \"Infinity\" : n < 0 ? \"-Infinity\" : \"NaN\";\n}\n\n/** Project a matrix onto clone-safe cells: finite primitives pass through, symbolic cells and non-finite numbers become strings. */\nfunction serializeMatrix(m: MatrixData): SerializedMatrix {\n\tconst cells = m.data.map((cell: MatrixEntry): number | boolean | string => {\n\t\t// A `SymbolicNode` (the object-typed cell variant) flattens to its display\n\t\t// string. A non-finite number (a `[1/0, 2]` cell) cannot cross JSON any\n\t\t// more than a scalar reading can, so it takes the same string tag rather\n\t\t// than being passed through raw and turned into `null` by `JSON.stringify`\n\t\t// (which would diverge from the `structuredClone` path). A finite number\n\t\t// or a boolean is already clone-safe and passes through.\n\t\tif (typeof cell === \"object\" && cell !== null) return formatSymbolic(cell);\n\t\tif (typeof cell === \"number\" && !Number.isFinite(cell)) return nonFiniteTag(cell);\n\t\treturn cell;\n\t});\n\treturn { rows: m.rows, cols: m.cols, cells, hasSymbolic: m.hasSymbolic };\n}\n\n/**\n * Project a {@link Value} onto a {@link SerializedValue}.\n *\n * `text` and `number` are set for every value; the type-specific fields are\n * added only where the payload needs them, so the DTO stays minimal and a\n * deep-equal between the two evaluation paths does not trip on a property one\n * side left `undefined`.\n */\nexport function serializeValue(value: Value, settings?: FormattingSettings): SerializedValue {\n\tconst reading = value.toNumber();\n\tconst dto: SerializedValue = {\n\t\ttype: value.type,\n\t\ttext: formatValue(value, settings),\n\t\t// A non-finite reading (1/0, 0/0, an overflow) cannot cross JSON, which\n\t\t// turns it into null and breaks the round-trip the DTO guarantees. Keep\n\t\t// `number` finite and name the real value in `nonFinite` instead.\n\t\tnumber: Number.isFinite(reading) ? reading : 0,\n\t};\n\tif (!Number.isFinite(reading)) {\n\t\tdto.nonFinite = nonFiniteTag(reading);\n\t}\n\n\tif (value.unit !== undefined) dto.unit = value.unit;\n\tif (value.timedOut !== undefined) dto.timedOut = value.timedOut;\n\n\tconst raw = value.value;\n\tif (typeof raw === \"bigint\") {\n\t\t// Covers BigInt values and a Hex value that carries a bigint magnitude:\n\t\t// a base-ten string is the one representation that neither loses\n\t\t// precision nor breaks JSON.\n\t\tdto.bigint = raw.toString();\n\t} else if (value.type === ValueType.Matrix) {\n\t\tdto.matrix = serializeMatrix(raw as MatrixData);\n\t} else if (value.type === ValueType.Range) {\n\t\tconst r = raw as RangeData;\n\t\tdto.range = { min: r.min, max: r.max };\n\t} else if (value.type === ValueType.Colour) {\n\t\tconst c = raw as ColourData;\n\t\tdto.colour = { hex: toHexString(c), r: c.r, g: c.g, b: c.b, a: c.a, format: c.format, css: formatColour(c) };\n\t}\n\n\treturn dto;\n}\n\n/** Serialise a nullable value, the shape both `result` fields carry. */\nfunction serializeMaybe(value: Value | null | undefined, settings?: FormattingSettings): SerializedValue | null {\n\treturn value ? serializeValue(value, settings) : null;\n}\n\n/** Project an inline solve onto its DTO, serialising its result. */\nfunction serializeInlineSolve(solve: InlineSolvePosition, settings?: FormattingSettings): SerializedInlineSolve {\n\treturn {\n\t\tstart: solve.start,\n\t\tend: solve.end,\n\t\texpression: solve.expression,\n\t\tlineNumber: solve.lineNumber,\n\t\tcolumnNumber: solve.columnNumber,\n\t\tresult: serializeMaybe(solve.result, settings),\n\t\terror: solve.error ?? null,\n\t};\n}\n\n/** Project a parsed line onto its DTO, serialising its result and every inline solve. */\nexport function serializeParsedLine(line: ParsedLine, settings?: FormattingSettings): SerializedParsedLine {\n\treturn {\n\t\tlineNumber: line.lineNumber,\n\t\ttext: line.text,\n\t\tstartPosition: line.startPosition,\n\t\tendPosition: line.endPosition,\n\t\tisEmpty: line.isEmpty,\n\t\thasInlineSolves: line.hasInlineSolves,\n\t\tinlineSolves: line.inlineSolves.map((solve) => serializeInlineSolve(solve, settings)),\n\t\texpression: line.expression,\n\t\tresult: serializeMaybe(line.result, settings),\n\t\terror: line.error,\n\t};\n}\n\n/** Project a whole parsing result onto its DTO. */\nexport function serializeParsingResult(result: ParsingResult, settings?: FormattingSettings): SerializedParsingResult {\n\tconst dto: SerializedParsingResult = {\n\t\tlines: result.lines.map((line) => serializeParsedLine(line, settings)),\n\t\ttotalLines: result.totalLines,\n\t\terrors: [...result.errors],\n\t};\n\t// The diagnostics report is already the engine's own JSON form, so it\n\t// crosses unchanged; present only when the host asked for it.\n\tif (result.diagnostics !== undefined) dto.diagnostics = result.diagnostics;\n\treturn dto;\n}\n","/**\n * The worker-side half of the harness: it owns an {@link ExpressionEngine} and\n * answers the protocol.\n *\n * {@link startWorkerRuntime} is transport-agnostic, so the same function runs\n * behind a browser `Worker`, a Node `worker_threads` port, or an in-process\n * link. A host's worker entry file is two lines: adapt the environment onto a\n * {@link WorkerTransport} and call this.\n *\n * The runtime never posts a raw {@link Value}. Every result is projected onto a\n * DTO first (`worker/serialize.ts`), and every failure is caught and flattened\n * into a structured error, so a worker-side throw reaches the caller as an\n * `EngineError` rather than a lost promise.\n */\n\nimport { ExpressionEngine } from \"@solve-js/engine/ExpressionEngine\";\nimport type { AsyncResolutionEvent } from \"@solve-js/engine/AsyncResolutionBatcher\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport {\n\tErrorFactory,\n\tnormalizeUnknownError,\n\tserializeEngineError,\n\tWorkerErrorCodes,\n} from \"@solve-js/errors\";\nimport { serializeParsingResult, serializeParsedLine, serializeValue } from \"./serialize\";\nimport type { WorkerTransport } from \"./transport\";\nimport type {\n\tMainToWorkerMessage,\n\tInitMessage,\n\tRequestMessage,\n\tWorkerToMainMessage,\n\tAsyncResolvedLine,\n} from \"./protocol\";\n\n/** Options a host bakes into its own worker entry, chiefly its custom packages. */\nexport interface WorkerRuntimeOptions {\n\t/**\n\t * The packages available to register, defaulting to {@link BUILTIN_PACKAGES}.\n\t * A host with its own package authors a worker entry that passes them here,\n\t * then selects among them by name from the main side. This is how a\n\t * function-carrying package reaches the worker: baked into its bundle, never\n\t * posted across the boundary.\n\t */\n\tpackages?: IEnginePackage[];\n}\n\n/**\n * Resolve the requested package names against the available set.\n *\n * Undefined names means \"all of them\". A name with no match is a configuration\n * failure the caller must see, not a silent omission that would leave a feature\n * quietly missing from every result.\n */\nfunction resolvePackages(available: IEnginePackage[], names: string[] | undefined): IEnginePackage[] {\n\tif (names === undefined) return available;\n\tconst byName = new Map(available.map((pkg) => [pkg.name, pkg]));\n\tconst resolved: IEnginePackage[] = [];\n\tfor (const name of names) {\n\t\tconst pkg = byName.get(name);\n\t\tif (!pkg) {\n\t\t\tthrow ErrorFactory.config(\n\t\t\t\tWorkerErrorCodes.WORKER_UNKNOWN_PACKAGE,\n\t\t\t\t`No package named \"${name}\" is available in this worker runtime`,\n\t\t\t\t{ name, available: [...byName.keys()] },\n\t\t\t);\n\t\t}\n\t\tresolved.push(pkg);\n\t}\n\treturn resolved;\n}\n\n/**\n * Attach the runtime to a transport and start serving.\n *\n * Returns a teardown function that clears the engine and detaches, for a host\n * that reuses a transport or shuts a worker down cleanly.\n */\nexport function startWorkerRuntime(transport: WorkerTransport, options: WorkerRuntimeOptions = {}): () => void {\n\tconst available = options.packages ?? BUILTIN_PACKAGES;\n\n\tlet engine: ExpressionEngine | null = null;\n\tlet formatting: FormattingSettings | undefined;\n\t// One AbortController per in-flight request, so a `cancel` can map onto the\n\t// engine's keystroke signal for exactly the request the caller aborted.\n\tconst inFlight = new Map<number, AbortController>();\n\n\t// The line texts of the current document, keyed by the line number the engine\n\t// evaluates them under (1-based for a document, -1 for a lone expression). An\n\t// async resolution names the lines whose result changed but not the new value,\n\t// so this is what the event pump re-reads a line from to recover it.\n\tlet retainedLines = new Map<number, string>();\n\n\t// The current document's abort controller, kept alive past the request that\n\t// created it so this document's async resolutions can still land. Aborted when\n\t// a new document supersedes it: aborting drops the old document's in-flight\n\t// resolutions at the engine's own staleness guard (an aborted signal is\n\t// discarded before it reaches the batcher), so a stale value never reaches the\n\t// host as if it were current. See {@link handleRequest}.\n\tlet documentController: AbortController | null = null;\n\n\t// Cancels the event-stream reader on teardown. Null until the pump starts.\n\tlet stopEventPump: (() => void) | null = null;\n\n\tconst post = (message: WorkerToMainMessage): void => transport.postMessage(message);\n\n\tconst fail = (id: number, error: unknown): void => {\n\t\tpost({ kind: \"error\", id, error: serializeEngineError(normalizeUnknownError(error)) });\n\t};\n\n\t/**\n\t * Record the line texts a request evaluates, so a later async resolution can\n\t * re-read exactly the lines it names. A whole document splits into 1-based\n\t * lines; a lone `evaluateExpression` maps onto the engine's `-1` sentinel, the\n\t * same line number the engine registers and later reports for it.\n\t */\n\tconst retainLines = (message: RequestMessage): Map<number, string> => {\n\t\tconst map = new Map<number, string>();\n\t\tif (message.method === \"parseDocument\") {\n\t\t\t(message.args[0] as string).split(\"\\n\").forEach((text, index) => map.set(index + 1, text));\n\t\t} else if (message.method === \"evaluateLines\") {\n\t\t\t(message.args[0] as string[]).forEach((text, index) => map.set(index + 1, text));\n\t\t} else {\n\t\t\tmap.set(-1, message.args[0] as string);\n\t\t}\n\t\treturn map;\n\t};\n\n\t/**\n\t * Turn one async resolution event into a message home.\n\t *\n\t * A `lines-updated` event names the lines whose result changed; the resolved\n\t * value lives in the engine's cache, so each named line is re-evaluated (which\n\t * now reads the settled value from that cache rather than starting a fresh\n\t * fetch) and serialised. A line the current document no longer retains belongs\n\t * to a superseded document and is skipped. An `error` event carries the failed\n\t * query straight across as a structured error.\n\t */\n\tconst handleAsyncEvent = (eng: ExpressionEngine, event: AsyncResolutionEvent): void => {\n\t\tif (event.type === \"error\") {\n\t\t\tpost({\n\t\t\t\tkind: \"async-error\",\n\t\t\t\tqueryKey: event.queryKey,\n\t\t\t\tpackageId: event.packageId,\n\t\t\t\terror: serializeEngineError(normalizeUnknownError(event.error)),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst lines: AsyncResolvedLine[] = [];\n\t\tfor (const lineNumber of event.lineNumbers) {\n\t\t\tconst text = retainedLines.get(lineNumber);\n\t\t\tif (text === undefined) continue;\n\t\t\ttry {\n\t\t\t\tconst value = eng.evaluateLine(lineNumber, text);\n\t\t\t\tif (value) lines.push({ lineNumber, value: serializeValue(value, formatting) });\n\t\t\t} catch {\n\t\t\t\t// A line that resolved into an error re-throws on re-evaluation; the\n\t\t\t\t// batcher's own `error` event is the channel for that, so this keeps\n\t\t\t\t// the update to the lines that produced a value rather than posting a\n\t\t\t\t// second, half-formed failure here.\n\t\t\t}\n\t\t}\n\t\tif (lines.length > 0) post({ kind: \"async-update\", lines });\n\t};\n\n\t/**\n\t * Drain the engine's async-resolution event stream for the life of the\n\t * runtime, posting each event home. Started once the engine exists; the reader\n\t * loop ends when the stream closes (engine cleared) or the returned canceller\n\t * runs at teardown.\n\t */\n\tconst startEventPump = (eng: ExpressionEngine): void => {\n\t\tstopEventPump?.();\n\t\tconst reader = eng.getEventStream().getReader();\n\t\tstopEventPump = () => void reader.cancel();\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) return;\n\t\t\t\t\thandleAsyncEvent(eng, value);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// The stream errored or was cancelled (teardown); the loop is done.\n\t\t\t}\n\t\t})();\n\t};\n\n\tconst handleInit = (message: InitMessage): void => {\n\t\ttry {\n\t\t\tconst packages = resolvePackages(available, message.packages);\n\t\t\tengine = new ExpressionEngine({\n\t\t\t\tlocale: message.localeCode ?? \"en\",\n\t\t\t\tdiagnostics: message.diagnostics ?? false,\n\t\t\t\tconfig: message.config,\n\t\t\t\tpackages,\n\t\t\t});\n\t\t\tformatting = message.formatting;\n\t\t\t// Drain live-data resolutions for the engine's whole lifetime, so a\n\t\t\t// value that settles after a request already answered still reaches the\n\t\t\t// host. Started here, after the engine exists, and torn down with it.\n\t\t\tstartEventPump(engine);\n\t\t\tpost({ kind: \"ready\", id: message.id });\n\t\t} catch (error) {\n\t\t\t// A build failure leaves no engine; the caller's `createWorkerEngine`\n\t\t\t// promise rejects with this rather than hanging on a `ready` that\n\t\t\t// never comes.\n\t\t\tfail(message.id, error);\n\t\t}\n\t};\n\n\tconst runMethod = (eng: ExpressionEngine, message: RequestMessage): unknown => {\n\t\tconst { method, args } = message;\n\t\tswitch (method) {\n\t\t\tcase \"parseDocument\":\n\t\t\t\treturn serializeParsingResult(eng.parseDocument(args[0] as string, args[1] as never), formatting);\n\t\t\tcase \"evaluateLines\":\n\t\t\t\treturn eng.evaluateLines(args[0] as string[]).map((line) => serializeParsedLine(line, formatting));\n\t\t\tcase \"evaluateExpression\":\n\t\t\t\t// Mirrors ExpressionEngine.evaluateExpression: a single Value in,\n\t\t\t\t// a single serialized Value out.\n\t\t\t\treturn serializeValue(eng.evaluateExpression(args[0] as string), formatting);\n\t\t\tdefault:\n\t\t\t\tthrow ErrorFactory.execution(\n\t\t\t\t\tWorkerErrorCodes.WORKER_UNKNOWN_METHOD,\n\t\t\t\t\t`The worker runtime has no method named \"${String(method)}\"`,\n\t\t\t\t\t{ method },\n\t\t\t\t);\n\t\t}\n\t};\n\n\tconst handleRequest = (message: RequestMessage): void => {\n\t\tconst eng = engine;\n\t\tif (!eng) {\n\t\t\tfail(\n\t\t\t\tmessage.id,\n\t\t\t\tErrorFactory.execution(\n\t\t\t\t\tWorkerErrorCodes.WORKER_NOT_INITIALISED,\n\t\t\t\t\t\"The worker received a request before its engine finished initialising\",\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Supersede the previous document: abort its controller so any resolution\n\t\t// still in flight for it is dropped at the engine's staleness guard rather\n\t\t// than posted home as if it belonged to this request's document. The old\n\t\t// retained lines go with it. Every evaluate call shares one engine and one\n\t\t// document context, so the most recent call is the live one.\n\t\tdocumentController?.abort();\n\n\t\t// This request's controller doubles as the document controller: wired in as\n\t\t// the keystroke signal so a later `cancel` (or the next supersede) aborts\n\t\t// the async work this evaluation fires, the same mechanism a host uses on\n\t\t// the main thread. It is deliberately NOT aborted when the request settles,\n\t\t// so this document's live values can still resolve and stream back.\n\t\tconst controller = new AbortController();\n\t\tdocumentController = controller;\n\t\tretainedLines = retainLines(message);\n\t\tinFlight.set(message.id, controller);\n\t\teng.setKeystrokeSignal(controller.signal);\n\n\t\ttry {\n\t\t\tconst value = runMethod(eng, message);\n\t\t\tpost({ kind: \"result\", id: message.id, value });\n\t\t} catch (error) {\n\t\t\tfail(message.id, error);\n\t\t} finally {\n\t\t\tinFlight.delete(message.id);\n\t\t\teng.setKeystrokeSignal(null);\n\t\t}\n\t};\n\n\ttransport.onMessage((raw) => {\n\t\tconst message = raw as MainToWorkerMessage;\n\t\tswitch (message.kind) {\n\t\t\tcase \"init\":\n\t\t\t\thandleInit(message);\n\t\t\t\tbreak;\n\t\t\tcase \"request\":\n\t\t\t\thandleRequest(message);\n\t\t\t\tbreak;\n\t\t\tcase \"cancel\":\n\t\t\t\t// Abort maps onto the keystroke signal for the named request; a\n\t\t\t\t// cancel that arrives after the request already settled finds no\n\t\t\t\t// controller and is a harmless no-op.\n\t\t\t\tinFlight.get(message.id)?.abort();\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\treturn () => {\n\t\tstopEventPump?.();\n\t\tstopEventPump = null;\n\t\tdocumentController?.abort();\n\t\tdocumentController = null;\n\t\tretainedLines = new Map();\n\t\tfor (const controller of inFlight.values()) controller.abort();\n\t\tinFlight.clear();\n\t\tengine?.clear();\n\t\tengine = null;\n\t\ttransport.terminate();\n\t};\n}\n","/**\n * The seam between the harness and whatever actually carries messages.\n *\n * Both the client (`worker/client.ts`) and the runtime (`worker/runtime.ts`)\n * talk to a {@link WorkerTransport} and nothing more, so the same code drives a\n * browser `Worker`, a Node `worker_threads` port, or an in-process pair. The\n * three factory functions below adapt each of those onto the interface; a host\n * with a transport this file does not cover can implement the three methods\n * directly.\n */\n\n/**\n * A bidirectional message channel with a single receive handler.\n *\n * `onMessage` registers the one handler the harness needs; calling it again\n * replaces the previous handler. `terminate` tears the channel down and is safe\n * to call more than once.\n */\nexport interface WorkerTransport {\n\t/** Send one message to the other end. The message must be clone-safe. */\n\tpostMessage(message: unknown): void;\n\t/** Register the handler that receives messages from the other end. */\n\tonMessage(handler: (message: unknown) => void): void;\n\t/** Tear the channel down. Idempotent. */\n\tterminate(): void;\n}\n\n/**\n * Clone a message the way `postMessage` would, so an in-process transport has\n * the same value semantics as a real one.\n *\n * The harness protocol is clone-safe by construction, so the `JSON` fallback\n * (for a runtime without a global `structuredClone`) is lossless here; the\n * structured-clone path is preferred because it is what a real worker uses and\n * because it throws loudly if a non-clone-safe value ever reaches it, which is\n * exactly the mistake the DTO layer exists to prevent.\n *\n * A function, not a module-level const, so this module does no work at load\n * time and stays deletable under the package's `sideEffects: false` claim; the\n * `typeof` probe runs once per message, which is free next to the clone itself.\n */\nfunction cloneMessage<T>(value: T): T {\n\treturn typeof globalThis.structuredClone === \"function\"\n\t\t? globalThis.structuredClone(value)\n\t\t: JSON.parse(JSON.stringify(value));\n}\n\n/**\n * A pair of linked in-process transports.\n *\n * `client` and `host` are two ends of one channel: a message posted on either\n * is cloned at post time and delivered to the other on a microtask, so delivery\n * is asynchronous (as a real worker's is) but deterministic (no timers, no I/O).\n * Wire `client` into {@link createWorkerEngine} and `host` into\n * {@link startWorkerRuntime} to run the whole protocol, DTO serialisation and\n * cancellation included, without a second thread. This is the transport tests\n * use, and a fit for a host that wants the message-passing shape on one thread.\n */\nexport function createLinkedTransports(): { client: WorkerTransport; host: WorkerTransport } {\n\tlet clientHandler: ((message: unknown) => void) | null = null;\n\tlet hostHandler: ((message: unknown) => void) | null = null;\n\tlet alive = true;\n\n\t// The handler is read at delivery time rather than post time so setup order\n\t// (post before the other end has registered) cannot drop a message.\n\tconst deliver = (target: () => ((message: unknown) => void) | null, message: unknown): void => {\n\t\tconst cloned = cloneMessage(message);\n\t\tqueueMicrotask(() => {\n\t\t\tif (!alive) return;\n\t\t\ttarget()?.(cloned);\n\t\t});\n\t};\n\n\tconst client: WorkerTransport = {\n\t\tpostMessage: (message) => deliver(() => hostHandler, message),\n\t\tonMessage: (handler) => {\n\t\t\tclientHandler = handler;\n\t\t},\n\t\tterminate: () => {\n\t\t\talive = false;\n\t\t},\n\t};\n\n\tconst host: WorkerTransport = {\n\t\tpostMessage: (message) => deliver(() => clientHandler, message),\n\t\tonMessage: (handler) => {\n\t\t\thostHandler = handler;\n\t\t},\n\t\tterminate: () => {\n\t\t\talive = false;\n\t\t},\n\t};\n\n\treturn { client, host };\n}\n\n/** The `postMessage`/`onmessage`/event-listener shape a browser `Worker`, a worker's `self`, or a DOM `MessagePort` presents. */\ninterface EventTargetLike {\n\tpostMessage(message: unknown): void;\n\taddEventListener?(type: \"message\", handler: (event: { data: unknown }) => void): void;\n\tonmessage?: ((event: { data: unknown }) => void) | null;\n\tterminate?(): void;\n\tclose?(): void;\n\tstart?(): void;\n}\n\n/**\n * Adapt a browser-style message target onto a {@link WorkerTransport}.\n *\n * Covers the main-side `Worker`, the worker global `self`, and a DOM\n * `MessagePort`: each posts with `postMessage` and receives a `MessageEvent`\n * whose `data` is the payload. A `MessagePort` is `start`ed here so it begins\n * dispatching. On the main side pass a `Worker`; inside a browser worker pass\n * `self`.\n */\nexport function eventTargetTransport(target: EventTargetLike): WorkerTransport {\n\treturn {\n\t\tpostMessage: (message) => target.postMessage(message),\n\t\tonMessage: (handler) => {\n\t\t\tconst listener = (event: { data: unknown }): void => handler(event.data);\n\t\t\tif (typeof target.addEventListener === \"function\") {\n\t\t\t\ttarget.addEventListener(\"message\", listener);\n\t\t\t} else {\n\t\t\t\ttarget.onmessage = listener;\n\t\t\t}\n\t\t\ttarget.start?.();\n\t\t},\n\t\t// A main-side Worker terminates; a worker's own `self` closes. Calling\n\t\t// whichever exists keeps one adapter usable from both ends.\n\t\tterminate: () => {\n\t\t\ttarget.terminate?.();\n\t\t\ttarget.close?.();\n\t\t},\n\t};\n}\n\n/** The `postMessage`/`on(\"message\")` shape a Node `worker_threads` `Worker`, `parentPort`, or `MessagePort` presents. */\ninterface MessagePortLike {\n\tpostMessage(message: unknown): void;\n\ton(event: \"message\", handler: (message: unknown) => void): void;\n\tterminate?(): void;\n\tclose?(): void;\n}\n\n/**\n * Adapt a Node `worker_threads` port onto a {@link WorkerTransport}.\n *\n * Covers the main-side `Worker`, the worker's `parentPort`, and a\n * `worker_threads` `MessagePort`: each posts with `postMessage` and emits a\n * `\"message\"` event whose argument IS the payload (no `.data` wrapper, unlike\n * the DOM). On the main side pass the `Worker`; inside the worker pass\n * `parentPort`.\n */\nexport function messagePortTransport(port: MessagePortLike): WorkerTransport {\n\treturn {\n\t\tpostMessage: (message) => port.postMessage(message),\n\t\tonMessage: (handler) => {\n\t\t\tport.on(\"message\", (message) => handler(message));\n\t\t},\n\t\tterminate: () => {\n\t\t\tport.terminate?.();\n\t\t\tport.close?.();\n\t\t},\n\t};\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "solve-engine",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "An embeddable expression engine for natural-language calculations: units, currencies, percentages, dates and matrices, with the parsing and evaluation plumbing already built.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"expression-evaluator",
|
|
@@ -138,16 +138,6 @@
|
|
|
138
138
|
"default": "./dist/normalizer.cjs"
|
|
139
139
|
}
|
|
140
140
|
},
|
|
141
|
-
"./variables": {
|
|
142
|
-
"import": {
|
|
143
|
-
"types": "./dist/variables.d.ts",
|
|
144
|
-
"default": "./dist/variables.js"
|
|
145
|
-
},
|
|
146
|
-
"require": {
|
|
147
|
-
"types": "./dist/variables.d.cts",
|
|
148
|
-
"default": "./dist/variables.cjs"
|
|
149
|
-
}
|
|
150
|
-
},
|
|
151
141
|
"./resolvers": {
|
|
152
142
|
"import": {
|
|
153
143
|
"types": "./dist/resolvers.d.ts",
|
|
@@ -233,10 +223,8 @@
|
|
|
233
223
|
"devDependencies": {
|
|
234
224
|
"@jest/globals": "^30.4.1",
|
|
235
225
|
"@types/node": "^26.2.0",
|
|
236
|
-
"@types/semver": "^7.5.0",
|
|
237
226
|
"convert": "^7.0.0",
|
|
238
227
|
"jest": "^30.4.2",
|
|
239
|
-
"semver": "^7.6.0",
|
|
240
228
|
"ts-jest": "^29.4.12",
|
|
241
229
|
"tsup": "8.5.1",
|
|
242
230
|
"typescript": "5.9.3"
|
package/dist/chunk-3BOK2LDK.js
DELETED
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
// src/utilities/Strings.ts
|
|
2
|
-
function stripQuotes(value) {
|
|
3
|
-
return value.startsWith('"') && value.endsWith('"') && value.length >= 2 ? value.slice(1, -1) : value;
|
|
4
|
-
}
|
|
5
|
-
function countLines(text, stopAfter = Number.MAX_SAFE_INTEGER) {
|
|
6
|
-
let count = 1;
|
|
7
|
-
let index = text.indexOf("\n");
|
|
8
|
-
while (index !== -1) {
|
|
9
|
-
if (++count > stopAfter) return count;
|
|
10
|
-
index = text.indexOf("\n", index + 1);
|
|
11
|
-
}
|
|
12
|
-
return count;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export { countLines, stripQuotes };
|
|
16
|
-
//# sourceMappingURL=chunk-3BOK2LDK.js.map
|
|
17
|
-
//# sourceMappingURL=chunk-3BOK2LDK.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utilities/Strings.ts"],"names":[],"mappings":";AASO,SAAS,YAAY,KAAA,EAAuB;AAClD,EAAA,OAAO,KAAA,CAAM,UAAA,CAAW,GAAG,CAAA,IAAK,MAAM,QAAA,CAAS,GAAG,CAAA,IAAK,KAAA,CAAM,UAAU,CAAA,GACpE,KAAA,CAAM,KAAA,CAAM,CAAA,EAAG,EAAE,CAAA,GACjB,KAAA;AACJ;AAeO,SAAS,UAAA,CAAW,IAAA,EAAc,SAAA,GAAoB,MAAA,CAAO,gBAAA,EAA0B;AAC7F,EAAA,IAAI,KAAA,GAAQ,CAAA;AACZ,EAAA,IAAI,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA;AAC7B,EAAA,OAAO,UAAU,EAAA,EAAI;AACpB,IAAA,IAAI,EAAE,KAAA,GAAQ,SAAA,EAAW,OAAO,KAAA;AAChC,IAAA,KAAA,GAAQ,IAAA,CAAK,OAAA,CAAQ,IAAA,EAAM,KAAA,GAAQ,CAAC,CAAA;AAAA,EACrC;AACA,EAAA,OAAO,KAAA;AACR","file":"chunk-3BOK2LDK.js","sourcesContent":["/**\n * Strips a single layer of matching double quotes from a string, if present.\n * Returns the input unchanged if it isn't fully wrapped in quotes.\n *\n * Was needed for STRING token values, which the lexer used to emit with their\n * surrounding `\"...\"` quotes still attached. `tokenizeString()` now strips them\n * when it builds the token, so on that path this is a no-op kept as a defence\n * against text arriving from somewhere else already quoted.\n */\nexport function stripQuotes(value: string): string {\n\treturn value.startsWith('\"') && value.endsWith('\"') && value.length >= 2\n\t\t? value.slice(1, -1)\n\t\t: value;\n}\n\n/**\n * How many lines `text` has, without splitting it into an array.\n *\n * `split(\"\\n\").length` answers the same question and allocates the whole\n * document to do it, which is the wrong shape for a caller whose next move may\n * be to refuse the document for being too large. Counting stops as soon as the\n * answer is \"more than the caller cares about\".\n *\n * @param text - The document.\n * @param stopAfter - Stop counting once past this many lines.\n * @returns The line count, or `stopAfter + 1` for anything longer. A document\n * with no newline in it is one line, matching `split`.\n */\nexport function countLines(text: string, stopAfter: number = Number.MAX_SAFE_INTEGER): number {\n\tlet count = 1;\n\tlet index = text.indexOf(\"\\n\");\n\twhile (index !== -1) {\n\t\tif (++count > stopAfter) return count;\n\t\tindex = text.indexOf(\"\\n\", index + 1);\n\t}\n\treturn count;\n}\n"]}
|
package/dist/chunk-3VGDNEE3.js
DELETED
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
// src/resolvers/ResolverRegistry.ts
|
|
2
|
-
var ResolverRegistry = class {
|
|
3
|
-
constructor() {
|
|
4
|
-
this.resolvers = /* @__PURE__ */ new Map();
|
|
5
|
-
}
|
|
6
|
-
/**
|
|
7
|
-
* Register an async resolver.
|
|
8
|
-
*
|
|
9
|
-
* Each resolver must have a unique `namespace`. If a resolver with the
|
|
10
|
-
* same namespace is already registered, the old one is destroyed and
|
|
11
|
-
* replaced (with a console warning). Packages that need multiple async
|
|
12
|
-
* operations should use `asyncResolvers: [...]` with distinct namespaces
|
|
13
|
-
* (e.g., `"weather:current"`, `"weather:forecast"`).
|
|
14
|
-
*/
|
|
15
|
-
register(resolver) {
|
|
16
|
-
if (this.resolvers.has(resolver.namespace)) {
|
|
17
|
-
console.warn(
|
|
18
|
-
`[ResolverRegistry] Namespace "${resolver.namespace}" already registered. Destroying old resolver and overwriting. Use distinct namespaces (e.g., "${resolver.namespace}:sub1", "${resolver.namespace}:sub2") to avoid collisions when a package needs multiple async resolvers.`
|
|
19
|
-
);
|
|
20
|
-
this.resolvers.get(resolver.namespace).destroy();
|
|
21
|
-
}
|
|
22
|
-
this.resolvers.set(resolver.namespace, resolver);
|
|
23
|
-
}
|
|
24
|
-
/**
|
|
25
|
-
* Unregister a resolver by namespace.
|
|
26
|
-
* Calls destroy() and clears all cache entries with that namespace prefix.
|
|
27
|
-
*/
|
|
28
|
-
unregister(namespace, queryClient) {
|
|
29
|
-
const resolver = this.resolvers.get(namespace);
|
|
30
|
-
if (resolver) {
|
|
31
|
-
resolver.destroy();
|
|
32
|
-
this.resolvers.delete(namespace);
|
|
33
|
-
}
|
|
34
|
-
if (queryClient) {
|
|
35
|
-
queryClient.removeQueries({ queryKey: [namespace] });
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
* Run all registered resolvers' preflight checks against compiled bytecode.
|
|
40
|
-
*
|
|
41
|
-
* Returns the first AsyncCheckResult found, or null if all data is ready.
|
|
42
|
-
* Short-circuits on first pending, subsequent pending ops will be
|
|
43
|
-
* discovered on re-evaluation when the first resolves.
|
|
44
|
-
*/
|
|
45
|
-
preflightAll(tokens, bytecode, packageId, signal, queryClient) {
|
|
46
|
-
for (const resolver of this.resolvers.values()) {
|
|
47
|
-
if (!resolver.preflight) continue;
|
|
48
|
-
const result = resolver.preflight(tokens, bytecode, packageId, signal, queryClient);
|
|
49
|
-
if (result) return result;
|
|
50
|
-
}
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
/**
|
|
54
|
-
* Get a resolver by namespace.
|
|
55
|
-
* Returns undefined if no resolver is registered for that namespace.
|
|
56
|
-
*/
|
|
57
|
-
get(namespace) {
|
|
58
|
-
return this.resolvers.get(namespace);
|
|
59
|
-
}
|
|
60
|
-
/** Number of registered resolvers. */
|
|
61
|
-
get size() {
|
|
62
|
-
return this.resolvers.size;
|
|
63
|
-
}
|
|
64
|
-
/**
|
|
65
|
-
* Check if a resolver is registered for the given namespace.
|
|
66
|
-
*/
|
|
67
|
-
has(namespace) {
|
|
68
|
-
return this.resolvers.has(namespace);
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Clear all resolvers (document switch, engine reset).
|
|
72
|
-
* Calls destroy() on each resolver and clears the map.
|
|
73
|
-
*/
|
|
74
|
-
clear() {
|
|
75
|
-
for (const resolver of this.resolvers.values()) {
|
|
76
|
-
resolver.destroy();
|
|
77
|
-
}
|
|
78
|
-
this.resolvers.clear();
|
|
79
|
-
}
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
export { ResolverRegistry };
|
|
83
|
-
//# sourceMappingURL=chunk-3VGDNEE3.js.map
|
|
84
|
-
//# sourceMappingURL=chunk-3VGDNEE3.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/resolvers/ResolverRegistry.ts"],"names":[],"mappings":";AAuEO,IAAM,mBAAN,MAAuB;AAAA,EAAvB,WAAA,GAAA;AACN,IAAA,IAAA,CAAQ,SAAA,uBAAgB,GAAA,EAA4B;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWpD,SAAS,QAAA,EAAgC;AAExC,IAAA,IAAI,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,SAAS,CAAA,EAAG;AAC3C,MAAA,OAAA,CAAQ,IAAA;AAAA,QACP,CAAA,8BAAA,EAAiC,SAAS,SAAS,CAAA,+FAAA,EAExC,SAAS,SAAS,CAAA,SAAA,EAAY,SAAS,SAAS,CAAA,0EAAA;AAAA,OAE5D;AACA,MAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,SAAS,EAAG,OAAA,EAAQ;AAAA,IACjD;AACA,IAAA,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,QAAA,CAAS,SAAA,EAAW,QAAQ,CAAA;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAA,CAAW,WAAmB,WAAA,EAAiC;AAC9D,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,SAAS,CAAA;AAC7C,IAAA,IAAI,QAAA,EAAU;AACb,MAAA,QAAA,CAAS,OAAA,EAAQ;AACjB,MAAA,IAAA,CAAK,SAAA,CAAU,OAAO,SAAS,CAAA;AAAA,IAChC;AAGA,IAAA,IAAI,WAAA,EAAa;AAChB,MAAA,WAAA,CAAY,cAAc,EAAE,QAAA,EAAU,CAAC,SAAS,GAAG,CAAA;AAAA,IACpD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,YAAA,CAAa,MAAA,EAAiB,QAAA,EAA2B,SAAA,EAAmB,QAAqB,WAAA,EAAmD;AACnJ,IAAA,KAAA,MAAW,QAAA,IAAY,IAAA,CAAK,SAAA,CAAU,MAAA,EAAO,EAAG;AAC/C,MAAA,IAAI,CAAC,SAAS,SAAA,EAAW;AACzB,MAAA,MAAM,SAAS,QAAA,CAAS,SAAA,CAAU,QAAQ,QAAA,EAAU,SAAA,EAAW,QAAQ,WAAW,CAAA;AAClF,MAAA,IAAI,QAAQ,OAAO,MAAA;AAAA,IACpB;AACA,IAAA,OAAO,IAAA;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,SAAA,EAA+C;AAClD,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,SAAS,CAAA;AAAA,EACpC;AAAA;AAAA,EAGA,IAAI,IAAA,GAAe;AAClB,IAAA,OAAO,KAAK,SAAA,CAAU,IAAA;AAAA,EACvB;AAAA;AAAA;AAAA;AAAA,EAKA,IAAI,SAAA,EAA4B;AAC/B,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,GAAA,CAAI,SAAS,CAAA;AAAA,EACpC;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAA,GAAc;AACb,IAAA,KAAA,MAAW,QAAA,IAAY,IAAA,CAAK,SAAA,CAAU,MAAA,EAAO,EAAG;AAC/C,MAAA,QAAA,CAAS,OAAA,EAAQ;AAAA,IAClB;AACA,IAAA,IAAA,CAAK,UAAU,KAAA,EAAM;AAAA,EACtB;AACD","file":"chunk-3VGDNEE3.js","sourcesContent":["import type { QueryClient } from \"@tanstack/query-core\";\nimport type { Token } from \"@solve-js/lexer\";\nimport type { BytecodeProgram } from \"@solve-js/parser/BytecodeBuilder\";\nimport type { Value } from \"@solve-js/vm/Value\";\n\n/**\n * Result from a resolver's preflight() check.\n * Returned when async data is needed, the orchestrator uses this\n * to subscribe to the resolver and return a Pending value immediately.\n */\nexport interface AsyncCheckResult {\n\t/** Unique cache key for deduplication (e.g., \"{packageId}:rates:USD:GBP\") */\n\tqueryKey: string;\n\t/** Promise that resolves to the final Value */\n\tresolver: Promise<Value>;\n\t/** Package owning this resolver */\n\tpackageId: string;\n\t/** AbortSignal for stale-data prevention */\n\tsignal: AbortSignal;\n\t/** Optional metadata for diagnostics */\n\tmetadata?: Record<string, unknown>;\n}\n\n/**\n * Interface for async resolvers registered by packages/plugins.\n *\n * Each resolver handles a domain of async data (currency rates,\n * weather, stock prices, etc.). The preflight() method is called\n * BEFORE VM execution to check if all data is cached. If not,\n * it returns an AsyncCheckResult and the engine skips the VM,\n * returning a Pending value instead.\n */\nexport interface IAsyncResolver {\n\t/** Unique namespace for cache key scoping (e.g., \"currency\", \"weather\") */\n\treadonly namespace: string;\n\n\t/**\n\t * Pre-flight check: called BEFORE VM execution.\n\t *\n\t * Returns null if all data for this expression is cached and ready.\n\t * Returns an AsyncCheckResult if async work is needed.\n\t *\n\t * This method is synchronous, it only checks caches, never fetches.\n\t * If data is missing, it creates a Promise and returns immediately.\n\t *\n\t * @param tokens - The lexed tokens for the expression\n\t * @param bytecode - The compiled bytecode program\n\t * @param pluginId - The plugin ID (for cache key scoping)\n\t * @param signal - AbortSignal for the current evaluation\n\t */\n\tpreflight?(tokens: Token[], bytecode: BytecodeProgram, packageId: string, signal: AbortSignal, queryClient: QueryClient): AsyncCheckResult | null;\n\n\t/**\n\t * Called when the resolver's namespace is being unregistered.\n\t * Clean up any in-flight promises, clear caches, unsubscribe.\n\t */\n\tdestroy(): void;\n}\n\n/**\n * Registry of async resolvers, keyed by namespace.\n *\n * Plugins/packages register resolvers alongside their parselets\n * and opcode handlers. The engine calls preflightAll() before\n * VM execution to short-circuit async expressions.\n *\n * Lifecycle:\n * - register(), when a package is loaded\n * - unregister(), when a package is unloaded (clears cache entries)\n * - clear(), on document switch (clears all resolvers)\n */\nexport class ResolverRegistry {\n\tprivate resolvers = new Map<string, IAsyncResolver>();\n\n\t/**\n\t * Register an async resolver.\n\t *\n\t * Each resolver must have a unique `namespace`. If a resolver with the\n\t * same namespace is already registered, the old one is destroyed and\n\t * replaced (with a console warning). Packages that need multiple async\n\t * operations should use `asyncResolvers: [...]` with distinct namespaces\n\t * (e.g., `\"weather:current\"`, `\"weather:forecast\"`).\n\t */\n\tregister(resolver: IAsyncResolver): void {\n\t\t// Clean up previous resolver with same namespace if any\n\t\tif (this.resolvers.has(resolver.namespace)) {\n\t\t\tconsole.warn(\n\t\t\t\t`[ResolverRegistry] Namespace \"${resolver.namespace}\" already registered. ` +\n\t\t\t\t`Destroying old resolver and overwriting. Use distinct namespaces ` +\n\t\t\t\t`(e.g., \"${resolver.namespace}:sub1\", \"${resolver.namespace}:sub2\") ` +\n\t\t\t\t`to avoid collisions when a package needs multiple async resolvers.`,\n\t\t\t);\n\t\t\tthis.resolvers.get(resolver.namespace)!.destroy();\n\t\t}\n\t\tthis.resolvers.set(resolver.namespace, resolver);\n\t}\n\n\t/**\n\t * Unregister a resolver by namespace.\n\t * Calls destroy() and clears all cache entries with that namespace prefix.\n\t */\n\tunregister(namespace: string, queryClient?: QueryClient): void {\n\t\tconst resolver = this.resolvers.get(namespace);\n\t\tif (resolver) {\n\t\t\tresolver.destroy();\n\t\t\tthis.resolvers.delete(namespace);\n\t\t}\n\t\t// Clear all cache entries for this namespace via TanStack Query\n\t\t// Hierarchical keys: [\"osrs\"] clears all [\"osrs\", ...] queries\n\t\tif (queryClient) {\n\t\t\tqueryClient.removeQueries({ queryKey: [namespace] });\n\t\t}\n\t}\n\n\t/**\n\t * Run all registered resolvers' preflight checks against compiled bytecode.\n\t *\n\t * Returns the first AsyncCheckResult found, or null if all data is ready.\n\t * Short-circuits on first pending, subsequent pending ops will be\n\t * discovered on re-evaluation when the first resolves.\n\t */\n\tpreflightAll(tokens: Token[], bytecode: BytecodeProgram, packageId: string, signal: AbortSignal, queryClient: QueryClient): AsyncCheckResult | null {\n\t\tfor (const resolver of this.resolvers.values()) {\n\t\t\tif (!resolver.preflight) continue;\n\t\t\tconst result = resolver.preflight(tokens, bytecode, packageId, signal, queryClient);\n\t\t\tif (result) return result;\n\t\t}\n\t\treturn null;\n\t}\n\n\t/**\n\t * Get a resolver by namespace.\n\t * Returns undefined if no resolver is registered for that namespace.\n\t */\n\tget(namespace: string): IAsyncResolver | undefined {\n\t\treturn this.resolvers.get(namespace);\n\t}\n\n\t/** Number of registered resolvers. */\n\tget size(): number {\n\t\treturn this.resolvers.size;\n\t}\n\n\t/**\n\t * Check if a resolver is registered for the given namespace.\n\t */\n\thas(namespace: string): boolean {\n\t\treturn this.resolvers.has(namespace);\n\t}\n\n\t/**\n\t * Clear all resolvers (document switch, engine reset).\n\t * Calls destroy() on each resolver and clears the map.\n\t */\n\tclear(): void {\n\t\tfor (const resolver of this.resolvers.values()) {\n\t\t\tresolver.destroy();\n\t\t}\n\t\tthis.resolvers.clear();\n\t}\n}\n"]}
|
package/dist/chunk-4K5W7EH2.cjs
DELETED
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkKXDQKVNX_cjs = require('./chunk-KXDQKVNX.cjs');
|
|
4
|
-
var chunkIT74O4BE_cjs = require('./chunk-IT74O4BE.cjs');
|
|
5
|
-
|
|
6
|
-
// src/parser/OperandWidth.ts
|
|
7
|
-
var ONE_OPERAND = [
|
|
8
|
-
10 /* PUSH_NUMBER */,
|
|
9
|
-
11 /* PUSH_BIGINT */,
|
|
10
|
-
12 /* PUSH_HEX */,
|
|
11
|
-
13 /* PUSH_STRING */,
|
|
12
|
-
14 /* PUSH_BOOLEAN */,
|
|
13
|
-
// Its operand is a string-pool index holding the exact decimal text, so a
|
|
14
|
-
// scanner must step over one byte exactly as it does for PUSH_STRING.
|
|
15
|
-
16 /* PUSH_DECIMAL */,
|
|
16
|
-
60 /* LOAD_VAR */,
|
|
17
|
-
61 /* STORE_VAR */,
|
|
18
|
-
62 /* LOAD_GLOBAL_VAR */,
|
|
19
|
-
63 /* STORE_GLOBAL_VAR */,
|
|
20
|
-
150 /* DEFINE_USER_FUNCTION */,
|
|
21
|
-
159 /* BIND_UNKNOWN */,
|
|
22
|
-
// Its operand is a constant-pool index, like PUSH_NUMBER's: the epoch-ms
|
|
23
|
-
// was resolved at parse time and stored in `numbers`. Omitting it made
|
|
24
|
-
// every scanner read that index byte as an opcode, so an ordinary date
|
|
25
|
-
// literal desynchronised the whole preflight walk.
|
|
26
|
-
95 /* DATE_LITERAL */,
|
|
27
|
-
// One byte, the offset direction (0 forward, 1 backward) for "N working
|
|
28
|
-
// days after/before/from <date>". See WorkdayOffsetParselet. DATE_WORKDAYS_BETWEEN
|
|
29
|
-
// takes no operand and so is not listed here.
|
|
30
|
-
96 /* DATE_WORKDAY_OFFSET */
|
|
31
|
-
];
|
|
32
|
-
var TWO_OPERANDS = [
|
|
33
|
-
50 /* CALL_PLUGIN */,
|
|
34
|
-
51 /* CALL_BUILTIN */,
|
|
35
|
-
151 /* CALL_USER_FUNCTION */,
|
|
36
|
-
152 /* MAT_NEW */
|
|
37
|
-
];
|
|
38
|
-
var THREE_OPERANDS = [157 /* MAP_INVOKE */, 158 /* REDUCE_INVOKE */];
|
|
39
|
-
var OPERAND_BYTES = (() => {
|
|
40
|
-
const widths = new Array(256).fill(0);
|
|
41
|
-
for (const op of ONE_OPERAND) widths[op] = 1;
|
|
42
|
-
for (const op of TWO_OPERANDS) widths[op] = 2;
|
|
43
|
-
for (const op of THREE_OPERANDS) widths[op] = 3;
|
|
44
|
-
return widths;
|
|
45
|
-
})();
|
|
46
|
-
[
|
|
47
|
-
...ONE_OPERAND,
|
|
48
|
-
...TWO_OPERANDS,
|
|
49
|
-
...THREE_OPERANDS
|
|
50
|
-
];
|
|
51
|
-
function nextInstruction(opcodes, index) {
|
|
52
|
-
return index + 1 + (OPERAND_BYTES[opcodes[index]] ?? 0);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// src/uom/CurrencyResolver.ts
|
|
56
|
-
var CURRENCY_NS = "currency";
|
|
57
|
-
var CurrencyAsyncResolver = class {
|
|
58
|
-
constructor(exchange) {
|
|
59
|
-
this.namespace = CURRENCY_NS;
|
|
60
|
-
this.exchange = exchange ?? chunkKXDQKVNX_cjs.currencyExchangeService;
|
|
61
|
-
}
|
|
62
|
-
preflight(_tokens, bytecode, packageId, signal, queryClient) {
|
|
63
|
-
const { opcodes, strings } = bytecode;
|
|
64
|
-
const len = opcodes.length;
|
|
65
|
-
let i = 0;
|
|
66
|
-
let lastStrIdx = -1;
|
|
67
|
-
let prevStrIdx = -1;
|
|
68
|
-
while (i < len) {
|
|
69
|
-
const op = opcodes[i];
|
|
70
|
-
if (op === 13 /* PUSH_STRING */) {
|
|
71
|
-
prevStrIdx = lastStrIdx;
|
|
72
|
-
lastStrIdx = opcodes[i + 1];
|
|
73
|
-
}
|
|
74
|
-
const isCurrencyCombiningOp = op === 84 /* UOM_CONVERT_IN */ || op === 81 /* UOM_CONVERT_TO */ || op === 20 /* ADD */ || op === 21 /* SUB */ || op === 22 /* MUL */ || op === 23 /* DIV */;
|
|
75
|
-
if (isCurrencyCombiningOp) {
|
|
76
|
-
if (prevStrIdx >= 0 && lastStrIdx >= 0) {
|
|
77
|
-
const fromUnit = strings[prevStrIdx];
|
|
78
|
-
const toUnit = strings[lastStrIdx];
|
|
79
|
-
if (this.exchange.isCurrency(fromUnit) && this.exchange.isCurrency(toUnit) && fromUnit.toUpperCase() !== toUnit.toUpperCase()) {
|
|
80
|
-
const syncRate = this.exchange.getRateSync(fromUnit, toUnit);
|
|
81
|
-
if (syncRate === null) {
|
|
82
|
-
const fromUpper = fromUnit.toUpperCase();
|
|
83
|
-
const toUpper = toUnit.toUpperCase();
|
|
84
|
-
const cacheKey = [CURRENCY_NS, fromUpper, toUpper];
|
|
85
|
-
if (queryClient.getQueryData(cacheKey) !== void 0) {
|
|
86
|
-
i++;
|
|
87
|
-
continue;
|
|
88
|
-
}
|
|
89
|
-
const resolver = queryClient.fetchQuery({
|
|
90
|
-
queryKey: cacheKey,
|
|
91
|
-
queryFn: ({ signal: qSignal }) => {
|
|
92
|
-
return this.exchange.getRate(fromUnit, toUnit, qSignal).then((rate) => chunkIT74O4BE_cjs.numberValue(rate));
|
|
93
|
-
},
|
|
94
|
-
staleTime: 5 * 60 * 1e3
|
|
95
|
-
});
|
|
96
|
-
return { queryKey: cacheKey.join(":"), resolver, packageId, signal, metadata: { fromUnit, toUnit } };
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
i = nextInstruction(opcodes, i);
|
|
102
|
-
}
|
|
103
|
-
return null;
|
|
104
|
-
}
|
|
105
|
-
destroy() {
|
|
106
|
-
}
|
|
107
|
-
};
|
|
108
|
-
|
|
109
|
-
exports.CurrencyAsyncResolver = CurrencyAsyncResolver;
|
|
110
|
-
exports.nextInstruction = nextInstruction;
|
|
111
|
-
//# sourceMappingURL=chunk-4K5W7EH2.cjs.map
|
|
112
|
-
//# sourceMappingURL=chunk-4K5W7EH2.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/parser/OperandWidth.ts","../src/uom/CurrencyResolver.ts"],"names":["currencyExchangeService","numberValue"],"mappings":"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","file":"chunk-4K5W7EH2.cjs","sourcesContent":["/**\n * How many operand bytes follow each opcode, and how to step over one.\n *\n * Anything walking a bytecode stream without executing it needs this: the\n * resolver preflight scanners look for specific opcodes and must skip past\n * everything else without mistaking an operand byte for an instruction.\n *\n * It used to be a hand-copied switch in each of those scanners. They had\n * already drifted: two counted `CALL_PLUGIN` as three bytes wide and the third\n * omitted it from that arm, so a stream containing one desynchronised there and\n * every opcode after it was read at the wrong offset. Adding an opcode meant\n * remembering every copy, and nothing checked that you had.\n *\n * `__tests__/parser/OperandWidth.spec.ts` asserts every opcode has a width, so\n * a new one fails a test rather than silently defaulting to zero operands.\n */\n\nimport { OpCode } from \"@solve-js/parser/OpCode\";\n\n/**\n * Opcodes taking one operand byte.\n *\n * A constant-pool index, or a variable-name index.\n */\nconst ONE_OPERAND: readonly OpCode[] = [\n\tOpCode.PUSH_NUMBER,\n\tOpCode.PUSH_BIGINT,\n\tOpCode.PUSH_HEX,\n\tOpCode.PUSH_STRING,\n\tOpCode.PUSH_BOOLEAN,\n\t// Its operand is a string-pool index holding the exact decimal text, so a\n\t// scanner must step over one byte exactly as it does for PUSH_STRING.\n\tOpCode.PUSH_DECIMAL,\n\tOpCode.LOAD_VAR,\n\tOpCode.STORE_VAR,\n\tOpCode.LOAD_GLOBAL_VAR,\n\tOpCode.STORE_GLOBAL_VAR,\n\tOpCode.DEFINE_USER_FUNCTION,\n\tOpCode.BIND_UNKNOWN,\n\t// Its operand is a constant-pool index, like PUSH_NUMBER's: the epoch-ms\n\t// was resolved at parse time and stored in `numbers`. Omitting it made\n\t// every scanner read that index byte as an opcode, so an ordinary date\n\t// literal desynchronised the whole preflight walk.\n\tOpCode.DATE_LITERAL,\n\t// One byte, the offset direction (0 forward, 1 backward) for \"N working\n\t// days after/before/from <date>\". See WorkdayOffsetParselet. DATE_WORKDAYS_BETWEEN\n\t// takes no operand and so is not listed here.\n\tOpCode.DATE_WORKDAY_OFFSET,\n];\n\n/**\n * Opcodes taking two operand bytes.\n *\n * A callable index plus an argument count, or a matrix's row and column counts.\n */\nconst TWO_OPERANDS: readonly OpCode[] = [\n\tOpCode.CALL_PLUGIN,\n\tOpCode.CALL_BUILTIN,\n\tOpCode.CALL_USER_FUNCTION,\n\tOpCode.MAT_NEW,\n];\n\n/**\n * Opcodes taking three operand bytes.\n *\n * The map and reduce invocations, which carry a body index alongside their\n * other operands.\n */\nconst THREE_OPERANDS: readonly OpCode[] = [OpCode.MAP_INVOKE, OpCode.REDUCE_INVOKE];\n\n/**\n * Operand byte count for every opcode, indexed by opcode value.\n *\n * A dense array rather than a map, because the preflight scanners run on every\n * keystroke and this is read once per instruction.\n */\nexport const OPERAND_BYTES: readonly number[] = (() => {\n\tconst widths = new Array<number>(256).fill(0);\n\tfor (const op of ONE_OPERAND) widths[op] = 1;\n\tfor (const op of TWO_OPERANDS) widths[op] = 2;\n\tfor (const op of THREE_OPERANDS) widths[op] = 3;\n\treturn widths;\n})();\n\n/**\n * Every opcode that takes at least one operand.\n *\n * Exported so a test can assert the table stays complete as opcodes are added.\n */\nexport const OPCODES_WITH_OPERANDS: readonly OpCode[] = [\n\t...ONE_OPERAND,\n\t...TWO_OPERANDS,\n\t...THREE_OPERANDS,\n];\n\n/**\n * Offset of the instruction after the one at `index`.\n *\n * @param opcodes - The bytecode stream.\n * @param index - Offset of an opcode, not of an operand byte. Passing an\n * operand offset yields nonsense, which is the failure mode this exists to\n * prevent: a caller stepping by hand and getting one width wrong reads the rest\n * of the stream misaligned.\n * @returns Offset of the next opcode. May be past the end when the instruction\n * at `index` is the last one, so callers loop while it is under `opcodes.length`.\n */\nexport function nextInstruction(opcodes: Uint8Array, index: number): number {\n\treturn index + 1 + (OPERAND_BYTES[opcodes[index]] ?? 0);\n}\n","/**\n * Currency async resolver, bridges CurrencyExchangeService to the\n * IAsyncResolver interface for the Suspense architecture.\n *\n * Uses TanStack Query (injected via queryClient) as the single cache layer.\n */\nimport type { QueryClient } from \"@tanstack/query-core\";\nimport type { Token } from \"@solve-js/lexer\";\nimport type { BytecodeProgram } from \"@solve-js/parser/BytecodeBuilder\";\nimport { OpCode } from \"@solve-js/parser/OpCode\";\nimport { numberValue } from \"@solve-js/vm/Value\";\nimport {\n\tcurrencyExchangeService,\n\tCurrencyExchangeService,\n} from \"@solve-js/uom/CurrencyExchange\";\nimport type { IAsyncResolver, AsyncCheckResult } from \"@solve-js/resolvers/ResolverRegistry\";\nimport { nextInstruction } from \"@solve-js/parser/OperandWidth\";\n\nconst CURRENCY_NS = \"currency\";\n\n/**\n * Fetches exchange rates before the VM runs, so a conversion has real numbers.\n *\n * Until rates arrive the line evaluates to a pending value rather than a\n * guessed one, and re-evaluates when they land.\n */\nexport class CurrencyAsyncResolver implements IAsyncResolver {\n\treadonly namespace = CURRENCY_NS;\n\n\tprivate exchange: CurrencyExchangeService;\n\n\tconstructor(exchange?: CurrencyExchangeService) {\n\t\tthis.exchange = exchange ?? currencyExchangeService;\n\t}\n\n\tpreflight(_tokens: Token[], bytecode: BytecodeProgram, packageId: string, signal: AbortSignal, queryClient: QueryClient): AsyncCheckResult | null {\n\t\tconst { opcodes, strings } = bytecode;\n\t\tconst len = opcodes.length;\n\t\tlet i = 0;\n\n\t\tlet lastStrIdx = -1;\n\t\tlet prevStrIdx = -1;\n\n\t\twhile (i < len) {\n\t\t\tconst op = opcodes[i] as OpCode;\n\n\t\t\tif (op === OpCode.PUSH_STRING) {\n\t\t\t\tprevStrIdx = lastStrIdx;\n\t\t\t\tlastStrIdx = opcodes[i + 1];\n\t\t\t}\n\n\t\t\t// Explicit \"X to Y\"/\"X in Y\" conversions (UOM_CONVERT_IN/_TO) are\n\t\t\t// the obvious case, but arithmetic directly on two differently-\n\t\t\t// denominated currency literals, \"0.01 BTC + 1 ETH\", needs the\n\t\t\t// exact same preflight fetch and previously never got it: this\n\t\t\t// scanner only looked for the CONVERT opcodes, so ADD/SUB/MUL/DIV\n\t\t\t// between two currency UOMs skipped preflight entirely, ran with\n\t\t\t// no cached rate, and fell through to the VM's silent-wrong-math\n\t\t\t// fallback instead of ever reaching a network fetch.\n\t\t\tconst isCurrencyCombiningOp =\n\t\t\t\top === OpCode.UOM_CONVERT_IN || op === OpCode.UOM_CONVERT_TO ||\n\t\t\t\top === OpCode.ADD || op === OpCode.SUB || op === OpCode.MUL || op === OpCode.DIV;\n\t\t\tif (isCurrencyCombiningOp) {\n\t\t\t\tif (prevStrIdx >= 0 && lastStrIdx >= 0) {\n\t\t\t\t\tconst fromUnit = strings[prevStrIdx];\n\t\t\t\t\tconst toUnit = strings[lastStrIdx];\n\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.exchange.isCurrency(fromUnit) &&\n\t\t\t\t\t\tthis.exchange.isCurrency(toUnit) &&\n\t\t\t\t\t\tfromUnit.toUpperCase() !== toUnit.toUpperCase()\n\t\t\t\t\t) {\n\t\t\t\t\t\tconst syncRate = this.exchange.getRateSync(fromUnit, toUnit);\n\t\t\t\t\t\tif (syncRate === null) {\n\t\t\t\t\t\t\tconst fromUpper = fromUnit.toUpperCase();\n\t\t\t\t\t\t\tconst toUpper = toUnit.toUpperCase();\n\n\t\t\t\t\t\t\t// Check TanStack Query cache\n\t\t\t\t\t\t\tconst cacheKey = [CURRENCY_NS, fromUpper, toUpper];\n\t\t\t\t\t\t\tif (queryClient.getQueryData(cacheKey) !== undefined) {\n\t\t\t\t\t\t\t\ti++;\n\t\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t// Fetch via TanStack Query (dedup + retry automatic)\n\t\t\t\t\t\t\tconst resolver = queryClient.fetchQuery({\n\t\t\t\t\t\t\t\tqueryKey: cacheKey,\n\t\t\t\t\t\t\t\tqueryFn: ({ signal: qSignal }) => {\n\t\t\t\t\t\t\t\t\treturn this.exchange.getRate(fromUnit, toUnit, qSignal).then((rate) => numberValue(rate));\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\tstaleTime: 5 * 60 * 1000,\n\t\t\t\t\t\t\t});\n\n\t\t\t\t\t\t\treturn { queryKey: cacheKey.join(\":\"), resolver, packageId, signal, metadata: { fromUnit, toUnit } };\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Step over this instruction and its operands. Shared table, because\n\t\t\t// three hand-copied versions of this had already drifted.\n\t\t\ti = nextInstruction(opcodes, i);\n\t\t}\n\n\t\treturn null;\n\t}\n\n\tdestroy(): void {\n\t\t// Cache cleared by ResolverRegistry.unregister() via removeQueries({ queryKey: [\"currency\"] })\n\t}\n}\n"]}
|