solve-engine 1.0.2 → 1.1.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/dist/{BytecodeBuilder-B0xskcv5.d.cts → BytecodeBuilder-Bp9xeTmX.d.cts} +4 -0
- package/dist/{BytecodeBuilder-B0xskcv5.d.ts → BytecodeBuilder-Bp9xeTmX.d.ts} +4 -0
- package/dist/{Configuration-B-G5gTRn.d.cts → Configuration-C9W8tJv_.d.cts} +53 -1
- package/dist/{Configuration-B-G5gTRn.d.ts → Configuration-C9W8tJv_.d.ts} +53 -1
- package/dist/{EngineError-LU7W7AgI.d.cts → EngineError-B61GS1jp.d.cts} +14 -0
- package/dist/{EngineError-LU7W7AgI.d.ts → EngineError-B61GS1jp.d.ts} +14 -0
- package/dist/FormattingSettings-CJHyxcYu.d.cts +27 -0
- package/dist/FormattingSettings-CJHyxcYu.d.ts +27 -0
- package/dist/{Lexer-DpjdaQ98.d.cts → Lexer-BOs7euZe.d.cts} +28 -1
- package/dist/{Lexer-CNmWxabg.d.ts → Lexer-CSI_lwbW.d.ts} +28 -1
- package/dist/PackageCompatibility-B-7rK1TD.d.cts +76 -0
- package/dist/PackageCompatibility-Dh59eF-X.d.ts +76 -0
- package/dist/{PackageRegistry-zuzqt51V.d.cts → PackageRegistry-BHWJP83F.d.cts} +449 -11
- package/dist/{PackageRegistry-ClIFXxAe.d.ts → PackageRegistry-_8rDlvxI.d.ts} +449 -11
- package/dist/{Parselet-BaySkMV3.d.ts → Parselet-BBT8riYh.d.ts} +12 -3
- package/dist/{Parselet-DuI1Pjiq.d.cts → Parselet-BHcgK9S7.d.cts} +12 -3
- package/dist/{ScopeManager-B6GzdhVG.d.cts → ScopeManager-8vf02dwj.d.cts} +56 -5
- package/dist/{ScopeManager-udv4Twwq.d.ts → ScopeManager-CxA24W5n.d.ts} +56 -5
- package/dist/{Token-BzG5G4ja.d.cts → Token-B1hdkedD.d.cts} +9 -0
- package/dist/{Token-BzG5G4ja.d.ts → Token-B1hdkedD.d.ts} +9 -0
- package/dist/{TokenNormalizer-t_GotBxr.d.ts → TokenNormalizer-C6VzZgHa.d.ts} +1 -1
- package/dist/{TokenNormalizer-DGVa24Q-.d.cts → TokenNormalizer-DRc1Js1V.d.cts} +1 -1
- package/dist/{VMCheckpoints-DwLjivM7.d.cts → VMCheckpoints-ELYqITdF.d.cts} +3 -3
- package/dist/{VMCheckpoints-BiaIlOOY.d.ts → VMCheckpoints-MK--EBH2.d.ts} +3 -3
- package/dist/{Value-CXJqDH9J.d.cts → Value-BUi1RA3S.d.cts} +124 -5
- package/dist/{Value-CXJqDH9J.d.ts → Value-BUi1RA3S.d.ts} +124 -5
- package/dist/WorkerError-_-RkoQ5P.d.ts +75 -0
- package/dist/WorkerError-gzmaopj2.d.cts +75 -0
- package/dist/{chunk-GQCOSXMG.js → chunk-267JPOTF.js} +43 -5
- package/dist/chunk-267JPOTF.js.map +1 -0
- package/dist/{chunk-JMXUNXQS.cjs → chunk-2TZKENDH.cjs} +51 -8
- package/dist/chunk-2TZKENDH.cjs.map +1 -0
- package/dist/chunk-3OWCDIPN.js +215 -0
- package/dist/chunk-3OWCDIPN.js.map +1 -0
- package/dist/{chunk-VB37OC6I.js → chunk-4D6NIHE2.js} +40 -3
- package/dist/chunk-4D6NIHE2.js.map +1 -0
- package/dist/{chunk-TY3TLZAW.cjs → chunk-536WPM2V.cjs} +18 -2
- package/dist/chunk-536WPM2V.cjs.map +1 -0
- package/dist/chunk-5HRB36DK.js +405 -0
- package/dist/chunk-5HRB36DK.js.map +1 -0
- package/dist/chunk-5ON7PUAZ.js +12 -0
- package/dist/chunk-5ON7PUAZ.js.map +1 -0
- package/dist/{chunk-KV7UW6T6.js → chunk-7KYSUDQO.js} +12 -5
- package/dist/chunk-7KYSUDQO.js.map +1 -0
- package/dist/{chunk-6WFMPTGB.cjs → chunk-7ZX6B7SY.cjs} +774 -528
- package/dist/chunk-7ZX6B7SY.cjs.map +1 -0
- package/dist/chunk-ALYRJ72W.cjs +434 -0
- package/dist/chunk-ALYRJ72W.cjs.map +1 -0
- package/dist/{chunk-5KMIY374.cjs → chunk-B4HBEFTB.cjs} +17 -2
- package/dist/chunk-B4HBEFTB.cjs.map +1 -0
- package/dist/chunk-B7NLZMQ3.cjs +74 -0
- package/dist/chunk-B7NLZMQ3.cjs.map +1 -0
- package/dist/{chunk-UQ3UIZJC.js → chunk-BLI4NIQY.js} +6 -2
- package/dist/chunk-BLI4NIQY.js.map +1 -0
- package/dist/{chunk-T556MJDZ.cjs → chunk-C75AFGVD.cjs} +11 -11
- package/dist/{chunk-T556MJDZ.cjs.map → chunk-C75AFGVD.cjs.map} +1 -1
- package/dist/{chunk-G535KJEG.js → chunk-CCBZZQAE.js} +2 -2
- package/dist/{chunk-G535KJEG.js.map → chunk-CCBZZQAE.js.map} +1 -1
- package/dist/chunk-CKQMXMHR.cjs +219 -0
- package/dist/chunk-CKQMXMHR.cjs.map +1 -0
- package/dist/{chunk-PFUESQTW.cjs → chunk-EJ3ILXX6.cjs} +48 -2
- package/dist/chunk-EJ3ILXX6.cjs.map +1 -0
- package/dist/{chunk-526PMQOA.js → chunk-ENKKJYD3.js} +10 -4
- package/dist/chunk-ENKKJYD3.js.map +1 -0
- package/dist/{chunk-5X2PTP6F.cjs → chunk-ENRIK36Q.cjs} +2 -12
- package/dist/chunk-ENRIK36Q.cjs.map +1 -0
- package/dist/{chunk-3D7V24DG.js → chunk-ERCOHGXD.js} +17 -2
- package/dist/chunk-ERCOHGXD.js.map +1 -0
- package/dist/{chunk-IF532O7C.js → chunk-FD5ZZHEU.js} +3 -12
- package/dist/chunk-FD5ZZHEU.js.map +1 -0
- package/dist/{chunk-7FSDNNNC.js → chunk-G7Z4HJQA.js} +11 -5
- package/dist/chunk-G7Z4HJQA.js.map +1 -0
- package/dist/{chunk-FQGX2PA2.js → chunk-GQMUHVE3.js} +115 -4
- package/dist/chunk-GQMUHVE3.js.map +1 -0
- package/dist/chunk-GUG7SNSV.js +1764 -0
- package/dist/chunk-GUG7SNSV.js.map +1 -0
- package/dist/{chunk-UM6BVY2S.cjs → chunk-HIQ5HSZL.cjs} +175 -43
- package/dist/chunk-HIQ5HSZL.cjs.map +1 -0
- package/dist/{chunk-HVQFNJKE.cjs → chunk-HVRVSI2Z.cjs} +104 -86
- package/dist/chunk-HVRVSI2Z.cjs.map +1 -0
- package/dist/{chunk-3LAEG75D.js → chunk-I4GAWIPW.js} +24 -6
- package/dist/chunk-I4GAWIPW.js.map +1 -0
- package/dist/{chunk-PA4VC73I.cjs → chunk-J45BCEZ4.cjs} +33 -27
- package/dist/chunk-J45BCEZ4.cjs.map +1 -0
- package/dist/{chunk-NG2JHZHE.js → chunk-JIPATHVY.js} +1853 -2640
- package/dist/chunk-JIPATHVY.js.map +1 -0
- package/dist/{chunk-IP7ASJEW.js → chunk-JJIXHXFQ.js} +5 -5
- package/dist/{chunk-IP7ASJEW.js.map → chunk-JJIXHXFQ.js.map} +1 -1
- package/dist/chunk-L2TE7PMO.cjs +14 -0
- package/dist/chunk-L2TE7PMO.cjs.map +1 -0
- package/dist/{chunk-HBVFFBRR.cjs → chunk-MG6Q3DUO.cjs} +1962 -2748
- package/dist/chunk-MG6Q3DUO.cjs.map +1 -0
- package/dist/{chunk-R3PY4G7J.js → chunk-MVTOCRV2.js} +48 -3
- package/dist/chunk-MVTOCRV2.js.map +1 -0
- package/dist/{chunk-Y7FT4IQT.js → chunk-NKW7LKYU.js} +266 -28
- package/dist/chunk-NKW7LKYU.js.map +1 -0
- package/dist/{chunk-O3ANBHSA.js → chunk-NNQ2TYDF.js} +123 -5
- package/dist/chunk-NNQ2TYDF.js.map +1 -0
- package/dist/{chunk-AA3KTWTX.js → chunk-OADDUPT3.js} +4 -4
- package/dist/{chunk-AA3KTWTX.js.map → chunk-OADDUPT3.js.map} +1 -1
- package/dist/{chunk-SESSWASV.cjs → chunk-OTN6SZOD.cjs} +1868 -393
- package/dist/chunk-OTN6SZOD.cjs.map +1 -0
- package/dist/{chunk-5LI5EPGJ.cjs → chunk-QFTDTX6K.cjs} +40 -3
- package/dist/chunk-QFTDTX6K.cjs.map +1 -0
- package/dist/{chunk-YXCTLWOH.js → chunk-RRLHC37V.js} +1530 -57
- package/dist/chunk-RRLHC37V.js.map +1 -0
- package/dist/chunk-SNHVVOJK.cjs +1768 -0
- package/dist/chunk-SNHVVOJK.cjs.map +1 -0
- package/dist/{chunk-HDP7VK3C.cjs → chunk-SRGQ72IR.cjs} +649 -349
- package/dist/chunk-SRGQ72IR.cjs.map +1 -0
- package/dist/{chunk-4B2CNWQU.cjs → chunk-SSV46KFA.cjs} +14 -7
- package/dist/chunk-SSV46KFA.cjs.map +1 -0
- package/dist/{chunk-AJA6LUI7.js → chunk-UO6BUV6K.js} +18 -2
- package/dist/chunk-UO6BUV6K.js.map +1 -0
- package/dist/chunk-WWQEY7BV.js +67 -0
- package/dist/chunk-WWQEY7BV.js.map +1 -0
- package/dist/{chunk-5WVP4YHP.js → chunk-WXEHD6TT.js} +333 -33
- package/dist/chunk-WXEHD6TT.js.map +1 -0
- package/dist/{chunk-47LRVGOT.cjs → chunk-XA4CKRML.cjs} +2 -2
- package/dist/{chunk-47LRVGOT.cjs.map → chunk-XA4CKRML.cjs.map} +1 -1
- package/dist/{chunk-6KFYJ6TD.cjs → chunk-XIYYHA65.cjs} +6 -2
- package/dist/chunk-XIYYHA65.cjs.map +1 -0
- package/dist/{chunk-FE23VSSA.cjs → chunk-XJGJCF2R.cjs} +6 -6
- package/dist/{chunk-FE23VSSA.cjs.map → chunk-XJGJCF2R.cjs.map} +1 -1
- package/dist/{chunk-R7YVBHCV.cjs → chunk-YTIYVHL7.cjs} +184 -73
- package/dist/chunk-YTIYVHL7.cjs.map +1 -0
- package/dist/{chunk-TMA4RCEN.js → chunk-Z7XGGLI2.js} +3 -3
- package/dist/{chunk-TMA4RCEN.js.map → chunk-Z7XGGLI2.js.map} +1 -1
- package/dist/{chunk-A2N2GFCG.cjs → chunk-ZVTWQLK4.cjs} +10 -10
- package/dist/{chunk-A2N2GFCG.cjs.map → chunk-ZVTWQLK4.cjs.map} +1 -1
- package/dist/{chunk-524F3ATQ.cjs → chunk-ZXCESUJS.cjs} +15 -9
- package/dist/chunk-ZXCESUJS.cjs.map +1 -0
- package/dist/constants.cjs +5 -5
- package/dist/constants.d.cts +1 -1
- package/dist/constants.d.ts +1 -1
- package/dist/constants.js +2 -2
- package/dist/engine.cjs +52 -35
- package/dist/engine.d.cts +13 -13
- package/dist/engine.d.ts +13 -13
- package/dist/engine.js +26 -21
- package/dist/errors.cjs +44 -19
- package/dist/errors.d.cts +3 -2
- package/dist/errors.d.ts +3 -2
- package/dist/errors.js +2 -1
- package/dist/format.cjs +19 -169
- package/dist/format.cjs.map +1 -1
- package/dist/format.d.cts +18 -26
- package/dist/format.d.ts +18 -26
- package/dist/format.js +7 -171
- package/dist/format.js.map +1 -1
- package/dist/index.cjs +250 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +110 -74
- package/dist/index.d.ts +110 -74
- package/dist/index.js +228 -23
- package/dist/index.js.map +1 -1
- package/dist/language.cjs +9 -9
- package/dist/language.d.cts +12 -12
- package/dist/language.d.ts +12 -12
- package/dist/language.js +3 -3
- package/dist/lexer.cjs +16 -16
- package/dist/lexer.d.cts +3 -3
- package/dist/lexer.d.ts +3 -3
- package/dist/lexer.js +5 -5
- package/dist/normalizer.cjs +10 -10
- package/dist/normalizer.d.cts +3 -3
- package/dist/normalizer.d.ts +3 -3
- package/dist/normalizer.js +4 -4
- package/dist/packages.cjs +45 -36
- package/dist/packages.d.cts +135 -31
- package/dist/packages.d.ts +135 -31
- package/dist/packages.js +14 -13
- package/dist/parser.cjs +16 -16
- package/dist/parser.d.cts +6 -5
- package/dist/parser.d.ts +6 -5
- package/dist/parser.js +6 -6
- package/dist/{pipeline-BEb3hujr.d.cts → pipeline-CtfJtPQc.d.cts} +3 -3
- package/dist/{pipeline-B6k5lCB7.d.ts → pipeline-DCd5M6Gk.d.ts} +3 -3
- package/dist/resolvers.d.cts +3 -3
- package/dist/resolvers.d.ts +3 -3
- package/dist/testing.cjs +478 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +271 -0
- package/dist/testing.d.ts +271 -0
- package/dist/testing.js +470 -0
- package/dist/testing.js.map +1 -0
- package/dist/uom.cjs +16 -16
- package/dist/uom.d.cts +3 -3
- package/dist/uom.d.ts +3 -3
- package/dist/uom.js +6 -6
- package/dist/utilities.cjs +6 -5
- package/dist/utilities.js +2 -1
- package/dist/vm.cjs +34 -34
- package/dist/vm.d.cts +8 -8
- package/dist/vm.d.ts +8 -8
- package/dist/vm.js +9 -9
- package/dist/worker.cjs +493 -0
- package/dist/worker.cjs.map +1 -0
- package/dist/worker.d.cts +509 -0
- package/dist/worker.d.ts +509 -0
- package/dist/worker.js +484 -0
- package/dist/worker.js.map +1 -0
- package/package.json +21 -1
- package/dist/chunk-3D7V24DG.js.map +0 -1
- package/dist/chunk-3LAEG75D.js.map +0 -1
- package/dist/chunk-4B2CNWQU.cjs.map +0 -1
- package/dist/chunk-524F3ATQ.cjs.map +0 -1
- package/dist/chunk-526PMQOA.js.map +0 -1
- package/dist/chunk-5KMIY374.cjs.map +0 -1
- package/dist/chunk-5LI5EPGJ.cjs.map +0 -1
- package/dist/chunk-5WVP4YHP.js.map +0 -1
- package/dist/chunk-5X2PTP6F.cjs.map +0 -1
- package/dist/chunk-6KFYJ6TD.cjs.map +0 -1
- package/dist/chunk-6WFMPTGB.cjs.map +0 -1
- package/dist/chunk-7FSDNNNC.js.map +0 -1
- package/dist/chunk-AJA6LUI7.js.map +0 -1
- package/dist/chunk-FQGX2PA2.js.map +0 -1
- package/dist/chunk-GQCOSXMG.js.map +0 -1
- package/dist/chunk-HBVFFBRR.cjs.map +0 -1
- package/dist/chunk-HDP7VK3C.cjs.map +0 -1
- package/dist/chunk-HVQFNJKE.cjs.map +0 -1
- package/dist/chunk-IF532O7C.js.map +0 -1
- package/dist/chunk-JMXUNXQS.cjs.map +0 -1
- package/dist/chunk-KV7UW6T6.js.map +0 -1
- package/dist/chunk-NG2JHZHE.js.map +0 -1
- package/dist/chunk-O3ANBHSA.js.map +0 -1
- package/dist/chunk-PA4VC73I.cjs.map +0 -1
- package/dist/chunk-PFUESQTW.cjs.map +0 -1
- package/dist/chunk-R3PY4G7J.js.map +0 -1
- package/dist/chunk-R7YVBHCV.cjs.map +0 -1
- package/dist/chunk-SESSWASV.cjs.map +0 -1
- package/dist/chunk-TY3TLZAW.cjs.map +0 -1
- package/dist/chunk-UM6BVY2S.cjs.map +0 -1
- package/dist/chunk-UQ3UIZJC.js.map +0 -1
- package/dist/chunk-VB37OC6I.js.map +0 -1
- package/dist/chunk-Y7FT4IQT.js.map +0 -1
- package/dist/chunk-YXCTLWOH.js.map +0 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/PackageRegistry.ts"],"names":["Value","sharedParseletRegistry","sharedVariableResolver","assertEngineVersionCompatible","sharedLexer"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AA+PO,IAAM,kBAAN,MAAkD;AAAA,EAAlD,WAAA,GAAA;AACL,IAAA,IAAA,CAAA,KAAA,GAAQA,uBAAA;AAAA,EAAA;AAAA,EAER,sBAAA,CAAuB,WAAmB,QAAA,EAAgC;AACxE,IAAAC,wCAAA,CAAuB,cAAA,CAAe,WAAW,QAAQ,CAAA;AAAA,EAC3D;AAAA,EAEA,qBAAA,CAAsB,WAAmB,QAAA,EAA+B;AACtE,IAAAA,wCAAA,CAAuB,aAAA,CAAc,WAAW,QAAQ,CAAA;AAAA,EAC1D;AAAA,EAEA,uBAAuB,MAAA,EAA+B;AACpD,IAAAC,wCAAA,CAAuB,eAAe,MAAM,CAAA;AAAA,EAC9C;AAAA,EAEA,gBAAgB,GAAA,EAA2B;AAMzC,IAAAC,+CAAA,CAA8B,GAAG,CAAA;AAEjC,IAAA,IAAI,IAAI,eAAA,EAAiB;AACvB,MAAAC,6BAAA,CAAY,kBAAA,CAAmB,IAAI,eAAe,CAAA;AAAA,IACpD;AACA,IAAA,IAAI,IAAI,eAAA,EAAiB;AACvB,MAAA,KAAA,MAAW,EAAA,IAAM,IAAI,eAAA,EAAiB;AACpC,QAAA,IAAA,CAAK,sBAAA,CAAuB,EAAA,CAAG,SAAA,EAAW,EAAA,CAAG,QAAQ,CAAA;AAAA,MACvD;AAAA,IACF;AACA,IAAA,IAAI,IAAI,cAAA,EAAgB;AACtB,MAAA,KAAA,MAAW,EAAA,IAAM,IAAI,cAAA,EAAgB;AACnC,QAAA,IAAA,CAAK,qBAAA,CAAsB,EAAA,CAAG,SAAA,EAAW,EAAA,CAAG,QAAQ,CAAA;AAAA,MACtD;AAAA,IACF;AACA,IAAA,IAAI,IAAI,eAAA,EAAiB;AACvB,MAAA,KAAA,MAAW,EAAA,IAAM,IAAI,eAAA,EAAiB;AACpC,QAAA,IAAA,CAAK,uBAAuB,EAAE,CAAA;AAAA,MAChC;AAAA,IACF;AAAA,EAIF;AACF;AAQO,IAAM,eAAA,GAAkB,IAAI,eAAA","file":"index.cjs","sourcesContent":["import { sharedParseletRegistry } from \"@solve-js/parser/registry/ParseletRegistry\";\nimport { PrefixParselet, InfixParselet } from \"@solve-js/parser/Parselet\";\nimport { Value } from \"@solve-js/vm/Value\";\nimport { IVariableSource } from \"@solve-js/variables/IVariableSource\";\nimport { sharedVariableResolver } from \"@solve-js/variables/VariableResolver\";\nimport { sharedLexer } from \"@solve-js/lexer/Lexer\";\nimport type { LexerVocabulary } from \"@solve-js/lexer/ExpressionLexer\";\nimport type { IAsyncResolver } from \"@solve-js/resolvers/ResolverRegistry\";\nimport type { NormalizerRule } from \"@solve-js/normalizer/NormalizerRule\";\nimport type { TokenCategory } from \"@solve-js/language/TokenCategory\";\nimport type { CompletionItem } from \"@solve-js/language/LanguageService\";\nimport type { LineExecutionContext } from \"@solve-js/vm/VM\";\nimport { assertEngineVersionCompatible } from \"./EngineVersionCompatibility\";\n\n/**\n * Public API for registering plugins with the solve-js engine.\n *\n * All registration goes through this interface, parselets, variable\n * sources, and full packages. The default implementation is\n * {@link PackageRegistry} (singleton via {@link packageRegistry}).\n *\n * @example\n * ```typescript\n * import { packageRegistry } from \"solve-engine\";\n * packageRegistry.registerPackage(myCustomPackage);\n * ```\n */\nexport interface IPackageRegistry {\n /** Register a prefix parselet (e.g., `GE`, `NOW`, `floor`). */\n registerPrefixParselet(tokenType: string, parselet: PrefixParselet): void;\n /** Register an infix parselet (e.g., `+`, `in`, `to`). */\n registerInfixParselet(tokenType: string, parselet: InfixParselet): void;\n /** @deprecated Has no effect. See {@link IEnginePackage.variableSources}. */\n registerVariableSource(source: IVariableSource): void;\n /** Register a complete package (parselets + variable sources). */\n registerPackage(pkg: IEnginePackage): void;\n /** Convenience reference to the Value class for creating typed values. */\n Value: typeof Value;\n}\n\n/**\n * Package descriptor for registering a complete provider with the engine.\n *\n * A package bundles all the pieces needed for a domain-specific provider:\n * lexer plugins for custom token recognition, parselets for Pratt parsing,\n * plugin functions dispatched via CALL_PLUGIN bytecode, variable sources,\n * and optional async resolvers for data that loads asynchronously (e.g.,\n * exchange rates, game prices).\n *\n * @example\n * ```typescript\n * const myPackage: IEnginePackage = {\n * name: \"MyProvider\",\n * lexerVocabulary: myLexerVocabulary,\n * prefixParselets: [{ tokenType: \"MY_FUNC\", parselet: new MyParselet() }],\n * pluginFunctions: [{ index: MY_FN_IDX, handler: myHandler }],\n * asyncResolvers: [myAsyncResolver],\n * };\n * packageRegistry.registerPackage(myPackage);\n * ```\n */\nexport interface IEnginePackage {\n /** Human-readable name for debugging and error attribution. */\n name: string;\n /**\n * Semver range of `solve-engine` versions this package is compatible with\n * (e.g. `\"^0.1.0\"`, `\">=0.1.0 <0.3.0\"`), checked against the engine's own\n * running version ({@link ENGINE_VERSION}, `@solve-js/constants/version`)\n * via `checkEngineVersionCompatibility()`/`assertEngineVersionCompatible()`\n * (`@solve-js/api/EngineVersionCompatibility`) at registration time.\n *\n * Optional, omitted means \"no declared constraint,\" so every package\n * that predates this field (all built-ins, `examples/osrs`) keeps\n * registering exactly as before.\n *\n * Unlike every other compatibility signal in this codebase (e.g.\n * `checkPackageCompatibility()`'s sibling-package collision warnings,\n * which always log and proceed. See `api/PackageCompatibility.ts`), a\n * declared `engineVersion` range the running engine does NOT satisfy is\n * a deliberate, hard REJECTION: `registerPackage()` throws rather than\n * warning. See `ARCHITECTURE.md` §5.3.\n */\n engineVersion?: string;\n /** Optional lexer vocabulary (keywords/operators/units) for recognizing custom tokens (e.g., `GE`, `£`). */\n lexerVocabulary?: LexerVocabulary;\n /** Prefix parselets for this package's custom functions/operators. */\n prefixParselets?: Array<{ tokenType: string; parselet: PrefixParselet }>;\n /** Infix parselets for this package's custom binary operators. */\n infixParselets?: Array<{ tokenType: string; parselet: InfixParselet }>;\n /**\n * Functions dispatched via CALL_PLUGIN bytecode (emitted by this package's\n * parselets with `builder.emitIndex(index)`).\n *\n * Each entry's `index` MUST come from {@link allocatePluginFunctionIndex}\n * (`@solve-js/vm/VMBuiltins`), never hardcode a number. Two packages\n * independently picking the same index would silently overwrite each\n * other's handler in the shared registry.\n *\n * The handler's optional second parameter, `context`, carries the\n * current line's {@link LineExecutionContext} (line number, and, only\n * inside a real document, never `evaluateExpression()`'s single-shot\n * path, closures for reading another line's cached result). Every\n * handler that doesn't need cross-line data can ignore it entirely.\n *\n * @example\n * ```ts\n * const MY_FN_IDX = allocatePluginFunctionIndex();\n * // In a parselet's parse(): builder.emitOpcode(OpCode.CALL_PLUGIN); builder.emitIndex(MY_FN_IDX); builder.emitIndex(argCount);\n * pluginFunctions: [{ index: MY_FN_IDX, handler: myHandler }]\n * ```\n */\n pluginFunctions?: Array<{ index: number; handler: (args: Value[], context?: LineExecutionContext) => Value | Promise<Value> }>;\n /**\n * Named-variable sources.\n *\n * @deprecated Currently has no effect. Sources declared here are registered\n * into the engine's {@link EngineContext} and unregistered again on package\n * removal, but no evaluation path ever calls `VariableResolver.resolve()`, so\n * a variable a source provides is never found. Verified by searching every\n * use of `IVariableSource` outside its own declaration: they are all\n * registration bookkeeping.\n *\n * Declared here rather than deleted because removing a public field is a\n * breaking change and the intended behaviour is worth keeping. Documented as\n * dead so a package author does not spend an afternoon working out why their\n * variables resolve to nothing. To expose a value today, contribute a plugin\n * function through {@link IEnginePackage.pluginFunctions}.\n */\n variableSources?: IVariableSource[];\n /**\n * Async resolvers for this package's domain.\n * When set, the ExpressionEngine runs preflight() before VM execution\n * for each resolver. If async data is needed, a Pending result is\n * returned immediately and the line re-evaluates when the data resolves.\n *\n * Each resolver must have a unique `namespace`, the ResolverRegistry\n * is keyed by namespace. Multiple resolvers let a package handle\n * distinct async operations (e.g., `fetch`, `wait`, `poll`) in\n * separate, focused classes rather than one monolithic preflight().\n */\n asyncResolvers?: IAsyncResolver[];\n /**\n * Multi-word phrases to fuse into single compound tokens.\n * Each key is a space-separated phrase (e.g., \"to the power of\"),\n * each value is the target token type after fusion (e.g., \"CARET\").\n *\n * Registered into the engine's {@link PhraseTrie} for single-pass\n * O(depth) matching, no separate rule scanning per phrase.\n *\n * @example\n * ```ts\n * phrases: {\n * \"to the power of\": \"CARET\",\n * \"abyssal whip\": \"ITEM\",\n * }\n * ```\n */\n phrases?: Record<string, string>;\n /**\n * Normalizer rules for post-lexer token transformation.\n * Applied by the TokenNormalizer between lexing and parsing.\n * For phrase fusion, prefer the declarative {@link phrases} field\n * which uses the faster PhraseTrie. Use this for non-phrase rules\n * like implicit operator insertion.\n */\n normalizerRules?: NormalizerRule[];\n /**\n * Semantic highlight categories for this package's custom token types\n * (introduced via {@link lexerVocabulary} or {@link normalizerRules}), the\n * plugin-facing half of solve-js's editor-agnostic language service (see\n * `language/TokenCategoryMap.ts`). Without an entry here, a package's\n * custom tokens (e.g. a game-item name fused from several identifiers)\n * are still lexed and parsed correctly, but render with no highlight\n * category in any editor integration.\n *\n * @example\n * ```ts\n * tokenCategories: { MY_KEYWORD: \"keyword\", MY_ITEM: \"my-plugin-item\" }\n * ```\n */\n tokenCategories?: Record<string, TokenCategory>;\n /**\n * Completion candidates for this package, the plugin-facing half of\n * solve-js's editor-agnostic completions API\n * (`LanguageService.getCompletions()`). A package's single-word\n * keywords (via {@link lexerVocabulary}) already flow into completions\n * automatically; this field is for candidates that AREN'T lexer\n * keywords, such as a vocabulary of item/entity names. A plain,\n * pre-built list, not a callback, completion candidate lists are\n * meant to be cheap and static within one engine configuration.\n *\n * @example\n * ```ts\n * completionItems: [{ label: \"Abyssal whip\", category: \"my-plugin-item\", detail: \"Item\" }]\n * ```\n */\n completionItems?: CompletionItem[];\n /**\n * Custom `as <name>` converters, the extension point for the\n * Converters package's general `<expr> as <type>` grammar (e.g.\n * `50% as decimal`, `255 as hex`). The built-in converter names\n * (`percent`, `decimal`, `hex`, `fraction`, `multiplier`, `sci`,\n * `binary`, `octal`, ...) dispatch to dedicated fast opcodes; anything\n * else, including any name a third-party package registers here\n * resolves through `OpCode.CALL_AS_CONVERTER` against\n * `vm/VMBuiltins.ts`'s `asConverterRegistry` at runtime. No lexer\n * keyword registration is needed for a custom name: the AS parselet\n * accepts any bare-word token after \"as\" and reads its raw text.\n *\n * Each handler is a pure, synchronous `(value: Value) => Value`, for\n * async conversions (e.g. a live currency-style lookup), use\n * {@link asyncResolvers} instead.\n *\n * @example\n * ```ts\n * asConverters: { roman: (v) => stringValue(toRomanNumeral(v.toNumber())) }\n * ```\n */\n asConverters?: Record<string, (value: Value) => Value>;\n}\n\n/**\n * Default implementation of {@link IPackageRegistry}, the plugin registration API.\n *\n * All registrations delegate to shared singletons (parselet registry,\n * variable resolver, lexer). This ensures that packages registered through\n * any PackageRegistry instance are visible engine-wide.\n *\n * @example\n * ```typescript\n * import { packageRegistry } from \"solve-engine\";\n *\n * // Register a complete provider package\n * packageRegistry.registerPackage({\n * name: \"MyProvider\",\n * prefixParselets: [{ tokenType: \"MY_FUNC\", parselet: new MyParselet() }],\n * });\n * ```\n *\n * @deprecated Register on an engine instead:\n * `engine.registerPackage(pkg)`.\n *\n * This class writes into process-wide singletons, which is incompatible with an\n * engine owning its own registries. Since the introduction of\n * {@link EngineContext}, an engine reads plugin functions, opcode handlers and\n * variable sources from its own context, so a package registered here is not\n * visible to any engine. Parselets and lexer vocabulary registered here reach\n * the shared registries, which an engine also does not read: it builds its own\n * `ParseletRegistry` and its own `Lexer`.\n *\n * In other words this path registers into state nothing evaluates against. It\n * remains exported because removing it is a breaking change, and it is where\n * the singletons that survive are still written from, but it should not be used\n * in new code and will be removed before 1.0 proper.\n */\nexport class PackageRegistry implements IPackageRegistry {\n Value = Value;\n\n registerPrefixParselet(tokenType: string, parselet: PrefixParselet): void {\n sharedParseletRegistry.registerPrefix(tokenType, parselet);\n }\n\n registerInfixParselet(tokenType: string, parselet: InfixParselet): void {\n sharedParseletRegistry.registerInfix(tokenType, parselet);\n }\n\n registerVariableSource(source: IVariableSource): void {\n sharedVariableResolver.registerSource(source);\n }\n\n registerPackage(pkg: IEnginePackage): void {\n // Same hard engine-version gate ExpressionEngine.registerPackage() uses\n // (see its own comment and ARCHITECTURE.md §5.3). This weaker\n // shared-singleton path had no compatibility checking of any kind\n // before this, so without this call the version gate would be\n // trivially bypassable through this entry point.\n assertEngineVersionCompatible(pkg);\n\n if (pkg.lexerVocabulary) {\n sharedLexer.registerVocabulary(pkg.lexerVocabulary);\n }\n if (pkg.prefixParselets) {\n for (const pp of pkg.prefixParselets) {\n this.registerPrefixParselet(pp.tokenType, pp.parselet);\n }\n }\n if (pkg.infixParselets) {\n for (const ip of pkg.infixParselets) {\n this.registerInfixParselet(ip.tokenType, ip.parselet);\n }\n }\n if (pkg.variableSources) {\n for (const vs of pkg.variableSources) {\n this.registerVariableSource(vs);\n }\n }\n // Note: asyncResolvers are NOT registered here, the shared PackageRegistry singleton\n // doesn't have a ResolverRegistry (that lives inside ExpressionEngine).\n // Use ExpressionEngine.registerPackage() directly if you need async resolvers.\n }\n}\n\n/**\n * Singleton PackageRegistry instance, the default plugin registration API.\n *\n * All packages should register through this instance. The underlying registries\n * are shared singletons, so multiple PackageRegistry instances would be redundant.\n */\nexport const packageRegistry = new PackageRegistry();\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/api/PackageRegistry.ts","../src/api/defineFunction.ts"],"names":["Value","sharedParseletRegistry","sharedVariableResolver","assertEngineVersionCompatible","sharedLexer","ErrorFactory","numberValue","stringValue","boolValue","BindingPower","allocatePluginFunctionIndex"],"mappings":"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","file":"index.cjs","sourcesContent":["import { sharedParseletRegistry } from \"@solve-js/parser/registry/ParseletRegistry\";\nimport { PrefixParselet, InfixParselet } from \"@solve-js/parser/Parselet\";\nimport { Value } from \"@solve-js/vm/Value\";\nimport { IVariableSource } from \"@solve-js/variables/IVariableSource\";\nimport { sharedVariableResolver } from \"@solve-js/variables/VariableResolver\";\nimport { sharedLexer } from \"@solve-js/lexer/Lexer\";\nimport type { LexerVocabulary } from \"@solve-js/lexer/ExpressionLexer\";\nimport type { IAsyncResolver } from \"@solve-js/resolvers/ResolverRegistry\";\nimport type { NormalizerRule } from \"@solve-js/normalizer/NormalizerRule\";\nimport type { TokenCategory } from \"@solve-js/language/TokenCategory\";\nimport type { CompletionItem } from \"@solve-js/language/LanguageService\";\nimport type { LineExecutionContext } from \"@solve-js/vm/VM\";\nimport { assertEngineVersionCompatible } from \"./EngineVersionCompatibility\";\n\n/**\n * Public API for registering plugins with the solve-js engine.\n *\n * All registration goes through this interface, parselets, variable\n * sources, and full packages. The default implementation is\n * {@link PackageRegistry} (singleton via {@link packageRegistry}).\n *\n * @example\n * ```typescript\n * import { packageRegistry } from \"solve-engine\";\n * packageRegistry.registerPackage(myCustomPackage);\n * ```\n */\nexport interface IPackageRegistry {\n /** Register a prefix parselet (e.g., `GE`, `NOW`, `floor`). */\n registerPrefixParselet(tokenType: string, parselet: PrefixParselet): void;\n /** Register an infix parselet (e.g., `+`, `in`, `to`). */\n registerInfixParselet(tokenType: string, parselet: InfixParselet): void;\n /** @deprecated Has no effect. See {@link IEnginePackage.variableSources}. */\n registerVariableSource(source: IVariableSource): void;\n /** Register a complete package (parselets + variable sources). */\n registerPackage(pkg: IEnginePackage): void;\n /** Convenience reference to the Value class for creating typed values. */\n Value: typeof Value;\n}\n\n/**\n * Package descriptor for registering a complete provider with the engine.\n *\n * A package bundles all the pieces needed for a domain-specific provider:\n * lexer plugins for custom token recognition, parselets for Pratt parsing,\n * plugin functions dispatched via CALL_PLUGIN bytecode, variable sources,\n * and optional async resolvers for data that loads asynchronously (e.g.,\n * exchange rates, game prices).\n *\n * @example\n * ```typescript\n * const myPackage: IEnginePackage = {\n * name: \"MyProvider\",\n * lexerVocabulary: myLexerVocabulary,\n * prefixParselets: [{ tokenType: \"MY_FUNC\", parselet: new MyParselet() }],\n * pluginFunctions: [{ index: MY_FN_IDX, handler: myHandler }],\n * asyncResolvers: [myAsyncResolver],\n * };\n * packageRegistry.registerPackage(myPackage);\n * ```\n */\nexport interface IEnginePackage {\n /** Human-readable name for debugging and error attribution. */\n name: string;\n /**\n * Semver range of `solve-engine` versions this package is compatible with\n * (e.g. `\"^0.1.0\"`, `\">=0.1.0 <0.3.0\"`), checked against the engine's own\n * running version ({@link ENGINE_VERSION}, `@solve-js/constants/version`)\n * via `checkEngineVersionCompatibility()`/`assertEngineVersionCompatible()`\n * (`@solve-js/api/EngineVersionCompatibility`) at registration time.\n *\n * Optional, omitted means \"no declared constraint,\" so every package\n * that predates this field (all built-ins, `examples/osrs`) keeps\n * registering exactly as before.\n *\n * Unlike every other compatibility signal in this codebase (e.g.\n * `checkPackageCompatibility()`'s sibling-package collision warnings,\n * which always log and proceed. See `api/PackageCompatibility.ts`), a\n * declared `engineVersion` range the running engine does NOT satisfy is\n * a deliberate, hard REJECTION: `registerPackage()` throws rather than\n * warning. See `ARCHITECTURE.md` §5.3.\n */\n engineVersion?: string;\n /** Optional lexer vocabulary (keywords/operators/units) for recognizing custom tokens (e.g., `GE`, `£`). */\n lexerVocabulary?: LexerVocabulary;\n /** Prefix parselets for this package's custom functions/operators. */\n prefixParselets?: Array<{ tokenType: string; parselet: PrefixParselet }>;\n /** Infix parselets for this package's custom binary operators. */\n infixParselets?: Array<{ tokenType: string; parselet: InfixParselet }>;\n /**\n * Functions dispatched via CALL_PLUGIN bytecode (emitted by this package's\n * parselets with `builder.emitIndex(index)`).\n *\n * Each entry's `index` MUST come from {@link allocatePluginFunctionIndex}\n * (`@solve-js/vm/VMBuiltins`), never hardcode a number. Two packages\n * independently picking the same index would silently overwrite each\n * other's handler in the shared registry.\n *\n * The handler's optional second parameter, `context`, carries the\n * current line's {@link LineExecutionContext} (line number, and, only\n * inside a real document, never `evaluateExpression()`'s single-shot\n * path, closures for reading another line's cached result). Every\n * handler that doesn't need cross-line data can ignore it entirely.\n *\n * @example\n * ```ts\n * const MY_FN_IDX = allocatePluginFunctionIndex();\n * // In a parselet's parse(): builder.emitOpcode(OpCode.CALL_PLUGIN); builder.emitIndex(MY_FN_IDX); builder.emitIndex(argCount);\n * pluginFunctions: [{ index: MY_FN_IDX, handler: myHandler }]\n * ```\n */\n pluginFunctions?: Array<{ index: number; handler: (args: Value[], context?: LineExecutionContext) => Value | Promise<Value> }>;\n /**\n * Named-variable sources.\n *\n * @deprecated Currently has no effect. Sources declared here are registered\n * into the engine's {@link EngineContext} and unregistered again on package\n * removal, but no evaluation path ever calls `VariableResolver.resolve()`, so\n * a variable a source provides is never found. Verified by searching every\n * use of `IVariableSource` outside its own declaration: they are all\n * registration bookkeeping.\n *\n * Declared here rather than deleted because removing a public field is a\n * breaking change and the intended behaviour is worth keeping. Documented as\n * dead so a package author does not spend an afternoon working out why their\n * variables resolve to nothing. To expose a value today, contribute a plugin\n * function through {@link IEnginePackage.pluginFunctions}.\n */\n variableSources?: IVariableSource[];\n /**\n * Async resolvers for this package's domain.\n * When set, the ExpressionEngine runs preflight() before VM execution\n * for each resolver. If async data is needed, a Pending result is\n * returned immediately and the line re-evaluates when the data resolves.\n *\n * Each resolver must have a unique `namespace`, the ResolverRegistry\n * is keyed by namespace. Multiple resolvers let a package handle\n * distinct async operations (e.g., `fetch`, `wait`, `poll`) in\n * separate, focused classes rather than one monolithic preflight().\n */\n asyncResolvers?: IAsyncResolver[];\n /**\n * Multi-word phrases to fuse into single compound tokens.\n * Each key is a space-separated phrase (e.g., \"to the power of\"),\n * each value is the target token type after fusion (e.g., \"CARET\").\n *\n * Registered into the engine's {@link PhraseTrie} for single-pass\n * O(depth) matching, no separate rule scanning per phrase.\n *\n * @example\n * ```ts\n * phrases: {\n * \"to the power of\": \"CARET\",\n * \"abyssal whip\": \"ITEM\",\n * }\n * ```\n */\n phrases?: Record<string, string>;\n /**\n * Normalizer rules for post-lexer token transformation.\n * Applied by the TokenNormalizer between lexing and parsing.\n * For phrase fusion, prefer the declarative {@link phrases} field\n * which uses the faster PhraseTrie. Use this for non-phrase rules\n * like implicit operator insertion.\n */\n normalizerRules?: NormalizerRule[];\n /**\n * Semantic highlight categories for this package's custom token types\n * (introduced via {@link lexerVocabulary} or {@link normalizerRules}), the\n * plugin-facing half of solve-js's editor-agnostic language service (see\n * `language/TokenCategoryMap.ts`). Without an entry here, a package's\n * custom tokens (e.g. a game-item name fused from several identifiers)\n * are still lexed and parsed correctly, but render with no highlight\n * category in any editor integration.\n *\n * @example\n * ```ts\n * tokenCategories: { MY_KEYWORD: \"keyword\", MY_ITEM: \"my-plugin-item\" }\n * ```\n */\n tokenCategories?: Record<string, TokenCategory>;\n /**\n * Completion candidates for this package, the plugin-facing half of\n * solve-js's editor-agnostic completions API\n * (`LanguageService.getCompletions()`). A package's single-word\n * keywords (via {@link lexerVocabulary}) already flow into completions\n * automatically; this field is for candidates that AREN'T lexer\n * keywords, such as a vocabulary of item/entity names. A plain,\n * pre-built list, not a callback, completion candidate lists are\n * meant to be cheap and static within one engine configuration.\n *\n * @example\n * ```ts\n * completionItems: [{ label: \"Abyssal whip\", category: \"my-plugin-item\", detail: \"Item\" }]\n * ```\n */\n completionItems?: CompletionItem[];\n /**\n * Custom `as <name>` converters, the extension point for the\n * Converters package's general `<expr> as <type>` grammar (e.g.\n * `50% as decimal`, `255 as hex`). The built-in converter names\n * (`percent`, `decimal`, `hex`, `fraction`, `multiplier`, `sci`,\n * `binary`, `octal`, ...) dispatch to dedicated fast opcodes; anything\n * else, including any name a third-party package registers here\n * resolves through `OpCode.CALL_AS_CONVERTER` against\n * `vm/VMBuiltins.ts`'s `asConverterRegistry` at runtime. No lexer\n * keyword registration is needed for a custom name: the AS parselet\n * accepts any bare-word token after \"as\" and reads its raw text.\n *\n * Each handler is a pure, synchronous `(value: Value) => Value`, for\n * async conversions (e.g. a live currency-style lookup), use\n * {@link asyncResolvers} instead.\n *\n * @example\n * ```ts\n * asConverters: { roman: (v) => stringValue(toRomanNumeral(v.toNumber())) }\n * ```\n */\n asConverters?: Record<string, (value: Value) => Value>;\n}\n\n/**\n * Default implementation of {@link IPackageRegistry}, the plugin registration API.\n *\n * All registrations delegate to shared singletons (parselet registry,\n * variable resolver, lexer). This ensures that packages registered through\n * any PackageRegistry instance are visible engine-wide.\n *\n * @example\n * ```typescript\n * import { packageRegistry } from \"solve-engine\";\n *\n * // Register a complete provider package\n * packageRegistry.registerPackage({\n * name: \"MyProvider\",\n * prefixParselets: [{ tokenType: \"MY_FUNC\", parselet: new MyParselet() }],\n * });\n * ```\n *\n * @deprecated Register on an engine instead:\n * `engine.registerPackage(pkg)`.\n *\n * This class writes into process-wide singletons, which is incompatible with an\n * engine owning its own registries. Since the introduction of\n * {@link EngineContext}, an engine reads plugin functions, opcode handlers and\n * variable sources from its own context, so a package registered here is not\n * visible to any engine. Parselets and lexer vocabulary registered here reach\n * the shared registries, which an engine also does not read: it builds its own\n * `ParseletRegistry` and its own `Lexer`.\n *\n * In other words this path registers into state nothing evaluates against. It\n * remains exported because removing it is a breaking change, and it is where\n * the singletons that survive are still written from, but it should not be used\n * in new code and will be removed before 1.0 proper.\n */\nexport class PackageRegistry implements IPackageRegistry {\n Value = Value;\n\n registerPrefixParselet(tokenType: string, parselet: PrefixParselet): void {\n sharedParseletRegistry.registerPrefix(tokenType, parselet);\n }\n\n registerInfixParselet(tokenType: string, parselet: InfixParselet): void {\n sharedParseletRegistry.registerInfix(tokenType, parselet);\n }\n\n registerVariableSource(source: IVariableSource): void {\n sharedVariableResolver.registerSource(source);\n }\n\n registerPackage(pkg: IEnginePackage): void {\n // Same hard engine-version gate ExpressionEngine.registerPackage() uses\n // (see its own comment and ARCHITECTURE.md §5.3). This weaker\n // shared-singleton path had no compatibility checking of any kind\n // before this, so without this call the version gate would be\n // trivially bypassable through this entry point.\n assertEngineVersionCompatible(pkg);\n\n if (pkg.lexerVocabulary) {\n sharedLexer.registerVocabulary(pkg.lexerVocabulary);\n }\n if (pkg.prefixParselets) {\n for (const pp of pkg.prefixParselets) {\n this.registerPrefixParselet(pp.tokenType, pp.parselet);\n }\n }\n if (pkg.infixParselets) {\n for (const ip of pkg.infixParselets) {\n this.registerInfixParselet(ip.tokenType, ip.parselet);\n }\n }\n if (pkg.variableSources) {\n for (const vs of pkg.variableSources) {\n this.registerVariableSource(vs);\n }\n }\n // Note: asyncResolvers are NOT registered here, the shared PackageRegistry singleton\n // doesn't have a ResolverRegistry (that lives inside ExpressionEngine).\n // Use ExpressionEngine.registerPackage() directly if you need async resolvers.\n }\n}\n\n/**\n * Singleton PackageRegistry instance, the default plugin registration API.\n *\n * All packages should register through this instance. The underlying registries\n * are shared singletons, so multiple PackageRegistry instances would be redundant.\n */\nexport const packageRegistry = new PackageRegistry();\n","import type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport type { PrefixParselet } from \"@solve-js/parser/Parselet\";\nimport type { Parser } from \"@solve-js/parser/Parser\";\nimport type { Token } from \"@solve-js/lexer/Token\";\nimport type { BytecodeBuilder } from \"@solve-js/parser/BytecodeBuilder\";\nimport { OpCode } from \"@solve-js/parser/OpCode\";\nimport { BindingPower } from \"@solve-js/parser/BindingPower\";\nimport { allocatePluginFunctionIndex } from \"@solve-js/vm/VMBuiltins\";\nimport {\n Value,\n ValueType,\n numberValue,\n stringValue,\n boolValue,\n} from \"@solve-js/vm/Value\";\nimport { ErrorFactory } from \"@solve-js/errors/UnifiedErrorFramework\";\n\n/**\n * A higher-level, declarative way to contribute a single `name(args)`\n * function, sitting ON TOP OF the package contract rather than replacing it.\n *\n * The low-level contract (allocate a plugin function index, write a parselet,\n * emit `CALL_PLUGIN`) stays exactly as it was and remains the way to add\n * anything that needs custom parsing. This module derives that same wiring\n * from a declaration for the common case, a function called with parenthesised\n * arguments, so adding `vat(x)` costs a spec object rather than an\n * understanding of the parser and the VM. See `defineFunction`.\n */\n\n/** The value types a declared argument or return may take. */\nexport type FunctionValueType = \"number\" | \"string\" | \"boolean\";\n\n/** The JavaScript type a {@link FunctionValueType} maps to at the `call` boundary. */\ntype JsValue<T extends FunctionValueType> = T extends \"number\"\n ? number\n : T extends \"string\"\n ? string\n : boolean;\n\n/** One declared parameter: a name (for error messages) and a value type. */\nexport interface FunctionArg {\n /** Parameter name, used only in the generated type-mismatch messages. */\n name: string;\n /** The value type this parameter accepts. */\n type: FunctionValueType;\n}\n\n/** Map a tuple of {@link FunctionArg} specs to the tuple of JS values `call` receives. */\ntype CallArgs<A extends readonly FunctionArg[]> = {\n [K in keyof A]: JsValue<A[K][\"type\"]>;\n};\n\n/**\n * A declarative function definition.\n *\n * `A` and `R` are inferred from the literal `args`/`returns` (via\n * `defineFunction`'s `const` type parameter), so `call`'s parameters and\n * return are typed from the declaration with no annotations: an\n * `{ type: \"number\" }` argument arrives as a `number`, and a `returns:\n * \"string\"` demands a `string` back.\n */\nexport interface FunctionSpec<\n A extends readonly FunctionArg[] = readonly FunctionArg[],\n R extends FunctionValueType = FunctionValueType,\n> {\n /**\n * The call name, a single identifier (`/^[a-z_][a-z0-9_]*$/i`). Registered\n * as a lexer keyword, so it is matched case-insensitively and cannot collide\n * with a built-in keyword (that collision throws at registration time).\n */\n name: string;\n /** The parameters, in order. A fixed-length list: variadic and optional args are out of scope (see {@link defineFunction}). */\n args: A;\n /** The value type the function returns. */\n returns: R;\n /** The implementation, receiving plain JS values and returning one. Must be synchronous (see {@link defineFunction}). */\n call: (...args: CallArgs<A>) => JsValue<R>;\n}\n\n/**\n * Error codes the declarative function API raises. Kept as a co-located const\n * (the convention `errors/ErrorCode.ts` documents for a domain's own codes) so\n * the strings have one source of truth.\n */\nexport const DefineFunctionErrorCodes = {\n /** The spec's `name` is not a single identifier. Thrown by `defineFunction`, before any engine sees it. */\n DEFINE_FUNCTION_INVALID_NAME: \"DEFINE_FUNCTION_INVALID_NAME\",\n /** The spec is otherwise malformed (bad `args`, unsupported type, missing `call`). Thrown by `defineFunction`. */\n DEFINE_FUNCTION_INVALID_SPEC: \"DEFINE_FUNCTION_INVALID_SPEC\",\n /** The call site passed the wrong number of arguments. Raised at evaluation time. */\n DEFINE_FUNCTION_ARITY_MISMATCH: \"DEFINE_FUNCTION_ARITY_MISMATCH\",\n /** An argument was the wrong value type. Raised at evaluation time. */\n DEFINE_FUNCTION_ARGUMENT_TYPE: \"DEFINE_FUNCTION_ARGUMENT_TYPE\",\n /** The `call` implementation returned a value that did not match `returns`. Raised at evaluation time, an authoring bug rather than a user one. */\n DEFINE_FUNCTION_RETURN_TYPE: \"DEFINE_FUNCTION_RETURN_TYPE\",\n} as const;\n\n/** A single identifier: a letter or underscore, then letters, digits, or underscores. */\nconst NAME_PATTERN = /^[a-z_][a-z0-9_]*$/i;\n\nconst SUPPORTED_TYPES: ReadonlySet<string> = new Set([\"number\", \"string\", \"boolean\"]);\n\n/** \"1 argument\" / \"2 arguments\", so a count reads as English either way. Mirrors `VMBuiltinArity.ts`. */\nfunction plural(count: number): string {\n return count === 1 ? \"1 argument\" : `${count} arguments`;\n}\n\n/**\n * A human noun for the type a Value actually carries, for the \"was given ...\"\n * half of a mismatch message. Covers the three declarable types by their own\n * names and everything else by a readable category, so the message never reads\n * \"given a 6\".\n */\nfunction describeValueType(v: Value): string {\n switch (v.type) {\n case ValueType.Number:\n case ValueType.Hex:\n return \"a number\";\n case ValueType.String:\n return \"a string\";\n case ValueType.Boolean:\n return \"a boolean\";\n case ValueType.BigInt:\n return \"a big integer\";\n case ValueType.Percentage:\n return \"a percentage\";\n case ValueType.Uom:\n return \"a value with a unit\";\n case ValueType.Datetime:\n return \"a date\";\n case ValueType.Matrix:\n return \"a matrix\";\n case ValueType.Range:\n return \"a range\";\n case ValueType.Symbolic:\n return \"a symbolic expression\";\n default:\n return \"an unsupported value\";\n }\n}\n\n/**\n * Read one runtime Value as the JS primitive its declared type promises, or\n * raise the engine's structured type error.\n *\n * A \"number\" accepts a plain number or a based literal (`0xFF`), both of which\n * ARE numbers written differently, and reads it with `toNumber()`. Nothing\n * else is coerced: a percentage, a unit-bearing value or a string is a\n * genuinely different kind of value, and silently reinterpreting it is the\n * class of wrong-answer this API exists to avoid.\n */\nfunction coerceArgument(\n value: Value,\n arg: FunctionArg,\n fnName: string,\n): number | string | boolean {\n switch (arg.type) {\n case \"number\":\n // Hex is a number in another base (see `hexValue`), so it reads as one here.\n if (value.type === ValueType.Number || value.type === ValueType.Hex) {\n return value.toNumber();\n }\n break;\n case \"string\":\n if (value.type === ValueType.String) return value.value as string;\n break;\n case \"boolean\":\n if (value.type === ValueType.Boolean) return value.value as boolean;\n break;\n }\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARGUMENT_TYPE,\n message: `${fnName}() expects \"${arg.name}\" to be a ${arg.type}, but was given ${describeValueType(value)}`,\n expected: `a ${arg.type}`,\n found: describeValueType(value),\n context: { functionName: fnName, argName: arg.name, expectedType: arg.type },\n });\n}\n\n/**\n * Wrap the `call` result back into a Value of the declared return type, or\n * raise a structured error if the implementation handed back something else.\n *\n * The type check here catches an authoring mistake (a function declared to\n * return a number that returns `undefined`, or a Promise from an accidental\n * `async`), turning it into a named error rather than a Value that lies about\n * its own type downstream.\n */\nfunction wrapReturn(result: unknown, returns: FunctionValueType, fnName: string): Value {\n switch (returns) {\n case \"number\":\n if (typeof result === \"number\") return numberValue(result);\n break;\n case \"string\":\n if (typeof result === \"string\") return stringValue(result);\n break;\n case \"boolean\":\n if (typeof result === \"boolean\") return boolValue(result);\n break;\n }\n throw ErrorFactory.internal({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_RETURN_TYPE,\n message: `${fnName}() is declared to return a ${returns}, but its implementation returned ${typeof result}`,\n expected: `a ${returns}`,\n found: typeof result,\n context: { functionName: fnName, expectedType: returns },\n });\n}\n\n/**\n * The call-syntax parselet generated for one declared function.\n *\n * Identical in shape to the built-in `FunctionCallParselet`: consume the open\n * paren, parse a comma-separated argument list, then emit `CALL_PLUGIN` with\n * the function's index and the argument count. The count is whatever was\n * written, arity is checked at the dispatch point (see {@link makeHandler}),\n * the same place the built-in arity check lives.\n */\nclass DefinedFunctionParselet implements PrefixParselet {\n readonly category = \"Function\";\n\n constructor(\n private readonly fnIndex: number,\n private readonly fnName: string,\n ) {}\n\n parse(parser: Parser, _token: Token, builder: BytecodeBuilder): void {\n parser.consume(\"LPAREN\");\n\n let argCount = 0;\n if (parser.peek()?.type !== \"RPAREN\") {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n while (parser.match(\"COMMA\")) {\n parser.parseExpression(BindingPower.Lowest, builder);\n argCount++;\n }\n }\n\n parser.consume(\"RPAREN\");\n\n builder.emitOpcode(OpCode.CALL_PLUGIN);\n builder.emitIndex(this.fnIndex);\n builder.emitIndex(argCount);\n }\n}\n\n/**\n * Build the plugin function that checks arity and argument types, calls the\n * host implementation, and wraps the result.\n *\n * The VM has already screened out faulted arguments (an errored or still\n * pending operand short-circuits before the handler runs, see\n * `VM.ts`'s `CALL_PLUGIN` case), so every Value reaching here carries a real\n * result. Arity is checked first, before any argument is read, so a wrong\n * count is reported as a wrong count rather than as a type error on a missing\n * argument.\n */\nfunction makeHandler(spec: FunctionSpec): (args: Value[]) => Value {\n const arity = spec.args.length;\n return (args: Value[]): Value => {\n if (args.length !== arity) {\n throw ErrorFactory.execution({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_ARITY_MISMATCH,\n message: `${spec.name}() takes ${plural(arity)}, but was given ${args.length === 0 ? \"none\" : plural(args.length)}`,\n expected: plural(arity),\n found: args.length === 0 ? \"none\" : plural(args.length),\n context: { functionName: spec.name, expected: arity, actual: args.length },\n });\n }\n\n const jsArgs: (number | string | boolean)[] = new Array(arity);\n for (let i = 0; i < arity; i++) {\n jsArgs[i] = coerceArgument(args[i], spec.args[i], spec.name);\n }\n\n const result = (spec.call as (...a: (number | string | boolean)[]) => unknown)(...jsArgs);\n return wrapReturn(result, spec.returns, spec.name);\n };\n}\n\n/** Reject a spec that could not produce a working function, before any engine sees it. */\nfunction validateSpec(spec: FunctionSpec): void {\n if (typeof spec?.name !== \"string\" || !NAME_PATTERN.test(spec.name)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_NAME,\n message: `defineFunction: name must be a single identifier, got ${JSON.stringify(spec?.name)}`,\n suggestion: 'e.g. \"vat\" or \"net_price\"',\n context: { name: spec?.name },\n });\n }\n if (!Array.isArray(spec.args)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" args must be an array`,\n context: { name: spec.name },\n });\n }\n for (const arg of spec.args) {\n if (typeof arg?.name !== \"string\" || arg.name.length === 0) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has an argument with no name`,\n context: { name: spec.name },\n });\n }\n if (!SUPPORTED_TYPES.has(arg.type)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" argument \"${arg.name}\" has unsupported type ${JSON.stringify(arg.type)}`,\n suggestion: \"supported argument types are number, string, boolean\",\n context: { name: spec.name, argName: arg.name, type: arg.type },\n });\n }\n }\n if (!SUPPORTED_TYPES.has(spec.returns)) {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" has unsupported return type ${JSON.stringify(spec.returns)}`,\n suggestion: \"supported return types are number, string, boolean\",\n context: { name: spec.name, returns: spec.returns },\n });\n }\n if (typeof spec.call !== \"function\") {\n throw ErrorFactory.config({\n code: DefineFunctionErrorCodes.DEFINE_FUNCTION_INVALID_SPEC,\n message: `defineFunction: \"${spec.name}\" is missing a call implementation`,\n context: { name: spec.name },\n });\n }\n}\n\n/**\n * Turn a declarative {@link FunctionSpec} into a ready-to-register\n * {@link IEnginePackage}.\n *\n * This is the higher-level API from issue #102. It derives, from the\n * declaration alone, everything the low-level contract asks an author to write\n * by hand: a plugin function index ({@link allocatePluginFunctionIndex}), a\n * lexer keyword so the name tokenises, a call-syntax parselet emitting\n * `CALL_PLUGIN`, and a handler that checks arity and argument types (yielding\n * the engine's own structured errors) before invoking `call` and wrapping its\n * result. Anything needing custom parsing keeps writing a raw parselet exactly\n * as before, this sits on top of that contract and does not change it.\n *\n * @example\n * ```ts\n * const engine = new ExpressionEngine(\"en\", false, undefined, undefined, [\n * ...BUILTIN_PACKAGES,\n * defineFunction({\n * name: \"vat\",\n * args: [{ name: \"amount\", type: \"number\" }],\n * returns: \"number\",\n * call: (amount) => amount * 1.2,\n * }),\n * ]);\n * engine.evaluateExpression(\"vat(100)\"); // 120\n * ```\n *\n * The returned package is self-contained and composes with any others through\n * the engine's `packages` array; register several functions by passing several\n * packages. Its name is `solve-fn-<name>`.\n *\n * Scope: arguments are a fixed-length list of `number`/`string`/`boolean`, and\n * `call` is synchronous. Variadic and optional arguments, other value types\n * (units, percentages, dates, matrices), and async work are deliberately out\n * of scope, a function needing any of those keeps using the low-level\n * contract, whose parselets and async resolvers are unchanged.\n *\n * @throws {EngineError} (category CONFIG) if the spec is malformed, at the\n * point `defineFunction` is called, before the package reaches an engine.\n */\nexport function defineFunction<\n const A extends readonly FunctionArg[],\n R extends FunctionValueType,\n>(spec: FunctionSpec<A, R>): IEnginePackage {\n validateSpec(spec as FunctionSpec);\n\n const name = spec.name;\n // Uppercased so the generated type is a valid, collision-resistant token\n // type; the name pattern guarantees it forms one. Distinct from the\n // built-in FUNC type, so this never routes through the builtin name map.\n const tokenType = `DEFINE_FN_${name.toUpperCase()}`;\n // Allocated at definition time (not module load), so importing this module\n // consumes no index and the export stays side-effect free.\n const index = allocatePluginFunctionIndex();\n\n return {\n name: `solve-fn-${name}`,\n lexerVocabulary: {\n // Lowercased because the lexer lowercases input before lookup, so the\n // call is matched case-insensitively.\n keywords: { [name.toLowerCase()]: tokenType },\n },\n prefixParselets: [\n { tokenType, parselet: new DefinedFunctionParselet(index, name) },\n ],\n pluginFunctions: [\n { index, handler: makeHandler(spec as FunctionSpec) },\n ],\n };\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,92 +1,128 @@
|
|
|
1
|
-
import { I as IEnginePackage } from './PackageRegistry-
|
|
2
|
-
export {
|
|
1
|
+
import { I as IEnginePackage } from './PackageRegistry-BHWJP83F.cjs';
|
|
2
|
+
export { a as EngineRestoreOptions, b as EngineSnapshot, c as EvalResults, d as Explanation, e as ExplanationStep, E as ExpressionEngine, f as IPackageRegistry, L as LineEvaluation, P as PackageRegistry, S as SNAPSHOT_FORMAT, g as SNAPSHOT_VERSION, h as SerializedAnonymousBody, i as SerializedBytecode, j as SerializedDecimal, k as SerializedLineCacheEntry, l as SerializedNumber, m as SerializedRational, n as SerializedUserFunction, o as SerializedValue, p as SnapshotErrorCodes, q as packageRegistry } from './PackageRegistry-BHWJP83F.cjs';
|
|
3
|
+
export { a as CompatibilityConflict, b as CompatibilityConflictKind, C as CompatibilityReport, c as CompatibilitySeverity, d as checkPackageCompatibility } from './PackageCompatibility-B-7rK1TD.cjs';
|
|
3
4
|
export { ENGINE_VERSION } from './constants.cjs';
|
|
4
|
-
import './Parselet-
|
|
5
|
-
import './BytecodeBuilder-
|
|
6
|
-
import './Token-
|
|
7
|
-
import './pipeline-
|
|
8
|
-
import './Value-
|
|
5
|
+
import './Parselet-BHcgK9S7.cjs';
|
|
6
|
+
import './BytecodeBuilder-Bp9xeTmX.cjs';
|
|
7
|
+
import './Token-B1hdkedD.cjs';
|
|
8
|
+
import './pipeline-CtfJtPQc.cjs';
|
|
9
|
+
import './Value-BUi1RA3S.cjs';
|
|
9
10
|
import './variables.cjs';
|
|
10
|
-
import './Lexer-
|
|
11
|
+
import './Lexer-BOs7euZe.cjs';
|
|
11
12
|
import './resolvers.cjs';
|
|
12
13
|
import '@tanstack/query-core';
|
|
13
|
-
import './TokenNormalizer-
|
|
14
|
-
import './ScopeManager-
|
|
15
|
-
import './EngineError-
|
|
16
|
-
import './Configuration-
|
|
14
|
+
import './TokenNormalizer-DRc1Js1V.cjs';
|
|
15
|
+
import './ScopeManager-8vf02dwj.cjs';
|
|
16
|
+
import './EngineError-B61GS1jp.cjs';
|
|
17
|
+
import './Configuration-C9W8tJv_.cjs';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* A higher-level, declarative way to contribute a single `name(args)`
|
|
21
|
+
* function, sitting ON TOP OF the package contract rather than replacing it.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* `ParseletRegistry.registerPrefix()`'s collision-visibility fix closed for
|
|
29
|
-
* parselets specifically (see `ARCHITECTURE.md`'s punch list). And none of
|
|
30
|
-
* these existing checks can be run BEFORE registration, they only fire at
|
|
31
|
-
* the moment a collision actually happens, deep inside a live engine.
|
|
32
|
-
*
|
|
33
|
-
* `checkPackageCompatibility()` is a single, pure, side-effect-free function
|
|
34
|
-
* that statically compares one candidate package's declared descriptor
|
|
35
|
-
* against a list of already-registered packages' descriptors, across every
|
|
36
|
-
* collision-capable field `IEnginePackage` has, callable standalone (a host
|
|
37
|
-
* building a plugin marketplace could run it before ever constructing an
|
|
38
|
-
* engine) or wired into registration itself (see
|
|
39
|
-
* `ExpressionEngine.registerPackage()`, which calls this automatically and
|
|
40
|
-
* logs every conflict found, the "load-up resiliency" half of this
|
|
41
|
-
* mechanism).
|
|
42
|
-
*
|
|
43
|
-
* A real, concrete motivating bug (found the same session this module was
|
|
44
|
-
* built): the currency package's real `IEnginePackage` descriptor
|
|
45
|
-
* (`CurrencyPackage.ts`) and its parallel test-harness registration helper
|
|
46
|
-
* (`parselets/index.ts`'s `registerCurrencyParselets()`) drifted out of sync
|
|
47
|
-
*, new currency-symbol token types were wired into one but not the other
|
|
48
|
-
* caught only by a test happening to exercise the stale path. This module
|
|
49
|
-
* doesn't catch THAT specific class of bug (two hand-written registration
|
|
50
|
-
* functions for the same logical package diverging is a source-consistency
|
|
51
|
-
* problem, not a runtime collision), but it DOES catch the more common and
|
|
52
|
-
* more dangerous sibling: two DIFFERENT, independently-authored packages
|
|
53
|
-
* unknowingly claiming the same token type, phrase, converter name, plugin
|
|
54
|
-
* function index, or lexer keyword.
|
|
23
|
+
* The low-level contract (allocate a plugin function index, write a parselet,
|
|
24
|
+
* emit `CALL_PLUGIN`) stays exactly as it was and remains the way to add
|
|
25
|
+
* anything that needs custom parsing. This module derives that same wiring
|
|
26
|
+
* from a declaration for the common case, a function called with parenthesised
|
|
27
|
+
* arguments, so adding `vat(x)` costs a spec object rather than an
|
|
28
|
+
* understanding of the parser and the VM. See `defineFunction`.
|
|
55
29
|
*/
|
|
56
|
-
/**
|
|
57
|
-
type
|
|
58
|
-
/** The
|
|
59
|
-
type
|
|
60
|
-
/** One
|
|
61
|
-
interface
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
/** The two package names involved, [existing, candidate]. */
|
|
67
|
-
packages: [string, string];
|
|
30
|
+
/** The value types a declared argument or return may take. */
|
|
31
|
+
type FunctionValueType = "number" | "string" | "boolean";
|
|
32
|
+
/** The JavaScript type a {@link FunctionValueType} maps to at the `call` boundary. */
|
|
33
|
+
type JsValue<T extends FunctionValueType> = T extends "number" ? number : T extends "string" ? string : boolean;
|
|
34
|
+
/** One declared parameter: a name (for error messages) and a value type. */
|
|
35
|
+
interface FunctionArg {
|
|
36
|
+
/** Parameter name, used only in the generated type-mismatch messages. */
|
|
37
|
+
name: string;
|
|
38
|
+
/** The value type this parameter accepts. */
|
|
39
|
+
type: FunctionValueType;
|
|
68
40
|
}
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
41
|
+
/** Map a tuple of {@link FunctionArg} specs to the tuple of JS values `call` receives. */
|
|
42
|
+
type CallArgs<A extends readonly FunctionArg[]> = {
|
|
43
|
+
[K in keyof A]: JsValue<A[K]["type"]>;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* A declarative function definition.
|
|
47
|
+
*
|
|
48
|
+
* `A` and `R` are inferred from the literal `args`/`returns` (via
|
|
49
|
+
* `defineFunction`'s `const` type parameter), so `call`'s parameters and
|
|
50
|
+
* return are typed from the declaration with no annotations: an
|
|
51
|
+
* `{ type: "number" }` argument arrives as a `number`, and a `returns:
|
|
52
|
+
* "string"` demands a `string` back.
|
|
53
|
+
*/
|
|
54
|
+
interface FunctionSpec<A extends readonly FunctionArg[] = readonly FunctionArg[], R extends FunctionValueType = FunctionValueType> {
|
|
55
|
+
/**
|
|
56
|
+
* The call name, a single identifier (`/^[a-z_][a-z0-9_]*$/i`). Registered
|
|
57
|
+
* as a lexer keyword, so it is matched case-insensitively and cannot collide
|
|
58
|
+
* with a built-in keyword (that collision throws at registration time).
|
|
59
|
+
*/
|
|
60
|
+
name: string;
|
|
61
|
+
/** The parameters, in order. A fixed-length list: variadic and optional args are out of scope (see {@link defineFunction}). */
|
|
62
|
+
args: A;
|
|
63
|
+
/** The value type the function returns. */
|
|
64
|
+
returns: R;
|
|
65
|
+
/** The implementation, receiving plain JS values and returning one. Must be synchronous (see {@link defineFunction}). */
|
|
66
|
+
call: (...args: CallArgs<A>) => JsValue<R>;
|
|
74
67
|
}
|
|
75
68
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
|
|
69
|
+
* Error codes the declarative function API raises. Kept as a co-located const
|
|
70
|
+
* (the convention `errors/ErrorCode.ts` documents for a domain's own codes) so
|
|
71
|
+
* the strings have one source of truth.
|
|
72
|
+
*/
|
|
73
|
+
declare const DefineFunctionErrorCodes: {
|
|
74
|
+
/** The spec's `name` is not a single identifier. Thrown by `defineFunction`, before any engine sees it. */
|
|
75
|
+
readonly DEFINE_FUNCTION_INVALID_NAME: "DEFINE_FUNCTION_INVALID_NAME";
|
|
76
|
+
/** The spec is otherwise malformed (bad `args`, unsupported type, missing `call`). Thrown by `defineFunction`. */
|
|
77
|
+
readonly DEFINE_FUNCTION_INVALID_SPEC: "DEFINE_FUNCTION_INVALID_SPEC";
|
|
78
|
+
/** The call site passed the wrong number of arguments. Raised at evaluation time. */
|
|
79
|
+
readonly DEFINE_FUNCTION_ARITY_MISMATCH: "DEFINE_FUNCTION_ARITY_MISMATCH";
|
|
80
|
+
/** An argument was the wrong value type. Raised at evaluation time. */
|
|
81
|
+
readonly DEFINE_FUNCTION_ARGUMENT_TYPE: "DEFINE_FUNCTION_ARGUMENT_TYPE";
|
|
82
|
+
/** The `call` implementation returned a value that did not match `returns`. Raised at evaluation time, an authoring bug rather than a user one. */
|
|
83
|
+
readonly DEFINE_FUNCTION_RETURN_TYPE: "DEFINE_FUNCTION_RETURN_TYPE";
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Turn a declarative {@link FunctionSpec} into a ready-to-register
|
|
87
|
+
* {@link IEnginePackage}.
|
|
88
|
+
*
|
|
89
|
+
* This is the higher-level API from issue #102. It derives, from the
|
|
90
|
+
* declaration alone, everything the low-level contract asks an author to write
|
|
91
|
+
* by hand: a plugin function index ({@link allocatePluginFunctionIndex}), a
|
|
92
|
+
* lexer keyword so the name tokenises, a call-syntax parselet emitting
|
|
93
|
+
* `CALL_PLUGIN`, and a handler that checks arity and argument types (yielding
|
|
94
|
+
* the engine's own structured errors) before invoking `call` and wrapping its
|
|
95
|
+
* result. Anything needing custom parsing keeps writing a raw parselet exactly
|
|
96
|
+
* as before, this sits on top of that contract and does not change it.
|
|
80
97
|
*
|
|
81
98
|
* @example
|
|
82
99
|
* ```ts
|
|
83
|
-
* const
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
100
|
+
* const engine = new ExpressionEngine("en", false, undefined, undefined, [
|
|
101
|
+
* ...BUILTIN_PACKAGES,
|
|
102
|
+
* defineFunction({
|
|
103
|
+
* name: "vat",
|
|
104
|
+
* args: [{ name: "amount", type: "number" }],
|
|
105
|
+
* returns: "number",
|
|
106
|
+
* call: (amount) => amount * 1.2,
|
|
107
|
+
* }),
|
|
108
|
+
* ]);
|
|
109
|
+
* engine.evaluateExpression("vat(100)"); // 120
|
|
87
110
|
* ```
|
|
111
|
+
*
|
|
112
|
+
* The returned package is self-contained and composes with any others through
|
|
113
|
+
* the engine's `packages` array; register several functions by passing several
|
|
114
|
+
* packages. Its name is `solve-fn-<name>`.
|
|
115
|
+
*
|
|
116
|
+
* Scope: arguments are a fixed-length list of `number`/`string`/`boolean`, and
|
|
117
|
+
* `call` is synchronous. Variadic and optional arguments, other value types
|
|
118
|
+
* (units, percentages, dates, matrices), and async work are deliberately out
|
|
119
|
+
* of scope, a function needing any of those keeps using the low-level
|
|
120
|
+
* contract, whose parselets and async resolvers are unchanged.
|
|
121
|
+
*
|
|
122
|
+
* @throws {EngineError} (category CONFIG) if the spec is malformed, at the
|
|
123
|
+
* point `defineFunction` is called, before the package reaches an engine.
|
|
88
124
|
*/
|
|
89
|
-
declare function
|
|
125
|
+
declare function defineFunction<const A extends readonly FunctionArg[], R extends FunctionValueType>(spec: FunctionSpec<A, R>): IEnginePackage;
|
|
90
126
|
|
|
91
127
|
/**
|
|
92
128
|
* Engine-version package compatibility gating, the "reject a package built
|
|
@@ -149,4 +185,4 @@ declare function checkEngineVersionCompatibility(pkg: IEnginePackage, engineVers
|
|
|
149
185
|
*/
|
|
150
186
|
declare function assertEngineVersionCompatible(pkg: IEnginePackage, engineVersion?: string): void;
|
|
151
187
|
|
|
152
|
-
export {
|
|
188
|
+
export { DefineFunctionErrorCodes, type EngineVersionCheckResult, type FunctionArg, type FunctionSpec, type FunctionValueType, IEnginePackage, assertEngineVersionCompatible, checkEngineVersionCompatibility, defineFunction };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,92 +1,128 @@
|
|
|
1
|
-
import { I as IEnginePackage } from './PackageRegistry-
|
|
2
|
-
export {
|
|
1
|
+
import { I as IEnginePackage } from './PackageRegistry-_8rDlvxI.js';
|
|
2
|
+
export { a as EngineRestoreOptions, b as EngineSnapshot, c as EvalResults, d as Explanation, e as ExplanationStep, E as ExpressionEngine, f as IPackageRegistry, L as LineEvaluation, P as PackageRegistry, S as SNAPSHOT_FORMAT, g as SNAPSHOT_VERSION, h as SerializedAnonymousBody, i as SerializedBytecode, j as SerializedDecimal, k as SerializedLineCacheEntry, l as SerializedNumber, m as SerializedRational, n as SerializedUserFunction, o as SerializedValue, p as SnapshotErrorCodes, q as packageRegistry } from './PackageRegistry-_8rDlvxI.js';
|
|
3
|
+
export { a as CompatibilityConflict, b as CompatibilityConflictKind, C as CompatibilityReport, c as CompatibilitySeverity, d as checkPackageCompatibility } from './PackageCompatibility-Dh59eF-X.js';
|
|
3
4
|
export { ENGINE_VERSION } from './constants.js';
|
|
4
|
-
import './Parselet-
|
|
5
|
-
import './BytecodeBuilder-
|
|
6
|
-
import './Token-
|
|
7
|
-
import './pipeline-
|
|
8
|
-
import './Value-
|
|
5
|
+
import './Parselet-BBT8riYh.js';
|
|
6
|
+
import './BytecodeBuilder-Bp9xeTmX.js';
|
|
7
|
+
import './Token-B1hdkedD.js';
|
|
8
|
+
import './pipeline-DCd5M6Gk.js';
|
|
9
|
+
import './Value-BUi1RA3S.js';
|
|
9
10
|
import './variables.js';
|
|
10
|
-
import './Lexer-
|
|
11
|
+
import './Lexer-CSI_lwbW.js';
|
|
11
12
|
import './resolvers.js';
|
|
12
13
|
import '@tanstack/query-core';
|
|
13
|
-
import './TokenNormalizer-
|
|
14
|
-
import './ScopeManager-
|
|
15
|
-
import './EngineError-
|
|
16
|
-
import './Configuration-
|
|
14
|
+
import './TokenNormalizer-C6VzZgHa.js';
|
|
15
|
+
import './ScopeManager-CxA24W5n.js';
|
|
16
|
+
import './EngineError-B61GS1jp.js';
|
|
17
|
+
import './Configuration-C9W8tJv_.js';
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
|
-
*
|
|
20
|
-
*
|
|
20
|
+
* A higher-level, declarative way to contribute a single `name(args)`
|
|
21
|
+
* function, sitting ON TOP OF the package contract rather than replacing it.
|
|
21
22
|
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
* `ParseletRegistry.registerPrefix()`'s collision-visibility fix closed for
|
|
29
|
-
* parselets specifically (see `ARCHITECTURE.md`'s punch list). And none of
|
|
30
|
-
* these existing checks can be run BEFORE registration, they only fire at
|
|
31
|
-
* the moment a collision actually happens, deep inside a live engine.
|
|
32
|
-
*
|
|
33
|
-
* `checkPackageCompatibility()` is a single, pure, side-effect-free function
|
|
34
|
-
* that statically compares one candidate package's declared descriptor
|
|
35
|
-
* against a list of already-registered packages' descriptors, across every
|
|
36
|
-
* collision-capable field `IEnginePackage` has, callable standalone (a host
|
|
37
|
-
* building a plugin marketplace could run it before ever constructing an
|
|
38
|
-
* engine) or wired into registration itself (see
|
|
39
|
-
* `ExpressionEngine.registerPackage()`, which calls this automatically and
|
|
40
|
-
* logs every conflict found, the "load-up resiliency" half of this
|
|
41
|
-
* mechanism).
|
|
42
|
-
*
|
|
43
|
-
* A real, concrete motivating bug (found the same session this module was
|
|
44
|
-
* built): the currency package's real `IEnginePackage` descriptor
|
|
45
|
-
* (`CurrencyPackage.ts`) and its parallel test-harness registration helper
|
|
46
|
-
* (`parselets/index.ts`'s `registerCurrencyParselets()`) drifted out of sync
|
|
47
|
-
*, new currency-symbol token types were wired into one but not the other
|
|
48
|
-
* caught only by a test happening to exercise the stale path. This module
|
|
49
|
-
* doesn't catch THAT specific class of bug (two hand-written registration
|
|
50
|
-
* functions for the same logical package diverging is a source-consistency
|
|
51
|
-
* problem, not a runtime collision), but it DOES catch the more common and
|
|
52
|
-
* more dangerous sibling: two DIFFERENT, independently-authored packages
|
|
53
|
-
* unknowingly claiming the same token type, phrase, converter name, plugin
|
|
54
|
-
* function index, or lexer keyword.
|
|
23
|
+
* The low-level contract (allocate a plugin function index, write a parselet,
|
|
24
|
+
* emit `CALL_PLUGIN`) stays exactly as it was and remains the way to add
|
|
25
|
+
* anything that needs custom parsing. This module derives that same wiring
|
|
26
|
+
* from a declaration for the common case, a function called with parenthesised
|
|
27
|
+
* arguments, so adding `vat(x)` costs a spec object rather than an
|
|
28
|
+
* understanding of the parser and the VM. See `defineFunction`.
|
|
55
29
|
*/
|
|
56
|
-
/**
|
|
57
|
-
type
|
|
58
|
-
/** The
|
|
59
|
-
type
|
|
60
|
-
/** One
|
|
61
|
-
interface
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
/**
|
|
65
|
-
|
|
66
|
-
/** The two package names involved, [existing, candidate]. */
|
|
67
|
-
packages: [string, string];
|
|
30
|
+
/** The value types a declared argument or return may take. */
|
|
31
|
+
type FunctionValueType = "number" | "string" | "boolean";
|
|
32
|
+
/** The JavaScript type a {@link FunctionValueType} maps to at the `call` boundary. */
|
|
33
|
+
type JsValue<T extends FunctionValueType> = T extends "number" ? number : T extends "string" ? string : boolean;
|
|
34
|
+
/** One declared parameter: a name (for error messages) and a value type. */
|
|
35
|
+
interface FunctionArg {
|
|
36
|
+
/** Parameter name, used only in the generated type-mismatch messages. */
|
|
37
|
+
name: string;
|
|
38
|
+
/** The value type this parameter accepts. */
|
|
39
|
+
type: FunctionValueType;
|
|
68
40
|
}
|
|
69
|
-
/**
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
41
|
+
/** Map a tuple of {@link FunctionArg} specs to the tuple of JS values `call` receives. */
|
|
42
|
+
type CallArgs<A extends readonly FunctionArg[]> = {
|
|
43
|
+
[K in keyof A]: JsValue<A[K]["type"]>;
|
|
44
|
+
};
|
|
45
|
+
/**
|
|
46
|
+
* A declarative function definition.
|
|
47
|
+
*
|
|
48
|
+
* `A` and `R` are inferred from the literal `args`/`returns` (via
|
|
49
|
+
* `defineFunction`'s `const` type parameter), so `call`'s parameters and
|
|
50
|
+
* return are typed from the declaration with no annotations: an
|
|
51
|
+
* `{ type: "number" }` argument arrives as a `number`, and a `returns:
|
|
52
|
+
* "string"` demands a `string` back.
|
|
53
|
+
*/
|
|
54
|
+
interface FunctionSpec<A extends readonly FunctionArg[] = readonly FunctionArg[], R extends FunctionValueType = FunctionValueType> {
|
|
55
|
+
/**
|
|
56
|
+
* The call name, a single identifier (`/^[a-z_][a-z0-9_]*$/i`). Registered
|
|
57
|
+
* as a lexer keyword, so it is matched case-insensitively and cannot collide
|
|
58
|
+
* with a built-in keyword (that collision throws at registration time).
|
|
59
|
+
*/
|
|
60
|
+
name: string;
|
|
61
|
+
/** The parameters, in order. A fixed-length list: variadic and optional args are out of scope (see {@link defineFunction}). */
|
|
62
|
+
args: A;
|
|
63
|
+
/** The value type the function returns. */
|
|
64
|
+
returns: R;
|
|
65
|
+
/** The implementation, receiving plain JS values and returning one. Must be synchronous (see {@link defineFunction}). */
|
|
66
|
+
call: (...args: CallArgs<A>) => JsValue<R>;
|
|
74
67
|
}
|
|
75
68
|
/**
|
|
76
|
-
*
|
|
77
|
-
*
|
|
78
|
-
*
|
|
79
|
-
|
|
69
|
+
* Error codes the declarative function API raises. Kept as a co-located const
|
|
70
|
+
* (the convention `errors/ErrorCode.ts` documents for a domain's own codes) so
|
|
71
|
+
* the strings have one source of truth.
|
|
72
|
+
*/
|
|
73
|
+
declare const DefineFunctionErrorCodes: {
|
|
74
|
+
/** The spec's `name` is not a single identifier. Thrown by `defineFunction`, before any engine sees it. */
|
|
75
|
+
readonly DEFINE_FUNCTION_INVALID_NAME: "DEFINE_FUNCTION_INVALID_NAME";
|
|
76
|
+
/** The spec is otherwise malformed (bad `args`, unsupported type, missing `call`). Thrown by `defineFunction`. */
|
|
77
|
+
readonly DEFINE_FUNCTION_INVALID_SPEC: "DEFINE_FUNCTION_INVALID_SPEC";
|
|
78
|
+
/** The call site passed the wrong number of arguments. Raised at evaluation time. */
|
|
79
|
+
readonly DEFINE_FUNCTION_ARITY_MISMATCH: "DEFINE_FUNCTION_ARITY_MISMATCH";
|
|
80
|
+
/** An argument was the wrong value type. Raised at evaluation time. */
|
|
81
|
+
readonly DEFINE_FUNCTION_ARGUMENT_TYPE: "DEFINE_FUNCTION_ARGUMENT_TYPE";
|
|
82
|
+
/** The `call` implementation returned a value that did not match `returns`. Raised at evaluation time, an authoring bug rather than a user one. */
|
|
83
|
+
readonly DEFINE_FUNCTION_RETURN_TYPE: "DEFINE_FUNCTION_RETURN_TYPE";
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Turn a declarative {@link FunctionSpec} into a ready-to-register
|
|
87
|
+
* {@link IEnginePackage}.
|
|
88
|
+
*
|
|
89
|
+
* This is the higher-level API from issue #102. It derives, from the
|
|
90
|
+
* declaration alone, everything the low-level contract asks an author to write
|
|
91
|
+
* by hand: a plugin function index ({@link allocatePluginFunctionIndex}), a
|
|
92
|
+
* lexer keyword so the name tokenises, a call-syntax parselet emitting
|
|
93
|
+
* `CALL_PLUGIN`, and a handler that checks arity and argument types (yielding
|
|
94
|
+
* the engine's own structured errors) before invoking `call` and wrapping its
|
|
95
|
+
* result. Anything needing custom parsing keeps writing a raw parselet exactly
|
|
96
|
+
* as before, this sits on top of that contract and does not change it.
|
|
80
97
|
*
|
|
81
98
|
* @example
|
|
82
99
|
* ```ts
|
|
83
|
-
* const
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
*
|
|
100
|
+
* const engine = new ExpressionEngine("en", false, undefined, undefined, [
|
|
101
|
+
* ...BUILTIN_PACKAGES,
|
|
102
|
+
* defineFunction({
|
|
103
|
+
* name: "vat",
|
|
104
|
+
* args: [{ name: "amount", type: "number" }],
|
|
105
|
+
* returns: "number",
|
|
106
|
+
* call: (amount) => amount * 1.2,
|
|
107
|
+
* }),
|
|
108
|
+
* ]);
|
|
109
|
+
* engine.evaluateExpression("vat(100)"); // 120
|
|
87
110
|
* ```
|
|
111
|
+
*
|
|
112
|
+
* The returned package is self-contained and composes with any others through
|
|
113
|
+
* the engine's `packages` array; register several functions by passing several
|
|
114
|
+
* packages. Its name is `solve-fn-<name>`.
|
|
115
|
+
*
|
|
116
|
+
* Scope: arguments are a fixed-length list of `number`/`string`/`boolean`, and
|
|
117
|
+
* `call` is synchronous. Variadic and optional arguments, other value types
|
|
118
|
+
* (units, percentages, dates, matrices), and async work are deliberately out
|
|
119
|
+
* of scope, a function needing any of those keeps using the low-level
|
|
120
|
+
* contract, whose parselets and async resolvers are unchanged.
|
|
121
|
+
*
|
|
122
|
+
* @throws {EngineError} (category CONFIG) if the spec is malformed, at the
|
|
123
|
+
* point `defineFunction` is called, before the package reaches an engine.
|
|
88
124
|
*/
|
|
89
|
-
declare function
|
|
125
|
+
declare function defineFunction<const A extends readonly FunctionArg[], R extends FunctionValueType>(spec: FunctionSpec<A, R>): IEnginePackage;
|
|
90
126
|
|
|
91
127
|
/**
|
|
92
128
|
* Engine-version package compatibility gating, the "reject a package built
|
|
@@ -149,4 +185,4 @@ declare function checkEngineVersionCompatibility(pkg: IEnginePackage, engineVers
|
|
|
149
185
|
*/
|
|
150
186
|
declare function assertEngineVersionCompatible(pkg: IEnginePackage, engineVersion?: string): void;
|
|
151
187
|
|
|
152
|
-
export {
|
|
188
|
+
export { DefineFunctionErrorCodes, type EngineVersionCheckResult, type FunctionArg, type FunctionSpec, type FunctionValueType, IEnginePackage, assertEngineVersionCompatible, checkEngineVersionCompatibility, defineFunction };
|