solve-engine 2.30.0 → 2.31.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/{DateCalendar-B85t6Vk6.d.ts → DateCalendar-CTz538dw.d.ts} +41 -1
- package/dist/{DateCalendar-CUGI1fT4.d.cts → DateCalendar-GFQDX1ng.d.cts} +41 -1
- package/dist/chunk-5EL4WXLF.cjs +3 -0
- package/dist/chunk-5EL4WXLF.cjs.map +1 -0
- package/dist/{chunk-CIC2YO2M.js → chunk-64OGL465.js} +2 -2
- package/dist/chunk-64OGL465.js.map +1 -0
- package/dist/chunk-D4UHCZAW.js +3 -0
- package/dist/chunk-D4UHCZAW.js.map +1 -0
- package/dist/chunk-JPT6L7BG.cjs +5 -0
- package/dist/chunk-JPT6L7BG.cjs.map +1 -0
- package/dist/{chunk-RHRAONDK.cjs → chunk-UHS4HMOQ.cjs} +2 -2
- package/dist/chunk-UHS4HMOQ.cjs.map +1 -0
- package/dist/chunk-VYB44JLS.js +5 -0
- package/dist/chunk-VYB44JLS.js.map +1 -0
- package/dist/constants.cjs +1 -1
- package/dist/constants.js +1 -1
- package/dist/engine.cjs +1 -1
- package/dist/engine.d.cts +1 -1
- package/dist/engine.d.ts +1 -1
- package/dist/engine.js +1 -1
- package/dist/engine.worker.cjs +2 -0
- package/dist/engine.worker.cjs.map +1 -0
- package/dist/engine.worker.d.cts +2 -0
- package/dist/engine.worker.d.ts +2 -0
- package/dist/engine.worker.js +2 -0
- package/dist/engine.worker.js.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/testing.cjs +2 -2
- package/dist/testing.js +1 -1
- package/dist/testing.js.map +1 -1
- package/dist/worker.cjs +2 -2
- package/dist/worker.js +2 -2
- package/dist/worker.js.map +1 -1
- package/package.json +11 -1
- package/dist/chunk-CIC2YO2M.js.map +0 -1
- package/dist/chunk-FNSQ6O4Y.js +0 -3
- package/dist/chunk-FNSQ6O4Y.js.map +0 -1
- package/dist/chunk-NNRTDLGC.cjs +0 -3
- package/dist/chunk-NNRTDLGC.cjs.map +0 -1
- package/dist/chunk-NOZKHMML.js +0 -5
- package/dist/chunk-NOZKHMML.js.map +0 -1
- package/dist/chunk-PNHTC3FM.cjs +0 -5
- package/dist/chunk-PNHTC3FM.cjs.map +0 -1
- package/dist/chunk-RHRAONDK.cjs.map +0 -1
package/dist/testing.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/testing/index.ts"],"names":["ExpectationError","_ExpectationError","init","createTestEngine","packages","options","locale","includeBuiltins","engine","ExpressionEngine","BUILTIN_PACKAGES","pkg","evaluate","expression","value","error","EngineError","message","Value","numbersEqual","a","b","epsilon","describeValue","describeOutcome","outcome","ExpressionAssertion","expected","unit","describeExpected","matches","valueToComparableString","code","base","expectExpression","COMMON_PROSE_WORDS","SEVERITY_ORDER","claimedWords","claimed","vocab","word","tokenType","phrase","PackageAssertion","words","prose","w","shadowed","c","list","s","others","strictness","report","checkPackageCompatibility","threshold","failing","engineVersion","ENGINE_VERSION","result","checkEngineVersionCompatibility","detail","expectPackage"],"mappings":"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","file":"testing.js","sourcesContent":["/**\n * A test kit for package authors, the supported way to test a package by the\n * expressions it enables rather than by the opcodes it emits.\n *\n * Before this entry point a package author had two options, both bad: reach\n * into engine internals, or assert on whatever bytecode a parselet happened to\n * emit. The first is unstable across engine versions, the second pins the\n * implementation instead of the behaviour, so a refactor that keeps every\n * answer correct still breaks the tests. This module is a thin, dependency-free\n * layer over the same public surface a host uses: it constructs an\n * {@link ExpressionEngine} with the given packages and evaluates strings.\n *\n * It speaks in expressions. {@link expectExpression} evaluates a string and\n * asserts on the result or the failure code; {@link expectPackage} asserts on\n * the three mistakes a package actually makes (shadowing prose, colliding with\n * another package's vocabulary, and declaring an `engineVersion` range that the\n * running engine does not satisfy).\n *\n * Framework-agnostic on purpose. Nothing here imports jest, vitest or any\n * runner: an assertion that fails throws an {@link ExpectationError}, and one\n * that passes returns, so the kit drops into whatever runner the author already\n * has (or into a plain script, or `node:assert`). Runtime dependency-free and\n * side-effect free, so `solve-engine/testing` stays honest under the package's\n * `\"sideEffects\": false` contract.\n *\n * @example\n * ```ts\n * import { createTestEngine, expectExpression } from \"solve-engine/testing\";\n *\n * const engine = createTestEngine([myPackage]);\n * expectExpression(engine, \"2 gp + 3 gp\").toEqual(5, \"gp\");\n * expectExpression(engine, \"gp\").toFailWith(\"UNDEFINED_VARIABLE\");\n * ```\n */\n\nimport { ExpressionEngine } from \"@solve-js/engine/ExpressionEngine\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport { Value, ValueType } from \"@solve-js/vm/Value\";\nimport { EngineError } from \"@solve-js/errors/EngineError\";\nimport {\n\tcheckPackageCompatibility,\n\ttype CompatibilityReport,\n\ttype CompatibilityConflict,\n\ttype CompatibilitySeverity,\n} from \"@solve-js/api/PackageCompatibility\";\nimport { checkEngineVersionCompatibility } from \"@solve-js/api/EngineVersionCompatibility\";\nimport { ENGINE_VERSION } from \"@solve-js/constants/version\";\n\n//#region Errors\n\n/**\n * The failure a matcher throws when an expectation is not met.\n *\n * A dedicated `Error` subclass rather than a bare `throw new Error`, so a\n * caller (or a reporter) can tell a kit assertion failure apart from an\n * unrelated exception with `instanceof`, and so the structured `expected` and\n * `actual` fields survive alongside the human-readable message. This is NOT an\n * {@link EngineError}: that type classifies pipeline-stage failures inside the\n * engine, whereas this classifies a test-assertion mismatch, a different\n * concern that would be miscategorised under any of `EngineError`'s categories.\n */\nexport class ExpectationError extends Error {\n\t/** A short, machine-readable label for which expectation failed. */\n\treadonly code: string;\n\t/** What the matcher was told to expect, in plain words. */\n\treadonly expected?: string;\n\t/** What it found instead. */\n\treadonly actual?: string;\n\n\tconstructor(init: { code: string; message: string; expected?: string; actual?: string }) {\n\t\tsuper(init.message);\n\t\tthis.name = \"ExpectationError\";\n\t\tthis.code = init.code;\n\t\tthis.expected = init.expected;\n\t\tthis.actual = init.actual;\n\t\t// Restore the prototype chain across the ES5 `Error` transpile target,\n\t\t// so `instanceof ExpectationError` holds for callers.\n\t\tObject.setPrototypeOf(this, ExpectationError.prototype);\n\t}\n}\n\n//#endregion\n\n//#region createTestEngine\n\n/** Options for {@link createTestEngine}. */\nexport interface TestEngineOptions {\n\t/** Locale passed to the engine. Defaults to `\"en\"`. */\n\tlocale?: string;\n\t/**\n\t * Whether to load the engine's built-in packages (arithmetic, units, dates,\n\t * and the rest) before the packages under test. Defaults to `true`, because\n\t * almost every package builds on arithmetic and most authors want a\n\t * realistic engine. Set `false` to test a package in isolation.\n\t */\n\tincludeBuiltins?: boolean;\n}\n\n/**\n * Build an {@link ExpressionEngine} loaded with the packages under test.\n *\n * The built-in packages load first (unless {@link TestEngineOptions.includeBuiltins}\n * is `false`), then each package in `packages` is registered in order, exactly\n * as a host would. Registration is honest: a package whose declared\n * `engineVersion` the running engine does not satisfy, or whose lexer keyword\n * collides with a built-in, throws here rather than being swallowed. That is\n * deliberately different from passing packages straight to the\n * `ExpressionEngine` constructor, which contains a bad package by logging and\n * continuing, useful in production, wrong for a test that needs to know the\n * package it is testing actually loaded.\n *\n * Call {@link ExpressionEngine.clear} when a test is finished with the engine\n * if the test creates many, see the engine's own lifecycle note.\n *\n * @example\n * ```ts\n * const engine = createTestEngine([myPackage]);\n * const engineOnly = createTestEngine([myPackage], { includeBuiltins: false });\n * ```\n */\nexport function createTestEngine(\n\tpackages: IEnginePackage[] = [],\n\toptions: TestEngineOptions = {},\n): ExpressionEngine {\n\tconst { locale = \"en\", includeBuiltins = true } = options;\n\n\t// Built-ins go through the constructor (their own containment applies);\n\t// the packages under test go through registerPackage() afterwards so their\n\t// failures surface as thrown errors instead of being logged and skipped.\n\tconst engine = new ExpressionEngine({ locale, packages: includeBuiltins ? BUILTIN_PACKAGES : [] });\n\tfor (const pkg of packages) {\n\t\tengine.registerPackage(pkg);\n\t}\n\treturn engine;\n}\n\n//#endregion\n\n//#region expectExpression\n\n/**\n * The normalised outcome of evaluating one expression, computed once when\n * {@link expectExpression} runs and read by every matcher on the result.\n *\n * The engine surfaces a failure two different ways, and a package author should\n * not have to know which: a parse/eval error is THROWN as an\n * {@link EngineError} (with a `.code`), while a plugin-raised error is RETURNED\n * as a {@link Value} of {@link ValueType.Error} (its `value` is the code, its\n * `unit` is the message). Both collapse to the `\"error\"` status here. A value\n * still resolving asynchronously is its own `\"pending\"` status, since the kit\n * evaluates synchronously and cannot report a final number for it.\n */\ntype Outcome =\n\t| { status: \"value\"; value: Value }\n\t| { status: \"pending\"; value: Value }\n\t| { status: \"error\"; code: string; message: string; source: EngineError | Value };\n\n/** Evaluate `expression` on `engine` and collapse both failure shapes to one outcome. */\nfunction evaluate(engine: ExpressionEngine, expression: string): Outcome {\n\ttry {\n\t\tconst value = engine.evaluateExpression(expression);\n\t\tif (value.isError()) {\n\t\t\treturn {\n\t\t\t\tstatus: \"error\",\n\t\t\t\tcode: value.errorCode ?? \"\",\n\t\t\t\tmessage: value.errorMessage ?? \"\",\n\t\t\t\tsource: value,\n\t\t\t};\n\t\t}\n\t\tif (value.isPending()) {\n\t\t\treturn { status: \"pending\", value };\n\t\t}\n\t\treturn { status: \"value\", value };\n\t} catch (error) {\n\t\tif (error instanceof EngineError) {\n\t\t\treturn { status: \"error\", code: error.code, message: error.message, source: error };\n\t\t}\n\t\t// Anything else thrown (a bug in a plugin handler, say) is still a\n\t\t// failure, wrapped so the matcher has a code and message to report.\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tstatus: \"error\",\n\t\t\tcode: \"UNKNOWN_ERROR\",\n\t\t\tmessage,\n\t\t\tsource: new Value(ValueType.Error, \"UNKNOWN_ERROR\", message),\n\t\t};\n\t}\n}\n\n/** Whether two numbers are equal within a small tolerance scaled to their magnitude. */\nfunction numbersEqual(a: number, b: number): boolean {\n\tif (Object.is(a, b)) return true;\n\tif (!Number.isFinite(a) || !Number.isFinite(b)) return false;\n\tconst epsilon = 1e-9 * Math.max(1, Math.abs(a), Math.abs(b));\n\treturn Math.abs(a - b) <= epsilon;\n}\n\n/** A short, readable rendering of a value for an assertion message, e.g. `5 gp` or `\"abc\"`. */\nfunction describeValue(value: Value): string {\n\tif (value.type === ValueType.String) return JSON.stringify(value.value);\n\tif (value.type === ValueType.Uom && typeof value.unit === \"string\") {\n\t\treturn `${String(value.value)} ${value.unit}`;\n\t}\n\treturn String(value.value);\n}\n\n/** A short, readable rendering of an outcome for an assertion message. */\nfunction describeOutcome(outcome: Outcome): string {\n\tswitch (outcome.status) {\n\t\tcase \"value\":\n\t\t\treturn describeValue(outcome.value);\n\t\tcase \"pending\":\n\t\t\treturn \"a pending async value\";\n\t\tcase \"error\":\n\t\t\treturn `an error (${outcome.code}: ${outcome.message})`;\n\t}\n}\n\n/**\n * Assertions about the result of one evaluated expression, returned by\n * {@link expectExpression}. Every matcher returns `this`, so assertions chain,\n * and throws an {@link ExpectationError} when it fails.\n */\nexport class ExpressionAssertion {\n\tconstructor(\n\t\tprivate readonly expression: string,\n\t\tprivate readonly outcome: Outcome,\n\t) {}\n\n\t/** The raw resolved {@link Value}, for an assertion the matchers do not cover. Throws if the expression failed. */\n\tget value(): Value {\n\t\tif (this.outcome.status === \"error\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_VALUE\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to evaluate, but it failed with ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: \"a resolved value\",\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\treturn this.outcome.value;\n\t}\n\n\t/**\n\t * Assert the expression evaluated to a value (not an error, not a pending\n\t * async result). Says nothing about what the value is.\n\t */\n\ttoEvaluate(): this {\n\t\tif (this.outcome.status !== \"value\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_EVALUATE\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to evaluate to a value, but got ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: \"a resolved value\",\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Assert the expression evaluated to `expected`, and, when `unit` is given,\n\t * that the result carries exactly that unit. A number compares against the\n\t * value's numeric magnitude within a small floating-point tolerance; a\n\t * string compares against the value's own string; a boolean against its\n\t * boolean reading. Omitting `unit` leaves the unit unchecked, so\n\t * `toEqual(5)` passes for both `5` and `5 gp`.\n\t */\n\ttoEqual(expected: number | string | boolean, unit?: string): this {\n\t\tif (this.outcome.status !== \"value\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_EQUAL\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to equal ${describeExpected(expected, unit)}, but got ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: describeExpected(expected, unit),\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\n\t\tconst value = this.outcome.value;\n\t\tlet matches: boolean;\n\t\tif (typeof expected === \"number\") {\n\t\t\tmatches = numbersEqual(value.toNumber(), expected);\n\t\t} else if (typeof expected === \"boolean\") {\n\t\t\t// A Boolean value stores the primitive directly; anything else can\n\t\t\t// never equal a boolean, so a mismatch reports the real value.\n\t\t\tmatches = value.type === ValueType.Boolean && value.value === expected;\n\t\t} else {\n\t\t\tmatches = valueToComparableString(value) === expected;\n\t\t}\n\n\t\tif (!matches) {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_EQUAL\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to equal ${describeExpected(expected, unit)}, but it was ${describeValue(value)}.`,\n\t\t\t\texpected: describeExpected(expected, unit),\n\t\t\t\tactual: describeValue(value),\n\t\t\t});\n\t\t}\n\n\t\tif (unit !== undefined && value.unit !== unit) {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_UNIT\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to carry the unit \"${unit}\", but it was ${value.unit === undefined ? \"unitless\" : `\"${value.unit}\"`}.`,\n\t\t\t\texpected: `unit \"${unit}\"`,\n\t\t\t\tactual: value.unit === undefined ? \"no unit\" : `unit \"${value.unit}\"`,\n\t\t\t});\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/** Assert the expression failed (a thrown engine error or a plugin-raised error value). Says nothing about the code. */\n\ttoBeError(): this {\n\t\tif (this.outcome.status !== \"error\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_ERROR\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to fail, but it produced ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: \"an error\",\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Assert the expression failed with exactly `code`, the error catalog code\n\t * (e.g. `\"UNDEFINED_VARIABLE\"`, or a package's own code). Reports the code\n\t * it actually got when they differ, so a near-miss is obvious.\n\t */\n\ttoFailWith(code: string): this {\n\t\tif (this.outcome.status !== \"error\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_FAIL_WITH\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to fail with \"${code}\", but it produced ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: `error code \"${code}\"`,\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\tif (this.outcome.code !== code) {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_FAIL_WITH\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to fail with \"${code}\", but it failed with \"${this.outcome.code}\" (${this.outcome.message}).`,\n\t\t\t\texpected: `error code \"${code}\"`,\n\t\t\t\tactual: `error code \"${this.outcome.code}\"`,\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Assert the expression returned a value still resolving asynchronously.\n\t * The kit evaluates synchronously, so a package whose result comes from an\n\t * async resolver reports pending on first evaluation, this is how a test\n\t * confirms the async path was taken without resolving it.\n\t */\n\ttoBePending(): this {\n\t\tif (this.outcome.status !== \"pending\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_PENDING\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to be pending, but got ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: \"a pending async value\",\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n}\n\n/** Render an expected value (with optional unit) for an assertion message. */\nfunction describeExpected(expected: number | string | boolean, unit?: string): string {\n\tconst base = typeof expected === \"string\" ? JSON.stringify(expected) : String(expected);\n\treturn unit === undefined ? base : `${base} ${unit}`;\n}\n\n/** The string a non-numeric value compares against in {@link ExpressionAssertion.toEqual}. */\nfunction valueToComparableString(value: Value): string {\n\t// The stored primitive stringified. For a String value this is the string\n\t// itself; for a Hex value, its `0x...` text, which is what an author writes\n\t// in a `toEqual(\"0xff\")` assertion.\n\treturn String(value.value);\n}\n\n/**\n * Evaluate `expression` on `engine` and return an assertion object.\n *\n * The expression is evaluated once, immediately, and every matcher reads that\n * one outcome, so calling several matchers on the same result does not\n * re-evaluate.\n *\n * @example\n * ```ts\n * expectExpression(engine, \"2 gp + 3 gp\").toEqual(5, \"gp\");\n * expectExpression(engine, \"gp\").toFailWith(\"UNDEFINED_VARIABLE\");\n * ```\n */\nexport function expectExpression(engine: ExpressionEngine, expression: string): ExpressionAssertion {\n\treturn new ExpressionAssertion(expression, evaluate(engine, expression));\n}\n\n//#endregion\n\n//#region expectPackage\n\n/**\n * A modest set of everyday English words a package's keywords should not claim.\n *\n * A starting point for {@link PackageAssertion.notToShadow}, not an exhaustive\n * dictionary: it leans on the function words and common nouns/verbs a package\n * is most tempted to grab as a trigger (`price`, `of`, `per`, `sum`, `total`).\n * Pass your own list to check against the specific prose your package sits in.\n */\nexport const COMMON_PROSE_WORDS: readonly string[] = [\n\t\"a\", \"an\", \"and\", \"or\", \"but\", \"if\", \"then\", \"the\", \"this\", \"that\", \"these\", \"those\",\n\t\"in\", \"on\", \"at\", \"to\", \"of\", \"for\", \"from\", \"with\", \"by\", \"as\", \"per\", \"into\", \"over\",\n\t\"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\", \"do\", \"does\", \"did\", \"have\", \"has\", \"had\",\n\t\"will\", \"would\", \"can\", \"could\", \"should\", \"may\", \"might\", \"must\",\n\t\"price\", \"cost\", \"value\", \"total\", \"sum\", \"count\", \"rate\", \"amount\", \"number\",\n\t\"time\", \"date\", \"day\", \"week\", \"month\", \"year\", \"hour\", \"minute\", \"second\",\n\t\"add\", \"buy\", \"sell\", \"hold\", \"make\", \"take\", \"give\", \"get\", \"set\", \"run\",\n\t\"up\", \"down\", \"out\", \"off\", \"all\", \"some\", \"any\", \"no\", \"not\", \"more\", \"less\",\n\t\"one\", \"two\", \"three\", \"first\", \"last\", \"next\", \"each\", \"every\", \"here\", \"there\",\n];\n\n/** How strict {@link PackageAssertion.notToCollideWith} is about the conflicts it will accept. */\nexport type CollisionStrictness = \"error\" | \"warning\" | \"info\";\n\n/** One shadowed word found by {@link PackageAssertion.notToShadow}: the prose word and how the package claims it. */\nexport interface ShadowedWord {\n\t/** The prose word the package claims. */\n\tword: string;\n\t/** Which descriptor field claims it. */\n\tvia: \"keyword\" | \"unit\" | \"operator\" | \"phrase\";\n\t/** The token type the word becomes, when the field maps to one. */\n\ttokenType?: string;\n}\n\n/** Severities at or above the strictness threshold, ordered most to least severe. */\nconst SEVERITY_ORDER: CompatibilitySeverity[] = [\"error\", \"warning\", \"info\"];\n\n/** Gather the single words a package claims through its declared vocabulary, which is where prose shadowing comes from. */\nfunction claimedWords(pkg: IEnginePackage): ShadowedWord[] {\n\tconst claimed: ShadowedWord[] = [];\n\tconst vocab = pkg.lexerVocabulary;\n\tif (vocab?.keywords) {\n\t\tfor (const [word, tokenType] of Object.entries(vocab.keywords)) {\n\t\t\tclaimed.push({ word, via: \"keyword\", tokenType });\n\t\t}\n\t}\n\tif (vocab?.units) {\n\t\tfor (const word of vocab.units) {\n\t\t\tclaimed.push({ word, via: \"unit\" });\n\t\t}\n\t}\n\tif (vocab?.operators) {\n\t\tfor (const [word, tokenType] of Object.entries(vocab.operators)) {\n\t\t\tclaimed.push({ word, via: \"operator\", tokenType });\n\t\t}\n\t}\n\tif (pkg.phrases) {\n\t\tfor (const [phrase, tokenType] of Object.entries(pkg.phrases)) {\n\t\t\t// A multi-word phrase is the SAFE pattern the trigger-words guide\n\t\t\t// recommends (`next friday` reserves neither word), so only a\n\t\t\t// single-word phrase can shadow a prose word.\n\t\t\tif (!phrase.includes(\" \")) {\n\t\t\t\tclaimed.push({ word: phrase, via: \"phrase\", tokenType });\n\t\t\t}\n\t\t}\n\t}\n\treturn claimed;\n}\n\n/**\n * Assertions about a package's declared descriptor, returned by\n * {@link expectPackage}. These catch the three mistakes the issue calls out,\n * before the package is ever registered. Every matcher returns `this` and\n * throws an {@link ExpectationError} when it fails.\n */\nexport class PackageAssertion {\n\tconstructor(private readonly pkg: IEnginePackage) {}\n\n\t/**\n\t * Assert none of the package's claimed words shadow a prose word.\n\t *\n\t * A trigger word that is also an ordinary word turns a line of prose into\n\t * arithmetic, the single most common package mistake and the subject of the\n\t * trigger-words guide. This checks the words the package declares\n\t * (lexer keywords, units, operators, and single-word phrases) against\n\t * `words` (defaulting to {@link COMMON_PROSE_WORDS}), case-insensitively.\n\t *\n\t * @returns the shadowed words, empty when the package is clean, for a test\n\t * that wants to inspect rather than assert.\n\t */\n\tnotToShadow(words: readonly string[] = COMMON_PROSE_WORDS): ShadowedWord[] {\n\t\tconst prose = new Set(words.map((w) => w.toLowerCase()));\n\t\tconst shadowed = claimedWords(this.pkg).filter((c) => prose.has(c.word.toLowerCase()));\n\t\tif (shadowed.length > 0) {\n\t\t\tconst list = shadowed.map((s) => `\"${s.word}\" (${s.via})`).join(\", \");\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"PACKAGE_SHADOWS_PROSE\",\n\t\t\t\tmessage: `Package \"${this.pkg.name}\" claims prose word(s) as syntax: ${list}. A word that is also ordinary English turns prose into arithmetic; prefer a multi-word phrase or a form that requires a parenthesis.`,\n\t\t\t\texpected: \"no prose words claimed as syntax\",\n\t\t\t\tactual: list,\n\t\t\t});\n\t\t}\n\t\treturn shadowed;\n\t}\n\n\t/**\n\t * Assert the package does not collide with any of `others` in a way that\n\t * would silently break one of them (two packages claiming the same lexer\n\t * keyword, plugin-function index, async-resolver namespace, and so on).\n\t *\n\t * `strictness` sets which severities fail the assertion: `\"error\"` (the\n\t * default) fails only on the collisions that always break something,\n\t * `\"warning\"` also fails on the ones that silently pick a winner, `\"info\"`\n\t * fails on cosmetic overlaps too.\n\t *\n\t * @returns the full compatibility report, so a test can inspect every\n\t * conflict, including ones below the strictness threshold.\n\t */\n\tnotToCollideWith(\n\t\tothers: IEnginePackage[],\n\t\tstrictness: CollisionStrictness = \"error\",\n\t): CompatibilityReport {\n\t\tconst report = checkPackageCompatibility(this.pkg, others);\n\t\tconst threshold = SEVERITY_ORDER.indexOf(strictness);\n\t\tconst failing = report.conflicts.filter(\n\t\t\t(c: CompatibilityConflict) => SEVERITY_ORDER.indexOf(c.severity) <= threshold,\n\t\t);\n\t\tif (failing.length > 0) {\n\t\t\tconst list = failing.map((c) => `[${c.severity}] ${c.detail}`).join(\"\\n\");\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"PACKAGE_VOCABULARY_COLLISION\",\n\t\t\t\tmessage: `Package \"${this.pkg.name}\" collides with another package:\\n${list}`,\n\t\t\t\texpected: `no conflicts at or above \"${strictness}\" severity`,\n\t\t\t\tactual: `${failing.length} conflict(s)`,\n\t\t\t});\n\t\t}\n\t\treturn report;\n\t}\n\n\t/**\n\t * Assert the package's declared `engineVersion` range is satisfied by the\n\t * running engine (or by `engineVersion` when given).\n\t *\n\t * A package that declares a range and never checks it resolves is the third\n\t * mistake the issue names: it looks fine until the one engine version it\n\t * cannot run against, where the range either fails to match or turns out to\n\t * be a malformed string. A package with no declared range passes (no\n\t * constraint is always compatible).\n\t */\n\ttoDeclareCompatibleEngineVersion(engineVersion: string = ENGINE_VERSION): this {\n\t\tconst result = checkEngineVersionCompatibility(this.pkg, engineVersion);\n\t\tif (!result.compatible) {\n\t\t\tconst detail =\n\t\t\t\tresult.reason === \"invalid-range\"\n\t\t\t\t\t? `its range \"${result.declaredRange}\" is not valid semver`\n\t\t\t\t\t: `its range \"${result.declaredRange}\" is not satisfied by engine version \"${result.engineVersion}\"`;\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"PACKAGE_ENGINE_VERSION_INCOMPATIBLE\",\n\t\t\t\tmessage: `Package \"${this.pkg.name}\" declares an engineVersion that will be rejected at registration: ${detail}.`,\n\t\t\t\texpected: `an engineVersion satisfied by \"${engineVersion}\"`,\n\t\t\t\tactual: `\"${result.declaredRange}\"`,\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n}\n\n/**\n * Begin an assertion about a package's declared descriptor.\n *\n * @example\n * ```ts\n * expectPackage(myPackage).notToShadow([\"price\", \"in\", \"of\"]);\n * expectPackage(myPackage).notToCollideWith(BUILTIN_PACKAGES);\n * expectPackage(myPackage).toDeclareCompatibleEngineVersion();\n * ```\n */\nexport function expectPackage(pkg: IEnginePackage): PackageAssertion {\n\treturn new PackageAssertion(pkg);\n}\n\n//#endregion\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/testing/index.ts"],"names":["ExpectationError","_ExpectationError","init","createTestEngine","packages","options","locale","includeBuiltins","engine","ExpressionEngine","BUILTIN_PACKAGES","pkg","evaluate","expression","value","error","EngineError","message","Value","numbersEqual","a","b","epsilon","describeValue","describeOutcome","outcome","ExpressionAssertion","expected","unit","describeExpected","matches","valueToComparableString","code","base","expectExpression","COMMON_PROSE_WORDS","SEVERITY_ORDER","claimedWords","claimed","vocab","word","tokenType","phrase","PackageAssertion","words","prose","w","shadowed","c","list","s","others","strictness","report","checkPackageCompatibility","threshold","failing","engineVersion","ENGINE_VERSION","result","checkEngineVersionCompatibility","detail","expectPackage"],"mappings":"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","file":"testing.js","sourcesContent":["/**\n * A test kit for package authors, the supported way to test a package by the\n * expressions it enables rather than by the opcodes it emits.\n *\n * Before this entry point a package author had two options, both bad: reach\n * into engine internals, or assert on whatever bytecode a parselet happened to\n * emit. The first is unstable across engine versions, the second pins the\n * implementation instead of the behaviour, so a refactor that keeps every\n * answer correct still breaks the tests. This module is a thin, dependency-free\n * layer over the same public surface a host uses: it constructs an\n * {@link ExpressionEngine} with the given packages and evaluates strings.\n *\n * It speaks in expressions. {@link expectExpression} evaluates a string and\n * asserts on the result or the failure code; {@link expectPackage} asserts on\n * the three mistakes a package actually makes (shadowing prose, colliding with\n * another package's vocabulary, and declaring an `engineVersion` range that the\n * running engine does not satisfy).\n *\n * Framework-agnostic on purpose. Nothing here imports jest, vitest or any\n * runner: an assertion that fails throws an {@link ExpectationError}, and one\n * that passes returns, so the kit drops into whatever runner the author already\n * has (or into a plain script, or `node:assert`). Runtime dependency-free and\n * side-effect free, so `solve-engine/testing` stays honest under the package's\n * `\"sideEffects\": false` contract.\n *\n * @example\n * ```ts\n * import { createTestEngine, expectExpression } from \"solve-engine/testing\";\n *\n * const engine = createTestEngine([myPackage]);\n * expectExpression(engine, \"2 gp + 3 gp\").toEqual(5, \"gp\");\n * expectExpression(engine, \"gp\").toFailWith(\"UNDEFINED_VARIABLE\");\n * ```\n */\n\nimport { ExpressionEngine } from \"@solve-js/engine/ExpressionEngine\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport { Value, ValueType } from \"@solve-js/vm/Value\";\nimport { EngineError } from \"@solve-js/errors/EngineError\";\nimport {\n\tcheckPackageCompatibility,\n\ttype CompatibilityReport,\n\ttype CompatibilityConflict,\n\ttype CompatibilitySeverity,\n} from \"@solve-js/api/PackageCompatibility\";\nimport { checkEngineVersionCompatibility } from \"@solve-js/api/EngineVersionCompatibility\";\nimport { ENGINE_VERSION } from \"@solve-js/constants/version\";\n\n//#region Errors\n\n/**\n * The failure a matcher throws when an expectation is not met.\n *\n * A dedicated `Error` subclass rather than a bare `throw new Error`, so a\n * caller (or a reporter) can tell a kit assertion failure apart from an\n * unrelated exception with `instanceof`, and so the structured `expected` and\n * `actual` fields survive alongside the human-readable message. This is NOT an\n * {@link EngineError}: that type classifies pipeline-stage failures inside the\n * engine, whereas this classifies a test-assertion mismatch, a different\n * concern that would be miscategorised under any of `EngineError`'s categories.\n */\nexport class ExpectationError extends Error {\n\t/** A short, machine-readable label for which expectation failed. */\n\treadonly code: string;\n\t/** What the matcher was told to expect, in plain words. */\n\treadonly expected?: string;\n\t/** What it found instead. */\n\treadonly actual?: string;\n\n\tconstructor(init: { code: string; message: string; expected?: string; actual?: string }) {\n\t\tsuper(init.message);\n\t\tthis.name = \"ExpectationError\";\n\t\tthis.code = init.code;\n\t\tthis.expected = init.expected;\n\t\tthis.actual = init.actual;\n\t\t// Restore the prototype chain across the ES5 `Error` transpile target,\n\t\t// so `instanceof ExpectationError` holds for callers.\n\t\tObject.setPrototypeOf(this, ExpectationError.prototype);\n\t}\n}\n\n//#endregion\n\n//#region createTestEngine\n\n/** Options for {@link createTestEngine}. */\nexport interface TestEngineOptions {\n\t/** Locale passed to the engine. Defaults to `\"en\"`. */\n\tlocale?: string;\n\t/**\n\t * Whether to load the engine's built-in packages (arithmetic, units, dates,\n\t * and the rest) before the packages under test. Defaults to `true`, because\n\t * almost every package builds on arithmetic and most authors want a\n\t * realistic engine. Set `false` to test a package in isolation.\n\t */\n\tincludeBuiltins?: boolean;\n}\n\n/**\n * Build an {@link ExpressionEngine} loaded with the packages under test.\n *\n * The built-in packages load first (unless {@link TestEngineOptions.includeBuiltins}\n * is `false`), then each package in `packages` is registered in order, exactly\n * as a host would. Registration is honest: a package whose declared\n * `engineVersion` the running engine does not satisfy, or whose lexer keyword\n * collides with a built-in, throws here rather than being swallowed. That is\n * deliberately different from passing packages straight to the\n * `ExpressionEngine` constructor, which contains a bad package by logging and\n * continuing, useful in production, wrong for a test that needs to know the\n * package it is testing actually loaded.\n *\n * Call {@link ExpressionEngine.clear} when a test is finished with the engine\n * if the test creates many, see the engine's own lifecycle note.\n *\n * @example\n * ```ts\n * const engine = createTestEngine([myPackage]);\n * const engineOnly = createTestEngine([myPackage], { includeBuiltins: false });\n * ```\n */\nexport function createTestEngine(\n\tpackages: IEnginePackage[] = [],\n\toptions: TestEngineOptions = {},\n): ExpressionEngine {\n\tconst { locale = \"en\", includeBuiltins = true } = options;\n\n\t// Built-ins go through the constructor (their own containment applies);\n\t// the packages under test go through registerPackage() afterwards so their\n\t// failures surface as thrown errors instead of being logged and skipped.\n\tconst engine = new ExpressionEngine({ locale, packages: includeBuiltins ? BUILTIN_PACKAGES : [] });\n\tfor (const pkg of packages) {\n\t\tengine.registerPackage(pkg);\n\t}\n\treturn engine;\n}\n\n//#endregion\n\n//#region expectExpression\n\n/**\n * The normalised outcome of evaluating one expression, computed once when\n * {@link expectExpression} runs and read by every matcher on the result.\n *\n * The engine surfaces a failure two different ways, and a package author should\n * not have to know which: a parse/eval error is THROWN as an\n * {@link EngineError} (with a `.code`), while a plugin-raised error is RETURNED\n * as a {@link Value} of {@link ValueType.Error} (its `value` is the code, its\n * `unit` is the message). Both collapse to the `\"error\"` status here. A value\n * still resolving asynchronously is its own `\"pending\"` status, since the kit\n * evaluates synchronously and cannot report a final number for it.\n */\ntype Outcome =\n\t| { status: \"value\"; value: Value }\n\t| { status: \"pending\"; value: Value }\n\t| { status: \"error\"; code: string; message: string; source: EngineError | Value };\n\n/** Evaluate `expression` on `engine` and collapse both failure shapes to one outcome. */\nfunction evaluate(engine: ExpressionEngine, expression: string): Outcome {\n\ttry {\n\t\tconst value = engine.evaluateExpression(expression);\n\t\tif (value.isError()) {\n\t\t\treturn {\n\t\t\t\tstatus: \"error\",\n\t\t\t\tcode: value.errorCode ?? \"\",\n\t\t\t\tmessage: value.errorMessage ?? \"\",\n\t\t\t\tsource: value,\n\t\t\t};\n\t\t}\n\t\tif (value.isPending()) {\n\t\t\treturn { status: \"pending\", value };\n\t\t}\n\t\treturn { status: \"value\", value };\n\t} catch (error) {\n\t\tif (error instanceof EngineError) {\n\t\t\treturn { status: \"error\", code: error.code, message: error.message, source: error };\n\t\t}\n\t\t// Anything else thrown (a bug in a plugin handler, say) is still a\n\t\t// failure, wrapped so the matcher has a code and message to report.\n\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\treturn {\n\t\t\tstatus: \"error\",\n\t\t\tcode: \"UNKNOWN_ERROR\",\n\t\t\tmessage,\n\t\t\tsource: new Value(ValueType.Error, \"UNKNOWN_ERROR\", message),\n\t\t};\n\t}\n}\n\n/** Whether two numbers are equal within a small tolerance scaled to their magnitude. */\nfunction numbersEqual(a: number, b: number): boolean {\n\tif (Object.is(a, b)) return true;\n\tif (!Number.isFinite(a) || !Number.isFinite(b)) return false;\n\tconst epsilon = 1e-9 * Math.max(1, Math.abs(a), Math.abs(b));\n\treturn Math.abs(a - b) <= epsilon;\n}\n\n/** A short, readable rendering of a value for an assertion message, e.g. `5 gp` or `\"abc\"`. */\nfunction describeValue(value: Value): string {\n\tif (value.type === ValueType.String) return JSON.stringify(value.value);\n\tif (value.type === ValueType.Uom && typeof value.unit === \"string\") {\n\t\treturn `${String(value.value)} ${value.unit}`;\n\t}\n\treturn String(value.value);\n}\n\n/** A short, readable rendering of an outcome for an assertion message. */\nfunction describeOutcome(outcome: Outcome): string {\n\tswitch (outcome.status) {\n\t\tcase \"value\":\n\t\t\treturn describeValue(outcome.value);\n\t\tcase \"pending\":\n\t\t\treturn \"a pending async value\";\n\t\tcase \"error\":\n\t\t\treturn `an error (${outcome.code}: ${outcome.message})`;\n\t}\n}\n\n/**\n * Assertions about the result of one evaluated expression, returned by\n * {@link expectExpression}. Every matcher returns `this`, so assertions chain,\n * and throws an {@link ExpectationError} when it fails.\n */\nexport class ExpressionAssertion {\n\tconstructor(\n\t\tprivate readonly expression: string,\n\t\tprivate readonly outcome: Outcome,\n\t) {}\n\n\t/** The raw resolved {@link Value}, for an assertion the matchers do not cover. Throws if the expression failed. */\n\tget value(): Value {\n\t\tif (this.outcome.status === \"error\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_VALUE\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to evaluate, but it failed with ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: \"a resolved value\",\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\treturn this.outcome.value;\n\t}\n\n\t/**\n\t * Assert the expression evaluated to a value (not an error, not a pending\n\t * async result). Says nothing about what the value is.\n\t */\n\ttoEvaluate(): this {\n\t\tif (this.outcome.status !== \"value\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_EVALUATE\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to evaluate to a value, but got ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: \"a resolved value\",\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Assert the expression evaluated to `expected`, and, when `unit` is given,\n\t * that the result carries exactly that unit. A number compares against the\n\t * value's numeric magnitude within a small floating-point tolerance; a\n\t * string compares against the value's own string; a boolean against its\n\t * boolean reading. Omitting `unit` leaves the unit unchecked, so\n\t * `toEqual(5)` passes for both `5` and `5 gp`.\n\t */\n\ttoEqual(expected: number | string | boolean, unit?: string): this {\n\t\tif (this.outcome.status !== \"value\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_EQUAL\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to equal ${describeExpected(expected, unit)}, but got ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: describeExpected(expected, unit),\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\n\t\tconst value = this.outcome.value;\n\t\tlet matches: boolean;\n\t\tif (typeof expected === \"number\") {\n\t\t\tmatches = numbersEqual(value.toNumber(), expected);\n\t\t} else if (typeof expected === \"boolean\") {\n\t\t\t// A Boolean value stores the primitive directly; anything else can\n\t\t\t// never equal a boolean, so a mismatch reports the real value.\n\t\t\tmatches = value.type === ValueType.Boolean && value.value === expected;\n\t\t} else {\n\t\t\tmatches = valueToComparableString(value) === expected;\n\t\t}\n\n\t\tif (!matches) {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_EQUAL\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to equal ${describeExpected(expected, unit)}, but it was ${describeValue(value)}.`,\n\t\t\t\texpected: describeExpected(expected, unit),\n\t\t\t\tactual: describeValue(value),\n\t\t\t});\n\t\t}\n\n\t\tif (unit !== undefined && value.unit !== unit) {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_UNIT\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to carry the unit \"${unit}\", but it was ${value.unit === undefined ? \"unitless\" : `\"${value.unit}\"`}.`,\n\t\t\t\texpected: `unit \"${unit}\"`,\n\t\t\t\tactual: value.unit === undefined ? \"no unit\" : `unit \"${value.unit}\"`,\n\t\t\t});\n\t\t}\n\n\t\treturn this;\n\t}\n\n\t/** Assert the expression failed (a thrown engine error or a plugin-raised error value). Says nothing about the code. */\n\ttoBeError(): this {\n\t\tif (this.outcome.status !== \"error\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_ERROR\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to fail, but it produced ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: \"an error\",\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Assert the expression failed with exactly `code`, the error catalog code\n\t * (e.g. `\"UNDEFINED_VARIABLE\"`, or a package's own code). Reports the code\n\t * it actually got when they differ, so a near-miss is obvious.\n\t */\n\ttoFailWith(code: string): this {\n\t\tif (this.outcome.status !== \"error\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_FAIL_WITH\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to fail with \"${code}\", but it produced ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: `error code \"${code}\"`,\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\tif (this.outcome.code !== code) {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_FAIL_WITH\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to fail with \"${code}\", but it failed with \"${this.outcome.code}\" (${this.outcome.message}).`,\n\t\t\t\texpected: `error code \"${code}\"`,\n\t\t\t\tactual: `error code \"${this.outcome.code}\"`,\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n\n\t/**\n\t * Assert the expression returned a value still resolving asynchronously.\n\t * The kit evaluates synchronously, so a package whose result comes from an\n\t * async resolver reports pending on first evaluation, this is how a test\n\t * confirms the async path was taken without resolving it.\n\t */\n\ttoBePending(): this {\n\t\tif (this.outcome.status !== \"pending\") {\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"EXPECTED_PENDING\",\n\t\t\t\tmessage: `Expected \"${this.expression}\" to be pending, but got ${describeOutcome(this.outcome)}.`,\n\t\t\t\texpected: \"a pending async value\",\n\t\t\t\tactual: describeOutcome(this.outcome),\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n}\n\n/** Render an expected value (with optional unit) for an assertion message. */\nfunction describeExpected(expected: number | string | boolean, unit?: string): string {\n\tconst base = typeof expected === \"string\" ? JSON.stringify(expected) : String(expected);\n\treturn unit === undefined ? base : `${base} ${unit}`;\n}\n\n/** The string a non-numeric value compares against in {@link ExpressionAssertion.toEqual}. */\nfunction valueToComparableString(value: Value): string {\n\t// The stored primitive stringified. For a String value this is the string\n\t// itself; for a Hex value, its `0x...` text, which is what an author writes\n\t// in a `toEqual(\"0xff\")` assertion.\n\treturn String(value.value);\n}\n\n/**\n * Evaluate `expression` on `engine` and return an assertion object.\n *\n * The expression is evaluated once, immediately, and every matcher reads that\n * one outcome, so calling several matchers on the same result does not\n * re-evaluate.\n *\n * @example\n * ```ts\n * expectExpression(engine, \"2 gp + 3 gp\").toEqual(5, \"gp\");\n * expectExpression(engine, \"gp\").toFailWith(\"UNDEFINED_VARIABLE\");\n * ```\n */\nexport function expectExpression(engine: ExpressionEngine, expression: string): ExpressionAssertion {\n\treturn new ExpressionAssertion(expression, evaluate(engine, expression));\n}\n\n//#endregion\n\n//#region expectPackage\n\n/**\n * A modest set of everyday English words a package's keywords should not claim.\n *\n * A starting point for {@link PackageAssertion.notToShadow}, not an exhaustive\n * dictionary: it leans on the function words and common nouns/verbs a package\n * is most tempted to grab as a trigger (`price`, `of`, `per`, `sum`, `total`).\n * Pass your own list to check against the specific prose your package sits in.\n */\nexport const COMMON_PROSE_WORDS: readonly string[] = [\n\t\"a\", \"an\", \"and\", \"or\", \"but\", \"if\", \"then\", \"the\", \"this\", \"that\", \"these\", \"those\",\n\t\"in\", \"on\", \"at\", \"to\", \"of\", \"for\", \"from\", \"with\", \"by\", \"as\", \"per\", \"into\", \"over\",\n\t\"is\", \"are\", \"was\", \"were\", \"be\", \"been\", \"being\", \"do\", \"does\", \"did\", \"have\", \"has\", \"had\",\n\t\"will\", \"would\", \"can\", \"could\", \"should\", \"may\", \"might\", \"must\",\n\t\"price\", \"cost\", \"value\", \"total\", \"sum\", \"count\", \"rate\", \"amount\", \"number\",\n\t\"time\", \"date\", \"day\", \"week\", \"month\", \"year\", \"hour\", \"minute\", \"second\",\n\t\"add\", \"buy\", \"sell\", \"hold\", \"make\", \"take\", \"give\", \"get\", \"set\", \"run\",\n\t\"up\", \"down\", \"out\", \"off\", \"all\", \"some\", \"any\", \"no\", \"not\", \"more\", \"less\",\n\t\"one\", \"two\", \"three\", \"first\", \"last\", \"next\", \"each\", \"every\", \"here\", \"there\",\n];\n\n/** How strict {@link PackageAssertion.notToCollideWith} is about the conflicts it will accept. */\nexport type CollisionStrictness = \"error\" | \"warning\" | \"info\";\n\n/** One shadowed word found by {@link PackageAssertion.notToShadow}: the prose word and how the package claims it. */\nexport interface ShadowedWord {\n\t/** The prose word the package claims. */\n\tword: string;\n\t/** Which descriptor field claims it. */\n\tvia: \"keyword\" | \"unit\" | \"operator\" | \"phrase\";\n\t/** The token type the word becomes, when the field maps to one. */\n\ttokenType?: string;\n}\n\n/** Severities at or above the strictness threshold, ordered most to least severe. */\nconst SEVERITY_ORDER: CompatibilitySeverity[] = [\"error\", \"warning\", \"info\"];\n\n/** Gather the single words a package claims through its declared vocabulary, which is where prose shadowing comes from. */\nfunction claimedWords(pkg: IEnginePackage): ShadowedWord[] {\n\tconst claimed: ShadowedWord[] = [];\n\tconst vocab = pkg.lexerVocabulary;\n\tif (vocab?.keywords) {\n\t\tfor (const [word, tokenType] of Object.entries(vocab.keywords)) {\n\t\t\tclaimed.push({ word, via: \"keyword\", tokenType });\n\t\t}\n\t}\n\tif (vocab?.units) {\n\t\tfor (const word of vocab.units) {\n\t\t\tclaimed.push({ word, via: \"unit\" });\n\t\t}\n\t}\n\tif (vocab?.operators) {\n\t\tfor (const [word, tokenType] of Object.entries(vocab.operators)) {\n\t\t\tclaimed.push({ word, via: \"operator\", tokenType });\n\t\t}\n\t}\n\tif (pkg.phrases) {\n\t\tfor (const [phrase, tokenType] of Object.entries(pkg.phrases)) {\n\t\t\t// A multi-word phrase is the SAFE pattern the trigger-words guide\n\t\t\t// recommends (`next friday` reserves neither word), so only a\n\t\t\t// single-word phrase can shadow a prose word.\n\t\t\tif (!phrase.includes(\" \")) {\n\t\t\t\tclaimed.push({ word: phrase, via: \"phrase\", tokenType });\n\t\t\t}\n\t\t}\n\t}\n\treturn claimed;\n}\n\n/**\n * Assertions about a package's declared descriptor, returned by\n * {@link expectPackage}. These catch the three mistakes the issue calls out,\n * before the package is ever registered. Every matcher returns `this` and\n * throws an {@link ExpectationError} when it fails.\n */\nexport class PackageAssertion {\n\tconstructor(private readonly pkg: IEnginePackage) {}\n\n\t/**\n\t * Assert none of the package's claimed words shadow a prose word.\n\t *\n\t * A trigger word that is also an ordinary word turns a line of prose into\n\t * arithmetic, the single most common package mistake and the subject of the\n\t * trigger-words guide. This checks the words the package declares\n\t * (lexer keywords, units, operators, and single-word phrases) against\n\t * `words` (defaulting to {@link COMMON_PROSE_WORDS}), case-insensitively.\n\t *\n\t * @returns the shadowed words, empty when the package is clean, for a test\n\t * that wants to inspect rather than assert.\n\t */\n\tnotToShadow(words: readonly string[] = COMMON_PROSE_WORDS): ShadowedWord[] {\n\t\tconst prose = new Set(words.map((w) => w.toLowerCase()));\n\t\tconst shadowed = claimedWords(this.pkg).filter((c) => prose.has(c.word.toLowerCase()));\n\t\tif (shadowed.length > 0) {\n\t\t\tconst list = shadowed.map((s) => `\"${s.word}\" (${s.via})`).join(\", \");\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"PACKAGE_SHADOWS_PROSE\",\n\t\t\t\tmessage: `Package \"${this.pkg.name}\" claims prose word(s) as syntax: ${list}. A word that is also ordinary English turns prose into arithmetic; prefer a multi-word phrase or a form that requires a parenthesis.`,\n\t\t\t\texpected: \"no prose words claimed as syntax\",\n\t\t\t\tactual: list,\n\t\t\t});\n\t\t}\n\t\treturn shadowed;\n\t}\n\n\t/**\n\t * Assert the package does not collide with any of `others` in a way that\n\t * would silently break one of them (two packages claiming the same lexer\n\t * keyword, plugin-function index, async-resolver namespace, and so on).\n\t *\n\t * `strictness` sets which severities fail the assertion: `\"error\"` (the\n\t * default) fails only on the collisions that always break something,\n\t * `\"warning\"` also fails on the ones that silently pick a winner, `\"info\"`\n\t * fails on cosmetic overlaps too.\n\t *\n\t * @returns the full compatibility report, so a test can inspect every\n\t * conflict, including ones below the strictness threshold.\n\t */\n\tnotToCollideWith(\n\t\tothers: IEnginePackage[],\n\t\tstrictness: CollisionStrictness = \"error\",\n\t): CompatibilityReport {\n\t\tconst report = checkPackageCompatibility(this.pkg, others);\n\t\tconst threshold = SEVERITY_ORDER.indexOf(strictness);\n\t\tconst failing = report.conflicts.filter(\n\t\t\t(c: CompatibilityConflict) => SEVERITY_ORDER.indexOf(c.severity) <= threshold,\n\t\t);\n\t\tif (failing.length > 0) {\n\t\t\tconst list = failing.map((c) => `[${c.severity}] ${c.detail}`).join(\"\\n\");\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"PACKAGE_VOCABULARY_COLLISION\",\n\t\t\t\tmessage: `Package \"${this.pkg.name}\" collides with another package:\\n${list}`,\n\t\t\t\texpected: `no conflicts at or above \"${strictness}\" severity`,\n\t\t\t\tactual: `${failing.length} conflict(s)`,\n\t\t\t});\n\t\t}\n\t\treturn report;\n\t}\n\n\t/**\n\t * Assert the package's declared `engineVersion` range is satisfied by the\n\t * running engine (or by `engineVersion` when given).\n\t *\n\t * A package that declares a range and never checks it resolves is the third\n\t * mistake the issue names: it looks fine until the one engine version it\n\t * cannot run against, where the range either fails to match or turns out to\n\t * be a malformed string. A package with no declared range passes (no\n\t * constraint is always compatible).\n\t */\n\ttoDeclareCompatibleEngineVersion(engineVersion: string = ENGINE_VERSION): this {\n\t\tconst result = checkEngineVersionCompatibility(this.pkg, engineVersion);\n\t\tif (!result.compatible) {\n\t\t\tconst detail =\n\t\t\t\tresult.reason === \"invalid-range\"\n\t\t\t\t\t? `its range \"${result.declaredRange}\" is not valid semver`\n\t\t\t\t\t: `its range \"${result.declaredRange}\" is not satisfied by engine version \"${result.engineVersion}\"`;\n\t\t\tthrow new ExpectationError({\n\t\t\t\tcode: \"PACKAGE_ENGINE_VERSION_INCOMPATIBLE\",\n\t\t\t\tmessage: `Package \"${this.pkg.name}\" declares an engineVersion that will be rejected at registration: ${detail}.`,\n\t\t\t\texpected: `an engineVersion satisfied by \"${engineVersion}\"`,\n\t\t\t\tactual: `\"${result.declaredRange}\"`,\n\t\t\t});\n\t\t}\n\t\treturn this;\n\t}\n}\n\n/**\n * Begin an assertion about a package's declared descriptor.\n *\n * @example\n * ```ts\n * expectPackage(myPackage).notToShadow([\"price\", \"in\", \"of\"]);\n * expectPackage(myPackage).notToCollideWith(BUILTIN_PACKAGES);\n * expectPackage(myPackage).toDeclareCompatibleEngineVersion();\n * ```\n */\nexport function expectPackage(pkg: IEnginePackage): PackageAssertion {\n\treturn new PackageAssertion(pkg);\n}\n\n//#endregion\n"]}
|
package/dist/worker.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var chunk7DJYS5PO_cjs=require('./chunk-7DJYS5PO.cjs'),
|
|
2
|
-
`).forEach((u,d)=>a.set(d+1,u)):o.method==="evaluateLines"?o.args[0].forEach((u,d)=>a.set(d+1,u)):a.set(-1,o.args[0]),a},V=(o,a)=>{if(a.type==="error"){g({kind:"async-error",queryKey:a.queryKey,packageId:a.packageId,error:chunk7DJYS5PO_cjs.b(chunkSUAGBRQ7_cjs.d(a.error))});return}let u=[];for(let d of a.lineNumbers){let f=l.get(d);if(f!==void 0)try{let T=o.evaluateLine(d,f);T&&u.push({lineNumber:d,value:m(T,s)});}catch{}}u.length>0&&g({kind:"async-update",lines:u});},U=o=>{p?.();let a=o.getEventStream().getReader();p=()=>{a.cancel();},(async()=>{try{for(;;){let{done:u,value:d}=await a.read();if(u)return;V(o,d);}}catch{}})();},j=o=>{try{let a=$(n,o.packages);t=new
|
|
1
|
+
'use strict';var chunk7DJYS5PO_cjs=require('./chunk-7DJYS5PO.cjs'),chunkJPT6L7BG_cjs=require('./chunk-JPT6L7BG.cjs');require('./chunk-Q7TBBV62.cjs'),require('./chunk-NGBBNL4K.cjs'),require('./chunk-ZVPZQ66D.cjs'),require('./chunk-TTFO4YDP.cjs'),require('./chunk-GWV273KZ.cjs'),require('./chunk-HG4NPDN5.cjs');var chunkP43SV4NJ_cjs=require('./chunk-P43SV4NJ.cjs');require('./chunk-R2SZFJTT.cjs');var chunkW7NN77PH_cjs=require('./chunk-W7NN77PH.cjs');require('./chunk-A755LVPT.cjs');var chunkWQGHJAW2_cjs=require('./chunk-WQGHJAW2.cjs');require('./chunk-5AKT36UK.cjs'),require('./chunk-4DR5RBHQ.cjs'),require('./chunk-UURM7P3P.cjs'),require('./chunk-ZLRJ7TDP.cjs'),require('./chunk-RAFOQ4T5.cjs'),require('./chunk-CM2WM5CM.cjs'),require('./chunk-DUFEONVN.cjs'),require('./chunk-ABVDKMNF.cjs'),require('./chunk-TLG7VZRX.cjs');var chunk5TVI2UPZ_cjs=require('./chunk-5TVI2UPZ.cjs'),chunkYWF6C2IO_cjs=require('./chunk-YWF6C2IO.cjs');require('./chunk-A764BY7L.cjs'),require('./chunk-E4HAKNBQ.cjs'),require('./chunk-OM7NOHJF.cjs'),require('./chunk-ZKFCKAIX.cjs');var chunkUHS4HMOQ_cjs=require('./chunk-UHS4HMOQ.cjs');require('./chunk-AGCNMEP2.cjs'),require('./chunk-Y7O4D3BJ.cjs'),require('./chunk-WU7SBKVU.cjs'),require('./chunk-YBQOQTVL.cjs'),require('./chunk-S3DFU33X.cjs'),require('./chunk-J4LSAHCY.cjs'),require('./chunk-EZKR44MA.cjs');var chunkSUAGBRQ7_cjs=require('./chunk-SUAGBRQ7.cjs');function B(e){if(e?.date?.inputOrder!=="locale")return e;let r={...e.date,inputOrder:chunkWQGHJAW2_cjs.h({...chunkUHS4HMOQ_cjs.b.date,...e.date}).order};return delete r.inputLocale,{...e,date:r}}var x=class{constructor(r){this.nextId=1;this.pending=new Map;this.resolvedListeners=new Set;this.asyncErrorListeners=new Set;this.terminated=false;this.transport=r,this.transport.onMessage(n=>this.onMessage(n));}init(r){let n=this.nextId++;return new Promise((t,s)=>{this.pending.set(n,{resolve:()=>t(),reject:s}),this.transport.postMessage({kind:"init",id:n,localeCode:r.localeCode,diagnostics:r.diagnostics,config:B(r.config),packages:r.packages,formatting:r.formatting});})}parseDocument(r,n){let{signal:t,...s}=n??{},i=Object.keys(s).length>0?s:void 0;return this.call("parseDocument",[r,i],t)}evaluateLines(r,n){return this.call("evaluateLines",[r],n?.signal)}evaluateExpression(r,n){return this.call("evaluateExpression",[r],n?.signal)}onResolved(r){return this.resolvedListeners.add(r),()=>this.resolvedListeners.delete(r)}onAsyncError(r){return this.asyncErrorListeners.add(r),()=>this.asyncErrorListeners.delete(r)}terminate(){if(this.terminated)return;this.terminated=true;let r=chunk7DJYS5PO_cjs.e();for(let n of this.pending.values())this.unhook(n),n.reject(r);this.pending.clear(),this.resolvedListeners.clear(),this.asyncErrorListeners.clear(),this.transport.terminate();}call(r,n,t){if(this.terminated)return Promise.reject(chunk7DJYS5PO_cjs.e());if(t?.aborted)return Promise.reject(chunk7DJYS5PO_cjs.d(r));let s=this.nextId++;return new Promise((i,l)=>{let c={resolve:i,reject:l};if(t){let p=()=>{this.pending.has(s)&&(this.pending.delete(s),this.transport.postMessage({kind:"cancel",id:s}),l(chunk7DJYS5PO_cjs.d(r)));};c.signal=t,c.onAbort=p,t.addEventListener("abort",p,{once:true});}this.pending.set(s,c),this.transport.postMessage({kind:"request",id:s,method:r,args:n});})}onMessage(r){let n=r;switch(n.kind){case "ready":case "result":{let t=n.kind==="result"?n.value:void 0;this.settle(n.id,s=>s.resolve(t));break}case "error":this.settle(n.id,t=>t.reject(chunk7DJYS5PO_cjs.c(n.error)));break;case "async-update":for(let t of [...this.resolvedListeners])t(n.lines);break;case "async-error":for(let t of [...this.asyncErrorListeners])t({queryKey:n.queryKey,packageId:n.packageId,error:chunk7DJYS5PO_cjs.c(n.error)});break}}settle(r,n){let t=this.pending.get(r);t&&(this.pending.delete(r),this.unhook(t),n(t));}unhook(r){r.signal&&r.onAbort&&r.signal.removeEventListener("abort",r.onAbort);}};async function G(e){let r=new x(e.transport);return await r.init(e),r}function F(e){return e>0?"Infinity":e<0?"-Infinity":"NaN"}function H(e){let r=e.data.map(n=>typeof n=="object"&&n!==null?chunkYWF6C2IO_cjs.R(n):typeof n=="number"&&!Number.isFinite(n)?F(n):n);return {rows:e.rows,cols:e.cols,cells:r,hasSymbolic:e.hasSymbolic}}function m(e,r){let n=e.toNumber(),t={type:e.type,text:chunkP43SV4NJ_cjs.c(e,r),number:Number.isFinite(n)?n:0};Number.isFinite(n)||(t.nonFinite=F(n)),e.unit!==void 0&&(t.unit=e.unit),e.timedOut!==void 0&&(t.timedOut=e.timedOut),e.grain!==void 0&&(t.grain=e.grain),e.zone!==void 0&&(t.zone=e.zone);let s=e.value;if(typeof s=="bigint")t.bigint=s.toString();else if(e.type===7)t.matrix=H(s);else if(e.type===8){let i=s;t.range={min:i.min,max:i.max};}else if(e.type===14){let i=s;t.colour={hex:chunk5TVI2UPZ_cjs.f(i),r:i.r,g:i.g,b:i.b,a:i.a,format:i.format,css:chunk5TVI2UPZ_cjs.g(i)};}else if(e.type===16){let i=s;t.chart={kind:i.kind,points:i.points.map(l=>[l[0],l[1]]),label:i.label,domain:[i.domain[0],i.domain[1]],range:[i.range[0],i.range[1]],...i.expr!==void 0?{expr:i.expr}:{}};}else if(e.type===17){let i=s;t.ipCidr={...i.addr!==void 0?{addr:i.addr}:{},...i.prefix!==void 0?{prefix:i.prefix}:{},text:chunkP43SV4NJ_cjs.c(e).replace(/^=\s*/,"")};}return t}function q(e,r){return e?m(e,r):null}function J(e,r){return {start:e.start,end:e.end,expression:e.expression,lineNumber:e.lineNumber,columnNumber:e.columnNumber,result:q(e.result,r),error:e.error??null}}function y(e,r){return {lineNumber:e.lineNumber,text:e.text,startPosition:e.startPosition,endPosition:e.endPosition,isEmpty:e.isEmpty,hasInlineSolves:e.hasInlineSolves,inlineSolves:e.inlineSolves.map(n=>J(n,r)),expression:e.expression,result:q(e.result,r),error:e.error}}function R(e,r){let n={lines:e.lines.map(t=>y(t,r)),totalLines:e.totalLines,errors:[...e.errors]};return e.diagnostics!==void 0&&(n.diagnostics=e.diagnostics),n}function $(e,r){if(r===void 0)return e;let n=new Map(e.map(s=>[s.name,s])),t=[];for(let s of r){let i=n.get(s);if(!i)throw chunkSUAGBRQ7_cjs.c.config(chunk7DJYS5PO_cjs.a.WORKER_UNKNOWN_PACKAGE,`No package named "${s}" is available in this worker runtime`,{name:s,available:[...n.keys()]});t.push(i);}return t}function Q(e,r={}){let n=r.packages??chunkW7NN77PH_cjs.z,t=null,s,i=new Map,l=new Map,c=null,p=null,g=o=>e.postMessage(o),E=(o,a)=>{g({kind:"error",id:o,error:chunk7DJYS5PO_cjs.b(chunkSUAGBRQ7_cjs.d(a))});},D=o=>{let a=new Map;return o.method==="parseDocument"?o.args[0].split(`
|
|
2
|
+
`).forEach((u,d)=>a.set(d+1,u)):o.method==="evaluateLines"?o.args[0].forEach((u,d)=>a.set(d+1,u)):a.set(-1,o.args[0]),a},V=(o,a)=>{if(a.type==="error"){g({kind:"async-error",queryKey:a.queryKey,packageId:a.packageId,error:chunk7DJYS5PO_cjs.b(chunkSUAGBRQ7_cjs.d(a.error))});return}let u=[];for(let d of a.lineNumbers){let f=l.get(d);if(f!==void 0)try{let T=o.evaluateLine(d,f);T&&u.push({lineNumber:d,value:m(T,s)});}catch{}}u.length>0&&g({kind:"async-update",lines:u});},U=o=>{p?.();let a=o.getEventStream().getReader();p=()=>{a.cancel();},(async()=>{try{for(;;){let{done:u,value:d}=await a.read();if(u)return;V(o,d);}}catch{}})();},j=o=>{try{let a=$(n,o.packages);t=new chunkJPT6L7BG_cjs.o({locale:o.localeCode??"en",diagnostics:o.diagnostics??!1,config:o.config,packages:a,calendar:r.calendar}),s=r.calendar?{...o.formatting??chunkP43SV4NJ_cjs.a,calendar:r.calendar}:o.formatting,U(t),g({kind:"ready",id:o.id});}catch(a){E(o.id,a);}},K=(o,a)=>{let{method:u,args:d}=a;switch(u){case "parseDocument":return R(o.parseDocument(d[0],d[1]),s);case "evaluateLines":return o.evaluateLines(d[0]).map(f=>y(f,s));case "evaluateExpression":return m(o.evaluateExpression(d[0]),s);default:throw chunkSUAGBRQ7_cjs.c.execution(chunk7DJYS5PO_cjs.a.WORKER_UNKNOWN_METHOD,`The worker runtime has no method named "${String(u)}"`,{method:u})}},_=o=>{let a=t;if(!a){E(o.id,chunkSUAGBRQ7_cjs.c.execution(chunk7DJYS5PO_cjs.a.WORKER_NOT_INITIALISED,"The worker received a request before its engine finished initialising"));return}c?.abort();let u=new AbortController;c=u,l=D(o),i.set(o.id,u),a.setKeystrokeSignal(u.signal);try{let d=K(a,o);g({kind:"result",id:o.id,value:d});}catch(d){E(o.id,d);}finally{i.delete(o.id),a.setKeystrokeSignal(null);}};return e.onMessage(o=>{let a=o;switch(a.kind){case "init":j(a);break;case "request":_(a);break;case "cancel":i.get(a.id)?.abort();break}}),()=>{p?.(),p=null,c?.abort(),c=null,l=new Map;for(let o of i.values())o.abort();i.clear(),t?.clear(),t=null,e.terminate();}}function X(e){return typeof globalThis.structuredClone=="function"?globalThis.structuredClone(e):JSON.parse(JSON.stringify(e))}function Y(){let e=null,r=null,n=true,t=(l,c)=>{let p=X(c);queueMicrotask(()=>{n&&l()?.(p);});};return {client:{postMessage:l=>t(()=>r,l),onMessage:l=>{e=l;},terminate:()=>{n=false;}},host:{postMessage:l=>t(()=>e,l),onMessage:l=>{r=l;},terminate:()=>{n=false;}}}}function Z(e){return {postMessage:r=>e.postMessage(r),onMessage:r=>{let n=t=>r(t.data);typeof e.addEventListener=="function"?e.addEventListener("message",n):e.onmessage=n,e.start?.();},terminate:()=>{e.terminate?.(),e.close?.();}}}function ee(e){return {postMessage:r=>e.postMessage(r),onMessage:r=>{e.on("message",n=>r(n));},terminate:()=>{e.terminate?.(),e.close?.();}}}exports.createLinkedTransports=Y;exports.createWorkerEngine=G;exports.eventTargetTransport=Z;exports.messagePortTransport=ee;exports.serializeParsedLine=y;exports.serializeParsingResult=R;exports.serializeValue=m;exports.startWorkerRuntime=Q;//# sourceMappingURL=worker.cjs.map
|
|
3
3
|
//# sourceMappingURL=worker.cjs.map
|
package/dist/worker.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import {a as a$1,e,d,c as c$2,b}from'./chunk-G3POUURF.js';import {
|
|
2
|
-
`).forEach((u,d)=>a.set(d+1,u)):o.method==="evaluateLines"?o.args[0].forEach((u,d)=>a.set(d+1,u)):a.set(-1,o.args[0]),a},V=(o,a)=>{if(a.type==="error"){g({kind:"async-error",queryKey:a.queryKey,packageId:a.packageId,error:b(d$1(a.error))});return}let u=[];for(let d of a.lineNumbers){let f=l.get(d);if(f!==void 0)try{let T=o.evaluateLine(d,f);T&&u.push({lineNumber:d,value:m(T,s)});}catch{}}u.length>0&&g({kind:"async-update",lines:u});},U=o=>{p?.();let a=o.getEventStream().getReader();p=()=>{a.cancel();},(async()=>{try{for(;;){let{done:u,value:d}=await a.read();if(u)return;V(o,d);}}catch{}})();},j=o=>{try{let a$1=$(n$1
|
|
1
|
+
import {a as a$1,e,d,c as c$2,b}from'./chunk-G3POUURF.js';import {o}from'./chunk-VYB44JLS.js';import'./chunk-CB3EXUM2.js';import'./chunk-2RWAXT6O.js';import'./chunk-IJHL3LMH.js';import'./chunk-MIQBJGGR.js';import'./chunk-2PGGPFF3.js';import'./chunk-JP4JMQOG.js';import {c,a}from'./chunk-IQVSCL2R.js';import'./chunk-XEIDV5JP.js';import {z}from'./chunk-V7LXOTCU.js';import'./chunk-SFM4XFGJ.js';import {h}from'./chunk-FXB5GCBT.js';import'./chunk-VLX7ZVK4.js';import'./chunk-B2NL65FI.js';import'./chunk-76F3LCIL.js';import'./chunk-TCZSPH4A.js';import'./chunk-YN5H54GM.js';import'./chunk-3ZGFAE3Q.js';import'./chunk-PTXUWGRR.js';import'./chunk-TZYMXNIB.js';import'./chunk-HFKDWQUL.js';import {g,f}from'./chunk-5TCSFTZD.js';import {R as R$1}from'./chunk-KH4QXKLT.js';import'./chunk-NQFCXLEF.js';import'./chunk-J4K72CQN.js';import'./chunk-X5K72MBV.js';import'./chunk-4CNYGIND.js';import {b as b$1}from'./chunk-64OGL465.js';import'./chunk-CDE2ZUGG.js';import'./chunk-JPFCXLJV.js';import'./chunk-LP3JYC3A.js';import'./chunk-FAO6DQ74.js';import'./chunk-LHLW7JLS.js';import'./chunk-CHVGFTO3.js';import'./chunk-PRSXXDTA.js';import {c as c$1,d as d$1}from'./chunk-RELMEWY6.js';function B(e){if(e?.date?.inputOrder!=="locale")return e;let r={...e.date,inputOrder:h({...b$1.date,...e.date}).order};return delete r.inputLocale,{...e,date:r}}var x=class{constructor(r){this.nextId=1;this.pending=new Map;this.resolvedListeners=new Set;this.asyncErrorListeners=new Set;this.terminated=false;this.transport=r,this.transport.onMessage(n=>this.onMessage(n));}init(r){let n=this.nextId++;return new Promise((t,s)=>{this.pending.set(n,{resolve:()=>t(),reject:s}),this.transport.postMessage({kind:"init",id:n,localeCode:r.localeCode,diagnostics:r.diagnostics,config:B(r.config),packages:r.packages,formatting:r.formatting});})}parseDocument(r,n){let{signal:t,...s}=n??{},i=Object.keys(s).length>0?s:void 0;return this.call("parseDocument",[r,i],t)}evaluateLines(r,n){return this.call("evaluateLines",[r],n?.signal)}evaluateExpression(r,n){return this.call("evaluateExpression",[r],n?.signal)}onResolved(r){return this.resolvedListeners.add(r),()=>this.resolvedListeners.delete(r)}onAsyncError(r){return this.asyncErrorListeners.add(r),()=>this.asyncErrorListeners.delete(r)}terminate(){if(this.terminated)return;this.terminated=true;let r=e();for(let n of this.pending.values())this.unhook(n),n.reject(r);this.pending.clear(),this.resolvedListeners.clear(),this.asyncErrorListeners.clear(),this.transport.terminate();}call(r,n,t){if(this.terminated)return Promise.reject(e());if(t?.aborted)return Promise.reject(d(r));let s=this.nextId++;return new Promise((i,l)=>{let c={resolve:i,reject:l};if(t){let p=()=>{this.pending.has(s)&&(this.pending.delete(s),this.transport.postMessage({kind:"cancel",id:s}),l(d(r)));};c.signal=t,c.onAbort=p,t.addEventListener("abort",p,{once:true});}this.pending.set(s,c),this.transport.postMessage({kind:"request",id:s,method:r,args:n});})}onMessage(r){let n=r;switch(n.kind){case "ready":case "result":{let t=n.kind==="result"?n.value:void 0;this.settle(n.id,s=>s.resolve(t));break}case "error":this.settle(n.id,t=>t.reject(c$2(n.error)));break;case "async-update":for(let t of [...this.resolvedListeners])t(n.lines);break;case "async-error":for(let t of [...this.asyncErrorListeners])t({queryKey:n.queryKey,packageId:n.packageId,error:c$2(n.error)});break}}settle(r,n){let t=this.pending.get(r);t&&(this.pending.delete(r),this.unhook(t),n(t));}unhook(r){r.signal&&r.onAbort&&r.signal.removeEventListener("abort",r.onAbort);}};async function G(e){let r=new x(e.transport);return await r.init(e),r}function F(e){return e>0?"Infinity":e<0?"-Infinity":"NaN"}function H(e){let r=e.data.map(n=>typeof n=="object"&&n!==null?R$1(n):typeof n=="number"&&!Number.isFinite(n)?F(n):n);return {rows:e.rows,cols:e.cols,cells:r,hasSymbolic:e.hasSymbolic}}function m(e,r){let n=e.toNumber(),t={type:e.type,text:c(e,r),number:Number.isFinite(n)?n:0};Number.isFinite(n)||(t.nonFinite=F(n)),e.unit!==void 0&&(t.unit=e.unit),e.timedOut!==void 0&&(t.timedOut=e.timedOut),e.grain!==void 0&&(t.grain=e.grain),e.zone!==void 0&&(t.zone=e.zone);let s=e.value;if(typeof s=="bigint")t.bigint=s.toString();else if(e.type===7)t.matrix=H(s);else if(e.type===8){let i=s;t.range={min:i.min,max:i.max};}else if(e.type===14){let i=s;t.colour={hex:f(i),r:i.r,g:i.g,b:i.b,a:i.a,format:i.format,css:g(i)};}else if(e.type===16){let i=s;t.chart={kind:i.kind,points:i.points.map(l=>[l[0],l[1]]),label:i.label,domain:[i.domain[0],i.domain[1]],range:[i.range[0],i.range[1]],...i.expr!==void 0?{expr:i.expr}:{}};}else if(e.type===17){let i=s;t.ipCidr={...i.addr!==void 0?{addr:i.addr}:{},...i.prefix!==void 0?{prefix:i.prefix}:{},text:c(e).replace(/^=\s*/,"")};}return t}function q(e,r){return e?m(e,r):null}function J(e,r){return {start:e.start,end:e.end,expression:e.expression,lineNumber:e.lineNumber,columnNumber:e.columnNumber,result:q(e.result,r),error:e.error??null}}function y(e,r){return {lineNumber:e.lineNumber,text:e.text,startPosition:e.startPosition,endPosition:e.endPosition,isEmpty:e.isEmpty,hasInlineSolves:e.hasInlineSolves,inlineSolves:e.inlineSolves.map(n=>J(n,r)),expression:e.expression,result:q(e.result,r),error:e.error}}function R(e,r){let n={lines:e.lines.map(t=>y(t,r)),totalLines:e.totalLines,errors:[...e.errors]};return e.diagnostics!==void 0&&(n.diagnostics=e.diagnostics),n}function $(e,r){if(r===void 0)return e;let n=new Map(e.map(s=>[s.name,s])),t=[];for(let s of r){let i=n.get(s);if(!i)throw c$1.config(a$1.WORKER_UNKNOWN_PACKAGE,`No package named "${s}" is available in this worker runtime`,{name:s,available:[...n.keys()]});t.push(i);}return t}function Q(e,r={}){let n=r.packages??z,t=null,s,i=new Map,l=new Map,c=null,p=null,g=o=>e.postMessage(o),E=(o,a)=>{g({kind:"error",id:o,error:b(d$1(a))});},D=o=>{let a=new Map;return o.method==="parseDocument"?o.args[0].split(`
|
|
2
|
+
`).forEach((u,d)=>a.set(d+1,u)):o.method==="evaluateLines"?o.args[0].forEach((u,d)=>a.set(d+1,u)):a.set(-1,o.args[0]),a},V=(o,a)=>{if(a.type==="error"){g({kind:"async-error",queryKey:a.queryKey,packageId:a.packageId,error:b(d$1(a.error))});return}let u=[];for(let d of a.lineNumbers){let f=l.get(d);if(f!==void 0)try{let T=o.evaluateLine(d,f);T&&u.push({lineNumber:d,value:m(T,s)});}catch{}}u.length>0&&g({kind:"async-update",lines:u});},U=o=>{p?.();let a=o.getEventStream().getReader();p=()=>{a.cancel();},(async()=>{try{for(;;){let{done:u,value:d}=await a.read();if(u)return;V(o,d);}}catch{}})();},j=o$1=>{try{let a$1=$(n,o$1.packages);t=new o({locale:o$1.localeCode??"en",diagnostics:o$1.diagnostics??!1,config:o$1.config,packages:a$1,calendar:r.calendar}),s=r.calendar?{...o$1.formatting??a,calendar:r.calendar}:o$1.formatting,U(t),g({kind:"ready",id:o$1.id});}catch(a){E(o$1.id,a);}},K=(o,a)=>{let{method:u,args:d}=a;switch(u){case "parseDocument":return R(o.parseDocument(d[0],d[1]),s);case "evaluateLines":return o.evaluateLines(d[0]).map(f=>y(f,s));case "evaluateExpression":return m(o.evaluateExpression(d[0]),s);default:throw c$1.execution(a$1.WORKER_UNKNOWN_METHOD,`The worker runtime has no method named "${String(u)}"`,{method:u})}},_=o=>{let a=t;if(!a){E(o.id,c$1.execution(a$1.WORKER_NOT_INITIALISED,"The worker received a request before its engine finished initialising"));return}c?.abort();let u=new AbortController;c=u,l=D(o),i.set(o.id,u),a.setKeystrokeSignal(u.signal);try{let d=K(a,o);g({kind:"result",id:o.id,value:d});}catch(d){E(o.id,d);}finally{i.delete(o.id),a.setKeystrokeSignal(null);}};return e.onMessage(o=>{let a=o;switch(a.kind){case "init":j(a);break;case "request":_(a);break;case "cancel":i.get(a.id)?.abort();break}}),()=>{p?.(),p=null,c?.abort(),c=null,l=new Map;for(let o of i.values())o.abort();i.clear(),t?.clear(),t=null,e.terminate();}}function X(e){return typeof globalThis.structuredClone=="function"?globalThis.structuredClone(e):JSON.parse(JSON.stringify(e))}function Y(){let e=null,r=null,n=true,t=(l,c)=>{let p=X(c);queueMicrotask(()=>{n&&l()?.(p);});};return {client:{postMessage:l=>t(()=>r,l),onMessage:l=>{e=l;},terminate:()=>{n=false;}},host:{postMessage:l=>t(()=>e,l),onMessage:l=>{r=l;},terminate:()=>{n=false;}}}}function Z(e){return {postMessage:r=>e.postMessage(r),onMessage:r=>{let n=t=>r(t.data);typeof e.addEventListener=="function"?e.addEventListener("message",n):e.onmessage=n,e.start?.();},terminate:()=>{e.terminate?.(),e.close?.();}}}function ee(e){return {postMessage:r=>e.postMessage(r),onMessage:r=>{e.on("message",n=>r(n));},terminate:()=>{e.terminate?.(),e.close?.();}}}export{Y as createLinkedTransports,G as createWorkerEngine,Z as eventTargetTransport,ee as messagePortTransport,y as serializeParsedLine,R as serializeParsingResult,m as serializeValue,Q as startWorkerRuntime};//# sourceMappingURL=worker.js.map
|
|
3
3
|
//# sourceMappingURL=worker.js.map
|
package/dist/worker.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/worker/client.ts","../src/worker/serialize.ts","../src/worker/runtime.ts","../src/worker/transport.ts"],"names":["resolveDateOrderForWorker","config","date","resolveDateOrderPolicy","DEFAULT_CONFIG","WorkerEngineClient","transport","raw","options","id","resolve","reject","input","signal","parsing","parseOptions","lines","expression","listener","error","workerTerminatedError","entry","method","args","workerCancelledError","onAbort","message","value","deserializeEngineError","apply","createWorkerEngine","client","nonFiniteTag","n","serializeMatrix","m","cells","cell","formatSymbolic","serializeValue","settings","reading","dto","formatValue","r","c","toHexString","formatColour","pt","ip","serializeMaybe","serializeInlineSolve","solve","serializeParsedLine","line","serializeParsingResult","result","resolvePackages","available","names","byName","pkg","resolved","name","ErrorFactory","WorkerErrorCodes","startWorkerRuntime","BUILTIN_PACKAGES","engine","formatting","inFlight","retainedLines","documentController","stopEventPump","post","fail","serializeEngineError","normalizeUnknownError","retainLines","map","text","index","handleAsyncEvent","eng","event","lineNumber","startEventPump","reader","done","handleInit","packages","ExpressionEngine","DEFAULT_FORMATTING_SETTINGS","runMethod","handleRequest","controller","cloneMessage","createLinkedTransports","clientHandler","hostHandler","alive","deliver","target","cloned","handler","eventTargetTransport","messagePortTransport","port"],"mappings":"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","file":"worker.js","sourcesContent":["/**\n * The main-side half of the harness: an async proxy of the core evaluate\n * methods.\n *\n * {@link createWorkerEngine} performs the init handshake and resolves once the\n * worker's engine is built, so the returned {@link WorkerEngine} is ready to\n * call. Each call stamps a request id, tracks the pending promise, and settles\n * it when the matching answer arrives, so several requests can be outstanding at\n * once. An `AbortSignal` rejects the local promise and posts a `cancel` for the\n * same id, mapping keystroke-level cancellation onto the boundary rather than\n * re-inventing it.\n */\n\nimport { DEFAULT_CONFIG, type EngineConfigOverride } from \"@solve-js/constants/Configuration\";\nimport { resolveDateOrderPolicy } from \"@solve-js/packages/datetime/DateReading\";\nimport type { UnifiedParsingOptions } from \"@solve-js/types/ParsingResult\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport type { EngineError } from \"@solve-js/errors\";\nimport {\n\tdeserializeEngineError,\n\tworkerCancelledError,\n\tworkerTerminatedError,\n} from \"@solve-js/errors\";\nimport type { WorkerTransport } from \"./transport\";\nimport type {\n\tWorkerMethod,\n\tWorkerRequestArgs,\n\tWorkerToMainMessage,\n} from \"./protocol\";\nimport type {\n\tSerializedWorkerValue,\n\tSerializedParsedLine,\n\tSerializedParsingResult,\n} from \"./dto\";\n\n/** Configuration for {@link createWorkerEngine}. */\nexport interface WorkerEngineOptions {\n\t/** The channel to the worker runtime. See `worker/transport.ts` for adapters. */\n\ttransport: WorkerTransport;\n\t/** Locale for keywords and number formatting; defaults to English worker-side. */\n\tlocaleCode?: string;\n\t/** Whether the worker builds its engine with diagnostics enabled. */\n\tdiagnostics?: boolean;\n\t/** Config overrides, merged per section over the defaults worker-side. */\n\tconfig?: EngineConfigOverride;\n\t/**\n\t * Names of built-in packages the worker should register. Omitted registers\n\t * them all. Names rather than the packages themselves, since a package\n\t * carries functions that cannot cross a `postMessage` boundary; a host with\n\t * a custom package bakes it into its own worker entry and selects it here by\n\t * name.\n\t */\n\tpackages?: string[];\n\t/** Formatting settings the worker uses when it renders a DTO's display text. */\n\tformatting?: FormattingSettings;\n}\n\n/** Per-call options common to every proxied method. */\nexport interface WorkerCallOptions {\n\t/** Abort the request. Rejects the returned promise and cancels the work worker-side. */\n\tsignal?: AbortSignal;\n}\n\n/**\n * One line whose result changed after a live value resolved worker-side, carried\n * as its freshly re-evaluated {@link SerializedWorkerValue}. The value the host renders\n * against `lineNumber`, recovered worker-side so the main thread needs no further\n * round-trip to display it.\n */\nexport interface WorkerAsyncUpdate {\n\tlineNumber: number;\n\tvalue: SerializedWorkerValue;\n}\n\n/**\n * A live-data resolution that failed worker-side. `error` is the same structured\n * {@link EngineError} an in-process resolver failure would surface, rebuilt from\n * its transported form, so a host branches on `code`/`category` as it always has.\n */\nexport interface WorkerAsyncError {\n\tqueryKey: string;\n\tpackageId: string;\n\terror: EngineError;\n}\n\n/**\n * An async proxy of {@link ExpressionEngine}'s core evaluate methods.\n *\n * Each method mirrors its synchronous counterpart but returns a Promise of the\n * serialisable DTO rather than a live `Value`, and accepts an `AbortSignal`.\n */\nexport interface WorkerEngine {\n\t/** Parse a whole document off-thread. Mirrors `ExpressionEngine.parseDocument`. */\n\tparseDocument(input: string, options?: UnifiedParsingOptions & WorkerCallOptions): Promise<SerializedParsingResult>;\n\t/** Evaluate an array of lines off-thread. Mirrors `ExpressionEngine.evaluateLines`. */\n\tevaluateLines(lines: string[], options?: WorkerCallOptions): Promise<SerializedParsedLine[]>;\n\t/** Evaluate a single expression off-thread. Mirrors `ExpressionEngine.evaluateExpression`. */\n\tevaluateExpression(expression: string, options?: WorkerCallOptions): Promise<SerializedWorkerValue>;\n\t/**\n\t * Subscribe to live-data resolutions that land after a request already\n\t * answered.\n\t *\n\t * A currency, weather or historical-rate value resolves inside the worker some\n\t * time after `parseDocument` returned its pending result. When it does, the\n\t * affected lines are re-evaluated worker-side and their fresh values arrive\n\t * here as one batch. This is a subscription rather than a per-request promise\n\t * because a resolution is tied to no single request: it belongs to whichever\n\t * document is current when the value lands. Returns an unsubscribe function.\n\t */\n\tonResolved(listener: (lines: WorkerAsyncUpdate[]) => void): () => void;\n\t/**\n\t * Subscribe to live-data resolutions that failed. Returns an unsubscribe\n\t * function. See {@link onResolved}; this is its failure channel.\n\t */\n\tonAsyncError(listener: (error: WorkerAsyncError) => void): () => void;\n\t/** Reject every in-flight request and tear the transport down. Idempotent. */\n\tterminate(): void;\n}\n\n/** A promise awaiting one worker answer, plus the abort wiring to unhook when it settles. */\ninterface PendingRequest {\n\tresolve: (value: unknown) => void;\n\treject: (error: unknown) => void;\n\tsignal?: AbortSignal;\n\tonAbort?: () => void;\n}\n\n/**\n * Replaces `date.inputOrder: 'locale'` with the order this side resolves it\n * to, before the config crosses to the worker.\n *\n * `'locale'` means \"ask the reader's machine\", and the reader's machine is\n * this one. A worker re-inferring it would be asking a different environment\n * the same question: a worker thread can carry different `Intl` data (a\n * bundler-provided shim, a small-ICU runtime), so the same document could be\n * read day-first on the main thread and month-first in the worker with nothing\n * to show for it. The resolved order crosses instead, so both sides read the\n * document the same way, and `date.inputLocale` is dropped with it because it\n * has already done its work.\n *\n * Anything else passes through untouched, including an absent config.\n */\nfunction resolveDateOrderForWorker(config: EngineConfigOverride | undefined): EngineConfigOverride | undefined {\n\tif (config?.date?.inputOrder !== \"locale\") return config;\n\tconst date = { ...config.date, inputOrder: resolveDateOrderPolicy({ ...DEFAULT_CONFIG.date, ...config.date }).order };\n\tdelete date.inputLocale;\n\treturn { ...config, date };\n}\n\nclass WorkerEngineClient implements WorkerEngine {\n\tprivate readonly transport: WorkerTransport;\n\tprivate nextId = 1;\n\tprivate readonly pending = new Map<number, PendingRequest>();\n\t// Broadcast subscribers for async resolutions. Sets, not one callback each, so\n\t// several views can watch the same worker; a resolution is not tied to a\n\t// request id, so these live outside `pending`.\n\tprivate readonly resolvedListeners = new Set<(lines: WorkerAsyncUpdate[]) => void>();\n\tprivate readonly asyncErrorListeners = new Set<(error: WorkerAsyncError) => void>();\n\tprivate terminated = false;\n\n\tconstructor(transport: WorkerTransport) {\n\t\tthis.transport = transport;\n\t\tthis.transport.onMessage((raw) => this.onMessage(raw));\n\t}\n\n\t/** Perform the init handshake, resolving once the worker posts `ready`. */\n\tinit(options: WorkerEngineOptions): Promise<void> {\n\t\tconst id = this.nextId++;\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve: () => resolve(), reject });\n\t\t\tthis.transport.postMessage({\n\t\t\t\tkind: \"init\",\n\t\t\t\tid,\n\t\t\t\tlocaleCode: options.localeCode,\n\t\t\t\tdiagnostics: options.diagnostics,\n\t\t\t\tconfig: resolveDateOrderForWorker(options.config),\n\t\t\t\tpackages: options.packages,\n\t\t\t\tformatting: options.formatting,\n\t\t\t});\n\t\t});\n\t}\n\n\tparseDocument(\n\t\tinput: string,\n\t\toptions?: UnifiedParsingOptions & WorkerCallOptions,\n\t): Promise<SerializedParsingResult> {\n\t\t// The signal stays main-side and drives a `cancel`; only the parsing\n\t\t// options cross, so an AbortSignal never reaches `postMessage`.\n\t\tconst { signal, ...parsing } = options ?? {};\n\t\tconst parseOptions = Object.keys(parsing).length > 0 ? (parsing as UnifiedParsingOptions) : undefined;\n\t\treturn this.call<SerializedParsingResult>(\"parseDocument\", [input, parseOptions], signal);\n\t}\n\n\tevaluateLines(lines: string[], options?: WorkerCallOptions): Promise<SerializedParsedLine[]> {\n\t\treturn this.call<SerializedParsedLine[]>(\"evaluateLines\", [lines], options?.signal);\n\t}\n\n\tevaluateExpression(expression: string, options?: WorkerCallOptions): Promise<SerializedWorkerValue> {\n\t\treturn this.call<SerializedWorkerValue>(\"evaluateExpression\", [expression], options?.signal);\n\t}\n\n\tonResolved(listener: (lines: WorkerAsyncUpdate[]) => void): () => void {\n\t\tthis.resolvedListeners.add(listener);\n\t\treturn () => this.resolvedListeners.delete(listener);\n\t}\n\n\tonAsyncError(listener: (error: WorkerAsyncError) => void): () => void {\n\t\tthis.asyncErrorListeners.add(listener);\n\t\treturn () => this.asyncErrorListeners.delete(listener);\n\t}\n\n\tterminate(): void {\n\t\tif (this.terminated) return;\n\t\tthis.terminated = true;\n\t\tconst error = workerTerminatedError();\n\t\tfor (const entry of this.pending.values()) {\n\t\t\tthis.unhook(entry);\n\t\t\tentry.reject(error);\n\t\t}\n\t\tthis.pending.clear();\n\t\t// No more resolutions can arrive across a torn-down transport, so drop the\n\t\t// subscribers rather than leaving them referenced for the client's lifetime.\n\t\tthis.resolvedListeners.clear();\n\t\tthis.asyncErrorListeners.clear();\n\t\tthis.transport.terminate();\n\t}\n\n\t/** Dispatch one request and return the promise that settles on its answer. */\n\tprivate call<T>(method: WorkerMethod, args: WorkerRequestArgs, signal?: AbortSignal): Promise<T> {\n\t\tif (this.terminated) return Promise.reject(workerTerminatedError());\n\t\tif (signal?.aborted) return Promise.reject(workerCancelledError(method));\n\n\t\tconst id = this.nextId++;\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst entry: PendingRequest = { resolve: resolve as (value: unknown) => void, reject };\n\n\t\t\tif (signal) {\n\t\t\t\tconst onAbort = (): void => {\n\t\t\t\t\t// Nothing to do if the answer already arrived and settled this id.\n\t\t\t\t\tif (!this.pending.has(id)) return;\n\t\t\t\t\tthis.pending.delete(id);\n\t\t\t\t\tthis.transport.postMessage({ kind: \"cancel\", id });\n\t\t\t\t\treject(workerCancelledError(method));\n\t\t\t\t};\n\t\t\t\tentry.signal = signal;\n\t\t\t\tentry.onAbort = onAbort;\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t}\n\n\t\t\tthis.pending.set(id, entry);\n\t\t\tthis.transport.postMessage({ kind: \"request\", id, method, args });\n\t\t});\n\t}\n\n\t/** Route one incoming message to the request that is waiting on its id. */\n\tprivate onMessage(raw: unknown): void {\n\t\tconst message = raw as WorkerToMainMessage;\n\t\tswitch (message.kind) {\n\t\t\tcase \"ready\":\n\t\t\tcase \"result\": {\n\t\t\t\tconst value = message.kind === \"result\" ? message.value : undefined;\n\t\t\t\tthis.settle(message.id, (entry) => entry.resolve(value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"error\":\n\t\t\t\tthis.settle(message.id, (entry) => entry.reject(deserializeEngineError(message.error)));\n\t\t\t\tbreak;\n\t\t\tcase \"async-update\":\n\t\t\t\t// A broadcast, not an answer to a request: fan it out to every\n\t\t\t\t// subscriber. A copy of the listener set is iterated so a listener\n\t\t\t\t// that unsubscribes itself mid-callback cannot disturb the walk.\n\t\t\t\tfor (const listener of [...this.resolvedListeners]) listener(message.lines);\n\t\t\t\tbreak;\n\t\t\tcase \"async-error\":\n\t\t\t\tfor (const listener of [...this.asyncErrorListeners]) {\n\t\t\t\t\tlistener({\n\t\t\t\t\t\tqueryKey: message.queryKey,\n\t\t\t\t\t\tpackageId: message.packageId,\n\t\t\t\t\t\terror: deserializeEngineError(message.error),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/** Remove a pending request by id and run the settle callback, if it is still pending. */\n\tprivate settle(id: number, apply: (entry: PendingRequest) => void): void {\n\t\tconst entry = this.pending.get(id);\n\t\tif (!entry) return;\n\t\tthis.pending.delete(id);\n\t\tthis.unhook(entry);\n\t\tapply(entry);\n\t}\n\n\t/** Detach an entry's abort listener so a settled request leaves nothing on the signal. */\n\tprivate unhook(entry: PendingRequest): void {\n\t\tif (entry.signal && entry.onAbort) entry.signal.removeEventListener(\"abort\", entry.onAbort);\n\t}\n}\n\n/**\n * Build a worker-backed engine and wait for it to be ready.\n *\n * ```ts\n * const { client, host } = createLinkedTransports();\n * startWorkerRuntime(host);\n * const engine = await createWorkerEngine({ transport: client });\n * const result = await engine.parseDocument(text);\n * ```\n *\n * In production `client` wraps a real `Worker` (see `eventTargetTransport` /\n * `messagePortTransport`), and `startWorkerRuntime` runs inside that worker.\n */\nexport async function createWorkerEngine(options: WorkerEngineOptions): Promise<WorkerEngine> {\n\tconst client = new WorkerEngineClient(options.transport);\n\tawait client.init(options);\n\treturn client;\n}\n","/**\n * Turn live engine results into the clone-safe DTOs the worker harness posts.\n *\n * These functions run on the worker side, just before a result crosses the\n * boundary, and are also what the main side re-runs on a synchronous result to\n * compare the two paths in tests. They are pure and deterministic given the\n * same {@link FormattingSettings}, so a value serialised on either side is\n * byte-for-byte the same DTO.\n */\n\nimport { Value, ValueType, type MatrixData, type MatrixEntry, type RangeData, type ColourData, type ChartData, type IpCidrData } from \"@solve-js/vm/Value\";\nimport { formatValue } from \"@solve-js/format/FormatEngine\";\nimport { toHexString, formatColour } from \"@solve-js/packages/colour/ColourMath\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport { formatSymbolic } from \"@solve-js/symbolic\";\nimport type { ParsedLine, InlineSolvePosition, ParsingResult } from \"@solve-js/types/ParsingResult\";\nimport type {\n\tSerializedWorkerValue,\n\tSerializedMatrix,\n\tSerializedParsedLine,\n\tSerializedInlineSolve,\n\tSerializedParsingResult,\n} from \"./dto\";\n\n/**\n * The JSON-safe string tag for a non-finite reading. `Infinity`/`-Infinity`/`NaN`\n * cannot cross `JSON` (which turns each into `null`), so this one string form is\n * what survives both `structuredClone` and `JSON`, and a host recovers the value\n * with `Number(tag)`. Shared by the scalar `nonFinite` field and matrix cells.\n */\nfunction nonFiniteTag(n: number): \"Infinity\" | \"-Infinity\" | \"NaN\" {\n\treturn n > 0 ? \"Infinity\" : n < 0 ? \"-Infinity\" : \"NaN\";\n}\n\n/** Project a matrix onto clone-safe cells: finite primitives pass through, symbolic cells and non-finite numbers become strings. */\nfunction serializeMatrix(m: MatrixData): SerializedMatrix {\n\tconst cells = m.data.map((cell: MatrixEntry): number | boolean | string => {\n\t\t// A `SymbolicNode` (the object-typed cell variant) flattens to its display\n\t\t// string. A non-finite number (a `[1/0, 2]` cell) cannot cross JSON any\n\t\t// more than a scalar reading can, so it takes the same string tag rather\n\t\t// than being passed through raw and turned into `null` by `JSON.stringify`\n\t\t// (which would diverge from the `structuredClone` path). A finite number\n\t\t// or a boolean is already clone-safe and passes through.\n\t\tif (typeof cell === \"object\" && cell !== null) return formatSymbolic(cell);\n\t\tif (typeof cell === \"number\" && !Number.isFinite(cell)) return nonFiniteTag(cell);\n\t\treturn cell;\n\t});\n\treturn { rows: m.rows, cols: m.cols, cells, hasSymbolic: m.hasSymbolic };\n}\n\n/**\n * Project a {@link Value} onto a {@link SerializedWorkerValue}.\n *\n * `text` and `number` are set for every value; the type-specific fields are\n * added only where the payload needs them, so the DTO stays minimal and a\n * deep-equal between the two evaluation paths does not trip on a property one\n * side left `undefined`.\n */\nexport function serializeValue(value: Value, settings?: FormattingSettings): SerializedWorkerValue {\n\tconst reading = value.toNumber();\n\tconst dto: SerializedWorkerValue = {\n\t\ttype: value.type,\n\t\ttext: formatValue(value, settings),\n\t\t// A non-finite reading (1/0, 0/0, an overflow) cannot cross JSON, which\n\t\t// turns it into null and breaks the round-trip the DTO guarantees. Keep\n\t\t// `number` finite and name the real value in `nonFinite` instead.\n\t\tnumber: Number.isFinite(reading) ? reading : 0,\n\t};\n\tif (!Number.isFinite(reading)) {\n\t\tdto.nonFinite = nonFiniteTag(reading);\n\t}\n\n\tif (value.unit !== undefined) dto.unit = value.unit;\n\tif (value.timedOut !== undefined) dto.timedOut = value.timedOut;\n\t// The two datetime sidecars cross as themselves: both are plain JSON\n\t// scalars, so the clone guarantee is untouched, and a worker result that\n\t// dropped them would answer a different question from the synchronous one.\n\tif (value.grain !== undefined) dto.grain = value.grain;\n\tif (value.zone !== undefined) dto.zone = value.zone;\n\n\tconst raw = value.value;\n\tif (typeof raw === \"bigint\") {\n\t\t// Covers BigInt values and a Hex value that carries a bigint magnitude:\n\t\t// a base-ten string is the one representation that neither loses\n\t\t// precision nor breaks JSON.\n\t\tdto.bigint = raw.toString();\n\t} else if (value.type === ValueType.Matrix) {\n\t\tdto.matrix = serializeMatrix(raw as MatrixData);\n\t} else if (value.type === ValueType.Range) {\n\t\tconst r = raw as RangeData;\n\t\tdto.range = { min: r.min, max: r.max };\n\t} else if (value.type === ValueType.Colour) {\n\t\tconst c = raw as ColourData;\n\t\tdto.colour = { hex: toHexString(c), r: c.r, g: c.g, b: c.b, a: c.a, format: c.format, css: formatColour(c) };\n\t} else if (value.type === ValueType.Chart) {\n\t\tconst c = raw as ChartData;\n\t\tdto.chart = {\n\t\t\tkind: c.kind,\n\t\t\tpoints: c.points.map((pt) => [pt[0], pt[1]]),\n\t\t\tlabel: c.label,\n\t\t\tdomain: [c.domain[0], c.domain[1]],\n\t\t\trange: [c.range[0], c.range[1]],\n\t\t\t...(c.expr !== undefined ? { expr: c.expr } : {}),\n\t\t};\n\t} else if (value.type === ValueType.IpCidr) {\n\t\tconst ip = raw as IpCidrData;\n\t\tdto.ipCidr = {\n\t\t\t...(ip.addr !== undefined ? { addr: ip.addr } : {}),\n\t\t\t...(ip.prefix !== undefined ? { prefix: ip.prefix } : {}),\n\t\t\ttext: formatValue(value).replace(/^=\\s*/, \"\"),\n\t\t};\n\t}\n\n\treturn dto;\n}\n\n/** Serialise a nullable value, the shape both `result` fields carry. */\nfunction serializeMaybe(value: Value | null | undefined, settings?: FormattingSettings): SerializedWorkerValue | null {\n\treturn value ? serializeValue(value, settings) : null;\n}\n\n/** Project an inline solve onto its DTO, serialising its result. */\nfunction serializeInlineSolve(solve: InlineSolvePosition, settings?: FormattingSettings): SerializedInlineSolve {\n\treturn {\n\t\tstart: solve.start,\n\t\tend: solve.end,\n\t\texpression: solve.expression,\n\t\tlineNumber: solve.lineNumber,\n\t\tcolumnNumber: solve.columnNumber,\n\t\tresult: serializeMaybe(solve.result, settings),\n\t\terror: solve.error ?? null,\n\t};\n}\n\n/** Project a parsed line onto its DTO, serialising its result and every inline solve. */\nexport function serializeParsedLine(line: ParsedLine, settings?: FormattingSettings): SerializedParsedLine {\n\treturn {\n\t\tlineNumber: line.lineNumber,\n\t\ttext: line.text,\n\t\tstartPosition: line.startPosition,\n\t\tendPosition: line.endPosition,\n\t\tisEmpty: line.isEmpty,\n\t\thasInlineSolves: line.hasInlineSolves,\n\t\tinlineSolves: line.inlineSolves.map((solve) => serializeInlineSolve(solve, settings)),\n\t\texpression: line.expression,\n\t\tresult: serializeMaybe(line.result, settings),\n\t\terror: line.error,\n\t};\n}\n\n/** Project a whole parsing result onto its DTO. */\nexport function serializeParsingResult(result: ParsingResult, settings?: FormattingSettings): SerializedParsingResult {\n\tconst dto: SerializedParsingResult = {\n\t\tlines: result.lines.map((line) => serializeParsedLine(line, settings)),\n\t\ttotalLines: result.totalLines,\n\t\terrors: [...result.errors],\n\t};\n\t// The diagnostics report is already the engine's own JSON form, so it\n\t// crosses unchanged; present only when the host asked for it.\n\tif (result.diagnostics !== undefined) dto.diagnostics = result.diagnostics;\n\treturn dto;\n}\n","/**\n * The worker-side half of the harness: it owns an {@link ExpressionEngine} and\n * answers the protocol.\n *\n * {@link startWorkerRuntime} is transport-agnostic, so the same function runs\n * behind a browser `Worker`, a Node `worker_threads` port, or an in-process\n * link. A host's worker entry file is two lines: adapt the environment onto a\n * {@link WorkerTransport} and call this.\n *\n * The runtime never posts a raw {@link Value}. Every result is projected onto a\n * DTO first (`worker/serialize.ts`), and every failure is caught and flattened\n * into a structured error, so a worker-side throw reaches the caller as an\n * `EngineError` rather than a lost promise.\n */\n\nimport { ExpressionEngine } from \"@solve-js/engine/ExpressionEngine\";\nimport type { AsyncResolutionEvent } from \"@solve-js/engine/AsyncResolutionBatcher\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport { DEFAULT_FORMATTING_SETTINGS, type FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport type { CalendarBackend } from \"@solve-js/calendar/CalendarBackend\";\nimport {\n\tErrorFactory,\n\tnormalizeUnknownError,\n\tserializeEngineError,\n\tWorkerErrorCodes,\n} from \"@solve-js/errors\";\nimport { serializeParsingResult, serializeParsedLine, serializeValue } from \"./serialize\";\nimport type { WorkerTransport } from \"./transport\";\nimport type {\n\tMainToWorkerMessage,\n\tInitMessage,\n\tRequestMessage,\n\tWorkerToMainMessage,\n\tAsyncResolvedLine,\n} from \"./protocol\";\n\n/** Options a host bakes into its own worker entry: its custom packages, and its calendar backend. */\nexport interface WorkerRuntimeOptions {\n\t/**\n\t * The packages available to register, defaulting to {@link BUILTIN_PACKAGES}.\n\t * A host with its own package authors a worker entry that passes them here,\n\t * then selects among them by name from the main side. This is how a\n\t * function-carrying package reaches the worker: baked into its bundle, never\n\t * posted across the boundary.\n\t */\n\tpackages?: IEnginePackage[];\n\t/**\n\t * The calendar backend the worker's engine computes dates with, and writes\n\t * them out with, as the engine's own `calendar` option. Defaults to the\n\t * built-in `Date` backend. Baked in here for the same reason a package is:\n\t * a backend is an object of functions and cannot be posted across the\n\t * boundary, so the main side's formatting settings never carry one.\n\t */\n\tcalendar?: CalendarBackend;\n}\n\n/**\n * Resolve the requested package names against the available set.\n *\n * Undefined names means \"all of them\". A name with no match is a configuration\n * failure the caller must see, not a silent omission that would leave a feature\n * quietly missing from every result.\n */\nfunction resolvePackages(available: IEnginePackage[], names: string[] | undefined): IEnginePackage[] {\n\tif (names === undefined) return available;\n\tconst byName = new Map(available.map((pkg) => [pkg.name, pkg]));\n\tconst resolved: IEnginePackage[] = [];\n\tfor (const name of names) {\n\t\tconst pkg = byName.get(name);\n\t\tif (!pkg) {\n\t\t\tthrow ErrorFactory.config(\n\t\t\t\tWorkerErrorCodes.WORKER_UNKNOWN_PACKAGE,\n\t\t\t\t`No package named \"${name}\" is available in this worker runtime`,\n\t\t\t\t{ name, available: [...byName.keys()] },\n\t\t\t);\n\t\t}\n\t\tresolved.push(pkg);\n\t}\n\treturn resolved;\n}\n\n/**\n * Attach the runtime to a transport and start serving.\n *\n * Returns a teardown function that clears the engine and detaches, for a host\n * that reuses a transport or shuts a worker down cleanly.\n */\nexport function startWorkerRuntime(transport: WorkerTransport, options: WorkerRuntimeOptions = {}): () => void {\n\tconst available = options.packages ?? BUILTIN_PACKAGES;\n\n\tlet engine: ExpressionEngine | null = null;\n\tlet formatting: FormattingSettings | undefined;\n\t// One AbortController per in-flight request, so a `cancel` can map onto the\n\t// engine's keystroke signal for exactly the request the caller aborted.\n\tconst inFlight = new Map<number, AbortController>();\n\n\t// The line texts of the current document, keyed by the line number the engine\n\t// evaluates them under (1-based for a document, -1 for a lone expression). An\n\t// async resolution names the lines whose result changed but not the new value,\n\t// so this is what the event pump re-reads a line from to recover it.\n\tlet retainedLines = new Map<number, string>();\n\n\t// The current document's abort controller, kept alive past the request that\n\t// created it so this document's async resolutions can still land. Aborted when\n\t// a new document supersedes it: aborting drops the old document's in-flight\n\t// resolutions at the engine's own staleness guard (an aborted signal is\n\t// discarded before it reaches the batcher), so a stale value never reaches the\n\t// host as if it were current. See {@link handleRequest}.\n\tlet documentController: AbortController | null = null;\n\n\t// Cancels the event-stream reader on teardown. Null until the pump starts.\n\tlet stopEventPump: (() => void) | null = null;\n\n\tconst post = (message: WorkerToMainMessage): void => transport.postMessage(message);\n\n\tconst fail = (id: number, error: unknown): void => {\n\t\tpost({ kind: \"error\", id, error: serializeEngineError(normalizeUnknownError(error)) });\n\t};\n\n\t/**\n\t * Record the line texts a request evaluates, so a later async resolution can\n\t * re-read exactly the lines it names. A whole document splits into 1-based\n\t * lines; a lone `evaluateExpression` maps onto the engine's `-1` sentinel, the\n\t * same line number the engine registers and later reports for it.\n\t */\n\tconst retainLines = (message: RequestMessage): Map<number, string> => {\n\t\tconst map = new Map<number, string>();\n\t\tif (message.method === \"parseDocument\") {\n\t\t\t(message.args[0] as string).split(\"\\n\").forEach((text, index) => map.set(index + 1, text));\n\t\t} else if (message.method === \"evaluateLines\") {\n\t\t\t(message.args[0] as string[]).forEach((text, index) => map.set(index + 1, text));\n\t\t} else {\n\t\t\tmap.set(-1, message.args[0] as string);\n\t\t}\n\t\treturn map;\n\t};\n\n\t/**\n\t * Turn one async resolution event into a message home.\n\t *\n\t * A `lines-updated` event names the lines whose result changed; the resolved\n\t * value lives in the engine's cache, so each named line is re-evaluated (which\n\t * now reads the settled value from that cache rather than starting a fresh\n\t * fetch) and serialised. A line the current document no longer retains belongs\n\t * to a superseded document and is skipped. An `error` event carries the failed\n\t * query straight across as a structured error.\n\t */\n\tconst handleAsyncEvent = (eng: ExpressionEngine, event: AsyncResolutionEvent): void => {\n\t\tif (event.type === \"error\") {\n\t\t\tpost({\n\t\t\t\tkind: \"async-error\",\n\t\t\t\tqueryKey: event.queryKey,\n\t\t\t\tpackageId: event.packageId,\n\t\t\t\terror: serializeEngineError(normalizeUnknownError(event.error)),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst lines: AsyncResolvedLine[] = [];\n\t\tfor (const lineNumber of event.lineNumbers) {\n\t\t\tconst text = retainedLines.get(lineNumber);\n\t\t\tif (text === undefined) continue;\n\t\t\ttry {\n\t\t\t\tconst value = eng.evaluateLine(lineNumber, text);\n\t\t\t\tif (value) lines.push({ lineNumber, value: serializeValue(value, formatting) });\n\t\t\t} catch {\n\t\t\t\t// A line that resolved into an error re-throws on re-evaluation; the\n\t\t\t\t// batcher's own `error` event is the channel for that, so this keeps\n\t\t\t\t// the update to the lines that produced a value rather than posting a\n\t\t\t\t// second, half-formed failure here.\n\t\t\t}\n\t\t}\n\t\tif (lines.length > 0) post({ kind: \"async-update\", lines });\n\t};\n\n\t/**\n\t * Drain the engine's async-resolution event stream for the life of the\n\t * runtime, posting each event home. Started once the engine exists; the reader\n\t * loop ends when the stream closes (engine cleared) or the returned canceller\n\t * runs at teardown.\n\t */\n\tconst startEventPump = (eng: ExpressionEngine): void => {\n\t\tstopEventPump?.();\n\t\tconst reader = eng.getEventStream().getReader();\n\t\tstopEventPump = () => void reader.cancel();\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) return;\n\t\t\t\t\thandleAsyncEvent(eng, value);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// The stream errored or was cancelled (teardown); the loop is done.\n\t\t\t}\n\t\t})();\n\t};\n\n\tconst handleInit = (message: InitMessage): void => {\n\t\ttry {\n\t\t\tconst packages = resolvePackages(available, message.packages);\n\t\t\tengine = new ExpressionEngine({\n\t\t\t\tlocale: message.localeCode ?? \"en\",\n\t\t\t\tdiagnostics: message.diagnostics ?? false,\n\t\t\t\tconfig: message.config,\n\t\t\t\tpackages,\n\t\t\t\tcalendar: options.calendar,\n\t\t\t});\n\t\t\t// The display reads the same backend the engine computes with, so a\n\t\t\t// date in a DTO names the day it was computed on; the main side's\n\t\t\t// settings cannot carry the backend, so it is joined here.\n\t\t\tformatting = options.calendar\n\t\t\t\t? { ...(message.formatting ?? DEFAULT_FORMATTING_SETTINGS), calendar: options.calendar }\n\t\t\t\t: message.formatting;\n\t\t\t// Drain live-data resolutions for the engine's whole lifetime, so a\n\t\t\t// value that settles after a request already answered still reaches the\n\t\t\t// host. Started here, after the engine exists, and torn down with it.\n\t\t\tstartEventPump(engine);\n\t\t\tpost({ kind: \"ready\", id: message.id });\n\t\t} catch (error) {\n\t\t\t// A build failure leaves no engine; the caller's `createWorkerEngine`\n\t\t\t// promise rejects with this rather than hanging on a `ready` that\n\t\t\t// never comes.\n\t\t\tfail(message.id, error);\n\t\t}\n\t};\n\n\tconst runMethod = (eng: ExpressionEngine, message: RequestMessage): unknown => {\n\t\tconst { method, args } = message;\n\t\tswitch (method) {\n\t\t\tcase \"parseDocument\":\n\t\t\t\treturn serializeParsingResult(eng.parseDocument(args[0] as string, args[1] as never), formatting);\n\t\t\tcase \"evaluateLines\":\n\t\t\t\treturn eng.evaluateLines(args[0] as string[]).map((line) => serializeParsedLine(line, formatting));\n\t\t\tcase \"evaluateExpression\":\n\t\t\t\t// Mirrors ExpressionEngine.evaluateExpression: a single Value in,\n\t\t\t\t// a single serialized Value out.\n\t\t\t\treturn serializeValue(eng.evaluateExpression(args[0] as string), formatting);\n\t\t\tdefault:\n\t\t\t\tthrow ErrorFactory.execution(\n\t\t\t\t\tWorkerErrorCodes.WORKER_UNKNOWN_METHOD,\n\t\t\t\t\t`The worker runtime has no method named \"${String(method)}\"`,\n\t\t\t\t\t{ method },\n\t\t\t\t);\n\t\t}\n\t};\n\n\tconst handleRequest = (message: RequestMessage): void => {\n\t\tconst eng = engine;\n\t\tif (!eng) {\n\t\t\tfail(\n\t\t\t\tmessage.id,\n\t\t\t\tErrorFactory.execution(\n\t\t\t\t\tWorkerErrorCodes.WORKER_NOT_INITIALISED,\n\t\t\t\t\t\"The worker received a request before its engine finished initialising\",\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Supersede the previous document: abort its controller so any resolution\n\t\t// still in flight for it is dropped at the engine's staleness guard rather\n\t\t// than posted home as if it belonged to this request's document. The old\n\t\t// retained lines go with it. Every evaluate call shares one engine and one\n\t\t// document context, so the most recent call is the live one.\n\t\tdocumentController?.abort();\n\n\t\t// This request's controller doubles as the document controller: wired in as\n\t\t// the keystroke signal so a later `cancel` (or the next supersede) aborts\n\t\t// the async work this evaluation fires, the same mechanism a host uses on\n\t\t// the main thread. It is deliberately NOT aborted when the request settles,\n\t\t// so this document's live values can still resolve and stream back.\n\t\tconst controller = new AbortController();\n\t\tdocumentController = controller;\n\t\tretainedLines = retainLines(message);\n\t\tinFlight.set(message.id, controller);\n\t\teng.setKeystrokeSignal(controller.signal);\n\n\t\ttry {\n\t\t\tconst value = runMethod(eng, message);\n\t\t\tpost({ kind: \"result\", id: message.id, value });\n\t\t} catch (error) {\n\t\t\tfail(message.id, error);\n\t\t} finally {\n\t\t\tinFlight.delete(message.id);\n\t\t\teng.setKeystrokeSignal(null);\n\t\t}\n\t};\n\n\ttransport.onMessage((raw) => {\n\t\tconst message = raw as MainToWorkerMessage;\n\t\tswitch (message.kind) {\n\t\t\tcase \"init\":\n\t\t\t\thandleInit(message);\n\t\t\t\tbreak;\n\t\t\tcase \"request\":\n\t\t\t\thandleRequest(message);\n\t\t\t\tbreak;\n\t\t\tcase \"cancel\":\n\t\t\t\t// Abort maps onto the keystroke signal for the named request; a\n\t\t\t\t// cancel that arrives after the request already settled finds no\n\t\t\t\t// controller and is a harmless no-op.\n\t\t\t\tinFlight.get(message.id)?.abort();\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\treturn () => {\n\t\tstopEventPump?.();\n\t\tstopEventPump = null;\n\t\tdocumentController?.abort();\n\t\tdocumentController = null;\n\t\tretainedLines = new Map();\n\t\tfor (const controller of inFlight.values()) controller.abort();\n\t\tinFlight.clear();\n\t\tengine?.clear();\n\t\tengine = null;\n\t\ttransport.terminate();\n\t};\n}\n","/**\n * The seam between the harness and whatever actually carries messages.\n *\n * Both the client (`worker/client.ts`) and the runtime (`worker/runtime.ts`)\n * talk to a {@link WorkerTransport} and nothing more, so the same code drives a\n * browser `Worker`, a Node `worker_threads` port, or an in-process pair. The\n * three factory functions below adapt each of those onto the interface; a host\n * with a transport this file does not cover can implement the three methods\n * directly.\n */\n\n/**\n * A bidirectional message channel with a single receive handler.\n *\n * `onMessage` registers the one handler the harness needs; calling it again\n * replaces the previous handler. `terminate` tears the channel down and is safe\n * to call more than once.\n */\nexport interface WorkerTransport {\n\t/** Send one message to the other end. The message must be clone-safe. */\n\tpostMessage(message: unknown): void;\n\t/** Register the handler that receives messages from the other end. */\n\tonMessage(handler: (message: unknown) => void): void;\n\t/** Tear the channel down. Idempotent. */\n\tterminate(): void;\n}\n\n/**\n * Clone a message the way `postMessage` would, so an in-process transport has\n * the same value semantics as a real one.\n *\n * The harness protocol is clone-safe by construction, so the `JSON` fallback\n * (for a runtime without a global `structuredClone`) is lossless here; the\n * structured-clone path is preferred because it is what a real worker uses and\n * because it throws loudly if a non-clone-safe value ever reaches it, which is\n * exactly the mistake the DTO layer exists to prevent.\n *\n * A function, not a module-level const, so this module does no work at load\n * time and stays deletable under the package's `sideEffects: false` claim; the\n * `typeof` probe runs once per message, which is free next to the clone itself.\n */\nfunction cloneMessage<T>(value: T): T {\n\treturn typeof globalThis.structuredClone === \"function\"\n\t\t? globalThis.structuredClone(value)\n\t\t: JSON.parse(JSON.stringify(value));\n}\n\n/**\n * A pair of linked in-process transports.\n *\n * `client` and `host` are two ends of one channel: a message posted on either\n * is cloned at post time and delivered to the other on a microtask, so delivery\n * is asynchronous (as a real worker's is) but deterministic (no timers, no I/O).\n * Wire `client` into {@link createWorkerEngine} and `host` into\n * {@link startWorkerRuntime} to run the whole protocol, DTO serialisation and\n * cancellation included, without a second thread. This is the transport tests\n * use, and a fit for a host that wants the message-passing shape on one thread.\n */\nexport function createLinkedTransports(): { client: WorkerTransport; host: WorkerTransport } {\n\tlet clientHandler: ((message: unknown) => void) | null = null;\n\tlet hostHandler: ((message: unknown) => void) | null = null;\n\tlet alive = true;\n\n\t// The handler is read at delivery time rather than post time so setup order\n\t// (post before the other end has registered) cannot drop a message.\n\tconst deliver = (target: () => ((message: unknown) => void) | null, message: unknown): void => {\n\t\tconst cloned = cloneMessage(message);\n\t\tqueueMicrotask(() => {\n\t\t\tif (!alive) return;\n\t\t\ttarget()?.(cloned);\n\t\t});\n\t};\n\n\tconst client: WorkerTransport = {\n\t\tpostMessage: (message) => deliver(() => hostHandler, message),\n\t\tonMessage: (handler) => {\n\t\t\tclientHandler = handler;\n\t\t},\n\t\tterminate: () => {\n\t\t\talive = false;\n\t\t},\n\t};\n\n\tconst host: WorkerTransport = {\n\t\tpostMessage: (message) => deliver(() => clientHandler, message),\n\t\tonMessage: (handler) => {\n\t\t\thostHandler = handler;\n\t\t},\n\t\tterminate: () => {\n\t\t\talive = false;\n\t\t},\n\t};\n\n\treturn { client, host };\n}\n\n/** The `postMessage`/`onmessage`/event-listener shape a browser `Worker`, a worker's `self`, or a DOM `MessagePort` presents. */\ninterface EventTargetLike {\n\tpostMessage(message: unknown): void;\n\taddEventListener?(type: \"message\", handler: (event: { data: unknown }) => void): void;\n\tonmessage?: ((event: { data: unknown }) => void) | null;\n\tterminate?(): void;\n\tclose?(): void;\n\tstart?(): void;\n}\n\n/**\n * Adapt a browser-style message target onto a {@link WorkerTransport}.\n *\n * Covers the main-side `Worker`, the worker global `self`, and a DOM\n * `MessagePort`: each posts with `postMessage` and receives a `MessageEvent`\n * whose `data` is the payload. A `MessagePort` is `start`ed here so it begins\n * dispatching. On the main side pass a `Worker`; inside a browser worker pass\n * `self`.\n */\nexport function eventTargetTransport(target: EventTargetLike): WorkerTransport {\n\treturn {\n\t\tpostMessage: (message) => target.postMessage(message),\n\t\tonMessage: (handler) => {\n\t\t\tconst listener = (event: { data: unknown }): void => handler(event.data);\n\t\t\tif (typeof target.addEventListener === \"function\") {\n\t\t\t\ttarget.addEventListener(\"message\", listener);\n\t\t\t} else {\n\t\t\t\ttarget.onmessage = listener;\n\t\t\t}\n\t\t\ttarget.start?.();\n\t\t},\n\t\t// A main-side Worker terminates; a worker's own `self` closes. Calling\n\t\t// whichever exists keeps one adapter usable from both ends.\n\t\tterminate: () => {\n\t\t\ttarget.terminate?.();\n\t\t\ttarget.close?.();\n\t\t},\n\t};\n}\n\n/** The `postMessage`/`on(\"message\")` shape a Node `worker_threads` `Worker`, `parentPort`, or `MessagePort` presents. */\ninterface MessagePortLike {\n\tpostMessage(message: unknown): void;\n\ton(event: \"message\", handler: (message: unknown) => void): void;\n\tterminate?(): void;\n\tclose?(): void;\n}\n\n/**\n * Adapt a Node `worker_threads` port onto a {@link WorkerTransport}.\n *\n * Covers the main-side `Worker`, the worker's `parentPort`, and a\n * `worker_threads` `MessagePort`: each posts with `postMessage` and emits a\n * `\"message\"` event whose argument IS the payload (no `.data` wrapper, unlike\n * the DOM). On the main side pass the `Worker`; inside the worker pass\n * `parentPort`.\n */\nexport function messagePortTransport(port: MessagePortLike): WorkerTransport {\n\treturn {\n\t\tpostMessage: (message) => port.postMessage(message),\n\t\tonMessage: (handler) => {\n\t\t\tport.on(\"message\", (message) => handler(message));\n\t\t},\n\t\tterminate: () => {\n\t\t\tport.terminate?.();\n\t\t\tport.close?.();\n\t\t},\n\t};\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/worker/client.ts","../src/worker/serialize.ts","../src/worker/runtime.ts","../src/worker/transport.ts"],"names":["resolveDateOrderForWorker","config","date","resolveDateOrderPolicy","DEFAULT_CONFIG","WorkerEngineClient","transport","raw","options","id","resolve","reject","input","signal","parsing","parseOptions","lines","expression","listener","error","workerTerminatedError","entry","method","args","workerCancelledError","onAbort","message","value","deserializeEngineError","apply","createWorkerEngine","client","nonFiniteTag","n","serializeMatrix","m","cells","cell","formatSymbolic","serializeValue","settings","reading","dto","formatValue","r","c","toHexString","formatColour","pt","ip","serializeMaybe","serializeInlineSolve","solve","serializeParsedLine","line","serializeParsingResult","result","resolvePackages","available","names","byName","pkg","resolved","name","ErrorFactory","WorkerErrorCodes","startWorkerRuntime","BUILTIN_PACKAGES","engine","formatting","inFlight","retainedLines","documentController","stopEventPump","post","fail","serializeEngineError","normalizeUnknownError","retainLines","map","text","index","handleAsyncEvent","eng","event","lineNumber","startEventPump","reader","done","handleInit","packages","ExpressionEngine","DEFAULT_FORMATTING_SETTINGS","runMethod","handleRequest","controller","cloneMessage","createLinkedTransports","clientHandler","hostHandler","alive","deliver","target","cloned","handler","eventTargetTransport","messagePortTransport","port"],"mappings":"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","file":"worker.js","sourcesContent":["/**\n * The main-side half of the harness: an async proxy of the core evaluate\n * methods.\n *\n * {@link createWorkerEngine} performs the init handshake and resolves once the\n * worker's engine is built, so the returned {@link WorkerEngine} is ready to\n * call. Each call stamps a request id, tracks the pending promise, and settles\n * it when the matching answer arrives, so several requests can be outstanding at\n * once. An `AbortSignal` rejects the local promise and posts a `cancel` for the\n * same id, mapping keystroke-level cancellation onto the boundary rather than\n * re-inventing it.\n */\n\nimport { DEFAULT_CONFIG, type EngineConfigOverride } from \"@solve-js/constants/Configuration\";\nimport { resolveDateOrderPolicy } from \"@solve-js/packages/datetime/DateReading\";\nimport type { UnifiedParsingOptions } from \"@solve-js/types/ParsingResult\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport type { EngineError } from \"@solve-js/errors\";\nimport {\n\tdeserializeEngineError,\n\tworkerCancelledError,\n\tworkerTerminatedError,\n} from \"@solve-js/errors\";\nimport type { WorkerTransport } from \"./transport\";\nimport type {\n\tWorkerMethod,\n\tWorkerRequestArgs,\n\tWorkerToMainMessage,\n} from \"./protocol\";\nimport type {\n\tSerializedWorkerValue,\n\tSerializedParsedLine,\n\tSerializedParsingResult,\n} from \"./dto\";\n\n/** Configuration for {@link createWorkerEngine}. */\nexport interface WorkerEngineOptions {\n\t/** The channel to the worker runtime. See `worker/transport.ts` for adapters. */\n\ttransport: WorkerTransport;\n\t/** Locale for keywords and number formatting; defaults to English worker-side. */\n\tlocaleCode?: string;\n\t/** Whether the worker builds its engine with diagnostics enabled. */\n\tdiagnostics?: boolean;\n\t/** Config overrides, merged per section over the defaults worker-side. */\n\tconfig?: EngineConfigOverride;\n\t/**\n\t * Names of built-in packages the worker should register. Omitted registers\n\t * them all. Names rather than the packages themselves, since a package\n\t * carries functions that cannot cross a `postMessage` boundary; a host with\n\t * a custom package bakes it into its own worker entry and selects it here by\n\t * name.\n\t */\n\tpackages?: string[];\n\t/** Formatting settings the worker uses when it renders a DTO's display text. */\n\tformatting?: FormattingSettings;\n}\n\n/** Per-call options common to every proxied method. */\nexport interface WorkerCallOptions {\n\t/** Abort the request. Rejects the returned promise and cancels the work worker-side. */\n\tsignal?: AbortSignal;\n}\n\n/**\n * One line whose result changed after a live value resolved worker-side, carried\n * as its freshly re-evaluated {@link SerializedWorkerValue}. The value the host renders\n * against `lineNumber`, recovered worker-side so the main thread needs no further\n * round-trip to display it.\n */\nexport interface WorkerAsyncUpdate {\n\tlineNumber: number;\n\tvalue: SerializedWorkerValue;\n}\n\n/**\n * A live-data resolution that failed worker-side. `error` is the same structured\n * {@link EngineError} an in-process resolver failure would surface, rebuilt from\n * its transported form, so a host branches on `code`/`category` as it always has.\n */\nexport interface WorkerAsyncError {\n\tqueryKey: string;\n\tpackageId: string;\n\terror: EngineError;\n}\n\n/**\n * An async proxy of {@link ExpressionEngine}'s core evaluate methods.\n *\n * Each method mirrors its synchronous counterpart but returns a Promise of the\n * serialisable DTO rather than a live `Value`, and accepts an `AbortSignal`.\n */\nexport interface WorkerEngine {\n\t/** Parse a whole document off-thread. Mirrors `ExpressionEngine.parseDocument`. */\n\tparseDocument(input: string, options?: UnifiedParsingOptions & WorkerCallOptions): Promise<SerializedParsingResult>;\n\t/** Evaluate an array of lines off-thread. Mirrors `ExpressionEngine.evaluateLines`. */\n\tevaluateLines(lines: string[], options?: WorkerCallOptions): Promise<SerializedParsedLine[]>;\n\t/** Evaluate a single expression off-thread. Mirrors `ExpressionEngine.evaluateExpression`. */\n\tevaluateExpression(expression: string, options?: WorkerCallOptions): Promise<SerializedWorkerValue>;\n\t/**\n\t * Subscribe to live-data resolutions that land after a request already\n\t * answered.\n\t *\n\t * A currency, weather or historical-rate value resolves inside the worker some\n\t * time after `parseDocument` returned its pending result. When it does, the\n\t * affected lines are re-evaluated worker-side and their fresh values arrive\n\t * here as one batch. This is a subscription rather than a per-request promise\n\t * because a resolution is tied to no single request: it belongs to whichever\n\t * document is current when the value lands. Returns an unsubscribe function.\n\t */\n\tonResolved(listener: (lines: WorkerAsyncUpdate[]) => void): () => void;\n\t/**\n\t * Subscribe to live-data resolutions that failed. Returns an unsubscribe\n\t * function. See {@link onResolved}; this is its failure channel.\n\t */\n\tonAsyncError(listener: (error: WorkerAsyncError) => void): () => void;\n\t/** Reject every in-flight request and tear the transport down. Idempotent. */\n\tterminate(): void;\n}\n\n/** A promise awaiting one worker answer, plus the abort wiring to unhook when it settles. */\ninterface PendingRequest {\n\tresolve: (value: unknown) => void;\n\treject: (error: unknown) => void;\n\tsignal?: AbortSignal;\n\tonAbort?: () => void;\n}\n\n/**\n * Replaces `date.inputOrder: 'locale'` with the order this side resolves it\n * to, before the config crosses to the worker.\n *\n * `'locale'` means \"ask the reader's machine\", and the reader's machine is\n * this one. A worker re-inferring it would be asking a different environment\n * the same question: a worker thread can carry different `Intl` data (a\n * bundler-provided shim, a small-ICU runtime), so the same document could be\n * read day-first on the main thread and month-first in the worker with nothing\n * to show for it. The resolved order crosses instead, so both sides read the\n * document the same way, and `date.inputLocale` is dropped with it because it\n * has already done its work.\n *\n * Anything else passes through untouched, including an absent config.\n */\nfunction resolveDateOrderForWorker(config: EngineConfigOverride | undefined): EngineConfigOverride | undefined {\n\tif (config?.date?.inputOrder !== \"locale\") return config;\n\tconst date = { ...config.date, inputOrder: resolveDateOrderPolicy({ ...DEFAULT_CONFIG.date, ...config.date }).order };\n\tdelete date.inputLocale;\n\treturn { ...config, date };\n}\n\nclass WorkerEngineClient implements WorkerEngine {\n\tprivate readonly transport: WorkerTransport;\n\tprivate nextId = 1;\n\tprivate readonly pending = new Map<number, PendingRequest>();\n\t// Broadcast subscribers for async resolutions. Sets, not one callback each, so\n\t// several views can watch the same worker; a resolution is not tied to a\n\t// request id, so these live outside `pending`.\n\tprivate readonly resolvedListeners = new Set<(lines: WorkerAsyncUpdate[]) => void>();\n\tprivate readonly asyncErrorListeners = new Set<(error: WorkerAsyncError) => void>();\n\tprivate terminated = false;\n\n\tconstructor(transport: WorkerTransport) {\n\t\tthis.transport = transport;\n\t\tthis.transport.onMessage((raw) => this.onMessage(raw));\n\t}\n\n\t/** Perform the init handshake, resolving once the worker posts `ready`. */\n\tinit(options: WorkerEngineOptions): Promise<void> {\n\t\tconst id = this.nextId++;\n\t\treturn new Promise<void>((resolve, reject) => {\n\t\t\tthis.pending.set(id, { resolve: () => resolve(), reject });\n\t\t\tthis.transport.postMessage({\n\t\t\t\tkind: \"init\",\n\t\t\t\tid,\n\t\t\t\tlocaleCode: options.localeCode,\n\t\t\t\tdiagnostics: options.diagnostics,\n\t\t\t\tconfig: resolveDateOrderForWorker(options.config),\n\t\t\t\tpackages: options.packages,\n\t\t\t\tformatting: options.formatting,\n\t\t\t});\n\t\t});\n\t}\n\n\tparseDocument(\n\t\tinput: string,\n\t\toptions?: UnifiedParsingOptions & WorkerCallOptions,\n\t): Promise<SerializedParsingResult> {\n\t\t// The signal stays main-side and drives a `cancel`; only the parsing\n\t\t// options cross, so an AbortSignal never reaches `postMessage`.\n\t\tconst { signal, ...parsing } = options ?? {};\n\t\tconst parseOptions = Object.keys(parsing).length > 0 ? (parsing as UnifiedParsingOptions) : undefined;\n\t\treturn this.call<SerializedParsingResult>(\"parseDocument\", [input, parseOptions], signal);\n\t}\n\n\tevaluateLines(lines: string[], options?: WorkerCallOptions): Promise<SerializedParsedLine[]> {\n\t\treturn this.call<SerializedParsedLine[]>(\"evaluateLines\", [lines], options?.signal);\n\t}\n\n\tevaluateExpression(expression: string, options?: WorkerCallOptions): Promise<SerializedWorkerValue> {\n\t\treturn this.call<SerializedWorkerValue>(\"evaluateExpression\", [expression], options?.signal);\n\t}\n\n\tonResolved(listener: (lines: WorkerAsyncUpdate[]) => void): () => void {\n\t\tthis.resolvedListeners.add(listener);\n\t\treturn () => this.resolvedListeners.delete(listener);\n\t}\n\n\tonAsyncError(listener: (error: WorkerAsyncError) => void): () => void {\n\t\tthis.asyncErrorListeners.add(listener);\n\t\treturn () => this.asyncErrorListeners.delete(listener);\n\t}\n\n\tterminate(): void {\n\t\tif (this.terminated) return;\n\t\tthis.terminated = true;\n\t\tconst error = workerTerminatedError();\n\t\tfor (const entry of this.pending.values()) {\n\t\t\tthis.unhook(entry);\n\t\t\tentry.reject(error);\n\t\t}\n\t\tthis.pending.clear();\n\t\t// No more resolutions can arrive across a torn-down transport, so drop the\n\t\t// subscribers rather than leaving them referenced for the client's lifetime.\n\t\tthis.resolvedListeners.clear();\n\t\tthis.asyncErrorListeners.clear();\n\t\tthis.transport.terminate();\n\t}\n\n\t/** Dispatch one request and return the promise that settles on its answer. */\n\tprivate call<T>(method: WorkerMethod, args: WorkerRequestArgs, signal?: AbortSignal): Promise<T> {\n\t\tif (this.terminated) return Promise.reject(workerTerminatedError());\n\t\tif (signal?.aborted) return Promise.reject(workerCancelledError(method));\n\n\t\tconst id = this.nextId++;\n\t\treturn new Promise<T>((resolve, reject) => {\n\t\t\tconst entry: PendingRequest = { resolve: resolve as (value: unknown) => void, reject };\n\n\t\t\tif (signal) {\n\t\t\t\tconst onAbort = (): void => {\n\t\t\t\t\t// Nothing to do if the answer already arrived and settled this id.\n\t\t\t\t\tif (!this.pending.has(id)) return;\n\t\t\t\t\tthis.pending.delete(id);\n\t\t\t\t\tthis.transport.postMessage({ kind: \"cancel\", id });\n\t\t\t\t\treject(workerCancelledError(method));\n\t\t\t\t};\n\t\t\t\tentry.signal = signal;\n\t\t\t\tentry.onAbort = onAbort;\n\t\t\t\tsignal.addEventListener(\"abort\", onAbort, { once: true });\n\t\t\t}\n\n\t\t\tthis.pending.set(id, entry);\n\t\t\tthis.transport.postMessage({ kind: \"request\", id, method, args });\n\t\t});\n\t}\n\n\t/** Route one incoming message to the request that is waiting on its id. */\n\tprivate onMessage(raw: unknown): void {\n\t\tconst message = raw as WorkerToMainMessage;\n\t\tswitch (message.kind) {\n\t\t\tcase \"ready\":\n\t\t\tcase \"result\": {\n\t\t\t\tconst value = message.kind === \"result\" ? message.value : undefined;\n\t\t\t\tthis.settle(message.id, (entry) => entry.resolve(value));\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tcase \"error\":\n\t\t\t\tthis.settle(message.id, (entry) => entry.reject(deserializeEngineError(message.error)));\n\t\t\t\tbreak;\n\t\t\tcase \"async-update\":\n\t\t\t\t// A broadcast, not an answer to a request: fan it out to every\n\t\t\t\t// subscriber. A copy of the listener set is iterated so a listener\n\t\t\t\t// that unsubscribes itself mid-callback cannot disturb the walk.\n\t\t\t\tfor (const listener of [...this.resolvedListeners]) listener(message.lines);\n\t\t\t\tbreak;\n\t\t\tcase \"async-error\":\n\t\t\t\tfor (const listener of [...this.asyncErrorListeners]) {\n\t\t\t\t\tlistener({\n\t\t\t\t\t\tqueryKey: message.queryKey,\n\t\t\t\t\t\tpackageId: message.packageId,\n\t\t\t\t\t\terror: deserializeEngineError(message.error),\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t}\n\t}\n\n\t/** Remove a pending request by id and run the settle callback, if it is still pending. */\n\tprivate settle(id: number, apply: (entry: PendingRequest) => void): void {\n\t\tconst entry = this.pending.get(id);\n\t\tif (!entry) return;\n\t\tthis.pending.delete(id);\n\t\tthis.unhook(entry);\n\t\tapply(entry);\n\t}\n\n\t/** Detach an entry's abort listener so a settled request leaves nothing on the signal. */\n\tprivate unhook(entry: PendingRequest): void {\n\t\tif (entry.signal && entry.onAbort) entry.signal.removeEventListener(\"abort\", entry.onAbort);\n\t}\n}\n\n/**\n * Build a worker-backed engine and wait for it to be ready.\n *\n * ```ts\n * const { client, host } = createLinkedTransports();\n * startWorkerRuntime(host);\n * const engine = await createWorkerEngine({ transport: client });\n * const result = await engine.parseDocument(text);\n * ```\n *\n * In production `client` wraps a real `Worker` (see `eventTargetTransport` /\n * `messagePortTransport`), and `startWorkerRuntime` runs inside that worker.\n */\nexport async function createWorkerEngine(options: WorkerEngineOptions): Promise<WorkerEngine> {\n\tconst client = new WorkerEngineClient(options.transport);\n\tawait client.init(options);\n\treturn client;\n}\n","/**\n * Turn live engine results into the clone-safe DTOs the worker harness posts.\n *\n * These functions run on the worker side, just before a result crosses the\n * boundary, and are also what the main side re-runs on a synchronous result to\n * compare the two paths in tests. They are pure and deterministic given the\n * same {@link FormattingSettings}, so a value serialised on either side is\n * byte-for-byte the same DTO.\n */\n\nimport { Value, ValueType, type MatrixData, type MatrixEntry, type RangeData, type ColourData, type ChartData, type IpCidrData } from \"@solve-js/vm/Value\";\nimport { formatValue } from \"@solve-js/format/FormatEngine\";\nimport { toHexString, formatColour } from \"@solve-js/packages/colour/ColourMath\";\nimport type { FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport { formatSymbolic } from \"@solve-js/symbolic\";\nimport type { ParsedLine, InlineSolvePosition, ParsingResult } from \"@solve-js/types/ParsingResult\";\nimport type {\n\tSerializedWorkerValue,\n\tSerializedMatrix,\n\tSerializedParsedLine,\n\tSerializedInlineSolve,\n\tSerializedParsingResult,\n} from \"./dto\";\n\n/**\n * The JSON-safe string tag for a non-finite reading. `Infinity`/`-Infinity`/`NaN`\n * cannot cross `JSON` (which turns each into `null`), so this one string form is\n * what survives both `structuredClone` and `JSON`, and a host recovers the value\n * with `Number(tag)`. Shared by the scalar `nonFinite` field and matrix cells.\n */\nfunction nonFiniteTag(n: number): \"Infinity\" | \"-Infinity\" | \"NaN\" {\n\treturn n > 0 ? \"Infinity\" : n < 0 ? \"-Infinity\" : \"NaN\";\n}\n\n/** Project a matrix onto clone-safe cells: finite primitives pass through, symbolic cells and non-finite numbers become strings. */\nfunction serializeMatrix(m: MatrixData): SerializedMatrix {\n\tconst cells = m.data.map((cell: MatrixEntry): number | boolean | string => {\n\t\t// A `SymbolicNode` (the object-typed cell variant) flattens to its display\n\t\t// string. A non-finite number (a `[1/0, 2]` cell) cannot cross JSON any\n\t\t// more than a scalar reading can, so it takes the same string tag rather\n\t\t// than being passed through raw and turned into `null` by `JSON.stringify`\n\t\t// (which would diverge from the `structuredClone` path). A finite number\n\t\t// or a boolean is already clone-safe and passes through.\n\t\tif (typeof cell === \"object\" && cell !== null) return formatSymbolic(cell);\n\t\tif (typeof cell === \"number\" && !Number.isFinite(cell)) return nonFiniteTag(cell);\n\t\treturn cell;\n\t});\n\treturn { rows: m.rows, cols: m.cols, cells, hasSymbolic: m.hasSymbolic };\n}\n\n/**\n * Project a {@link Value} onto a {@link SerializedWorkerValue}.\n *\n * `text` and `number` are set for every value; the type-specific fields are\n * added only where the payload needs them, so the DTO stays minimal and a\n * deep-equal between the two evaluation paths does not trip on a property one\n * side left `undefined`.\n */\nexport function serializeValue(value: Value, settings?: FormattingSettings): SerializedWorkerValue {\n\tconst reading = value.toNumber();\n\tconst dto: SerializedWorkerValue = {\n\t\ttype: value.type,\n\t\ttext: formatValue(value, settings),\n\t\t// A non-finite reading (1/0, 0/0, an overflow) cannot cross JSON, which\n\t\t// turns it into null and breaks the round-trip the DTO guarantees. Keep\n\t\t// `number` finite and name the real value in `nonFinite` instead.\n\t\tnumber: Number.isFinite(reading) ? reading : 0,\n\t};\n\tif (!Number.isFinite(reading)) {\n\t\tdto.nonFinite = nonFiniteTag(reading);\n\t}\n\n\tif (value.unit !== undefined) dto.unit = value.unit;\n\tif (value.timedOut !== undefined) dto.timedOut = value.timedOut;\n\t// The two datetime sidecars cross as themselves: both are plain JSON\n\t// scalars, so the clone guarantee is untouched, and a worker result that\n\t// dropped them would answer a different question from the synchronous one.\n\tif (value.grain !== undefined) dto.grain = value.grain;\n\tif (value.zone !== undefined) dto.zone = value.zone;\n\n\tconst raw = value.value;\n\tif (typeof raw === \"bigint\") {\n\t\t// Covers BigInt values and a Hex value that carries a bigint magnitude:\n\t\t// a base-ten string is the one representation that neither loses\n\t\t// precision nor breaks JSON.\n\t\tdto.bigint = raw.toString();\n\t} else if (value.type === ValueType.Matrix) {\n\t\tdto.matrix = serializeMatrix(raw as MatrixData);\n\t} else if (value.type === ValueType.Range) {\n\t\tconst r = raw as RangeData;\n\t\tdto.range = { min: r.min, max: r.max };\n\t} else if (value.type === ValueType.Colour) {\n\t\tconst c = raw as ColourData;\n\t\tdto.colour = { hex: toHexString(c), r: c.r, g: c.g, b: c.b, a: c.a, format: c.format, css: formatColour(c) };\n\t} else if (value.type === ValueType.Chart) {\n\t\tconst c = raw as ChartData;\n\t\tdto.chart = {\n\t\t\tkind: c.kind,\n\t\t\tpoints: c.points.map((pt) => [pt[0], pt[1]]),\n\t\t\tlabel: c.label,\n\t\t\tdomain: [c.domain[0], c.domain[1]],\n\t\t\trange: [c.range[0], c.range[1]],\n\t\t\t...(c.expr !== undefined ? { expr: c.expr } : {}),\n\t\t};\n\t} else if (value.type === ValueType.IpCidr) {\n\t\tconst ip = raw as IpCidrData;\n\t\tdto.ipCidr = {\n\t\t\t...(ip.addr !== undefined ? { addr: ip.addr } : {}),\n\t\t\t...(ip.prefix !== undefined ? { prefix: ip.prefix } : {}),\n\t\t\ttext: formatValue(value).replace(/^=\\s*/, \"\"),\n\t\t};\n\t}\n\n\treturn dto;\n}\n\n/** Serialise a nullable value, the shape both `result` fields carry. */\nfunction serializeMaybe(value: Value | null | undefined, settings?: FormattingSettings): SerializedWorkerValue | null {\n\treturn value ? serializeValue(value, settings) : null;\n}\n\n/** Project an inline solve onto its DTO, serialising its result. */\nfunction serializeInlineSolve(solve: InlineSolvePosition, settings?: FormattingSettings): SerializedInlineSolve {\n\treturn {\n\t\tstart: solve.start,\n\t\tend: solve.end,\n\t\texpression: solve.expression,\n\t\tlineNumber: solve.lineNumber,\n\t\tcolumnNumber: solve.columnNumber,\n\t\tresult: serializeMaybe(solve.result, settings),\n\t\terror: solve.error ?? null,\n\t};\n}\n\n/** Project a parsed line onto its DTO, serialising its result and every inline solve. */\nexport function serializeParsedLine(line: ParsedLine, settings?: FormattingSettings): SerializedParsedLine {\n\treturn {\n\t\tlineNumber: line.lineNumber,\n\t\ttext: line.text,\n\t\tstartPosition: line.startPosition,\n\t\tendPosition: line.endPosition,\n\t\tisEmpty: line.isEmpty,\n\t\thasInlineSolves: line.hasInlineSolves,\n\t\tinlineSolves: line.inlineSolves.map((solve) => serializeInlineSolve(solve, settings)),\n\t\texpression: line.expression,\n\t\tresult: serializeMaybe(line.result, settings),\n\t\terror: line.error,\n\t};\n}\n\n/** Project a whole parsing result onto its DTO. */\nexport function serializeParsingResult(result: ParsingResult, settings?: FormattingSettings): SerializedParsingResult {\n\tconst dto: SerializedParsingResult = {\n\t\tlines: result.lines.map((line) => serializeParsedLine(line, settings)),\n\t\ttotalLines: result.totalLines,\n\t\terrors: [...result.errors],\n\t};\n\t// The diagnostics report is already the engine's own JSON form, so it\n\t// crosses unchanged; present only when the host asked for it.\n\tif (result.diagnostics !== undefined) dto.diagnostics = result.diagnostics;\n\treturn dto;\n}\n","/**\n * The worker-side half of the harness: it owns an {@link ExpressionEngine} and\n * answers the protocol.\n *\n * {@link startWorkerRuntime} is transport-agnostic, so the same function runs\n * behind a browser `Worker`, a Node `worker_threads` port, or an in-process\n * link. A host's worker entry file is two lines: adapt the environment onto a\n * {@link WorkerTransport} and call this.\n *\n * The runtime never posts a raw {@link Value}. Every result is projected onto a\n * DTO first (`worker/serialize.ts`), and every failure is caught and flattened\n * into a structured error, so a worker-side throw reaches the caller as an\n * `EngineError` rather than a lost promise.\n */\n\nimport { ExpressionEngine } from \"@solve-js/engine/ExpressionEngine\";\nimport type { AsyncResolutionEvent } from \"@solve-js/engine/AsyncResolutionBatcher\";\nimport type { IEnginePackage } from \"@solve-js/api/PackageRegistry\";\nimport { BUILTIN_PACKAGES } from \"@solve-js/packages/builtins\";\nimport { DEFAULT_FORMATTING_SETTINGS, type FormattingSettings } from \"@solve-js/format/FormattingSettings\";\nimport type { CalendarBackend } from \"@solve-js/calendar/CalendarBackend\";\nimport {\n\tErrorFactory,\n\tnormalizeUnknownError,\n\tserializeEngineError,\n\tWorkerErrorCodes,\n} from \"@solve-js/errors\";\nimport { serializeParsingResult, serializeParsedLine, serializeValue } from \"./serialize\";\nimport type { WorkerTransport } from \"./transport\";\nimport type {\n\tMainToWorkerMessage,\n\tInitMessage,\n\tRequestMessage,\n\tWorkerToMainMessage,\n\tAsyncResolvedLine,\n} from \"./protocol\";\n\n/** Options a host bakes into its own worker entry: its custom packages, and its calendar backend. */\nexport interface WorkerRuntimeOptions {\n\t/**\n\t * The packages available to register, defaulting to {@link BUILTIN_PACKAGES}.\n\t * A host with its own package authors a worker entry that passes them here,\n\t * then selects among them by name from the main side. This is how a\n\t * function-carrying package reaches the worker: baked into its bundle, never\n\t * posted across the boundary.\n\t */\n\tpackages?: IEnginePackage[];\n\t/**\n\t * The calendar backend the worker's engine computes dates with, and writes\n\t * them out with, as the engine's own `calendar` option. Defaults to the\n\t * built-in `Date` backend. Baked in here for the same reason a package is:\n\t * a backend is an object of functions and cannot be posted across the\n\t * boundary, so the main side's formatting settings never carry one.\n\t */\n\tcalendar?: CalendarBackend;\n}\n\n/**\n * Resolve the requested package names against the available set.\n *\n * Undefined names means \"all of them\". A name with no match is a configuration\n * failure the caller must see, not a silent omission that would leave a feature\n * quietly missing from every result.\n */\nfunction resolvePackages(available: IEnginePackage[], names: string[] | undefined): IEnginePackage[] {\n\tif (names === undefined) return available;\n\tconst byName = new Map(available.map((pkg) => [pkg.name, pkg]));\n\tconst resolved: IEnginePackage[] = [];\n\tfor (const name of names) {\n\t\tconst pkg = byName.get(name);\n\t\tif (!pkg) {\n\t\t\tthrow ErrorFactory.config(\n\t\t\t\tWorkerErrorCodes.WORKER_UNKNOWN_PACKAGE,\n\t\t\t\t`No package named \"${name}\" is available in this worker runtime`,\n\t\t\t\t{ name, available: [...byName.keys()] },\n\t\t\t);\n\t\t}\n\t\tresolved.push(pkg);\n\t}\n\treturn resolved;\n}\n\n/**\n * Attach the runtime to a transport and start serving.\n *\n * Returns a teardown function that clears the engine and detaches, for a host\n * that reuses a transport or shuts a worker down cleanly.\n */\nexport function startWorkerRuntime(transport: WorkerTransport, options: WorkerRuntimeOptions = {}): () => void {\n\tconst available = options.packages ?? BUILTIN_PACKAGES;\n\n\tlet engine: ExpressionEngine | null = null;\n\tlet formatting: FormattingSettings | undefined;\n\t// One AbortController per in-flight request, so a `cancel` can map onto the\n\t// engine's keystroke signal for exactly the request the caller aborted.\n\tconst inFlight = new Map<number, AbortController>();\n\n\t// The line texts of the current document, keyed by the line number the engine\n\t// evaluates them under (1-based for a document, -1 for a lone expression). An\n\t// async resolution names the lines whose result changed but not the new value,\n\t// so this is what the event pump re-reads a line from to recover it.\n\tlet retainedLines = new Map<number, string>();\n\n\t// The current document's abort controller, kept alive past the request that\n\t// created it so this document's async resolutions can still land. Aborted when\n\t// a new document supersedes it: aborting drops the old document's in-flight\n\t// resolutions at the engine's own staleness guard (an aborted signal is\n\t// discarded before it reaches the batcher), so a stale value never reaches the\n\t// host as if it were current. See {@link handleRequest}.\n\tlet documentController: AbortController | null = null;\n\n\t// Cancels the event-stream reader on teardown. Null until the pump starts.\n\tlet stopEventPump: (() => void) | null = null;\n\n\tconst post = (message: WorkerToMainMessage): void => transport.postMessage(message);\n\n\tconst fail = (id: number, error: unknown): void => {\n\t\tpost({ kind: \"error\", id, error: serializeEngineError(normalizeUnknownError(error)) });\n\t};\n\n\t/**\n\t * Record the line texts a request evaluates, so a later async resolution can\n\t * re-read exactly the lines it names. A whole document splits into 1-based\n\t * lines; a lone `evaluateExpression` maps onto the engine's `-1` sentinel, the\n\t * same line number the engine registers and later reports for it.\n\t */\n\tconst retainLines = (message: RequestMessage): Map<number, string> => {\n\t\tconst map = new Map<number, string>();\n\t\tif (message.method === \"parseDocument\") {\n\t\t\t(message.args[0] as string).split(\"\\n\").forEach((text, index) => map.set(index + 1, text));\n\t\t} else if (message.method === \"evaluateLines\") {\n\t\t\t(message.args[0] as string[]).forEach((text, index) => map.set(index + 1, text));\n\t\t} else {\n\t\t\tmap.set(-1, message.args[0] as string);\n\t\t}\n\t\treturn map;\n\t};\n\n\t/**\n\t * Turn one async resolution event into a message home.\n\t *\n\t * A `lines-updated` event names the lines whose result changed; the resolved\n\t * value lives in the engine's cache, so each named line is re-evaluated (which\n\t * now reads the settled value from that cache rather than starting a fresh\n\t * fetch) and serialised. A line the current document no longer retains belongs\n\t * to a superseded document and is skipped. An `error` event carries the failed\n\t * query straight across as a structured error.\n\t */\n\tconst handleAsyncEvent = (eng: ExpressionEngine, event: AsyncResolutionEvent): void => {\n\t\tif (event.type === \"error\") {\n\t\t\tpost({\n\t\t\t\tkind: \"async-error\",\n\t\t\t\tqueryKey: event.queryKey,\n\t\t\t\tpackageId: event.packageId,\n\t\t\t\terror: serializeEngineError(normalizeUnknownError(event.error)),\n\t\t\t});\n\t\t\treturn;\n\t\t}\n\n\t\tconst lines: AsyncResolvedLine[] = [];\n\t\tfor (const lineNumber of event.lineNumbers) {\n\t\t\tconst text = retainedLines.get(lineNumber);\n\t\t\tif (text === undefined) continue;\n\t\t\ttry {\n\t\t\t\tconst value = eng.evaluateLine(lineNumber, text);\n\t\t\t\tif (value) lines.push({ lineNumber, value: serializeValue(value, formatting) });\n\t\t\t} catch {\n\t\t\t\t// A line that resolved into an error re-throws on re-evaluation; the\n\t\t\t\t// batcher's own `error` event is the channel for that, so this keeps\n\t\t\t\t// the update to the lines that produced a value rather than posting a\n\t\t\t\t// second, half-formed failure here.\n\t\t\t}\n\t\t}\n\t\tif (lines.length > 0) post({ kind: \"async-update\", lines });\n\t};\n\n\t/**\n\t * Drain the engine's async-resolution event stream for the life of the\n\t * runtime, posting each event home. Started once the engine exists; the reader\n\t * loop ends when the stream closes (engine cleared) or the returned canceller\n\t * runs at teardown.\n\t */\n\tconst startEventPump = (eng: ExpressionEngine): void => {\n\t\tstopEventPump?.();\n\t\tconst reader = eng.getEventStream().getReader();\n\t\tstopEventPump = () => void reader.cancel();\n\t\tvoid (async () => {\n\t\t\ttry {\n\t\t\t\tfor (;;) {\n\t\t\t\t\tconst { done, value } = await reader.read();\n\t\t\t\t\tif (done) return;\n\t\t\t\t\thandleAsyncEvent(eng, value);\n\t\t\t\t}\n\t\t\t} catch {\n\t\t\t\t// The stream errored or was cancelled (teardown); the loop is done.\n\t\t\t}\n\t\t})();\n\t};\n\n\tconst handleInit = (message: InitMessage): void => {\n\t\ttry {\n\t\t\tconst packages = resolvePackages(available, message.packages);\n\t\t\tengine = new ExpressionEngine({\n\t\t\t\tlocale: message.localeCode ?? \"en\",\n\t\t\t\tdiagnostics: message.diagnostics ?? false,\n\t\t\t\tconfig: message.config,\n\t\t\t\tpackages,\n\t\t\t\tcalendar: options.calendar,\n\t\t\t});\n\t\t\t// The display reads the same backend the engine computes with, so a\n\t\t\t// date in a DTO names the day it was computed on; the main side's\n\t\t\t// settings cannot carry the backend, so it is joined here.\n\t\t\tformatting = options.calendar\n\t\t\t\t? { ...(message.formatting ?? DEFAULT_FORMATTING_SETTINGS), calendar: options.calendar }\n\t\t\t\t: message.formatting;\n\t\t\t// Drain live-data resolutions for the engine's whole lifetime, so a\n\t\t\t// value that settles after a request already answered still reaches the\n\t\t\t// host. Started here, after the engine exists, and torn down with it.\n\t\t\tstartEventPump(engine);\n\t\t\tpost({ kind: \"ready\", id: message.id });\n\t\t} catch (error) {\n\t\t\t// A build failure leaves no engine; the caller's `createWorkerEngine`\n\t\t\t// promise rejects with this rather than hanging on a `ready` that\n\t\t\t// never comes.\n\t\t\tfail(message.id, error);\n\t\t}\n\t};\n\n\tconst runMethod = (eng: ExpressionEngine, message: RequestMessage): unknown => {\n\t\tconst { method, args } = message;\n\t\tswitch (method) {\n\t\t\tcase \"parseDocument\":\n\t\t\t\treturn serializeParsingResult(eng.parseDocument(args[0] as string, args[1] as never), formatting);\n\t\t\tcase \"evaluateLines\":\n\t\t\t\treturn eng.evaluateLines(args[0] as string[]).map((line) => serializeParsedLine(line, formatting));\n\t\t\tcase \"evaluateExpression\":\n\t\t\t\t// Mirrors ExpressionEngine.evaluateExpression: a single Value in,\n\t\t\t\t// a single serialized Value out.\n\t\t\t\treturn serializeValue(eng.evaluateExpression(args[0] as string), formatting);\n\t\t\tdefault:\n\t\t\t\tthrow ErrorFactory.execution(\n\t\t\t\t\tWorkerErrorCodes.WORKER_UNKNOWN_METHOD,\n\t\t\t\t\t`The worker runtime has no method named \"${String(method)}\"`,\n\t\t\t\t\t{ method },\n\t\t\t\t);\n\t\t}\n\t};\n\n\tconst handleRequest = (message: RequestMessage): void => {\n\t\tconst eng = engine;\n\t\tif (!eng) {\n\t\t\tfail(\n\t\t\t\tmessage.id,\n\t\t\t\tErrorFactory.execution(\n\t\t\t\t\tWorkerErrorCodes.WORKER_NOT_INITIALISED,\n\t\t\t\t\t\"The worker received a request before its engine finished initialising\",\n\t\t\t\t),\n\t\t\t);\n\t\t\treturn;\n\t\t}\n\n\t\t// Supersede the previous document: abort its controller so any resolution\n\t\t// still in flight for it is dropped at the engine's staleness guard rather\n\t\t// than posted home as if it belonged to this request's document. The old\n\t\t// retained lines go with it. Every evaluate call shares one engine and one\n\t\t// document context, so the most recent call is the live one.\n\t\tdocumentController?.abort();\n\n\t\t// This request's controller doubles as the document controller: wired in as\n\t\t// the keystroke signal so a later `cancel` (or the next supersede) aborts\n\t\t// the async work this evaluation fires, the same mechanism a host uses on\n\t\t// the main thread. It is deliberately NOT aborted when the request settles,\n\t\t// so this document's live values can still resolve and stream back.\n\t\tconst controller = new AbortController();\n\t\tdocumentController = controller;\n\t\tretainedLines = retainLines(message);\n\t\tinFlight.set(message.id, controller);\n\t\teng.setKeystrokeSignal(controller.signal);\n\n\t\ttry {\n\t\t\tconst value = runMethod(eng, message);\n\t\t\tpost({ kind: \"result\", id: message.id, value });\n\t\t} catch (error) {\n\t\t\tfail(message.id, error);\n\t\t} finally {\n\t\t\tinFlight.delete(message.id);\n\t\t\teng.setKeystrokeSignal(null);\n\t\t}\n\t};\n\n\ttransport.onMessage((raw) => {\n\t\tconst message = raw as MainToWorkerMessage;\n\t\tswitch (message.kind) {\n\t\t\tcase \"init\":\n\t\t\t\thandleInit(message);\n\t\t\t\tbreak;\n\t\t\tcase \"request\":\n\t\t\t\thandleRequest(message);\n\t\t\t\tbreak;\n\t\t\tcase \"cancel\":\n\t\t\t\t// Abort maps onto the keystroke signal for the named request; a\n\t\t\t\t// cancel that arrives after the request already settled finds no\n\t\t\t\t// controller and is a harmless no-op.\n\t\t\t\tinFlight.get(message.id)?.abort();\n\t\t\t\tbreak;\n\t\t}\n\t});\n\n\treturn () => {\n\t\tstopEventPump?.();\n\t\tstopEventPump = null;\n\t\tdocumentController?.abort();\n\t\tdocumentController = null;\n\t\tretainedLines = new Map();\n\t\tfor (const controller of inFlight.values()) controller.abort();\n\t\tinFlight.clear();\n\t\tengine?.clear();\n\t\tengine = null;\n\t\ttransport.terminate();\n\t};\n}\n","/**\n * The seam between the harness and whatever actually carries messages.\n *\n * Both the client (`worker/client.ts`) and the runtime (`worker/runtime.ts`)\n * talk to a {@link WorkerTransport} and nothing more, so the same code drives a\n * browser `Worker`, a Node `worker_threads` port, or an in-process pair. The\n * three factory functions below adapt each of those onto the interface; a host\n * with a transport this file does not cover can implement the three methods\n * directly.\n */\n\n/**\n * A bidirectional message channel with a single receive handler.\n *\n * `onMessage` registers the one handler the harness needs; calling it again\n * replaces the previous handler. `terminate` tears the channel down and is safe\n * to call more than once.\n */\nexport interface WorkerTransport {\n\t/** Send one message to the other end. The message must be clone-safe. */\n\tpostMessage(message: unknown): void;\n\t/** Register the handler that receives messages from the other end. */\n\tonMessage(handler: (message: unknown) => void): void;\n\t/** Tear the channel down. Idempotent. */\n\tterminate(): void;\n}\n\n/**\n * Clone a message the way `postMessage` would, so an in-process transport has\n * the same value semantics as a real one.\n *\n * The harness protocol is clone-safe by construction, so the `JSON` fallback\n * (for a runtime without a global `structuredClone`) is lossless here; the\n * structured-clone path is preferred because it is what a real worker uses and\n * because it throws loudly if a non-clone-safe value ever reaches it, which is\n * exactly the mistake the DTO layer exists to prevent.\n *\n * A function, not a module-level const, so this module does no work at load\n * time and stays deletable under the package's `sideEffects: false` claim; the\n * `typeof` probe runs once per message, which is free next to the clone itself.\n */\nfunction cloneMessage<T>(value: T): T {\n\treturn typeof globalThis.structuredClone === \"function\"\n\t\t? globalThis.structuredClone(value)\n\t\t: JSON.parse(JSON.stringify(value));\n}\n\n/**\n * A pair of linked in-process transports.\n *\n * `client` and `host` are two ends of one channel: a message posted on either\n * is cloned at post time and delivered to the other on a microtask, so delivery\n * is asynchronous (as a real worker's is) but deterministic (no timers, no I/O).\n * Wire `client` into {@link createWorkerEngine} and `host` into\n * {@link startWorkerRuntime} to run the whole protocol, DTO serialisation and\n * cancellation included, without a second thread. This is the transport tests\n * use, and a fit for a host that wants the message-passing shape on one thread.\n */\nexport function createLinkedTransports(): { client: WorkerTransport; host: WorkerTransport } {\n\tlet clientHandler: ((message: unknown) => void) | null = null;\n\tlet hostHandler: ((message: unknown) => void) | null = null;\n\tlet alive = true;\n\n\t// The handler is read at delivery time rather than post time so setup order\n\t// (post before the other end has registered) cannot drop a message.\n\tconst deliver = (target: () => ((message: unknown) => void) | null, message: unknown): void => {\n\t\tconst cloned = cloneMessage(message);\n\t\tqueueMicrotask(() => {\n\t\t\tif (!alive) return;\n\t\t\ttarget()?.(cloned);\n\t\t});\n\t};\n\n\tconst client: WorkerTransport = {\n\t\tpostMessage: (message) => deliver(() => hostHandler, message),\n\t\tonMessage: (handler) => {\n\t\t\tclientHandler = handler;\n\t\t},\n\t\tterminate: () => {\n\t\t\talive = false;\n\t\t},\n\t};\n\n\tconst host: WorkerTransport = {\n\t\tpostMessage: (message) => deliver(() => clientHandler, message),\n\t\tonMessage: (handler) => {\n\t\t\thostHandler = handler;\n\t\t},\n\t\tterminate: () => {\n\t\t\talive = false;\n\t\t},\n\t};\n\n\treturn { client, host };\n}\n\n/** The `postMessage`/`onmessage`/event-listener shape a browser `Worker`, a worker's `self`, or a DOM `MessagePort` presents. */\ninterface EventTargetLike {\n\tpostMessage(message: unknown): void;\n\taddEventListener?(type: \"message\", handler: (event: { data: unknown }) => void): void;\n\tonmessage?: ((event: { data: unknown }) => void) | null;\n\tterminate?(): void;\n\tclose?(): void;\n\tstart?(): void;\n}\n\n/**\n * Adapt a browser-style message target onto a {@link WorkerTransport}.\n *\n * Covers the main-side `Worker`, the worker global `self`, and a DOM\n * `MessagePort`: each posts with `postMessage` and receives a `MessageEvent`\n * whose `data` is the payload. A `MessagePort` is `start`ed here so it begins\n * dispatching. On the main side pass a `Worker`; inside a browser worker pass\n * `self`.\n */\nexport function eventTargetTransport(target: EventTargetLike): WorkerTransport {\n\treturn {\n\t\tpostMessage: (message) => target.postMessage(message),\n\t\tonMessage: (handler) => {\n\t\t\tconst listener = (event: { data: unknown }): void => handler(event.data);\n\t\t\tif (typeof target.addEventListener === \"function\") {\n\t\t\t\ttarget.addEventListener(\"message\", listener);\n\t\t\t} else {\n\t\t\t\ttarget.onmessage = listener;\n\t\t\t}\n\t\t\ttarget.start?.();\n\t\t},\n\t\t// A main-side Worker terminates; a worker's own `self` closes. Calling\n\t\t// whichever exists keeps one adapter usable from both ends.\n\t\tterminate: () => {\n\t\t\ttarget.terminate?.();\n\t\t\ttarget.close?.();\n\t\t},\n\t};\n}\n\n/** The `postMessage`/`on(\"message\")` shape a Node `worker_threads` `Worker`, `parentPort`, or `MessagePort` presents. */\ninterface MessagePortLike {\n\tpostMessage(message: unknown): void;\n\ton(event: \"message\", handler: (message: unknown) => void): void;\n\tterminate?(): void;\n\tclose?(): void;\n}\n\n/**\n * Adapt a Node `worker_threads` port onto a {@link WorkerTransport}.\n *\n * Covers the main-side `Worker`, the worker's `parentPort`, and a\n * `worker_threads` `MessagePort`: each posts with `postMessage` and emits a\n * `\"message\"` event whose argument IS the payload (no `.data` wrapper, unlike\n * the DOM). On the main side pass the `Worker`; inside the worker pass\n * `parentPort`.\n */\nexport function messagePortTransport(port: MessagePortLike): WorkerTransport {\n\treturn {\n\t\tpostMessage: (message) => port.postMessage(message),\n\t\tonMessage: (handler) => {\n\t\t\tport.on(\"message\", (message) => handler(message));\n\t\t},\n\t\tterminate: () => {\n\t\t\tport.terminate?.();\n\t\t\tport.close?.();\n\t\t},\n\t};\n}\n"]}
|