From dd49c00bc0db65e6d8310290258048b2f7353263 Mon Sep 17 00:00:00 2001 From: Alexandre Nunes Date: Sun, 20 Sep 2020 15:48:15 -0300 Subject: [PATCH] feat: add nested mtable use case and fix matrix logic --- __test__/mocks/mathmlStrings.ts | 222 ++++++++++++++++++ .../mathml-tags/MFenced.ts | 78 ++++-- .../mathml-tag-to-latex/mathml-tags/MTable.ts | 8 +- .../mathml-tags/MathMLTag.ts | 16 ++ 4 files changed, 300 insertions(+), 24 deletions(-) diff --git a/__test__/mocks/mathmlStrings.ts b/__test__/mocks/mathmlStrings.ts index 9be0676..383008a 100755 --- a/__test__/mocks/mathmlStrings.ts +++ b/__test__/mocks/mathmlStrings.ts @@ -397,6 +397,228 @@ export const mfencedAsPartialFunction = ` `; +export const mfencedWithNestedMtables = ` + + + + + + + + + + + + a + + + 11 + + + + + + + a + + + 12 + + + + + + + + + + + + + + + + + + + + + + a + + + 1 + n + + + + + + + + + + + + a + + + 21 + + + + + + + a + + + 22 + + + + + + + + + + + + + + + + + + + + + + a + + + 2 + n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + + + m + 1 + + + + + + + a + + + m + 2 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + a + + + m + n + + + + + + + + + + + + +`; + export const mfrac = ` diff --git a/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MFenced.ts b/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MFenced.ts index 7e95b06..009cfe2 100755 --- a/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MFenced.ts +++ b/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MFenced.ts @@ -41,37 +41,69 @@ class Vector { } class Matrix { - private readonly _open: string; - private readonly _close: string; + private readonly _separators: Separators; private readonly _genericCommand = 'matrix'; + constructor(open: string, close: string) { + this._separators = new Separators(open, close); + } + + apply(latex: string): string { + const command = this._command; + const matrix = `\\begin{${command}}\n${latex}\n\\end{${command}}`; + + return command === this._genericCommand ? this._separators.wrap(matrix) : matrix; + } + + private get _command(): string { + if (this._separators.areParentheses()) return 'pmatrix'; + if (this._separators.areSquareBrackets()) return 'bmatrix'; + if (this._separators.areBrackets()) return 'Bmatrix'; + if (this._separators.areDivides()) return 'vmatrix'; + if (this._separators.areParallels()) return 'Vmatrix'; + if (this._separators.areNotEqual()) return this._genericCommand; + return 'bmatrix'; + } +} + +class Separators { + readonly _open: string; + readonly _close: string; + constructor(open: string, close: string) { this._open = open; this._close = close; } - apply(latex: string): string { - if (this._close || !this._open) - return `\\begin{${this._customCommand}}\n` + latex + `\n\\end{${this._customCommand}}`; - - const matrix = `\\begin{${this._genericCommand}}\n` + latex + `\n\\end{${this._genericCommand}}`; - return new GenericWrapper(this._open, this._close).wrap(matrix); + wrap(str: string): string { + return new GenericWrapper(this._open, this._close).wrap(str); } - private get _customCommand(): string { - switch (this._open) { - case '(': - return 'pmatrix'; - case '|': - return 'vmatrix'; - case '||': - return 'Vmatrix'; - case '[': - return 'bmatrix'; - case '{': - return 'Bmatrix'; - default: - return this._genericCommand; - } + areParentheses(): boolean { + return this._compare('(', ')'); + } + + areSquareBrackets(): boolean { + return this._compare('[', ']'); + } + + areBrackets(): boolean { + return this._compare('{', '}'); + } + + areDivides(): boolean { + return this._compare('|', '|'); + } + + areParallels(): boolean { + return this._compare('||', '||'); + } + + areNotEqual(): boolean { + return this._open !== this._close; + } + + private _compare(openToCompare: string, closeToCompare: string): boolean { + return this._open === openToCompare && this._close === closeToCompare; } } diff --git a/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MTable.ts b/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MTable.ts index 6d2d653..8a85b8b 100644 --- a/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MTable.ts +++ b/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MTable.ts @@ -3,9 +3,15 @@ import { MathMLTag } from './MathMLTag'; export class MTable extends MathMLTag { constructor(value: string, attributes: Record, children: MathMLTag[]) { super('mtable', value, attributes, children); + this.addFlagRecursiveIfClassName(this.constructor.name, 'innerTable'); } convert(): string { - return this._mapChildrenToLaTeX().join(' \\\\\n'); + const tableContent = this._mapChildrenToLaTeX().join(' \\\\\n'); + return this.hasFlag('innerTable') ? this._wrap(tableContent) : tableContent; + } + + private _wrap(latex: string): string { + return `\\begin{matrix}${latex}\\end{matrix}`; } } diff --git a/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MathMLTag.ts b/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MathMLTag.ts index c853b56..e8a4b03 100755 --- a/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MathMLTag.ts +++ b/src/converters/mathml-interfaces-to-latex/mathml-tag-to-latex/mathml-tags/MathMLTag.ts @@ -3,6 +3,7 @@ export class MathMLTag { protected _value: string; protected _attributes: Record; protected _children: MathMLTag[]; + protected _flags: string[] = []; constructor(name: string, value: string, attributes: Record, children: MathMLTag[]) { this._name = name; @@ -29,4 +30,19 @@ export class MathMLTag { return firstChild.constructor.name === className || firstChild.isThere(className); } + + addFlag(flag: string): void { + if (!this._flags.includes(flag)) this._flags.push(flag); + } + + addFlagRecursiveIfClassName(className: string, flag: string): void { + this._children.forEach((child) => { + if (child.constructor.name === className) child.addFlag(flag); + child.addFlagRecursiveIfClassName(className, flag); + }); + } + + hasFlag(flag: string): boolean { + return this._flags.includes(flag); + } }