Keep numeric.js's functions on me.math in the js-compat drop-in - #87
Open
dqnykamp wants to merge 1 commit into
Open
Keep numeric.js's functions on me.math in the js-compat drop-in#87dqnykamp wants to merge 1 commit into
me.math in the js-compat drop-in#87dqnykamp wants to merge 1 commit into
Conversation
`me.math` in the original library was math.js *plus* numeric.js:
math.import(numeric, { wrap: true, silent: true });
The drop-in re-exports a bare math.js instance, so every name numeric
contributed and math.js has no equivalent of is gone. DoenetML's
`<odeSystem>` integrates with `me.math.dopri`, which is one of them — so
moving to this package turns a working ODE into `dopri is not a
function`. Import numeric here too; `silent` keeps math.js's own
implementations for the names both define.
Registering numeric on the global object is part of making it usable.
numeric.js builds most of its helpers at load time with the `Function`
constructor, and the generated bodies reference a bare `numeric` — e.g.
`if(typeof _s === "undefined") _s = numeric.dim(x);`. Functions made that
way are evaluated in global scope, so that reference resolves only if
`numeric` is a property of the global object. numeric.js puts it there
itself, but only through Node's `global`, which a browser and a web
worker both lack; there, every generated helper throws `ReferenceError:
numeric is not defined` on first call, `dopri` included.
The assignment is unconditional rather than guarded on
`globalThis.numeric === undefined`: on a page holding an element whose id
is `numeric`, the named-element global makes the slot look occupied while
still being useless to the generated code.
`spec/quick_mathjs-numeric.spec.ts` deletes `global` before the first
import of `lib/mathjs`, reproducing the shape a browser sees, then
integrates x' = x from x(0) = 1 and checks it lands on e.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to #86, which fixes the same underlying problem on the
2.xbranch. This one is about the drop-in onmain.me.mathlost numeric's functionsThe original library built
me.mathas math.js plus numeric.js:packages/math-expressions-js-compat/lib/mathjs.tsre-exports a bare math.js instance, so every name numeric contributed and math.js has no equivalent of is simply gone. DoenetML's<odeSystem>integrates withme.math.dopri, which is one of them — it is the only numeric-only name DoenetML reaches for, but it is load-bearing: adopting this package as published would turn a working ODE intodopri is not a function.So this imports numeric here too.
silentskips the names math.js already defines (add,sqrt,round, …), leaving math.js's own implementations in place — the same arrangement the 2.x line has always shipped.…and numeric needs a global to be usable
numeric.js builds most of its helpers at load time with the
Functionconstructor, and the generated bodies reference a barenumeric:Functions made with
Function(...)are evaluated in global scope, so that reference resolves only ifnumericis a property of the global object. numeric.js puts it there itself — but through a Node-ism:A browser main thread and a web worker both have no
global, so the assignment is skipped and every generated helper throwsReferenceError: numeric is not definedthe first time it is called.doprireaches those helpers immediately, which is why the bug is invisible to a Node test suite and fatal in the browser. Publishing it fromlib/mathjs.tscovers every runtime.The assignment is unconditional rather than guarded on
globalThis.numeric === undefined. On a page holding an element whose id isnumeric, the named-element global makes the slot look occupied while still being useless to the generated code — which is what happens in DoenetML, whose virtual keyboard has anumericbutton, and it turns the error into the more puzzlingdim is not a function.Test
spec/quick_mathjs-numeric.spec.tsdeletesglobalbefore the first import oflib/mathjs— reproducing the shape a browser sees — then checks that the module registered numeric itself, and integrates x' = x from x(0) = 1 to confirmdopriis both present and callable.The js-compat suite is not green on
main(hence the|| truein CI), so here is the before/after rather than a bare pass:mainExactly the one new test, no new failures.
prettier --checkis clean on the changed files, andtscreports nothing new for them beyond the pre-existingCannot find name 'describe'that every spec in the package already has.numeric@1.2.6is added to the package's dependencies; it was already resolved in the lockfile, so that diff is two lines.🤖 Generated with Claude Code