solve-engine 1.0.1 → 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-D78E2yDW.d.cts → Lexer-BOs7euZe.d.cts} +58 -1
- package/dist/{Lexer-BN5mt30n.d.ts → Lexer-CSI_lwbW.d.ts} +58 -1
- package/dist/PackageCompatibility-B-7rK1TD.d.cts +76 -0
- package/dist/PackageCompatibility-Dh59eF-X.d.ts +76 -0
- package/dist/{PackageRegistry-B37mRvvz.d.cts → PackageRegistry-BHWJP83F.d.cts} +449 -11
- package/dist/{PackageRegistry-DCUEzbQt.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-BHTNFEGZ.cjs → chunk-C75AFGVD.cjs} +11 -11
- package/dist/{chunk-BHTNFEGZ.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-TBN7DEHO.js → chunk-G7Z4HJQA.js} +11 -5
- package/dist/chunk-G7Z4HJQA.js.map +1 -0
- package/dist/{chunk-QY25VWBF.js → chunk-GQMUHVE3.js} +142 -6
- 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-V5PYO44Y.js → chunk-JIPATHVY.js} +1853 -2638
- package/dist/chunk-JIPATHVY.js.map +1 -0
- package/dist/{chunk-YPPPYLSR.js → chunk-JJIXHXFQ.js} +5 -5
- package/dist/{chunk-YPPPYLSR.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-B7TLZABL.cjs → chunk-MG6Q3DUO.cjs} +1962 -2746
- 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-5F4C26RU.js → chunk-OADDUPT3.js} +4 -4
- package/dist/{chunk-5F4C26RU.js.map → chunk-OADDUPT3.js.map} +1 -1
- package/dist/{chunk-3AFRJYP4.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-HMOISHXR.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-KBSXGXPM.cjs → chunk-XJGJCF2R.cjs} +6 -6
- package/dist/{chunk-KBSXGXPM.cjs.map → chunk-XJGJCF2R.cjs.map} +1 -1
- package/dist/{chunk-YWQ6V4ZN.cjs → chunk-YTIYVHL7.cjs} +211 -75
- 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-2XLQPQKI.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-2XLQPQKI.cjs.map +0 -1
- package/dist/chunk-3AFRJYP4.cjs.map +0 -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-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-AJA6LUI7.js.map +0 -1
- package/dist/chunk-B7TLZABL.cjs.map +0 -1
- package/dist/chunk-GQCOSXMG.js.map +0 -1
- package/dist/chunk-HDP7VK3C.cjs.map +0 -1
- package/dist/chunk-HMOISHXR.js.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-O3ANBHSA.js.map +0 -1
- package/dist/chunk-PA4VC73I.cjs.map +0 -1
- package/dist/chunk-PFUESQTW.cjs.map +0 -1
- package/dist/chunk-QY25VWBF.js.map +0 -1
- package/dist/chunk-R3PY4G7J.js.map +0 -1
- package/dist/chunk-TBN7DEHO.js.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-V5PYO44Y.js.map +0 -1
- package/dist/chunk-VB37OC6I.js.map +0 -1
- package/dist/chunk-Y7FT4IQT.js.map +0 -1
- package/dist/chunk-YWQ6V4ZN.cjs.map +0 -1
|
@@ -23,6 +23,7 @@ declare enum OpCode {
|
|
|
23
23
|
PUSH_STRING = 13,
|
|
24
24
|
PUSH_BOOLEAN = 14,
|
|
25
25
|
PUSH_VARIABLE = 15,
|
|
26
|
+
PUSH_DECIMAL = 16,
|
|
26
27
|
ADD = 20,
|
|
27
28
|
SUB = 21,
|
|
28
29
|
MUL = 22,
|
|
@@ -31,6 +32,7 @@ declare enum OpCode {
|
|
|
31
32
|
EXP = 25,
|
|
32
33
|
NEG = 26,
|
|
33
34
|
POS = 27,
|
|
35
|
+
MAKE_UNCERTAIN = 28,
|
|
34
36
|
LSHIFT = 30,
|
|
35
37
|
RSHIFT = 31,
|
|
36
38
|
URSHIFT = 32,
|
|
@@ -66,6 +68,8 @@ declare enum OpCode {
|
|
|
66
68
|
DATE_NEXT_WEEKDAY = 93,// "next <Weekday>" — the next occurrence strictly after now
|
|
67
69
|
DATE_LAST_WEEKDAY = 94,// "last <Weekday>" — the previous occurrence strictly before now
|
|
68
70
|
DATE_LITERAL = 95,// Push a datetime literal whose epoch-ms was already resolved at parse time (see DateLiteralParselet)
|
|
71
|
+
DATE_WORKDAY_OFFSET = 96,// "N working days after/before/from <date>" — a business-day walk from the anchor date. One operand byte: 0 forward, 1 backward. Same walk as `<date> + N workdays` (vm/VM.ts's addBusinessDays). See WorkdayOffsetParselet.
|
|
72
|
+
DATE_WORKDAYS_BETWEEN = 97,// "working days between <date> and <date>" — the count of working days in the inclusive span. See WorkdaysBetweenParselet and vm/BusinessDays.ts's countBusinessDaysBetween.
|
|
69
73
|
RATE_DIV = 110,// Uom ÷ Uom (different measures) -> Rate — the construction op
|
|
70
74
|
RATE_MUL = 111,// Rate × Uom (same measure as denominator) -> plain Uom (denominator cancels)
|
|
71
75
|
RATE_CONVERT = 112,// Rate -> Rate with a rescaled denominator unit (keeps the same real-world rate)
|
|
@@ -23,6 +23,7 @@ declare enum OpCode {
|
|
|
23
23
|
PUSH_STRING = 13,
|
|
24
24
|
PUSH_BOOLEAN = 14,
|
|
25
25
|
PUSH_VARIABLE = 15,
|
|
26
|
+
PUSH_DECIMAL = 16,
|
|
26
27
|
ADD = 20,
|
|
27
28
|
SUB = 21,
|
|
28
29
|
MUL = 22,
|
|
@@ -31,6 +32,7 @@ declare enum OpCode {
|
|
|
31
32
|
EXP = 25,
|
|
32
33
|
NEG = 26,
|
|
33
34
|
POS = 27,
|
|
35
|
+
MAKE_UNCERTAIN = 28,
|
|
34
36
|
LSHIFT = 30,
|
|
35
37
|
RSHIFT = 31,
|
|
36
38
|
URSHIFT = 32,
|
|
@@ -66,6 +68,8 @@ declare enum OpCode {
|
|
|
66
68
|
DATE_NEXT_WEEKDAY = 93,// "next <Weekday>" — the next occurrence strictly after now
|
|
67
69
|
DATE_LAST_WEEKDAY = 94,// "last <Weekday>" — the previous occurrence strictly before now
|
|
68
70
|
DATE_LITERAL = 95,// Push a datetime literal whose epoch-ms was already resolved at parse time (see DateLiteralParselet)
|
|
71
|
+
DATE_WORKDAY_OFFSET = 96,// "N working days after/before/from <date>" — a business-day walk from the anchor date. One operand byte: 0 forward, 1 backward. Same walk as `<date> + N workdays` (vm/VM.ts's addBusinessDays). See WorkdayOffsetParselet.
|
|
72
|
+
DATE_WORKDAYS_BETWEEN = 97,// "working days between <date> and <date>" — the count of working days in the inclusive span. See WorkdaysBetweenParselet and vm/BusinessDays.ts's countBusinessDaysBetween.
|
|
69
73
|
RATE_DIV = 110,// Uom ÷ Uom (different measures) -> Rate — the construction op
|
|
70
74
|
RATE_MUL = 111,// Rate × Uom (same measure as denominator) -> plain Uom (denominator cancels)
|
|
71
75
|
RATE_CONVERT = 112,// Rate -> Rate with a rescaled denominator unit (keeps the same real-world rate)
|
|
@@ -21,6 +21,28 @@
|
|
|
21
21
|
*
|
|
22
22
|
* @module Configuration
|
|
23
23
|
*/
|
|
24
|
+
/**
|
|
25
|
+
* A host's test for whether a calendar date is a public holiday, given the
|
|
26
|
+
* `Date` for that day at local midnight. Return `true` to exclude it from
|
|
27
|
+
* working-day arithmetic.
|
|
28
|
+
*/
|
|
29
|
+
type HolidayPredicate = (date: Date) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The host-supplied public-holiday calendar, in the same "bring your own data"
|
|
32
|
+
* shape the stocks and weather packages already use for a host callback (see
|
|
33
|
+
* `packages/stocks/StocksPackage.ts`): weekends are decidable from the date
|
|
34
|
+
* alone, holidays are not, so they come from the host or not at all.
|
|
35
|
+
*
|
|
36
|
+
* Either a {@link HolidayPredicate}, for a host that computes holidays itself
|
|
37
|
+
* (an existing library, a region rule), or an iterable of specific dates as
|
|
38
|
+
* `YYYY-MM-DD` strings, epoch-millisecond numbers or `Date` objects, for a host
|
|
39
|
+
* that just has a list. Resolved to one internal predicate by
|
|
40
|
+
* `vm/HolidayCalendar.ts`'s `resolveHolidayPredicate()`.
|
|
41
|
+
*
|
|
42
|
+
* Left unset, working-day arithmetic skips weekends only, which is the honest
|
|
43
|
+
* default: the engine excludes exactly the days it can prove are non-working.
|
|
44
|
+
*/
|
|
45
|
+
type HolidayCalendar = HolidayPredicate | Iterable<string | number | Date>;
|
|
24
46
|
/**
|
|
25
47
|
* Date-related configuration.
|
|
26
48
|
* Controls the bounds and formatting for date/time expression evaluation
|
|
@@ -50,6 +72,21 @@ interface DateConfig {
|
|
|
50
72
|
readonly minOffsetYears: number;
|
|
51
73
|
/** Default date string format for display (moment.js format string) */
|
|
52
74
|
readonly defaultFormat: string;
|
|
75
|
+
/**
|
|
76
|
+
* Public-holiday calendar for working-day arithmetic (`N working days after
|
|
77
|
+
* <date>`, `working days between <date> and <date>`, `<date> + N workdays`).
|
|
78
|
+
* See {@link HolidayCalendar}.
|
|
79
|
+
*
|
|
80
|
+
* Optional and unset by default: with no calendar, working-day arithmetic
|
|
81
|
+
* skips weekends only. A host that wants holidays excluded too supplies one
|
|
82
|
+
* here (`new ExpressionEngine("en", false, { date: { holidays } })`), the
|
|
83
|
+
* same way stocks and weather take a host data source. Threaded into the VM
|
|
84
|
+
* by `engine/ExpressionEngine.ts` exactly as {@link maxOffsetYears} is,
|
|
85
|
+
* because working-day math is a VM operation several grammar forms share, so
|
|
86
|
+
* the calendar has to be one source the VM owns rather than per-package state
|
|
87
|
+
* the VM cannot see.
|
|
88
|
+
*/
|
|
89
|
+
readonly holidays?: HolidayCalendar;
|
|
53
90
|
}
|
|
54
91
|
/**
|
|
55
92
|
* Performance-related configuration.
|
|
@@ -197,6 +234,21 @@ interface VMConfig {
|
|
|
197
234
|
* arguments and its result whatever its body says.
|
|
198
235
|
*/
|
|
199
236
|
readonly maxFunctionCalls: number;
|
|
237
|
+
/**
|
|
238
|
+
* Hard ceiling on how many bisection steps goal seek (`solve line N for
|
|
239
|
+
* <var> = <target>`, see `packages/goalseek/`) may take before it gives up
|
|
240
|
+
* with a structured error rather than continuing.
|
|
241
|
+
*
|
|
242
|
+
* Goal seek re-evaluates the target line's expression once per step while
|
|
243
|
+
* narrowing an interval, and an untrusted document must never be able to
|
|
244
|
+
* make that loop spin. `maxInstructions` bounds each individual
|
|
245
|
+
* re-evaluation, but not how many of them the search performs, so this is
|
|
246
|
+
* the tally that bounds the search itself, the same reason `maxFunctionCalls`
|
|
247
|
+
* exists alongside `maxInstructions`. Bisection halves the interval every
|
|
248
|
+
* step, so a hundred steps resolves an input to roughly one part in 2^100:
|
|
249
|
+
* far past any precision a document needs, and a definite stop either way.
|
|
250
|
+
*/
|
|
251
|
+
readonly maxGoalSeekIterations: number;
|
|
200
252
|
}
|
|
201
253
|
/**
|
|
202
254
|
* Complete engine configuration.
|
|
@@ -303,4 +355,4 @@ interface ValidationResult {
|
|
|
303
355
|
warnings?: string[];
|
|
304
356
|
}
|
|
305
357
|
|
|
306
|
-
export { ConfigManager as C, DEFAULT_CONFIG as D, type EngineConfig as E, type PerformanceConfig as P, type VMConfig as V, type WorkerConfig as W, type DateConfig as a, type DiagnosticConfig as b, type
|
|
358
|
+
export { ConfigManager as C, DEFAULT_CONFIG as D, type EngineConfig as E, type HolidayCalendar as H, type PerformanceConfig as P, type VMConfig as V, type WorkerConfig as W, type DateConfig as a, type DiagnosticConfig as b, type HolidayPredicate as c, type ValidationConfig as d, type ValidationResult as e };
|
|
@@ -21,6 +21,28 @@
|
|
|
21
21
|
*
|
|
22
22
|
* @module Configuration
|
|
23
23
|
*/
|
|
24
|
+
/**
|
|
25
|
+
* A host's test for whether a calendar date is a public holiday, given the
|
|
26
|
+
* `Date` for that day at local midnight. Return `true` to exclude it from
|
|
27
|
+
* working-day arithmetic.
|
|
28
|
+
*/
|
|
29
|
+
type HolidayPredicate = (date: Date) => boolean;
|
|
30
|
+
/**
|
|
31
|
+
* The host-supplied public-holiday calendar, in the same "bring your own data"
|
|
32
|
+
* shape the stocks and weather packages already use for a host callback (see
|
|
33
|
+
* `packages/stocks/StocksPackage.ts`): weekends are decidable from the date
|
|
34
|
+
* alone, holidays are not, so they come from the host or not at all.
|
|
35
|
+
*
|
|
36
|
+
* Either a {@link HolidayPredicate}, for a host that computes holidays itself
|
|
37
|
+
* (an existing library, a region rule), or an iterable of specific dates as
|
|
38
|
+
* `YYYY-MM-DD` strings, epoch-millisecond numbers or `Date` objects, for a host
|
|
39
|
+
* that just has a list. Resolved to one internal predicate by
|
|
40
|
+
* `vm/HolidayCalendar.ts`'s `resolveHolidayPredicate()`.
|
|
41
|
+
*
|
|
42
|
+
* Left unset, working-day arithmetic skips weekends only, which is the honest
|
|
43
|
+
* default: the engine excludes exactly the days it can prove are non-working.
|
|
44
|
+
*/
|
|
45
|
+
type HolidayCalendar = HolidayPredicate | Iterable<string | number | Date>;
|
|
24
46
|
/**
|
|
25
47
|
* Date-related configuration.
|
|
26
48
|
* Controls the bounds and formatting for date/time expression evaluation
|
|
@@ -50,6 +72,21 @@ interface DateConfig {
|
|
|
50
72
|
readonly minOffsetYears: number;
|
|
51
73
|
/** Default date string format for display (moment.js format string) */
|
|
52
74
|
readonly defaultFormat: string;
|
|
75
|
+
/**
|
|
76
|
+
* Public-holiday calendar for working-day arithmetic (`N working days after
|
|
77
|
+
* <date>`, `working days between <date> and <date>`, `<date> + N workdays`).
|
|
78
|
+
* See {@link HolidayCalendar}.
|
|
79
|
+
*
|
|
80
|
+
* Optional and unset by default: with no calendar, working-day arithmetic
|
|
81
|
+
* skips weekends only. A host that wants holidays excluded too supplies one
|
|
82
|
+
* here (`new ExpressionEngine("en", false, { date: { holidays } })`), the
|
|
83
|
+
* same way stocks and weather take a host data source. Threaded into the VM
|
|
84
|
+
* by `engine/ExpressionEngine.ts` exactly as {@link maxOffsetYears} is,
|
|
85
|
+
* because working-day math is a VM operation several grammar forms share, so
|
|
86
|
+
* the calendar has to be one source the VM owns rather than per-package state
|
|
87
|
+
* the VM cannot see.
|
|
88
|
+
*/
|
|
89
|
+
readonly holidays?: HolidayCalendar;
|
|
53
90
|
}
|
|
54
91
|
/**
|
|
55
92
|
* Performance-related configuration.
|
|
@@ -197,6 +234,21 @@ interface VMConfig {
|
|
|
197
234
|
* arguments and its result whatever its body says.
|
|
198
235
|
*/
|
|
199
236
|
readonly maxFunctionCalls: number;
|
|
237
|
+
/**
|
|
238
|
+
* Hard ceiling on how many bisection steps goal seek (`solve line N for
|
|
239
|
+
* <var> = <target>`, see `packages/goalseek/`) may take before it gives up
|
|
240
|
+
* with a structured error rather than continuing.
|
|
241
|
+
*
|
|
242
|
+
* Goal seek re-evaluates the target line's expression once per step while
|
|
243
|
+
* narrowing an interval, and an untrusted document must never be able to
|
|
244
|
+
* make that loop spin. `maxInstructions` bounds each individual
|
|
245
|
+
* re-evaluation, but not how many of them the search performs, so this is
|
|
246
|
+
* the tally that bounds the search itself, the same reason `maxFunctionCalls`
|
|
247
|
+
* exists alongside `maxInstructions`. Bisection halves the interval every
|
|
248
|
+
* step, so a hundred steps resolves an input to roughly one part in 2^100:
|
|
249
|
+
* far past any precision a document needs, and a definite stop either way.
|
|
250
|
+
*/
|
|
251
|
+
readonly maxGoalSeekIterations: number;
|
|
200
252
|
}
|
|
201
253
|
/**
|
|
202
254
|
* Complete engine configuration.
|
|
@@ -303,4 +355,4 @@ interface ValidationResult {
|
|
|
303
355
|
warnings?: string[];
|
|
304
356
|
}
|
|
305
357
|
|
|
306
|
-
export { ConfigManager as C, DEFAULT_CONFIG as D, type EngineConfig as E, type PerformanceConfig as P, type VMConfig as V, type WorkerConfig as W, type DateConfig as a, type DiagnosticConfig as b, type
|
|
358
|
+
export { ConfigManager as C, DEFAULT_CONFIG as D, type EngineConfig as E, type HolidayCalendar as H, type PerformanceConfig as P, type VMConfig as V, type WorkerConfig as W, type DateConfig as a, type DiagnosticConfig as b, type HolidayPredicate as c, type ValidationConfig as d, type ValidationResult as e };
|
|
@@ -75,12 +75,20 @@ declare const CoreErrorCodes: {
|
|
|
75
75
|
readonly MAP_REDUCE_ASYNC_UNSUPPORTED: "MAP_REDUCE_ASYNC_UNSUPPORTED";
|
|
76
76
|
/** An algebra verb's expression argument (`BIND_UNKNOWN`'s body) calling an async plugin. Same v1 scope restriction as the two above, and likewise refused at parse time first (`SYMBOLIC_ARGUMENT_MUST_BE_SYNCHRONOUS`, packages/symbolic/). */
|
|
77
77
|
readonly SYMBOLIC_ASYNC_UNSUPPORTED: "SYMBOLIC_ASYNC_UNSUPPORTED";
|
|
78
|
+
/** `explainLine()` asked to derive a line that resolves data asynchronously (a live-data or async-plugin line). A derivation is a sequence of settled intermediate values, which a pending result has none of, so the line is refused rather than explained with a hole in it. */
|
|
79
|
+
readonly EXPLAIN_ASYNC_UNSUPPORTED: "EXPLAIN_ASYNC_UNSUPPORTED";
|
|
78
80
|
/** `pushCallFrame()`'s recursion guard, a nested `CALL_USER_FUNCTION` re-enters `executeBytecode()`, so `maxInstructions` alone can't catch e.g. `f(x) = f(x)`; this is the dedicated backstop. `recoverable: true` (the default for `.execution()`), ordinary user-written infinite recursion, not an engine bug; the guard exists precisely so it surfaces as a clear error instead of overflowing the native call stack uncatchably. */
|
|
79
81
|
readonly FUNCTION_RECURSION_LIMIT_EXCEEDED: "FUNCTION_RECURSION_LIMIT_EXCEEDED";
|
|
80
82
|
/** The companion to the code above, and the half it could never see: how MANY user-defined-function calls one evaluation makes, rather than how deeply they nest. A twenty-two-line doubling chain nests twenty-two deep (legal) and makes two million calls (a fatal heap abort). Counted in `vm/AllocationBudget.ts`, because the tally has to survive `executeBytecode()` re-entering itself. Recoverable. */
|
|
81
83
|
readonly FUNCTION_CALL_LIMIT_EXCEEDED: "FUNCTION_CALL_LIMIT_EXCEEDED";
|
|
82
84
|
/** A `<date> + N workdays` offset outside `date.maxOffsetYears`/`minOffsetYears`. Workdays are the one date offset that walks the calendar a day at a time, so the one whose cost is the offset; every other one moves a Date field once. Recoverable. */
|
|
83
85
|
readonly DATE_OFFSET_LIMIT_EXCEEDED: "DATE_OFFSET_LIMIT_EXCEEDED";
|
|
86
|
+
/** The anchor of `N working days after/before/from <expr>` was not a date (e.g. `5 working days after 3`). The grammar guarantees the count is a number, so this only fires on the anchor. Emitted as a recoverable Error value, not thrown, matching the datetime package's other type guards. See `vm/VM.ts`'s `DATE_WORKDAY_OFFSET` case. */
|
|
87
|
+
readonly WORKDAY_OFFSET_EXPECTED_DATE: "WORKDAY_OFFSET_EXPECTED_DATE";
|
|
88
|
+
/** An endpoint of `working days between <expr> and <expr>` was not a date. Recoverable Error value. See `vm/VM.ts`'s `DATE_WORKDAYS_BETWEEN` case. */
|
|
89
|
+
readonly WORKDAYS_BETWEEN_EXPECTED_DATES: "WORKDAYS_BETWEEN_EXPECTED_DATES";
|
|
90
|
+
/** The two endpoints of `working days between <expr> and <expr>` are further apart than `date.maxOffsetYears`/`minOffsetYears` allow the count's calendar walk to run. Recoverable Error value, the between-count's equivalent of `DATE_OFFSET_LIMIT_EXCEEDED`. See `vm/VM.ts`'s `DATE_WORKDAYS_BETWEEN` case. */
|
|
91
|
+
readonly WORKDAYS_BETWEEN_RANGE_TOO_LARGE: "WORKDAYS_BETWEEN_RANGE_TOO_LARGE";
|
|
84
92
|
/** A `<<`/`>>` with a bigint operand whose exact result would pass `MAX_EXACT_SHIFT_BITS`, whichever operand is the bigint. Both spellings refuse as of 1.0.0: a bigint on the left used to fall through to `x * 2^n` in doubles and report a 19,870-digit integer as Infinity. See `vm/VM.ts`'s `bigIntShift()`. Recoverable. */
|
|
85
93
|
readonly BIGINT_SHIFT_LIMIT_EXCEEDED: "BIGINT_SHIFT_LIMIT_EXCEEDED";
|
|
86
94
|
/** The same ceiling for `^`, the operator it was written for: `2n ^ 100000` asks for the same 100,001-bit integer `1n << 100000` does, so the two spellings answer the same way. Also new in 1.0.0, and for the same reason: this used to fall through to the double path and answer Infinity. A fractional or negative exponent (`4n ^ 0.5`, `2n ^ -1`) has no exact answer to bound and still uses the double path. See `vm/VM.ts`'s `MAX_EXACT_POW_BITS`. Recoverable. */
|
|
@@ -148,6 +156,12 @@ declare const CoreErrorCodes: {
|
|
|
148
156
|
readonly THEREFORE_ASYNC_UNSUPPORTED: "THEREFORE_ASYNC_UNSUPPORTED";
|
|
149
157
|
/** Colon-separated numbers that are not a time any clock can show ("24:00", "9:60", "100:5"). Raised by the labeled-line fallback, which used to answer them with whatever stood after the colon. */
|
|
150
158
|
readonly INVALID_TIME_LITERAL: "INVALID_TIME_LITERAL";
|
|
159
|
+
/** `fromJSON()` handed an object that is not a snapshot at all, or whose serialised-shape version does not match this engine's reader. The versioning gate that refuses an incompatible snapshot clearly rather than restoring it wrongly. See `engine/EngineSnapshot.ts`'s `assertRestorable()`. */
|
|
160
|
+
readonly SNAPSHOT_VERSION_MISMATCH: "SNAPSHOT_VERSION_MISMATCH";
|
|
161
|
+
/** A snapshot with the right envelope but internally inconsistent contents (an unrecognised number sentinel, an unknown value tag). Distinct from a version mismatch: the format is right, the payload is not. */
|
|
162
|
+
readonly SNAPSHOT_MALFORMED: "SNAPSHOT_MALFORMED";
|
|
163
|
+
/** A value the v1 snapshot format cannot yet represent (a symbolic/algebra value, a symbolic matrix cell). Deferred to a follow-up; refused by name rather than dropped silently. */
|
|
164
|
+
readonly SNAPSHOT_UNSUPPORTED_VALUE: "SNAPSHOT_UNSUPPORTED_VALUE";
|
|
151
165
|
readonly CONFIG_PATH_NOT_FOUND: "CONFIG_PATH_NOT_FOUND";
|
|
152
166
|
readonly INVALID_CONFIG_PATH: "INVALID_CONFIG_PATH";
|
|
153
167
|
readonly CONFIG_SECTION_NOT_FOUND: "CONFIG_SECTION_NOT_FOUND";
|
|
@@ -75,12 +75,20 @@ declare const CoreErrorCodes: {
|
|
|
75
75
|
readonly MAP_REDUCE_ASYNC_UNSUPPORTED: "MAP_REDUCE_ASYNC_UNSUPPORTED";
|
|
76
76
|
/** An algebra verb's expression argument (`BIND_UNKNOWN`'s body) calling an async plugin. Same v1 scope restriction as the two above, and likewise refused at parse time first (`SYMBOLIC_ARGUMENT_MUST_BE_SYNCHRONOUS`, packages/symbolic/). */
|
|
77
77
|
readonly SYMBOLIC_ASYNC_UNSUPPORTED: "SYMBOLIC_ASYNC_UNSUPPORTED";
|
|
78
|
+
/** `explainLine()` asked to derive a line that resolves data asynchronously (a live-data or async-plugin line). A derivation is a sequence of settled intermediate values, which a pending result has none of, so the line is refused rather than explained with a hole in it. */
|
|
79
|
+
readonly EXPLAIN_ASYNC_UNSUPPORTED: "EXPLAIN_ASYNC_UNSUPPORTED";
|
|
78
80
|
/** `pushCallFrame()`'s recursion guard, a nested `CALL_USER_FUNCTION` re-enters `executeBytecode()`, so `maxInstructions` alone can't catch e.g. `f(x) = f(x)`; this is the dedicated backstop. `recoverable: true` (the default for `.execution()`), ordinary user-written infinite recursion, not an engine bug; the guard exists precisely so it surfaces as a clear error instead of overflowing the native call stack uncatchably. */
|
|
79
81
|
readonly FUNCTION_RECURSION_LIMIT_EXCEEDED: "FUNCTION_RECURSION_LIMIT_EXCEEDED";
|
|
80
82
|
/** The companion to the code above, and the half it could never see: how MANY user-defined-function calls one evaluation makes, rather than how deeply they nest. A twenty-two-line doubling chain nests twenty-two deep (legal) and makes two million calls (a fatal heap abort). Counted in `vm/AllocationBudget.ts`, because the tally has to survive `executeBytecode()` re-entering itself. Recoverable. */
|
|
81
83
|
readonly FUNCTION_CALL_LIMIT_EXCEEDED: "FUNCTION_CALL_LIMIT_EXCEEDED";
|
|
82
84
|
/** A `<date> + N workdays` offset outside `date.maxOffsetYears`/`minOffsetYears`. Workdays are the one date offset that walks the calendar a day at a time, so the one whose cost is the offset; every other one moves a Date field once. Recoverable. */
|
|
83
85
|
readonly DATE_OFFSET_LIMIT_EXCEEDED: "DATE_OFFSET_LIMIT_EXCEEDED";
|
|
86
|
+
/** The anchor of `N working days after/before/from <expr>` was not a date (e.g. `5 working days after 3`). The grammar guarantees the count is a number, so this only fires on the anchor. Emitted as a recoverable Error value, not thrown, matching the datetime package's other type guards. See `vm/VM.ts`'s `DATE_WORKDAY_OFFSET` case. */
|
|
87
|
+
readonly WORKDAY_OFFSET_EXPECTED_DATE: "WORKDAY_OFFSET_EXPECTED_DATE";
|
|
88
|
+
/** An endpoint of `working days between <expr> and <expr>` was not a date. Recoverable Error value. See `vm/VM.ts`'s `DATE_WORKDAYS_BETWEEN` case. */
|
|
89
|
+
readonly WORKDAYS_BETWEEN_EXPECTED_DATES: "WORKDAYS_BETWEEN_EXPECTED_DATES";
|
|
90
|
+
/** The two endpoints of `working days between <expr> and <expr>` are further apart than `date.maxOffsetYears`/`minOffsetYears` allow the count's calendar walk to run. Recoverable Error value, the between-count's equivalent of `DATE_OFFSET_LIMIT_EXCEEDED`. See `vm/VM.ts`'s `DATE_WORKDAYS_BETWEEN` case. */
|
|
91
|
+
readonly WORKDAYS_BETWEEN_RANGE_TOO_LARGE: "WORKDAYS_BETWEEN_RANGE_TOO_LARGE";
|
|
84
92
|
/** A `<<`/`>>` with a bigint operand whose exact result would pass `MAX_EXACT_SHIFT_BITS`, whichever operand is the bigint. Both spellings refuse as of 1.0.0: a bigint on the left used to fall through to `x * 2^n` in doubles and report a 19,870-digit integer as Infinity. See `vm/VM.ts`'s `bigIntShift()`. Recoverable. */
|
|
85
93
|
readonly BIGINT_SHIFT_LIMIT_EXCEEDED: "BIGINT_SHIFT_LIMIT_EXCEEDED";
|
|
86
94
|
/** The same ceiling for `^`, the operator it was written for: `2n ^ 100000` asks for the same 100,001-bit integer `1n << 100000` does, so the two spellings answer the same way. Also new in 1.0.0, and for the same reason: this used to fall through to the double path and answer Infinity. A fractional or negative exponent (`4n ^ 0.5`, `2n ^ -1`) has no exact answer to bound and still uses the double path. See `vm/VM.ts`'s `MAX_EXACT_POW_BITS`. Recoverable. */
|
|
@@ -148,6 +156,12 @@ declare const CoreErrorCodes: {
|
|
|
148
156
|
readonly THEREFORE_ASYNC_UNSUPPORTED: "THEREFORE_ASYNC_UNSUPPORTED";
|
|
149
157
|
/** Colon-separated numbers that are not a time any clock can show ("24:00", "9:60", "100:5"). Raised by the labeled-line fallback, which used to answer them with whatever stood after the colon. */
|
|
150
158
|
readonly INVALID_TIME_LITERAL: "INVALID_TIME_LITERAL";
|
|
159
|
+
/** `fromJSON()` handed an object that is not a snapshot at all, or whose serialised-shape version does not match this engine's reader. The versioning gate that refuses an incompatible snapshot clearly rather than restoring it wrongly. See `engine/EngineSnapshot.ts`'s `assertRestorable()`. */
|
|
160
|
+
readonly SNAPSHOT_VERSION_MISMATCH: "SNAPSHOT_VERSION_MISMATCH";
|
|
161
|
+
/** A snapshot with the right envelope but internally inconsistent contents (an unrecognised number sentinel, an unknown value tag). Distinct from a version mismatch: the format is right, the payload is not. */
|
|
162
|
+
readonly SNAPSHOT_MALFORMED: "SNAPSHOT_MALFORMED";
|
|
163
|
+
/** A value the v1 snapshot format cannot yet represent (a symbolic/algebra value, a symbolic matrix cell). Deferred to a follow-up; refused by name rather than dropped silently. */
|
|
164
|
+
readonly SNAPSHOT_UNSUPPORTED_VALUE: "SNAPSHOT_UNSUPPORTED_VALUE";
|
|
151
165
|
readonly CONFIG_PATH_NOT_FOUND: "CONFIG_PATH_NOT_FOUND";
|
|
152
166
|
readonly INVALID_CONFIG_PATH: "INVALID_CONFIG_PATH";
|
|
153
167
|
readonly CONFIG_SECTION_NOT_FOUND: "CONFIG_SECTION_NOT_FOUND";
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal formatting settings interface for the engine
|
|
3
|
+
* This allows the engine to format values without depending on app-specific settings
|
|
4
|
+
*/
|
|
5
|
+
interface FormattingSettings {
|
|
6
|
+
floatResult: {
|
|
7
|
+
decimalPlaces: number;
|
|
8
|
+
enableSeperator: boolean;
|
|
9
|
+
};
|
|
10
|
+
numberResult: {
|
|
11
|
+
decimalSeparatorLocale: string;
|
|
12
|
+
};
|
|
13
|
+
hexResult: {
|
|
14
|
+
enablePadding: boolean;
|
|
15
|
+
paddingZeros: number;
|
|
16
|
+
};
|
|
17
|
+
unitOfMeasurementResult: {
|
|
18
|
+
decimalPlaces: number;
|
|
19
|
+
};
|
|
20
|
+
percentageResult: {
|
|
21
|
+
decimalPlaces: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Formatting used when a host supplies none. */
|
|
25
|
+
declare const DEFAULT_FORMATTING_SETTINGS: FormattingSettings;
|
|
26
|
+
|
|
27
|
+
export { DEFAULT_FORMATTING_SETTINGS as D, type FormattingSettings as F };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal formatting settings interface for the engine
|
|
3
|
+
* This allows the engine to format values without depending on app-specific settings
|
|
4
|
+
*/
|
|
5
|
+
interface FormattingSettings {
|
|
6
|
+
floatResult: {
|
|
7
|
+
decimalPlaces: number;
|
|
8
|
+
enableSeperator: boolean;
|
|
9
|
+
};
|
|
10
|
+
numberResult: {
|
|
11
|
+
decimalSeparatorLocale: string;
|
|
12
|
+
};
|
|
13
|
+
hexResult: {
|
|
14
|
+
enablePadding: boolean;
|
|
15
|
+
paddingZeros: number;
|
|
16
|
+
};
|
|
17
|
+
unitOfMeasurementResult: {
|
|
18
|
+
decimalPlaces: number;
|
|
19
|
+
};
|
|
20
|
+
percentageResult: {
|
|
21
|
+
decimalPlaces: number;
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/** Formatting used when a host supplies none. */
|
|
25
|
+
declare const DEFAULT_FORMATTING_SETTINGS: FormattingSettings;
|
|
26
|
+
|
|
27
|
+
export { DEFAULT_FORMATTING_SETTINGS as D, type FormattingSettings as F };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as Token } from './Token-
|
|
1
|
+
import { T as Token } from './Token-B1hdkedD.cjs';
|
|
2
2
|
|
|
3
3
|
/** Trie node for multi-word phrase matching. */
|
|
4
4
|
interface PhraseNode {
|
|
@@ -48,6 +48,22 @@ interface LineClassification {
|
|
|
48
48
|
skip: boolean;
|
|
49
49
|
/** Whether the line contains inline solve markers (`s`...``) */
|
|
50
50
|
hasInlineSolve: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Offset of the first evaluable character, when structural markup precedes
|
|
53
|
+
* it. Absolute, in the same coordinates the classification was asked for,
|
|
54
|
+
* and absent when the whole line is evaluable.
|
|
55
|
+
*
|
|
56
|
+
* A list marker is markup, not arithmetic. `- 100 + 20` is a bullet holding
|
|
57
|
+
* `100 + 20`, but `-` is also a prefix operator, so without this the line
|
|
58
|
+
* evaluated as negative one hundred and answered -80: a wrong answer that
|
|
59
|
+
* looks like a right one. `*` and `+` in the same position could not even do
|
|
60
|
+
* that, one erroring and the other correct by luck, so the three markers
|
|
61
|
+
* disagreed with each other about the same document.
|
|
62
|
+
*
|
|
63
|
+
* Consumers must slice both the text and the token stream from here, or the
|
|
64
|
+
* two describe different lines.
|
|
65
|
+
*/
|
|
66
|
+
contentOffset?: number;
|
|
51
67
|
}
|
|
52
68
|
/** Inline solve position with precise coordinates */
|
|
53
69
|
interface InlineSolveSpan {
|
|
@@ -207,6 +223,7 @@ declare class ExpressionLexer {
|
|
|
207
223
|
private len;
|
|
208
224
|
private line;
|
|
209
225
|
private lineStartPos;
|
|
226
|
+
private groupingStack;
|
|
210
227
|
private keywordMap;
|
|
211
228
|
private mergedKeywords;
|
|
212
229
|
private mergedUnits;
|
|
@@ -356,6 +373,20 @@ declare class ExpressionLexer {
|
|
|
356
373
|
* if the next significant character is '('.
|
|
357
374
|
*/
|
|
358
375
|
private isFollowedByLParen;
|
|
376
|
+
/**
|
|
377
|
+
* Whether the `(` at `parenPos` opens a function call rather than a bare
|
|
378
|
+
* grouping, deciding whether a comma inside it is a separator or a thousands
|
|
379
|
+
* group (see {@link groupingStack}).
|
|
380
|
+
*
|
|
381
|
+
* It is a call when the nearest non-whitespace character before it belongs to
|
|
382
|
+
* the value the call applies to: a closing `)`/`]` (a call on a result), or an
|
|
383
|
+
* IDENTIFIER (`rgb(`, `vec2(`). A run of digits alone is a number, not an
|
|
384
|
+
* identifier, so `2(1,000)` is implicit multiplication over the grouping
|
|
385
|
+
* `(1,000)`, not a call, while `vec2(` and `atan2(` (identifiers that end in a
|
|
386
|
+
* digit) are calls. A `(` after an operator, a comma, or the line start is a
|
|
387
|
+
* grouping.
|
|
388
|
+
*/
|
|
389
|
+
private precededByCallTarget;
|
|
359
390
|
/**
|
|
360
391
|
* Reads an operator/punctuation token.
|
|
361
392
|
* Handles two-char operators (==, !=, >=, <=, **) and the special
|
|
@@ -399,6 +430,32 @@ declare class ExpressionLexer {
|
|
|
399
430
|
* Reads directly from this.input using start/end boundaries.
|
|
400
431
|
* DOES NOT modify this.pos, purely a read-only classifier.
|
|
401
432
|
*/
|
|
433
|
+
/**
|
|
434
|
+
* Advance past the whitespace after a list marker, and past a task-item
|
|
435
|
+
* checkbox if one follows.
|
|
436
|
+
*
|
|
437
|
+
* The checkbox is included because it is markup by the same argument the
|
|
438
|
+
* marker is, and because leaving it stopped the line dead: `- [ ] 100 + 20`
|
|
439
|
+
* lexed `[ ]` as a matrix literal and reported that a matrix cannot be
|
|
440
|
+
* empty, which tells a user writing a to-do list nothing they can act on.
|
|
441
|
+
*
|
|
442
|
+
* @param from - Offset just past the marker character.
|
|
443
|
+
* @param end - Line end, never read past.
|
|
444
|
+
* @returns Offset of the first evaluable character.
|
|
445
|
+
*/
|
|
446
|
+
private skipMarkerGap;
|
|
447
|
+
/**
|
|
448
|
+
* The end offset (exclusive) of a `#hex` colour literal starting at `hashPos`,
|
|
449
|
+
* or -1 if the run there is not one. A colour is `#` followed by EXACTLY 3, 4,
|
|
450
|
+
* 6 or 8 hex digits (the CSS forms `#rgb`/`#rgba`/`#rrggbb`/`#rrggbbaa`) and
|
|
451
|
+
* then a boundary, not a longer word or number. This is the one predicate that
|
|
452
|
+
* carves colours out of the two things `#` otherwise means, a markdown heading
|
|
453
|
+
* at line start and a comment mid-line, and it is pure character logic so line
|
|
454
|
+
* classification stays vocabulary-independent. Examples: `#f00`, `#ff0000`,
|
|
455
|
+
* `#deadbeef` match; `# Heading` (space), `#tag`/`#todo` (non-hex letter),
|
|
456
|
+
* `#12345` (length 5), `#ff0000zz` (trailing word) do not.
|
|
457
|
+
*/
|
|
458
|
+
private matchHexColourEnd;
|
|
402
459
|
private classifyFromPositions;
|
|
403
460
|
/**
|
|
404
461
|
* Classify a single line of markdown text.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { T as Token } from './Token-
|
|
1
|
+
import { T as Token } from './Token-B1hdkedD.js';
|
|
2
2
|
|
|
3
3
|
/** Trie node for multi-word phrase matching. */
|
|
4
4
|
interface PhraseNode {
|
|
@@ -48,6 +48,22 @@ interface LineClassification {
|
|
|
48
48
|
skip: boolean;
|
|
49
49
|
/** Whether the line contains inline solve markers (`s`...``) */
|
|
50
50
|
hasInlineSolve: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Offset of the first evaluable character, when structural markup precedes
|
|
53
|
+
* it. Absolute, in the same coordinates the classification was asked for,
|
|
54
|
+
* and absent when the whole line is evaluable.
|
|
55
|
+
*
|
|
56
|
+
* A list marker is markup, not arithmetic. `- 100 + 20` is a bullet holding
|
|
57
|
+
* `100 + 20`, but `-` is also a prefix operator, so without this the line
|
|
58
|
+
* evaluated as negative one hundred and answered -80: a wrong answer that
|
|
59
|
+
* looks like a right one. `*` and `+` in the same position could not even do
|
|
60
|
+
* that, one erroring and the other correct by luck, so the three markers
|
|
61
|
+
* disagreed with each other about the same document.
|
|
62
|
+
*
|
|
63
|
+
* Consumers must slice both the text and the token stream from here, or the
|
|
64
|
+
* two describe different lines.
|
|
65
|
+
*/
|
|
66
|
+
contentOffset?: number;
|
|
51
67
|
}
|
|
52
68
|
/** Inline solve position with precise coordinates */
|
|
53
69
|
interface InlineSolveSpan {
|
|
@@ -207,6 +223,7 @@ declare class ExpressionLexer {
|
|
|
207
223
|
private len;
|
|
208
224
|
private line;
|
|
209
225
|
private lineStartPos;
|
|
226
|
+
private groupingStack;
|
|
210
227
|
private keywordMap;
|
|
211
228
|
private mergedKeywords;
|
|
212
229
|
private mergedUnits;
|
|
@@ -356,6 +373,20 @@ declare class ExpressionLexer {
|
|
|
356
373
|
* if the next significant character is '('.
|
|
357
374
|
*/
|
|
358
375
|
private isFollowedByLParen;
|
|
376
|
+
/**
|
|
377
|
+
* Whether the `(` at `parenPos` opens a function call rather than a bare
|
|
378
|
+
* grouping, deciding whether a comma inside it is a separator or a thousands
|
|
379
|
+
* group (see {@link groupingStack}).
|
|
380
|
+
*
|
|
381
|
+
* It is a call when the nearest non-whitespace character before it belongs to
|
|
382
|
+
* the value the call applies to: a closing `)`/`]` (a call on a result), or an
|
|
383
|
+
* IDENTIFIER (`rgb(`, `vec2(`). A run of digits alone is a number, not an
|
|
384
|
+
* identifier, so `2(1,000)` is implicit multiplication over the grouping
|
|
385
|
+
* `(1,000)`, not a call, while `vec2(` and `atan2(` (identifiers that end in a
|
|
386
|
+
* digit) are calls. A `(` after an operator, a comma, or the line start is a
|
|
387
|
+
* grouping.
|
|
388
|
+
*/
|
|
389
|
+
private precededByCallTarget;
|
|
359
390
|
/**
|
|
360
391
|
* Reads an operator/punctuation token.
|
|
361
392
|
* Handles two-char operators (==, !=, >=, <=, **) and the special
|
|
@@ -399,6 +430,32 @@ declare class ExpressionLexer {
|
|
|
399
430
|
* Reads directly from this.input using start/end boundaries.
|
|
400
431
|
* DOES NOT modify this.pos, purely a read-only classifier.
|
|
401
432
|
*/
|
|
433
|
+
/**
|
|
434
|
+
* Advance past the whitespace after a list marker, and past a task-item
|
|
435
|
+
* checkbox if one follows.
|
|
436
|
+
*
|
|
437
|
+
* The checkbox is included because it is markup by the same argument the
|
|
438
|
+
* marker is, and because leaving it stopped the line dead: `- [ ] 100 + 20`
|
|
439
|
+
* lexed `[ ]` as a matrix literal and reported that a matrix cannot be
|
|
440
|
+
* empty, which tells a user writing a to-do list nothing they can act on.
|
|
441
|
+
*
|
|
442
|
+
* @param from - Offset just past the marker character.
|
|
443
|
+
* @param end - Line end, never read past.
|
|
444
|
+
* @returns Offset of the first evaluable character.
|
|
445
|
+
*/
|
|
446
|
+
private skipMarkerGap;
|
|
447
|
+
/**
|
|
448
|
+
* The end offset (exclusive) of a `#hex` colour literal starting at `hashPos`,
|
|
449
|
+
* or -1 if the run there is not one. A colour is `#` followed by EXACTLY 3, 4,
|
|
450
|
+
* 6 or 8 hex digits (the CSS forms `#rgb`/`#rgba`/`#rrggbb`/`#rrggbbaa`) and
|
|
451
|
+
* then a boundary, not a longer word or number. This is the one predicate that
|
|
452
|
+
* carves colours out of the two things `#` otherwise means, a markdown heading
|
|
453
|
+
* at line start and a comment mid-line, and it is pure character logic so line
|
|
454
|
+
* classification stays vocabulary-independent. Examples: `#f00`, `#ff0000`,
|
|
455
|
+
* `#deadbeef` match; `# Heading` (space), `#tag`/`#todo` (non-hex letter),
|
|
456
|
+
* `#12345` (length 5), `#ff0000zz` (trailing word) do not.
|
|
457
|
+
*/
|
|
458
|
+
private matchHexColourEnd;
|
|
402
459
|
private classifyFromPositions;
|
|
403
460
|
/**
|
|
404
461
|
* Classify a single line of markdown text.
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { I as IEnginePackage } from './PackageRegistry-BHWJP83F.cjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Package load-time compatibility checking, the "detect overlapping
|
|
5
|
+
* logic between packages" SDK surface.
|
|
6
|
+
*
|
|
7
|
+
* This engine's package system (`IEnginePackage`) has always had SOME
|
|
8
|
+
* collision visibility, but it's inconsistent and scattered: `ParseletRegistry`
|
|
9
|
+
* warns on a token-type overwrite, `asConverterRegistry` warns on a converter
|
|
10
|
+
* name overwrite, and `PhraseTrie` warns on... nothing at all, a second
|
|
11
|
+
* package fusing the exact same multi-word phrase to a different token type
|
|
12
|
+
* silently wins with zero signal, the same class of gap
|
|
13
|
+
* `ParseletRegistry.registerPrefix()`'s collision-visibility fix closed for
|
|
14
|
+
* parselets specifically (see `ARCHITECTURE.md`'s punch list). And none of
|
|
15
|
+
* these existing checks can be run BEFORE registration, they only fire at
|
|
16
|
+
* the moment a collision actually happens, deep inside a live engine.
|
|
17
|
+
*
|
|
18
|
+
* `checkPackageCompatibility()` is a single, pure, side-effect-free function
|
|
19
|
+
* that statically compares one candidate package's declared descriptor
|
|
20
|
+
* against a list of already-registered packages' descriptors, across every
|
|
21
|
+
* collision-capable field `IEnginePackage` has, callable standalone (a host
|
|
22
|
+
* building a plugin marketplace could run it before ever constructing an
|
|
23
|
+
* engine) or wired into registration itself (see
|
|
24
|
+
* `ExpressionEngine.registerPackage()`, which calls this automatically and
|
|
25
|
+
* logs every conflict found, the "load-up resiliency" half of this
|
|
26
|
+
* mechanism).
|
|
27
|
+
*
|
|
28
|
+
* A real, concrete motivating bug (found the same session this module was
|
|
29
|
+
* built): the currency package's real `IEnginePackage` descriptor
|
|
30
|
+
* (`CurrencyPackage.ts`) and its parallel test-harness registration helper
|
|
31
|
+
* (`parselets/index.ts`'s `registerCurrencyParselets()`) drifted out of sync
|
|
32
|
+
*, new currency-symbol token types were wired into one but not the other
|
|
33
|
+
* caught only by a test happening to exercise the stale path. This module
|
|
34
|
+
* doesn't catch THAT specific class of bug (two hand-written registration
|
|
35
|
+
* functions for the same logical package diverging is a source-consistency
|
|
36
|
+
* problem, not a runtime collision), but it DOES catch the more common and
|
|
37
|
+
* more dangerous sibling: two DIFFERENT, independently-authored packages
|
|
38
|
+
* unknowingly claiming the same token type, phrase, converter name, plugin
|
|
39
|
+
* function index, or lexer keyword.
|
|
40
|
+
*/
|
|
41
|
+
/** How serious a detected conflict is. */
|
|
42
|
+
type CompatibilitySeverity = "error" | "warning" | "info";
|
|
43
|
+
/** The category of overlap detected between two packages. */
|
|
44
|
+
type CompatibilityConflictKind = "prefixParseletTokenType" | "infixParseletTokenType" | "phrase" | "converterName" | "pluginFunctionIndex" | "lexerKeyword" | "lexerOperator" | "asyncResolverNamespace" | "tokenCategory";
|
|
45
|
+
/** One way two packages collide, for example claiming the same keyword. */
|
|
46
|
+
interface CompatibilityConflict {
|
|
47
|
+
kind: CompatibilityConflictKind;
|
|
48
|
+
severity: CompatibilitySeverity;
|
|
49
|
+
/** Human-readable description, safe to log directly. */
|
|
50
|
+
detail: string;
|
|
51
|
+
/** The two package names involved, [existing, candidate]. */
|
|
52
|
+
packages: [string, string];
|
|
53
|
+
}
|
|
54
|
+
/** Every conflict found between a candidate package and those already registered. */
|
|
55
|
+
interface CompatibilityReport {
|
|
56
|
+
/** `false` iff at least one "error"-severity conflict was found. */
|
|
57
|
+
compatible: boolean;
|
|
58
|
+
conflicts: CompatibilityConflict[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Statically check `candidate` against every package in `existing` for
|
|
62
|
+
* overlapping/conflicting declarations, across every collision-capable
|
|
63
|
+
* field `IEnginePackage` has. Pure and side-effect-free, does not touch
|
|
64
|
+
* any shared registry, does not require a live `ExpressionEngine`.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const report = checkPackageCompatibility(myNewPackage, BUILTIN_PACKAGES);
|
|
69
|
+
* if (!report.compatible) {
|
|
70
|
+
* for (const c of report.conflicts) console.error(c.detail);
|
|
71
|
+
* }
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
declare function checkPackageCompatibility(candidate: IEnginePackage, existing: IEnginePackage[]): CompatibilityReport;
|
|
75
|
+
|
|
76
|
+
export { type CompatibilityReport as C, type CompatibilityConflict as a, type CompatibilityConflictKind as b, type CompatibilitySeverity as c, checkPackageCompatibility as d };
|