From 386f21efbd5a68b01d80fa0e9213d6d5ca6cf428 Mon Sep 17 00:00:00 2001 From: Josh Hansen Date: Mon, 26 Jul 2021 13:23:45 -0700 Subject: [PATCH 1/6] Various improvements to the Typescript typings Allows instantiation of classes (e.g. new ConstantNode(5)) Corrects the default invocation of `rationalize` (the signatures were in the wrong order---MathNode is now the default return type) Makes `create` return a `MathJsStatic` rather than `Partial` which is painful to use and largely unnecessary because most fields on MathJsStatic are already optional. Adds convenient aliases for `subtract` Adds `implicit?: boolean` to MathNode Make the unit on Unit.toNumber and Unit.toNumeric optional like it is in practice Represent math.simplify.rules and math.simplify.simplifyCore --- types/index.d.ts | 185 ++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 173 insertions(+), 12 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index b5d1aee84..ed35e68d1 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -156,6 +156,131 @@ declare namespace math { isHexDigit(c: string): boolean; } + interface AccessorNode extends MathNode { + object: MathNode; + index: IndexNode; + name: string; + } + interface AccessorNodeCtor { + new(object: MathNode, index: IndexNode): AccessorNode; + } + + interface ArrayNode extends MathNode { + items: MathNode[]; + } + interface ArrayNodeCtor { + new(items: MathNode[]): ArrayNode; + } + + interface AssignmentNode { + object: SymbolNode | AccessorNode; + index: IndexNode | null; + value: MathNode; + name: string; + } + interface AssignmentNodeCtor { + new(object: SymbolNode, value: MathNode): AssignmentNode; + new(object: SymbolNode | AccessorNode, index: IndexNode, value: MathNode): AssignmentNode; + } + + interface BlockNode extends MathNode { + blocks: Array<{node: MathNode, visible: boolean}>; + } + interface BlockNodeCtor { + new(arr: Array<{node: MathNode} | {node: MathNode, visible: boolean}>): BlockNode; + } + + interface ConditionalNode extends MathNode { + condition: MathNode; + trueExpr: MathNode; + falseExpr: MathNode; + } + interface ConditionalNodeCtor { + new(condition: MathNode, trueExpr: MathNode, falseExpr: MathNode): ConditionalNode; + } + + interface ConstantNodeCtor { + new(constant: number): MathNode; + } + + interface FunctionAssignmentNode extends MathNode { + name: string; + params: string[]; + expr: MathNode; + } + interface FunctionAssignmentNodeCtor { + new(name: string, params: string[], expr: MathNode): FunctionAssignmentNode; + } + + interface FunctionNode extends MathNode { + //TODO Proper type for fn + // fn: MathNode | string; + args: MathNode[]; + } + interface FunctionNodeCtor { + new(fn: MathNode | string, args: MathNode[]): FunctionNode; + } + + interface IndexNode extends MathNode { + dimensions: MathNode[]; + dotNotation: boolean; + } + interface IndexNodeCtor { + new(dimensions: MathNode[]): IndexNode; + new(dimensions: MathNode[], dotNotation: boolean): IndexNode; + } + + interface ObjectNode extends MathNode { + properties: Record; + } + interface ObjectNodeCtor { + new(properties: Record): ObjectNode; + } + + interface OperatorNode extends MathNode { + op: string; + fn: string; + args: MathNode[]; + implicit: boolean; + isUnary(): boolean; + isBinary(): boolean; + } + interface OperatorNodeCtor { + new(op: string, fn: string, args: MathNode[], implicit?: boolean): OperatorNode; + } + + interface ParenthesisNode extends MathNode { + content: MathNode; + } + interface ParenthesisNodeCtor { + new(content: MathNode): ParenthesisNode; + } + + interface RangeNode extends MathNode { + start: MathNode; + end: MathNode; + step: MathNode | null; + } + interface RangeNodeCtor { + new(start: MathNode, end: MathNode, step?: MathNode): RangeNode; + } + + interface RelationalNode extends MathNode { + conditionals: string[]; + params: MathNode[]; + } + interface RelationalNodeCtor { + new(conditionals: string[], params: MathNode[]): RelationalNode; + } + + interface SymbolNode extends MathNode { + name: string; + } + interface SymbolNodeCtor { + new(name: string): SymbolNode; + } + + type MathJsFunctionName = keyof MathJsStatic; interface MathJsStatic extends FactoryDependencies { @@ -173,6 +298,23 @@ declare namespace math { SQRT2: number; tau: number; + // Class-like constructors + AccessorNode: AccessorNodeCtor; + ArrayNode: ArrayNodeCtor; + AssignmentNode: AssignmentNodeCtor; + BlockNode: BlockNodeCtor; + ConditionalNode: ConditionalNodeCtor; + ConstantNode: ConstantNodeCtor; + FunctionAssignmentNode: FunctionAssignmentNodeCtor; + FunctionNode: FunctionNodeCtor; + IndexNode: IndexNodeCtor; + ObjectNode: ObjectNodeCtor; + OperatorNode: OperatorNodeCtor; + ParenthesisNode: ParenthesisNodeCtor; + RangeNode: RangeNodeCtor; + RelationalNode: RelationalNodeCtor; + SymbolNode: SymbolNodeCtor; + /** * If null were to be included in this interface, it would be * auto-suggested as an import in VSCode. This causes issues because @@ -500,6 +642,7 @@ declare namespace math { */ qr(A: Matrix | MathArray): { Q: MathArray | Matrix; R: MathArray | Matrix }; + rationalize(expr: MathNode | string, optional?: object | boolean, detailed?: false): MathNode; /** * Transform a rationalizable expression in a rational fraction. If * rational fraction is one variable polynomial then converts the @@ -517,7 +660,7 @@ declare namespace math { optional?: object | boolean, detailed?: true ): { expression: MathNode | string; variables: string[]; coefficients: MathType[] }; - rationalize(expr: MathNode | string, optional?: object | boolean, detailed?: false): MathNode; + /** * Simplify an expression tree. @@ -530,13 +673,7 @@ declare namespace math { * @param [options] (optional) An object with simplify options * @returns Returns the simplified form of expr */ - simplify( - expr: MathNode | string, - rules?: Array<{ l: string; r: string } | string | ((node: MathNode) => MathNode)>, - scope?: object, - options?: SimplifyOptions, - ): MathNode; - simplify(expr: MathNode | string, scope?: object, options?: SimplifyOptions): MathNode; + simplify: Simplify; /** * Calculate the Sparse Matrix LU decomposition with full pivoting. @@ -649,6 +786,7 @@ declare namespace math { * @returns Quotient, x / y */ divide(x: Unit, y: Unit): Unit | number; + divide(x: Unit, y: number): Unit; divide(x: number, y: number): number; divide(x: MathType, y: MathType): MathType; @@ -941,6 +1079,8 @@ declare namespace math { * @param y Value to subtract from x * @returns Subtraction of x and y */ + subtract(x: number, y: number): number; + subtract(x: Unit, y: Unit): Unit; subtract(x: MathType, y: MathType): MathType; /** @@ -2540,7 +2680,7 @@ declare namespace math { * Factory and Dependencies ************************************************************************/ interface FactoryDependencies { - create: (factories: FactoryFunctionMap, config?: ConfigOptions) => Partial; + create: (factories: FactoryFunctionMap, config?: ConfigOptions) => MathJsStatic; factory: ( name: string, dependencies: MathJsFunctionName[], @@ -2941,8 +3081,8 @@ declare namespace math { pow(unit: Unit): Unit; abs(unit: Unit): Unit; to(unit: string): Unit; - toNumber(unit: string): number; - toNumeric(unit: string): number | Fraction | BigNumber; + toNumber(unit?: string): number; + toNumeric(unit?: string): number | Fraction | BigNumber; toSI(): Unit; toString(): string; toJSON(): MathJSON; @@ -2969,6 +3109,26 @@ declare namespace math { fractionsLimit?: number; } + type SimplifyRule = { l: string; r: string } | string | ((node: MathNode) => MathNode); + + interface Simplify { + ( + expr: MathNode | string, + rules?: Array, + scope?: object, + options?: SimplifyOptions, + ): MathNode; + ( + expr: MathNode | string, + scope?: object, + options?: SimplifyOptions, + ): MathNode; + + rules: Array; + + simplifyCore(expr: MathNode): MathNode; + } + interface UnitDefinition { definition?: string | Unit; prefixes?: string; @@ -3008,6 +3168,7 @@ declare namespace math { type: string; name?: string; value?: any; + implicit?: boolean; /** * Create a shallow clone of the node. The node itself is cloned, its @@ -3445,7 +3606,7 @@ declare namespace math { * can be specified as an object, string, or function. * @param scope Scope to variables */ - simplify(rules?: Array<{ l: string; r: string } | string | ((node: MathNode) => MathNode)>, scope?: object): MathJsChain; + simplify(rules?: Array, scope?: object): MathJsChain; /** * Calculate the Sparse Matrix LU decomposition with full pivoting. From 0a9881e3cfa046a28f6f4e4082cdb138da63a4f4 Mon Sep 17 00:00:00 2001 From: Josh Hansen Date: Thu, 16 Sep 2021 15:59:46 -0700 Subject: [PATCH 2/6] Make AssignmentNode extend MathNode --- types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index ed35e68d1..867e56b0e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -172,7 +172,7 @@ declare namespace math { new(items: MathNode[]): ArrayNode; } - interface AssignmentNode { + interface AssignmentNode extends MathNode { object: SymbolNode | AccessorNode; index: IndexNode | null; value: MathNode; From 8a80ed83a4a8dd838c7c9c1607fb0545196a3e2c Mon Sep 17 00:00:00 2001 From: Josh Hansen Date: Thu, 16 Sep 2021 16:00:04 -0700 Subject: [PATCH 3/6] Add ConstantNode as an alias for MathNode and return it --- types/index.d.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index 867e56b0e..4540c0ef5 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -199,8 +199,10 @@ declare namespace math { new(condition: MathNode, trueExpr: MathNode, falseExpr: MathNode): ConditionalNode; } + type ConstantNode = MathNode; + interface ConstantNodeCtor { - new(constant: number): MathNode; + new(constant: number): ConstantNode; } interface FunctionAssignmentNode extends MathNode { From 402fa0e3626926272e882635b1e18dd334a932db Mon Sep 17 00:00:00 2001 From: Josh Hansen Date: Thu, 16 Sep 2021 16:00:17 -0700 Subject: [PATCH 4/6] Array -> SimplifyRule[] --- types/index.d.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 4540c0ef5..0c3e3a3d1 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -3116,7 +3116,7 @@ declare namespace math { interface Simplify { ( expr: MathNode | string, - rules?: Array, + rules?: SimplifyRule[], scope?: object, options?: SimplifyOptions, ): MathNode; @@ -3126,7 +3126,7 @@ declare namespace math { options?: SimplifyOptions, ): MathNode; - rules: Array; + rules: SimplifyRule[]; simplifyCore(expr: MathNode): MathNode; } @@ -3608,7 +3608,7 @@ declare namespace math { * can be specified as an object, string, or function. * @param scope Scope to variables */ - simplify(rules?: Array, scope?: object): MathJsChain; + simplify(rules?: SimplifyRule[], scope?: object): MathJsChain; /** * Calculate the Sparse Matrix LU decomposition with full pivoting. From d01d9ea10148357cd5b64e066d34f75e4ca31016 Mon Sep 17 00:00:00 2001 From: Josh Hansen Date: Fri, 17 Sep 2021 01:36:05 -0700 Subject: [PATCH 5/6] Redefine MathNode as a union type of interfaces implementing MathNodeCommon --- types/index.d.ts | 102 +++++++++++++++++++++++++++-------------------- 1 file changed, 59 insertions(+), 43 deletions(-) diff --git a/types/index.d.ts b/types/index.d.ts index 0c3e3a3d1..8ac18635e 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -156,7 +156,9 @@ declare namespace math { isHexDigit(c: string): boolean; } - interface AccessorNode extends MathNode { + interface AccessorNode extends MathNodeCommon { + type: 'AccessorNode'; + isAccessorNode: true; object: MathNode; index: IndexNode; name: string; @@ -165,14 +167,18 @@ declare namespace math { new(object: MathNode, index: IndexNode): AccessorNode; } - interface ArrayNode extends MathNode { + interface ArrayNode extends MathNodeCommon { + type: 'ArrayNode'; + isArrayNode: true; items: MathNode[]; } interface ArrayNodeCtor { new(items: MathNode[]): ArrayNode; } - interface AssignmentNode extends MathNode { + interface AssignmentNode extends MathNodeCommon { + type: 'AssignmentNode'; + isAssignmentNode: true; object: SymbolNode | AccessorNode; index: IndexNode | null; value: MathNode; @@ -183,14 +189,18 @@ declare namespace math { new(object: SymbolNode | AccessorNode, index: IndexNode, value: MathNode): AssignmentNode; } - interface BlockNode extends MathNode { + interface BlockNode extends MathNodeCommon { + type: 'BlockNode'; + isBlockNode: true; blocks: Array<{node: MathNode, visible: boolean}>; } interface BlockNodeCtor { new(arr: Array<{node: MathNode} | {node: MathNode, visible: boolean}>): BlockNode; } - interface ConditionalNode extends MathNode { + interface ConditionalNode extends MathNodeCommon { + type: 'ConditionalNode'; + isConditionalnode: boolean; condition: MathNode; trueExpr: MathNode; falseExpr: MathNode; @@ -199,13 +209,19 @@ declare namespace math { new(condition: MathNode, trueExpr: MathNode, falseExpr: MathNode): ConditionalNode; } - type ConstantNode = MathNode; + interface ConstantNode extends MathNodeCommon { + type: 'ConstantNode'; + isConstantNode: true; + value: any; + } interface ConstantNodeCtor { new(constant: number): ConstantNode; } - interface FunctionAssignmentNode extends MathNode { + interface FunctionAssignmentNode extends MathNodeCommon { + type: 'FunctionAssignmentNode'; + isFunctionAssignmentNode: true; name: string; params: string[]; expr: MathNode; @@ -214,16 +230,19 @@ declare namespace math { new(name: string, params: string[], expr: MathNode): FunctionAssignmentNode; } - interface FunctionNode extends MathNode { - //TODO Proper type for fn - // fn: MathNode | string; + interface FunctionNode extends MathNodeCommon { + type: 'FunctionNode'; + isFunctionNode: true; + fn: SymbolNode; args: MathNode[]; } interface FunctionNodeCtor { new(fn: MathNode | string, args: MathNode[]): FunctionNode; } - interface IndexNode extends MathNode { + interface IndexNode extends MathNodeCommon { + type: 'IndexNode'; + isIndexNode: true; dimensions: MathNode[]; dotNotation: boolean; } @@ -232,14 +251,18 @@ declare namespace math { new(dimensions: MathNode[], dotNotation: boolean): IndexNode; } - interface ObjectNode extends MathNode { + interface ObjectNode extends MathNodeCommon { + type: 'ObjectNode'; + isObjectNode: true; properties: Record; } interface ObjectNodeCtor { new(properties: Record): ObjectNode; } - interface OperatorNode extends MathNode { + interface OperatorNode extends MathNodeCommon { + type: 'OperatorNode'; + isOperatorNode: true; op: string; fn: string; args: MathNode[]; @@ -251,14 +274,18 @@ declare namespace math { new(op: string, fn: string, args: MathNode[], implicit?: boolean): OperatorNode; } - interface ParenthesisNode extends MathNode { + interface ParenthesisNode extends MathNodeCommon { + type: 'ParenthesisNode'; + isParenthesisNode: true; content: MathNode; } interface ParenthesisNodeCtor { new(content: MathNode): ParenthesisNode; } - interface RangeNode extends MathNode { + interface RangeNode extends MathNodeCommon { + type: 'RangeNode'; + isRangeNode: true; start: MathNode; end: MathNode; step: MathNode | null; @@ -267,7 +294,9 @@ declare namespace math { new(start: MathNode, end: MathNode, step?: MathNode): RangeNode; } - interface RelationalNode extends MathNode { + interface RelationalNode extends MathNodeCommon { + type: 'RelationalNode'; + isRelationalNode: true; conditionals: string[]; params: MathNode[]; } @@ -275,13 +304,19 @@ declare namespace math { new(conditionals: string[], params: MathNode[]): RelationalNode; } - interface SymbolNode extends MathNode { + interface SymbolNode extends MathNodeCommon { + type: 'SymbolNode'; + isSymbolNode: true; name: string; } interface SymbolNodeCtor { new(name: string): SymbolNode; } + type MathNode = AccessorNode | ArrayNode | AssignmentNode | BlockNode | ConditionalNode | ConstantNode | + FunctionAssignmentNode | FunctionNode | IndexNode | ObjectNode | OperatorNode | ParenthesisNode | RangeNode | + RelationalNode | SymbolNode; + type MathJsFunctionName = keyof MathJsStatic; @@ -3144,33 +3179,14 @@ declare namespace math { evaluate(scope?: any): any; } - interface MathNode { - isNode: boolean; - isAccessorNode?: boolean; - isArrayNode?: boolean; - isAssignmentNode?: boolean; - isBlockNode?: boolean; - isConditionalNode?: boolean; - isConstantNode?: boolean; - isFunctionAssignmentNode?: boolean; - isFunctionNode?: boolean; - isIndexNode?: boolean; - isObjectNode?: boolean; - isOperatorNode?: boolean; - isParenthesisNode?: boolean; - isRangeNode?: boolean; - isRelationalNode?: boolean; - isSymbolNode?: boolean; + interface MathNodeCommon { + isNode: true; + comment: string; + type: 'AccessorNode' | 'ArrayNode' | 'AssignmentNode' | 'BlockNode' | 'ConditionalNode' | 'ConstantNode' | + 'FunctionAssignmentNode' | 'FunctionNode' | 'IndexNode' | 'ObjectNode' | 'OperatorNode' | 'ParenthesisNode' | + 'RangeNode' | 'RelationalNode' | 'SymbolNode'; + isUpdateNode?: boolean; - comment?: string; - content?: MathNode; - op?: string; - fn?: string; - args?: MathNode[]; - type: string; - name?: string; - value?: any; - implicit?: boolean; /** * Create a shallow clone of the node. The node itself is cloned, its From 8317eb5545e4e6d1f028a090f0b4f0fa44739ea7 Mon Sep 17 00:00:00 2001 From: Josh Hansen Date: Fri, 17 Sep 2021 01:54:32 -0700 Subject: [PATCH 6/6] Re-fix the isConditionalNode typo that was corrected in 9.4.5 --- types/index.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types/index.d.ts b/types/index.d.ts index 8ac18635e..afe817cc9 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -200,7 +200,7 @@ declare namespace math { interface ConditionalNode extends MathNodeCommon { type: 'ConditionalNode'; - isConditionalnode: boolean; + isConditionalNode: boolean; condition: MathNode; trueExpr: MathNode; falseExpr: MathNode;