solve-engine 1.0.2 → 1.1.1
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-YXCTLWOH.js → chunk-4HQKTMWG.js} +1530 -57
- package/dist/chunk-4HQKTMWG.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-IP7ASJEW.js → chunk-BYJBUL7U.js} +5 -5
- package/dist/{chunk-IP7ASJEW.js.map → chunk-BYJBUL7U.js.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-T556MJDZ.cjs → chunk-CUR2WLI4.cjs} +11 -11
- package/dist/{chunk-T556MJDZ.cjs.map → chunk-CUR2WLI4.cjs.map} +1 -1
- package/dist/{chunk-AA3KTWTX.js → chunk-DLEBSLF4.js} +4 -4
- package/dist/{chunk-AA3KTWTX.js.map → chunk-DLEBSLF4.js.map} +1 -1
- package/dist/{chunk-524F3ATQ.cjs → chunk-E23GZEWL.cjs} +15 -9
- package/dist/chunk-E23GZEWL.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-GLA4JXBO.js} +11 -5
- package/dist/chunk-GLA4JXBO.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-FQGX2PA2.js → chunk-JG6ZJ2WU.js} +128 -4
- package/dist/chunk-JG6ZJ2WU.js.map +1 -0
- package/dist/chunk-L2TE7PMO.cjs +14 -0
- package/dist/chunk-L2TE7PMO.cjs.map +1 -0
- package/dist/chunk-LHZ6VOA7.js +1764 -0
- package/dist/chunk-LHZ6VOA7.js.map +1 -0
- package/dist/{chunk-SESSWASV.cjs → chunk-MN3LHRGV.cjs} +1868 -393
- package/dist/chunk-MN3LHRGV.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-FE23VSSA.cjs → chunk-N5NNW4VG.cjs} +6 -6
- package/dist/{chunk-FE23VSSA.cjs.map → chunk-N5NNW4VG.cjs.map} +1 -1
- 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-NG2JHZHE.js → chunk-NNZAEUDW.js} +1853 -2640
- package/dist/chunk-NNZAEUDW.js.map +1 -0
- package/dist/{chunk-5LI5EPGJ.cjs → chunk-QFTDTX6K.cjs} +40 -3
- package/dist/chunk-QFTDTX6K.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-HBVFFBRR.cjs → chunk-T6ZYQJ63.cjs} +1962 -2748
- package/dist/chunk-T6ZYQJ63.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-YRIKITGF.cjs +1768 -0
- package/dist/chunk-YRIKITGF.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-R7YVBHCV.cjs → chunk-ZMW6NU2K.cjs} +197 -73
- package/dist/chunk-ZMW6NU2K.cjs.map +1 -0
- package/dist/{chunk-A2N2GFCG.cjs → chunk-ZVTWQLK4.cjs} +10 -10
- package/dist/{chunk-A2N2GFCG.cjs.map → chunk-ZVTWQLK4.cjs.map} +1 -1
- 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
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { I as IEnginePackage, E as ExpressionEngine } from './PackageRegistry-BHWJP83F.cjs';
|
|
2
|
+
import { V as Value } from './Value-BUi1RA3S.cjs';
|
|
3
|
+
import { E as EngineError } from './EngineError-B61GS1jp.cjs';
|
|
4
|
+
import { C as CompatibilityReport } from './PackageCompatibility-B-7rK1TD.cjs';
|
|
5
|
+
import './Parselet-BHcgK9S7.cjs';
|
|
6
|
+
import './BytecodeBuilder-Bp9xeTmX.cjs';
|
|
7
|
+
import './Token-B1hdkedD.cjs';
|
|
8
|
+
import './pipeline-CtfJtPQc.cjs';
|
|
9
|
+
import './variables.cjs';
|
|
10
|
+
import './Lexer-BOs7euZe.cjs';
|
|
11
|
+
import './resolvers.cjs';
|
|
12
|
+
import '@tanstack/query-core';
|
|
13
|
+
import './TokenNormalizer-DRc1Js1V.cjs';
|
|
14
|
+
import './ScopeManager-8vf02dwj.cjs';
|
|
15
|
+
import './Configuration-C9W8tJv_.cjs';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A test kit for package authors, the supported way to test a package by the
|
|
19
|
+
* expressions it enables rather than by the opcodes it emits.
|
|
20
|
+
*
|
|
21
|
+
* Before this entry point a package author had two options, both bad: reach
|
|
22
|
+
* into engine internals, or assert on whatever bytecode a parselet happened to
|
|
23
|
+
* emit. The first is unstable across engine versions, the second pins the
|
|
24
|
+
* implementation instead of the behaviour, so a refactor that keeps every
|
|
25
|
+
* answer correct still breaks the tests. This module is a thin, dependency-free
|
|
26
|
+
* layer over the same public surface a host uses: it constructs an
|
|
27
|
+
* {@link ExpressionEngine} with the given packages and evaluates strings.
|
|
28
|
+
*
|
|
29
|
+
* It speaks in expressions. {@link expectExpression} evaluates a string and
|
|
30
|
+
* asserts on the result or the failure code; {@link expectPackage} asserts on
|
|
31
|
+
* the three mistakes a package actually makes (shadowing prose, colliding with
|
|
32
|
+
* another package's vocabulary, and declaring an `engineVersion` range that the
|
|
33
|
+
* running engine does not satisfy).
|
|
34
|
+
*
|
|
35
|
+
* Framework-agnostic on purpose. Nothing here imports jest, vitest or any
|
|
36
|
+
* runner: an assertion that fails throws an {@link ExpectationError}, and one
|
|
37
|
+
* that passes returns, so the kit drops into whatever runner the author already
|
|
38
|
+
* has (or into a plain script, or `node:assert`). Runtime dependency-free and
|
|
39
|
+
* side-effect free, so `solve-engine/testing` stays honest under the package's
|
|
40
|
+
* `"sideEffects": false` contract.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { createTestEngine, expectExpression } from "solve-engine/testing";
|
|
45
|
+
*
|
|
46
|
+
* const engine = createTestEngine([myPackage]);
|
|
47
|
+
* expectExpression(engine, "2 gp + 3 gp").toEqual(5, "gp");
|
|
48
|
+
* expectExpression(engine, "gp").toFailWith("UNDEFINED_VARIABLE");
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The failure a matcher throws when an expectation is not met.
|
|
54
|
+
*
|
|
55
|
+
* A dedicated `Error` subclass rather than a bare `throw new Error`, so a
|
|
56
|
+
* caller (or a reporter) can tell a kit assertion failure apart from an
|
|
57
|
+
* unrelated exception with `instanceof`, and so the structured `expected` and
|
|
58
|
+
* `actual` fields survive alongside the human-readable message. This is NOT an
|
|
59
|
+
* {@link EngineError}: that type classifies pipeline-stage failures inside the
|
|
60
|
+
* engine, whereas this classifies a test-assertion mismatch, a different
|
|
61
|
+
* concern that would be miscategorised under any of `EngineError`'s categories.
|
|
62
|
+
*/
|
|
63
|
+
declare class ExpectationError extends Error {
|
|
64
|
+
/** A short, machine-readable label for which expectation failed. */
|
|
65
|
+
readonly code: string;
|
|
66
|
+
/** What the matcher was told to expect, in plain words. */
|
|
67
|
+
readonly expected?: string;
|
|
68
|
+
/** What it found instead. */
|
|
69
|
+
readonly actual?: string;
|
|
70
|
+
constructor(init: {
|
|
71
|
+
code: string;
|
|
72
|
+
message: string;
|
|
73
|
+
expected?: string;
|
|
74
|
+
actual?: string;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Options for {@link createTestEngine}. */
|
|
78
|
+
interface TestEngineOptions {
|
|
79
|
+
/** Locale passed to the engine. Defaults to `"en"`. */
|
|
80
|
+
locale?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Whether to load the engine's built-in packages (arithmetic, units, dates,
|
|
83
|
+
* and the rest) before the packages under test. Defaults to `true`, because
|
|
84
|
+
* almost every package builds on arithmetic and most authors want a
|
|
85
|
+
* realistic engine. Set `false` to test a package in isolation.
|
|
86
|
+
*/
|
|
87
|
+
includeBuiltins?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Build an {@link ExpressionEngine} loaded with the packages under test.
|
|
91
|
+
*
|
|
92
|
+
* The built-in packages load first (unless {@link TestEngineOptions.includeBuiltins}
|
|
93
|
+
* is `false`), then each package in `packages` is registered in order, exactly
|
|
94
|
+
* as a host would. Registration is honest: a package whose declared
|
|
95
|
+
* `engineVersion` the running engine does not satisfy, or whose lexer keyword
|
|
96
|
+
* collides with a built-in, throws here rather than being swallowed. That is
|
|
97
|
+
* deliberately different from passing packages straight to the
|
|
98
|
+
* `ExpressionEngine` constructor, which contains a bad package by logging and
|
|
99
|
+
* continuing, useful in production, wrong for a test that needs to know the
|
|
100
|
+
* package it is testing actually loaded.
|
|
101
|
+
*
|
|
102
|
+
* Call {@link ExpressionEngine.clear} when a test is finished with the engine
|
|
103
|
+
* if the test creates many, see the engine's own lifecycle note.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* const engine = createTestEngine([myPackage]);
|
|
108
|
+
* const engineOnly = createTestEngine([myPackage], { includeBuiltins: false });
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare function createTestEngine(packages?: IEnginePackage[], options?: TestEngineOptions): ExpressionEngine;
|
|
112
|
+
/**
|
|
113
|
+
* The normalised outcome of evaluating one expression, computed once when
|
|
114
|
+
* {@link expectExpression} runs and read by every matcher on the result.
|
|
115
|
+
*
|
|
116
|
+
* The engine surfaces a failure two different ways, and a package author should
|
|
117
|
+
* not have to know which: a parse/eval error is THROWN as an
|
|
118
|
+
* {@link EngineError} (with a `.code`), while a plugin-raised error is RETURNED
|
|
119
|
+
* as a {@link Value} of {@link ValueType.Error} (its `value` is the code, its
|
|
120
|
+
* `unit` is the message). Both collapse to the `"error"` status here. A value
|
|
121
|
+
* still resolving asynchronously is its own `"pending"` status, since the kit
|
|
122
|
+
* evaluates synchronously and cannot report a final number for it.
|
|
123
|
+
*/
|
|
124
|
+
type Outcome = {
|
|
125
|
+
status: "value";
|
|
126
|
+
value: Value;
|
|
127
|
+
} | {
|
|
128
|
+
status: "pending";
|
|
129
|
+
value: Value;
|
|
130
|
+
} | {
|
|
131
|
+
status: "error";
|
|
132
|
+
code: string;
|
|
133
|
+
message: string;
|
|
134
|
+
source: EngineError | Value;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Assertions about the result of one evaluated expression, returned by
|
|
138
|
+
* {@link expectExpression}. Every matcher returns `this`, so assertions chain,
|
|
139
|
+
* and throws an {@link ExpectationError} when it fails.
|
|
140
|
+
*/
|
|
141
|
+
declare class ExpressionAssertion {
|
|
142
|
+
private readonly expression;
|
|
143
|
+
private readonly outcome;
|
|
144
|
+
constructor(expression: string, outcome: Outcome);
|
|
145
|
+
/** The raw resolved {@link Value}, for an assertion the matchers do not cover. Throws if the expression failed. */
|
|
146
|
+
get value(): Value;
|
|
147
|
+
/**
|
|
148
|
+
* Assert the expression evaluated to a value (not an error, not a pending
|
|
149
|
+
* async result). Says nothing about what the value is.
|
|
150
|
+
*/
|
|
151
|
+
toEvaluate(): this;
|
|
152
|
+
/**
|
|
153
|
+
* Assert the expression evaluated to `expected`, and, when `unit` is given,
|
|
154
|
+
* that the result carries exactly that unit. A number compares against the
|
|
155
|
+
* value's numeric magnitude within a small floating-point tolerance; a
|
|
156
|
+
* string compares against the value's own string; a boolean against its
|
|
157
|
+
* boolean reading. Omitting `unit` leaves the unit unchecked, so
|
|
158
|
+
* `toEqual(5)` passes for both `5` and `5 gp`.
|
|
159
|
+
*/
|
|
160
|
+
toEqual(expected: number | string | boolean, unit?: string): this;
|
|
161
|
+
/** Assert the expression failed (a thrown engine error or a plugin-raised error value). Says nothing about the code. */
|
|
162
|
+
toBeError(): this;
|
|
163
|
+
/**
|
|
164
|
+
* Assert the expression failed with exactly `code`, the error catalog code
|
|
165
|
+
* (e.g. `"UNDEFINED_VARIABLE"`, or a package's own code). Reports the code
|
|
166
|
+
* it actually got when they differ, so a near-miss is obvious.
|
|
167
|
+
*/
|
|
168
|
+
toFailWith(code: string): this;
|
|
169
|
+
/**
|
|
170
|
+
* Assert the expression returned a value still resolving asynchronously.
|
|
171
|
+
* The kit evaluates synchronously, so a package whose result comes from an
|
|
172
|
+
* async resolver reports pending on first evaluation, this is how a test
|
|
173
|
+
* confirms the async path was taken without resolving it.
|
|
174
|
+
*/
|
|
175
|
+
toBePending(): this;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Evaluate `expression` on `engine` and return an assertion object.
|
|
179
|
+
*
|
|
180
|
+
* The expression is evaluated once, immediately, and every matcher reads that
|
|
181
|
+
* one outcome, so calling several matchers on the same result does not
|
|
182
|
+
* re-evaluate.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* expectExpression(engine, "2 gp + 3 gp").toEqual(5, "gp");
|
|
187
|
+
* expectExpression(engine, "gp").toFailWith("UNDEFINED_VARIABLE");
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
declare function expectExpression(engine: ExpressionEngine, expression: string): ExpressionAssertion;
|
|
191
|
+
/**
|
|
192
|
+
* A modest set of everyday English words a package's keywords should not claim.
|
|
193
|
+
*
|
|
194
|
+
* A starting point for {@link PackageAssertion.notToShadow}, not an exhaustive
|
|
195
|
+
* dictionary: it leans on the function words and common nouns/verbs a package
|
|
196
|
+
* is most tempted to grab as a trigger (`price`, `of`, `per`, `sum`, `total`).
|
|
197
|
+
* Pass your own list to check against the specific prose your package sits in.
|
|
198
|
+
*/
|
|
199
|
+
declare const COMMON_PROSE_WORDS: readonly string[];
|
|
200
|
+
/** How strict {@link PackageAssertion.notToCollideWith} is about the conflicts it will accept. */
|
|
201
|
+
type CollisionStrictness = "error" | "warning" | "info";
|
|
202
|
+
/** One shadowed word found by {@link PackageAssertion.notToShadow}: the prose word and how the package claims it. */
|
|
203
|
+
interface ShadowedWord {
|
|
204
|
+
/** The prose word the package claims. */
|
|
205
|
+
word: string;
|
|
206
|
+
/** Which descriptor field claims it. */
|
|
207
|
+
via: "keyword" | "unit" | "operator" | "phrase";
|
|
208
|
+
/** The token type the word becomes, when the field maps to one. */
|
|
209
|
+
tokenType?: string;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Assertions about a package's declared descriptor, returned by
|
|
213
|
+
* {@link expectPackage}. These catch the three mistakes the issue calls out,
|
|
214
|
+
* before the package is ever registered. Every matcher returns `this` and
|
|
215
|
+
* throws an {@link ExpectationError} when it fails.
|
|
216
|
+
*/
|
|
217
|
+
declare class PackageAssertion {
|
|
218
|
+
private readonly pkg;
|
|
219
|
+
constructor(pkg: IEnginePackage);
|
|
220
|
+
/**
|
|
221
|
+
* Assert none of the package's claimed words shadow a prose word.
|
|
222
|
+
*
|
|
223
|
+
* A trigger word that is also an ordinary word turns a line of prose into
|
|
224
|
+
* arithmetic, the single most common package mistake and the subject of the
|
|
225
|
+
* trigger-words guide. This checks the words the package declares
|
|
226
|
+
* (lexer keywords, units, operators, and single-word phrases) against
|
|
227
|
+
* `words` (defaulting to {@link COMMON_PROSE_WORDS}), case-insensitively.
|
|
228
|
+
*
|
|
229
|
+
* @returns the shadowed words, empty when the package is clean, for a test
|
|
230
|
+
* that wants to inspect rather than assert.
|
|
231
|
+
*/
|
|
232
|
+
notToShadow(words?: readonly string[]): ShadowedWord[];
|
|
233
|
+
/**
|
|
234
|
+
* Assert the package does not collide with any of `others` in a way that
|
|
235
|
+
* would silently break one of them (two packages claiming the same lexer
|
|
236
|
+
* keyword, plugin-function index, async-resolver namespace, and so on).
|
|
237
|
+
*
|
|
238
|
+
* `strictness` sets which severities fail the assertion: `"error"` (the
|
|
239
|
+
* default) fails only on the collisions that always break something,
|
|
240
|
+
* `"warning"` also fails on the ones that silently pick a winner, `"info"`
|
|
241
|
+
* fails on cosmetic overlaps too.
|
|
242
|
+
*
|
|
243
|
+
* @returns the full compatibility report, so a test can inspect every
|
|
244
|
+
* conflict, including ones below the strictness threshold.
|
|
245
|
+
*/
|
|
246
|
+
notToCollideWith(others: IEnginePackage[], strictness?: CollisionStrictness): CompatibilityReport;
|
|
247
|
+
/**
|
|
248
|
+
* Assert the package's declared `engineVersion` range is satisfied by the
|
|
249
|
+
* running engine (or by `engineVersion` when given).
|
|
250
|
+
*
|
|
251
|
+
* A package that declares a range and never checks it resolves is the third
|
|
252
|
+
* mistake the issue names: it looks fine until the one engine version it
|
|
253
|
+
* cannot run against, where the range either fails to match or turns out to
|
|
254
|
+
* be a malformed string. A package with no declared range passes (no
|
|
255
|
+
* constraint is always compatible).
|
|
256
|
+
*/
|
|
257
|
+
toDeclareCompatibleEngineVersion(engineVersion?: string): this;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Begin an assertion about a package's declared descriptor.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```ts
|
|
264
|
+
* expectPackage(myPackage).notToShadow(["price", "in", "of"]);
|
|
265
|
+
* expectPackage(myPackage).notToCollideWith(BUILTIN_PACKAGES);
|
|
266
|
+
* expectPackage(myPackage).toDeclareCompatibleEngineVersion();
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
declare function expectPackage(pkg: IEnginePackage): PackageAssertion;
|
|
270
|
+
|
|
271
|
+
export { COMMON_PROSE_WORDS, type CollisionStrictness, ExpectationError, ExpressionAssertion, PackageAssertion, type ShadowedWord, type TestEngineOptions, createTestEngine, expectExpression, expectPackage };
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { I as IEnginePackage, E as ExpressionEngine } from './PackageRegistry-_8rDlvxI.js';
|
|
2
|
+
import { V as Value } from './Value-BUi1RA3S.js';
|
|
3
|
+
import { E as EngineError } from './EngineError-B61GS1jp.js';
|
|
4
|
+
import { C as CompatibilityReport } from './PackageCompatibility-Dh59eF-X.js';
|
|
5
|
+
import './Parselet-BBT8riYh.js';
|
|
6
|
+
import './BytecodeBuilder-Bp9xeTmX.js';
|
|
7
|
+
import './Token-B1hdkedD.js';
|
|
8
|
+
import './pipeline-DCd5M6Gk.js';
|
|
9
|
+
import './variables.js';
|
|
10
|
+
import './Lexer-CSI_lwbW.js';
|
|
11
|
+
import './resolvers.js';
|
|
12
|
+
import '@tanstack/query-core';
|
|
13
|
+
import './TokenNormalizer-C6VzZgHa.js';
|
|
14
|
+
import './ScopeManager-CxA24W5n.js';
|
|
15
|
+
import './Configuration-C9W8tJv_.js';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* A test kit for package authors, the supported way to test a package by the
|
|
19
|
+
* expressions it enables rather than by the opcodes it emits.
|
|
20
|
+
*
|
|
21
|
+
* Before this entry point a package author had two options, both bad: reach
|
|
22
|
+
* into engine internals, or assert on whatever bytecode a parselet happened to
|
|
23
|
+
* emit. The first is unstable across engine versions, the second pins the
|
|
24
|
+
* implementation instead of the behaviour, so a refactor that keeps every
|
|
25
|
+
* answer correct still breaks the tests. This module is a thin, dependency-free
|
|
26
|
+
* layer over the same public surface a host uses: it constructs an
|
|
27
|
+
* {@link ExpressionEngine} with the given packages and evaluates strings.
|
|
28
|
+
*
|
|
29
|
+
* It speaks in expressions. {@link expectExpression} evaluates a string and
|
|
30
|
+
* asserts on the result or the failure code; {@link expectPackage} asserts on
|
|
31
|
+
* the three mistakes a package actually makes (shadowing prose, colliding with
|
|
32
|
+
* another package's vocabulary, and declaring an `engineVersion` range that the
|
|
33
|
+
* running engine does not satisfy).
|
|
34
|
+
*
|
|
35
|
+
* Framework-agnostic on purpose. Nothing here imports jest, vitest or any
|
|
36
|
+
* runner: an assertion that fails throws an {@link ExpectationError}, and one
|
|
37
|
+
* that passes returns, so the kit drops into whatever runner the author already
|
|
38
|
+
* has (or into a plain script, or `node:assert`). Runtime dependency-free and
|
|
39
|
+
* side-effect free, so `solve-engine/testing` stays honest under the package's
|
|
40
|
+
* `"sideEffects": false` contract.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```ts
|
|
44
|
+
* import { createTestEngine, expectExpression } from "solve-engine/testing";
|
|
45
|
+
*
|
|
46
|
+
* const engine = createTestEngine([myPackage]);
|
|
47
|
+
* expectExpression(engine, "2 gp + 3 gp").toEqual(5, "gp");
|
|
48
|
+
* expectExpression(engine, "gp").toFailWith("UNDEFINED_VARIABLE");
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* The failure a matcher throws when an expectation is not met.
|
|
54
|
+
*
|
|
55
|
+
* A dedicated `Error` subclass rather than a bare `throw new Error`, so a
|
|
56
|
+
* caller (or a reporter) can tell a kit assertion failure apart from an
|
|
57
|
+
* unrelated exception with `instanceof`, and so the structured `expected` and
|
|
58
|
+
* `actual` fields survive alongside the human-readable message. This is NOT an
|
|
59
|
+
* {@link EngineError}: that type classifies pipeline-stage failures inside the
|
|
60
|
+
* engine, whereas this classifies a test-assertion mismatch, a different
|
|
61
|
+
* concern that would be miscategorised under any of `EngineError`'s categories.
|
|
62
|
+
*/
|
|
63
|
+
declare class ExpectationError extends Error {
|
|
64
|
+
/** A short, machine-readable label for which expectation failed. */
|
|
65
|
+
readonly code: string;
|
|
66
|
+
/** What the matcher was told to expect, in plain words. */
|
|
67
|
+
readonly expected?: string;
|
|
68
|
+
/** What it found instead. */
|
|
69
|
+
readonly actual?: string;
|
|
70
|
+
constructor(init: {
|
|
71
|
+
code: string;
|
|
72
|
+
message: string;
|
|
73
|
+
expected?: string;
|
|
74
|
+
actual?: string;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Options for {@link createTestEngine}. */
|
|
78
|
+
interface TestEngineOptions {
|
|
79
|
+
/** Locale passed to the engine. Defaults to `"en"`. */
|
|
80
|
+
locale?: string;
|
|
81
|
+
/**
|
|
82
|
+
* Whether to load the engine's built-in packages (arithmetic, units, dates,
|
|
83
|
+
* and the rest) before the packages under test. Defaults to `true`, because
|
|
84
|
+
* almost every package builds on arithmetic and most authors want a
|
|
85
|
+
* realistic engine. Set `false` to test a package in isolation.
|
|
86
|
+
*/
|
|
87
|
+
includeBuiltins?: boolean;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Build an {@link ExpressionEngine} loaded with the packages under test.
|
|
91
|
+
*
|
|
92
|
+
* The built-in packages load first (unless {@link TestEngineOptions.includeBuiltins}
|
|
93
|
+
* is `false`), then each package in `packages` is registered in order, exactly
|
|
94
|
+
* as a host would. Registration is honest: a package whose declared
|
|
95
|
+
* `engineVersion` the running engine does not satisfy, or whose lexer keyword
|
|
96
|
+
* collides with a built-in, throws here rather than being swallowed. That is
|
|
97
|
+
* deliberately different from passing packages straight to the
|
|
98
|
+
* `ExpressionEngine` constructor, which contains a bad package by logging and
|
|
99
|
+
* continuing, useful in production, wrong for a test that needs to know the
|
|
100
|
+
* package it is testing actually loaded.
|
|
101
|
+
*
|
|
102
|
+
* Call {@link ExpressionEngine.clear} when a test is finished with the engine
|
|
103
|
+
* if the test creates many, see the engine's own lifecycle note.
|
|
104
|
+
*
|
|
105
|
+
* @example
|
|
106
|
+
* ```ts
|
|
107
|
+
* const engine = createTestEngine([myPackage]);
|
|
108
|
+
* const engineOnly = createTestEngine([myPackage], { includeBuiltins: false });
|
|
109
|
+
* ```
|
|
110
|
+
*/
|
|
111
|
+
declare function createTestEngine(packages?: IEnginePackage[], options?: TestEngineOptions): ExpressionEngine;
|
|
112
|
+
/**
|
|
113
|
+
* The normalised outcome of evaluating one expression, computed once when
|
|
114
|
+
* {@link expectExpression} runs and read by every matcher on the result.
|
|
115
|
+
*
|
|
116
|
+
* The engine surfaces a failure two different ways, and a package author should
|
|
117
|
+
* not have to know which: a parse/eval error is THROWN as an
|
|
118
|
+
* {@link EngineError} (with a `.code`), while a plugin-raised error is RETURNED
|
|
119
|
+
* as a {@link Value} of {@link ValueType.Error} (its `value` is the code, its
|
|
120
|
+
* `unit` is the message). Both collapse to the `"error"` status here. A value
|
|
121
|
+
* still resolving asynchronously is its own `"pending"` status, since the kit
|
|
122
|
+
* evaluates synchronously and cannot report a final number for it.
|
|
123
|
+
*/
|
|
124
|
+
type Outcome = {
|
|
125
|
+
status: "value";
|
|
126
|
+
value: Value;
|
|
127
|
+
} | {
|
|
128
|
+
status: "pending";
|
|
129
|
+
value: Value;
|
|
130
|
+
} | {
|
|
131
|
+
status: "error";
|
|
132
|
+
code: string;
|
|
133
|
+
message: string;
|
|
134
|
+
source: EngineError | Value;
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Assertions about the result of one evaluated expression, returned by
|
|
138
|
+
* {@link expectExpression}. Every matcher returns `this`, so assertions chain,
|
|
139
|
+
* and throws an {@link ExpectationError} when it fails.
|
|
140
|
+
*/
|
|
141
|
+
declare class ExpressionAssertion {
|
|
142
|
+
private readonly expression;
|
|
143
|
+
private readonly outcome;
|
|
144
|
+
constructor(expression: string, outcome: Outcome);
|
|
145
|
+
/** The raw resolved {@link Value}, for an assertion the matchers do not cover. Throws if the expression failed. */
|
|
146
|
+
get value(): Value;
|
|
147
|
+
/**
|
|
148
|
+
* Assert the expression evaluated to a value (not an error, not a pending
|
|
149
|
+
* async result). Says nothing about what the value is.
|
|
150
|
+
*/
|
|
151
|
+
toEvaluate(): this;
|
|
152
|
+
/**
|
|
153
|
+
* Assert the expression evaluated to `expected`, and, when `unit` is given,
|
|
154
|
+
* that the result carries exactly that unit. A number compares against the
|
|
155
|
+
* value's numeric magnitude within a small floating-point tolerance; a
|
|
156
|
+
* string compares against the value's own string; a boolean against its
|
|
157
|
+
* boolean reading. Omitting `unit` leaves the unit unchecked, so
|
|
158
|
+
* `toEqual(5)` passes for both `5` and `5 gp`.
|
|
159
|
+
*/
|
|
160
|
+
toEqual(expected: number | string | boolean, unit?: string): this;
|
|
161
|
+
/** Assert the expression failed (a thrown engine error or a plugin-raised error value). Says nothing about the code. */
|
|
162
|
+
toBeError(): this;
|
|
163
|
+
/**
|
|
164
|
+
* Assert the expression failed with exactly `code`, the error catalog code
|
|
165
|
+
* (e.g. `"UNDEFINED_VARIABLE"`, or a package's own code). Reports the code
|
|
166
|
+
* it actually got when they differ, so a near-miss is obvious.
|
|
167
|
+
*/
|
|
168
|
+
toFailWith(code: string): this;
|
|
169
|
+
/**
|
|
170
|
+
* Assert the expression returned a value still resolving asynchronously.
|
|
171
|
+
* The kit evaluates synchronously, so a package whose result comes from an
|
|
172
|
+
* async resolver reports pending on first evaluation, this is how a test
|
|
173
|
+
* confirms the async path was taken without resolving it.
|
|
174
|
+
*/
|
|
175
|
+
toBePending(): this;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Evaluate `expression` on `engine` and return an assertion object.
|
|
179
|
+
*
|
|
180
|
+
* The expression is evaluated once, immediately, and every matcher reads that
|
|
181
|
+
* one outcome, so calling several matchers on the same result does not
|
|
182
|
+
* re-evaluate.
|
|
183
|
+
*
|
|
184
|
+
* @example
|
|
185
|
+
* ```ts
|
|
186
|
+
* expectExpression(engine, "2 gp + 3 gp").toEqual(5, "gp");
|
|
187
|
+
* expectExpression(engine, "gp").toFailWith("UNDEFINED_VARIABLE");
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
declare function expectExpression(engine: ExpressionEngine, expression: string): ExpressionAssertion;
|
|
191
|
+
/**
|
|
192
|
+
* A modest set of everyday English words a package's keywords should not claim.
|
|
193
|
+
*
|
|
194
|
+
* A starting point for {@link PackageAssertion.notToShadow}, not an exhaustive
|
|
195
|
+
* dictionary: it leans on the function words and common nouns/verbs a package
|
|
196
|
+
* is most tempted to grab as a trigger (`price`, `of`, `per`, `sum`, `total`).
|
|
197
|
+
* Pass your own list to check against the specific prose your package sits in.
|
|
198
|
+
*/
|
|
199
|
+
declare const COMMON_PROSE_WORDS: readonly string[];
|
|
200
|
+
/** How strict {@link PackageAssertion.notToCollideWith} is about the conflicts it will accept. */
|
|
201
|
+
type CollisionStrictness = "error" | "warning" | "info";
|
|
202
|
+
/** One shadowed word found by {@link PackageAssertion.notToShadow}: the prose word and how the package claims it. */
|
|
203
|
+
interface ShadowedWord {
|
|
204
|
+
/** The prose word the package claims. */
|
|
205
|
+
word: string;
|
|
206
|
+
/** Which descriptor field claims it. */
|
|
207
|
+
via: "keyword" | "unit" | "operator" | "phrase";
|
|
208
|
+
/** The token type the word becomes, when the field maps to one. */
|
|
209
|
+
tokenType?: string;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Assertions about a package's declared descriptor, returned by
|
|
213
|
+
* {@link expectPackage}. These catch the three mistakes the issue calls out,
|
|
214
|
+
* before the package is ever registered. Every matcher returns `this` and
|
|
215
|
+
* throws an {@link ExpectationError} when it fails.
|
|
216
|
+
*/
|
|
217
|
+
declare class PackageAssertion {
|
|
218
|
+
private readonly pkg;
|
|
219
|
+
constructor(pkg: IEnginePackage);
|
|
220
|
+
/**
|
|
221
|
+
* Assert none of the package's claimed words shadow a prose word.
|
|
222
|
+
*
|
|
223
|
+
* A trigger word that is also an ordinary word turns a line of prose into
|
|
224
|
+
* arithmetic, the single most common package mistake and the subject of the
|
|
225
|
+
* trigger-words guide. This checks the words the package declares
|
|
226
|
+
* (lexer keywords, units, operators, and single-word phrases) against
|
|
227
|
+
* `words` (defaulting to {@link COMMON_PROSE_WORDS}), case-insensitively.
|
|
228
|
+
*
|
|
229
|
+
* @returns the shadowed words, empty when the package is clean, for a test
|
|
230
|
+
* that wants to inspect rather than assert.
|
|
231
|
+
*/
|
|
232
|
+
notToShadow(words?: readonly string[]): ShadowedWord[];
|
|
233
|
+
/**
|
|
234
|
+
* Assert the package does not collide with any of `others` in a way that
|
|
235
|
+
* would silently break one of them (two packages claiming the same lexer
|
|
236
|
+
* keyword, plugin-function index, async-resolver namespace, and so on).
|
|
237
|
+
*
|
|
238
|
+
* `strictness` sets which severities fail the assertion: `"error"` (the
|
|
239
|
+
* default) fails only on the collisions that always break something,
|
|
240
|
+
* `"warning"` also fails on the ones that silently pick a winner, `"info"`
|
|
241
|
+
* fails on cosmetic overlaps too.
|
|
242
|
+
*
|
|
243
|
+
* @returns the full compatibility report, so a test can inspect every
|
|
244
|
+
* conflict, including ones below the strictness threshold.
|
|
245
|
+
*/
|
|
246
|
+
notToCollideWith(others: IEnginePackage[], strictness?: CollisionStrictness): CompatibilityReport;
|
|
247
|
+
/**
|
|
248
|
+
* Assert the package's declared `engineVersion` range is satisfied by the
|
|
249
|
+
* running engine (or by `engineVersion` when given).
|
|
250
|
+
*
|
|
251
|
+
* A package that declares a range and never checks it resolves is the third
|
|
252
|
+
* mistake the issue names: it looks fine until the one engine version it
|
|
253
|
+
* cannot run against, where the range either fails to match or turns out to
|
|
254
|
+
* be a malformed string. A package with no declared range passes (no
|
|
255
|
+
* constraint is always compatible).
|
|
256
|
+
*/
|
|
257
|
+
toDeclareCompatibleEngineVersion(engineVersion?: string): this;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Begin an assertion about a package's declared descriptor.
|
|
261
|
+
*
|
|
262
|
+
* @example
|
|
263
|
+
* ```ts
|
|
264
|
+
* expectPackage(myPackage).notToShadow(["price", "in", "of"]);
|
|
265
|
+
* expectPackage(myPackage).notToCollideWith(BUILTIN_PACKAGES);
|
|
266
|
+
* expectPackage(myPackage).toDeclareCompatibleEngineVersion();
|
|
267
|
+
* ```
|
|
268
|
+
*/
|
|
269
|
+
declare function expectPackage(pkg: IEnginePackage): PackageAssertion;
|
|
270
|
+
|
|
271
|
+
export { COMMON_PROSE_WORDS, type CollisionStrictness, ExpectationError, ExpressionAssertion, PackageAssertion, type ShadowedWord, type TestEngineOptions, createTestEngine, expectExpression, expectPackage };
|