@danielsimonjr/mathts-expression 0.9.0 → 0.10.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/README.md CHANGED
@@ -15,6 +15,7 @@ npm install @danielsimonjr/mathts-expression
15
15
  - `createParse` / `createParserClass` / `createParser` — parse to an AST.
16
16
  - 16 AST node constructors (`createConstantNode`, `createOperatorNode`, …).
17
17
  - `compile` / `createEvaluate` / `compileExpression` — evaluate expressions.
18
+ - `createScalarBuilder` — build a scalar node tree (`number`, `symbol`, `op`, `call`, `from`). `ln` lowers to natural `log` and `log` lowers to `log10`. A formula string is rejected. Evaluate with `evaluateScalar` from `@danielsimonjr/mathts-functions`.
18
19
  - AST serializers on every node: `toString()`, `toTex()` (LaTeX), `toHTML()`, and `toMathML()` (MathML).
19
20
  - Focused re-exports are also published: `@danielsimonjr/mathts-{parser,ast,evaluator}`.
20
21
 
package/dist/index.d.ts CHANGED
@@ -32,5 +32,7 @@ export { createParenthesisNode } from './node/ParenthesisNode.js';
32
32
  export { createRangeNode } from './node/RangeNode.js';
33
33
  export { createRelationalNode } from './node/RelationalNode.js';
34
34
  export { createSymbolNode } from './node/SymbolNode.js';
35
+ export { createScalarBuilder, SCALAR_FUNCTIONS, SCALAR_FUNCTION_LOWERING, ScalarBuildError, } from './scalar-builder.js';
36
+ export type { LoweredScalarFn, ScalarBuilder, ScalarFunctionName, ScalarNode, ScalarOperator, } from './scalar-builder.js';
35
37
  export * from './transform/index.js';
36
38
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAMrC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAG9F,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAKxD,cAAc,sBAAsB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AACpD,cAAc,WAAW,CAAC;AAC1B,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAC;AAC9D,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AAMrC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAG9F,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,4BAA4B,EAAE,MAAM,kCAAkC,CAAC;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAC5D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAGxD,OAAO,EACL,mBAAmB,EACnB,gBAAgB,EAChB,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EACV,eAAe,EACf,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,cAAc,GACf,MAAM,qBAAqB,CAAC;AAK7B,cAAc,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -12409,6 +12409,161 @@ var createSymbolNode = /* @__PURE__ */ factory(
12409
12409
  { isClass: true, isNode: true }
12410
12410
  );
12411
12411
 
12412
+ // src/scalar-builder.ts
12413
+ var SCALAR_FUNCTION_LOWERING = {
12414
+ exp: "exp",
12415
+ ln: "log",
12416
+ log: "log10",
12417
+ log2: "log2",
12418
+ log10: "log10",
12419
+ sin: "sin",
12420
+ cos: "cos",
12421
+ tan: "tan",
12422
+ sinh: "sinh",
12423
+ cosh: "cosh",
12424
+ tanh: "tanh",
12425
+ abs: "abs"
12426
+ };
12427
+ var SCALAR_FUNCTIONS = [
12428
+ "exp",
12429
+ "ln",
12430
+ "log",
12431
+ "log2",
12432
+ "log10",
12433
+ "sin",
12434
+ "cos",
12435
+ "tan",
12436
+ "sinh",
12437
+ "cosh",
12438
+ "tanh",
12439
+ "abs"
12440
+ ];
12441
+ var LOWERED_FUNCTIONS = new Set(Object.values(SCALAR_FUNCTION_LOWERING));
12442
+ var ScalarBuildError = class extends Error {
12443
+ constructor(message) {
12444
+ super(message);
12445
+ this.name = "ScalarBuildError";
12446
+ }
12447
+ };
12448
+ var OPERATORS = /* @__PURE__ */ new Set(["+", "-", "*", "/", "^"]);
12449
+ function isOperator(op) {
12450
+ return OPERATORS.has(op);
12451
+ }
12452
+ function isScalarFunctionName(fn) {
12453
+ return Object.prototype.hasOwnProperty.call(SCALAR_FUNCTION_LOWERING, fn);
12454
+ }
12455
+ function isLoweredScalarFn(fn) {
12456
+ return LOWERED_FUNCTIONS.has(fn);
12457
+ }
12458
+ function isCanonicalNode(value) {
12459
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return false;
12460
+ const kind = value.kind;
12461
+ return kind === "number" || kind === "symbol" || kind === "op" || kind === "call";
12462
+ }
12463
+ function readRecord(node) {
12464
+ if (typeof node === "string") {
12465
+ throw new ScalarBuildError(
12466
+ "scalar builder reads a typed node. A formula string is not accepted."
12467
+ );
12468
+ }
12469
+ if (typeof node !== "object" || node === null || Array.isArray(node)) {
12470
+ throw new ScalarBuildError("scalar builder reads a typed node");
12471
+ }
12472
+ return node;
12473
+ }
12474
+ function createScalarBuilder() {
12475
+ function number(value) {
12476
+ if (typeof value !== "number") {
12477
+ throw new ScalarBuildError("scalar number node requires a number value");
12478
+ }
12479
+ return { kind: "number", value };
12480
+ }
12481
+ function symbol(name47) {
12482
+ if (typeof name47 !== "string") {
12483
+ throw new ScalarBuildError("scalar symbol node requires a string name");
12484
+ }
12485
+ return { kind: "symbol", name: name47 };
12486
+ }
12487
+ function call(fn, arg) {
12488
+ if (!isScalarFunctionName(fn)) {
12489
+ throw new ScalarBuildError(`unknown scalar function '${String(fn)}'`);
12490
+ }
12491
+ if (!isCanonicalNode(arg)) {
12492
+ throw new ScalarBuildError("scalar call argument must be a scalar node");
12493
+ }
12494
+ return { kind: "call", fn: SCALAR_FUNCTION_LOWERING[fn], arg };
12495
+ }
12496
+ function op(operator, args) {
12497
+ if (!isOperator(operator)) {
12498
+ throw new ScalarBuildError(`unknown scalar operator '${String(operator)}'`);
12499
+ }
12500
+ if (!Array.isArray(args)) {
12501
+ throw new ScalarBuildError("scalar operator args must be an array of scalar nodes");
12502
+ }
12503
+ const copied = [];
12504
+ for (const arg of args) {
12505
+ if (!isCanonicalNode(arg)) {
12506
+ throw new ScalarBuildError("scalar operator argument must be a scalar node");
12507
+ }
12508
+ copied.push(arg);
12509
+ }
12510
+ if (operator === "^" && copied.length !== 2) {
12511
+ throw new ScalarBuildError(`'^' needs exactly 2 args, got ${copied.length}`);
12512
+ }
12513
+ return { kind: "op", op: operator, args: copied };
12514
+ }
12515
+ function from(node) {
12516
+ const record = readRecord(node);
12517
+ const kind = record.kind;
12518
+ if (typeof kind !== "string") {
12519
+ throw new ScalarBuildError("scalar node is missing a string kind");
12520
+ }
12521
+ switch (kind) {
12522
+ case "number":
12523
+ return number(record.value);
12524
+ case "symbol":
12525
+ return symbol(record.name);
12526
+ case "op": {
12527
+ const operator = record.op;
12528
+ if (typeof operator !== "string" || !isOperator(operator)) {
12529
+ throw new ScalarBuildError(`unknown scalar operator '${String(operator)}'`);
12530
+ }
12531
+ const args = record.args;
12532
+ if (!Array.isArray(args)) {
12533
+ throw new ScalarBuildError("scalar operator node is missing args");
12534
+ }
12535
+ return op(
12536
+ operator,
12537
+ args.map((arg) => from(arg))
12538
+ );
12539
+ }
12540
+ case "call": {
12541
+ const fn = record.fn;
12542
+ if (typeof fn !== "string" || !isLoweredScalarFn(fn)) {
12543
+ throw new ScalarBuildError(
12544
+ `scalar call '${String(fn)}' must already use a lowered MathTS name`
12545
+ );
12546
+ }
12547
+ return { kind: "call", fn, arg: from(record.arg) };
12548
+ }
12549
+ case "transcendental": {
12550
+ const fn = record.fn;
12551
+ if (typeof fn !== "string" || !isScalarFunctionName(fn)) {
12552
+ throw new ScalarBuildError(`unknown scalar function '${String(fn)}'`);
12553
+ }
12554
+ return call(fn, from(record.arg));
12555
+ }
12556
+ case "abs":
12557
+ return call("abs", from(record.arg));
12558
+ default:
12559
+ throw new ScalarBuildError(
12560
+ `scalar builder: node kind '${kind}' is out of scope (symbol, op, transcendental, abs)`
12561
+ );
12562
+ }
12563
+ }
12564
+ return { number, symbol, op, call, from };
12565
+ }
12566
+
12412
12567
  // src/transform/and.transform.ts
12413
12568
  var name21 = "and";
12414
12569
  var dependencies21 = ["and"];
@@ -13184,6 +13339,9 @@ var createVarianceTransform = /* @__PURE__ */ factory(
13184
13339
  { isTransformFunction: true }
13185
13340
  );
13186
13341
  export {
13342
+ SCALAR_FUNCTIONS,
13343
+ SCALAR_FUNCTION_LOWERING,
13344
+ ScalarBuildError,
13187
13345
  compile,
13188
13346
  compileExpression,
13189
13347
  createAccessorNode,
@@ -13227,6 +13385,7 @@ export {
13227
13385
  createRangeTransform,
13228
13386
  createRelationalNode,
13229
13387
  createRowTransform,
13388
+ createScalarBuilder,
13230
13389
  createStdTransform,
13231
13390
  createSubsetTransform,
13232
13391
  createSumTransform,
@@ -0,0 +1,92 @@
1
+ /**
2
+ * Public scalar-expression builder.
3
+ *
4
+ * UPT lowers an `ExprNode` numeric tree onto this API instead of printing a
5
+ * formula and parsing it. `call('ln', x)` and a `transcendental` node whose
6
+ * `fn` is `ln` store MathTS natural `log`. `call('log', x)` and `fn: 'log'`
7
+ * store `log10`. `log10` and `log2` stay themselves.
8
+ *
9
+ * The node returned by {@link ScalarBuilder.call} and {@link ScalarBuilder.from}
10
+ * already carries the lowered MathTS name on `fn`. Passing that node through
11
+ * `from` again keeps natural `log`; it does not treat it as base-10.
12
+ *
13
+ * @packageDocumentation
14
+ */
15
+ /** Operators on the scalar numeric path (`+ - * / ^`). */
16
+ export type ScalarOperator = '+' | '-' | '*' | '/' | '^';
17
+ /**
18
+ * Input names accepted by {@link ScalarBuilder.call} and by a
19
+ * `transcendental` node. `ln` and `log` are in this set; the stored node uses
20
+ * the lowered name from {@link SCALAR_FUNCTION_LOWERING}.
21
+ */
22
+ export declare const SCALAR_FUNCTION_LOWERING: {
23
+ readonly exp: 'exp';
24
+ readonly ln: 'log';
25
+ readonly log: 'log10';
26
+ readonly log2: 'log2';
27
+ readonly log10: 'log10';
28
+ readonly sin: 'sin';
29
+ readonly cos: 'cos';
30
+ readonly tan: 'tan';
31
+ readonly sinh: 'sinh';
32
+ readonly cosh: 'cosh';
33
+ readonly tanh: 'tanh';
34
+ readonly abs: 'abs';
35
+ };
36
+ /** Names a caller may pass to {@link ScalarBuilder.call}. */
37
+ export type ScalarFunctionName = keyof typeof SCALAR_FUNCTION_LOWERING;
38
+ /** MathTS function stored on a built call node. */
39
+ export type LoweredScalarFn = (typeof SCALAR_FUNCTION_LOWERING)[ScalarFunctionName];
40
+ /**
41
+ * Input names, in lowering-table order. Present so a consumer can see the
42
+ * scalar set without parsing a formula.
43
+ */
44
+ export declare const SCALAR_FUNCTIONS: readonly ScalarFunctionName[];
45
+ /** A scalar node. Call `fn` is the lowered MathTS name. */
46
+ export type ScalarNode = {
47
+ readonly kind: 'number';
48
+ readonly value: number;
49
+ } | {
50
+ readonly kind: 'symbol';
51
+ readonly name: string;
52
+ } | {
53
+ readonly kind: 'op';
54
+ readonly op: ScalarOperator;
55
+ readonly args: readonly ScalarNode[];
56
+ } | {
57
+ readonly kind: 'call';
58
+ readonly fn: LoweredScalarFn;
59
+ readonly arg: ScalarNode;
60
+ };
61
+ /** Builds {@link ScalarNode} values. Each call returns a new builder. */
62
+ export interface ScalarBuilder {
63
+ /** A numeric leaf. `value` must be a number (finite or not). */
64
+ number(value: number): ScalarNode;
65
+ /** A named leaf. Resolution of the name happens at evaluation. */
66
+ symbol(name: string): ScalarNode;
67
+ /**
68
+ * An operator node. `^` requires exactly two arguments. `+`, `-`, `*`, and
69
+ * `/` may be empty or n-ary; evaluation folds them left to right.
70
+ */
71
+ op(op: ScalarOperator, args: readonly ScalarNode[]): ScalarNode;
72
+ /**
73
+ * A unary call. `ln` is stored as `log` (natural). `log` is stored as
74
+ * `log10`.
75
+ */
76
+ call(fn: ScalarFunctionName, arg: ScalarNode): ScalarNode;
77
+ /**
78
+ * Normalize a typed tree. Accepts builder nodes and the scalar arms
79
+ * `symbol`, `op`, `transcendental`, and `abs`. A string is rejected.
80
+ */
81
+ from(node: unknown): ScalarNode;
82
+ }
83
+ /** A node or name the builder cannot represent. */
84
+ export declare class ScalarBuildError extends Error {
85
+ constructor(message: string);
86
+ }
87
+ /**
88
+ * A builder of scalar nodes. Safe to call more than once; builders share no
89
+ * mutable state.
90
+ */
91
+ export declare function createScalarBuilder(): ScalarBuilder;
92
+ //# sourceMappingURL=scalar-builder.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scalar-builder.d.ts","sourceRoot":"","sources":["../src/scalar-builder.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,0DAA0D;AAC1D,MAAM,MAAM,cAAc,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,CAAC;AAEzD;;;;GAIG;AACH,eAAO,MAAM,wBAAwB;aACnC,GAAG,EAAE,KAAK;aACV,EAAE,EAAE,KAAK;aACT,GAAG,EAAE,OAAO;aACZ,IAAI,EAAE,MAAM;aACZ,KAAK,EAAE,OAAO;aACd,GAAG,EAAE,KAAK;aACV,GAAG,EAAE,KAAK;aACV,GAAG,EAAE,KAAK;aACV,IAAI,EAAE,MAAM;aACZ,IAAI,EAAE,MAAM;aACZ,IAAI,EAAE,MAAM;aACZ,GAAG,EAAE,KAAK;CACF,CAAC;AAEX,6DAA6D;AAC7D,MAAM,MAAM,kBAAkB,GAAG,MAAM,OAAO,wBAAwB,CAAC;AAEvE,mDAAmD;AACnD,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,wBAAwB,CAAC,CAAC,kBAAkB,CAAC,CAAC;AAEpF;;;GAGG;AACH,eAAO,MAAM,gBAAgB,EAAE,SAAS,kBAAkB,EAahD,CAAC;AAIX,2DAA2D;AAC3D,MAAM,MAAM,UAAU,GAClB;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,QAAQ,CAAC,IAAI,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAClD;IAAE,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,cAAc,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,SAAS,UAAU,EAAE,CAAA;CAAE,GAC1F;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,EAAE,eAAe,CAAC;IAAC,QAAQ,CAAC,GAAG,EAAE,UAAU,CAAA;CAAE,CAAC;AAEtF,yEAAyE;AACzE,MAAM,WAAW,aAAa;IAC5B,gEAAgE;IAChE,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,UAAU,CAAC;IAClC,kEAAkE;IAClE,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAC;IACjC;;;OAGG;IACH,EAAE,CAAC,EAAE,EAAE,cAAc,EAAE,IAAI,EAAE,SAAS,UAAU,EAAE,GAAG,UAAU,CAAC;IAChE;;;OAGG;IACH,IAAI,CAAC,EAAE,EAAE,kBAAkB,EAAE,GAAG,EAAE,UAAU,GAAG,UAAU,CAAC;IAC1D;;;OAGG;IACH,IAAI,CAAC,IAAI,EAAE,OAAO,GAAG,UAAU,CAAC;CACjC;AAED,mDAAmD;AACnD,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,YAAY,OAAO,EAAE,MAAM,EAG1B;CACF;AAkCD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,aAAa,CAgGnD"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@danielsimonjr/mathts-expression",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Expression parser and evaluator for MathTS",
5
5
  "author": "Daniel Simon Jr.",
6
6
  "license": "MIT",