refactor: change project to clean architecture design
This commit is contained in:
parent
688940bdd1
commit
c03e47709f
@ -1,4 +1,4 @@
|
||||
import XmlToMathMLAdapter from '../../../src/converters/xml-mathml-to-latex/xml-to-mathml';
|
||||
import { XmlToMathMLAdapter } from '../../../src/infra/usecases/xmldom-to-mathml-elements';
|
||||
import {
|
||||
singleMi,
|
||||
singleMiNoRoot,
|
||||
|
@ -1,18 +0,0 @@
|
||||
import { MathML } from '../../protocols/MathML';
|
||||
import MathmlToLatex from './xml-to-mathml/mathml-to-latex';
|
||||
import XmlToMathml from './xml-to-mathml';
|
||||
|
||||
export class XmlMathMLToLaTeX {
|
||||
constructor(private _mathml: string) {
|
||||
this._mathml = _mathml;
|
||||
}
|
||||
|
||||
static convert(_mathml: string): string {
|
||||
return new XmlMathMLToLaTeX(_mathml).convert();
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const mathmlInterfaces: MathML[] = new XmlToMathml(this._mathml).convert();
|
||||
return new MathmlToLatex(mathmlInterfaces).convert();
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
import { XmlMathMLToLaTeX } from './XmlMathMLToLaTeX';
|
||||
|
||||
export default XmlMathMLToLaTeX;
|
@ -1,33 +0,0 @@
|
||||
import { MathML } from '../../../protocols/MathML';
|
||||
|
||||
export class ElementsToMathMLAdapter {
|
||||
convert(els: Element[]): MathML[] {
|
||||
return els.filter((el: Element) => el.tagName !== undefined).map((el: Element) => this._convertElement(el));
|
||||
}
|
||||
|
||||
private _convertElement(el: Element): MathML {
|
||||
return {
|
||||
name: el.tagName,
|
||||
attributes: el.attributes ? this._convertElementAttributes(el.attributes) : {},
|
||||
value: this._hasElementChild(el) ? '' : el.textContent || '',
|
||||
children: this._hasElementChild(el) ? this.convert(Array.from(el.childNodes) as Element[]) : ([] as MathML[]),
|
||||
};
|
||||
}
|
||||
|
||||
private _convertElementAttributes(attributes: NamedNodeMap): Record<string, string> {
|
||||
return Array.from(attributes).reduce(
|
||||
(acc, attr: Attr) =>
|
||||
Object.assign({ [attr.nodeName]: attr.nodeValue === attr.nodeName ? '' : attr.nodeValue }, acc),
|
||||
{},
|
||||
);
|
||||
}
|
||||
|
||||
private _hasElementChild(el: Element): boolean {
|
||||
const childNodes = el.childNodes;
|
||||
return !!childNodes && childNodes.length !== 0 && this._isThereAnyNoTextNode(childNodes);
|
||||
}
|
||||
|
||||
private _isThereAnyNoTextNode(children: NodeListOf<ChildNode>): boolean {
|
||||
return Array.from(children).some((child) => child.nodeName !== '#text');
|
||||
}
|
||||
}
|
@ -1,42 +0,0 @@
|
||||
import xmldom = require('xmldom');
|
||||
|
||||
import { DOMParser } from 'xmldom';
|
||||
import { ErrorHandler } from './ErrorHandler';
|
||||
import { MathML } from '../../../protocols/MathML';
|
||||
import { ElementsToMathMLAdapter } from './ElementsToMathMLAdapter';
|
||||
|
||||
export class XmlToMathMLAdapter {
|
||||
private _xmlDOM: DOMParser;
|
||||
private _errorHandler: ErrorHandler;
|
||||
private _elementsConvertor: ElementsToMathMLAdapter;
|
||||
|
||||
constructor(private _xml: string) {
|
||||
this._xml = this._removeLineBreaks(_xml);
|
||||
|
||||
this._elementsConvertor = new ElementsToMathMLAdapter();
|
||||
this._errorHandler = new ErrorHandler();
|
||||
|
||||
this._xmlDOM = new xmldom.DOMParser({
|
||||
locator: this._errorHandler.errorLocator,
|
||||
errorHandler: this._fixError.bind(this),
|
||||
});
|
||||
}
|
||||
|
||||
convert(): MathML[] {
|
||||
return this._elementsConvertor.convert(this._mathMLElements);
|
||||
}
|
||||
|
||||
private _fixError(errorMessage: string): void {
|
||||
this._xml = this._errorHandler.fixError(this._xml, errorMessage);
|
||||
}
|
||||
|
||||
private _removeLineBreaks(xml: string): string {
|
||||
const LINE_BREAK = /\n|\r\n|\r/g;
|
||||
return xml.replace(LINE_BREAK, '');
|
||||
}
|
||||
|
||||
private get _mathMLElements(): Element[] {
|
||||
const elements = this._xmlDOM.parseFromString(this._xml).getElementsByTagName('math');
|
||||
return Array.from(elements) as Element[];
|
||||
}
|
||||
}
|
@ -1,2 +0,0 @@
|
||||
import { XmlToMathMLAdapter } from './XmlToMathMLAdapter';
|
||||
export default XmlToMathMLAdapter;
|
@ -1,20 +0,0 @@
|
||||
import { MathML } from '../../../../protocols/MathML';
|
||||
import Dispatcher from './mathml-to-latex';
|
||||
import { MathMLTag } from './mathml-to-latex/mathml-tags';
|
||||
|
||||
export class MathMLToLaTeX {
|
||||
constructor(private _mathMLInterfaces: MathML[]) {
|
||||
this._mathMLInterfaces = _mathMLInterfaces;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return this._mathMLInterfaces.map((mathml) => this._dispatch(mathml).convert()).join('');
|
||||
}
|
||||
|
||||
private _dispatch(mathml: MathML): MathMLTag {
|
||||
const { name, value, attributes } = mathml;
|
||||
const children = mathml.children.map((children) => this._dispatch(children));
|
||||
|
||||
return new Dispatcher(name, value, attributes, children).dispatch();
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
import { MathMLToLaTeX } from './MathMLToLaTeX';
|
||||
|
||||
export default MathMLToLaTeX;
|
@ -1,68 +0,0 @@
|
||||
import * as MathMLTags from './mathml-tags';
|
||||
|
||||
export class Dispatcher {
|
||||
private _name: string;
|
||||
private _value: string;
|
||||
private _attributes: Record<string, string>;
|
||||
private _children: MathMLTags.MathMLTag[];
|
||||
|
||||
constructor(name: string, value: string, attributes: Record<string, string>, children: MathMLTags.MathMLTag[]) {
|
||||
this._name = name;
|
||||
this._value = value;
|
||||
this._attributes = attributes;
|
||||
this._children = children;
|
||||
}
|
||||
|
||||
dispatch(): MathMLTags.MathMLTag {
|
||||
switch (this._name) {
|
||||
case 'math':
|
||||
return new MathMLTags.Math(this._value, this._attributes, this._children);
|
||||
case 'mi':
|
||||
return new MathMLTags.MI(this._value, this._attributes, this._children);
|
||||
case 'mo':
|
||||
return new MathMLTags.MO(this._value, this._attributes, this._children);
|
||||
case 'mn':
|
||||
return new MathMLTags.MN(this._value, this._attributes, this._children);
|
||||
case 'msqrt':
|
||||
return new MathMLTags.MSqrt(this._value, this._attributes, this._children);
|
||||
case 'mfenced':
|
||||
return new MathMLTags.MFenced(this._value, this._attributes, this._children);
|
||||
case 'mfrac':
|
||||
return new MathMLTags.MFrac(this._value, this._attributes, this._children);
|
||||
case 'mroot':
|
||||
return new MathMLTags.MRoot(this._value, this._attributes, this._children);
|
||||
case 'maction':
|
||||
return new MathMLTags.MAction(this._value, this._attributes, this._children);
|
||||
case 'menclose':
|
||||
return new MathMLTags.MEnclose(this._value, this._attributes, this._children);
|
||||
case 'merror':
|
||||
return new MathMLTags.MError(this._value, this._attributes, this._children);
|
||||
case 'mphantom':
|
||||
return new MathMLTags.MPhantom(this._value, this._attributes, this._children);
|
||||
case 'msup':
|
||||
return new MathMLTags.MSup(this._value, this._attributes, this._children);
|
||||
case 'msub':
|
||||
return new MathMLTags.MSub(this._value, this._attributes, this._children);
|
||||
case 'msubsup':
|
||||
return new MathMLTags.MSubsup(this._value, this._attributes, this._children);
|
||||
case 'mmultiscripts':
|
||||
return new MathMLTags.MMultiscripts(this._value, this._attributes, this._children);
|
||||
case 'mtext':
|
||||
return new MathMLTags.MText(this._value, this._attributes, this._children);
|
||||
case 'munderover':
|
||||
return new MathMLTags.MUnderover(this._value, this._attributes, this._children);
|
||||
case 'mtable':
|
||||
return new MathMLTags.MTable(this._value, this._attributes, this._children);
|
||||
case 'mtr':
|
||||
return new MathMLTags.MTr(this._value, this._attributes, this._children);
|
||||
case 'mover':
|
||||
case 'munder':
|
||||
return new MathMLTags.GenericUnderOverTag(this._name, this._value, this._attributes, this._children);
|
||||
case 'mrow':
|
||||
case 'mpadded':
|
||||
return new MathMLTags.GenericContentWrapperTag(this._name, this._value, this._attributes, this._children);
|
||||
default:
|
||||
return new MathMLTags.MathMLTag(this._name, this._value, this._attributes, this._children);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
import { Dispatcher } from './Dispatcher';
|
||||
|
||||
export default Dispatcher;
|
@ -1,7 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class GenericContentWrapperTag extends MathMLTag {
|
||||
convert(): string {
|
||||
return this._mapChildrenToLaTeX().join(' ');
|
||||
}
|
||||
}
|
@ -1,41 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { InvalidNumberOfChild } from '../../../../../../errors';
|
||||
import { latexAccents } from '../../../../../../syntax/latexAccents';
|
||||
|
||||
export class GenericUnderOverTag extends MathMLTag {
|
||||
convert(): string {
|
||||
if (this._children.length !== 2) throw new InvalidNumberOfChild(this.name, 2, this._children.length);
|
||||
|
||||
const content = this._children[0].convert();
|
||||
const accent = this._children[1].convert();
|
||||
|
||||
return this._applyCommand(content, accent);
|
||||
}
|
||||
|
||||
private _applyCommand(content: string, accent: string): string {
|
||||
const type = this.name.match(/under/) ? TagTypes.Under : TagTypes.Over;
|
||||
return new UnderOverSetter(type).apply(content, accent);
|
||||
}
|
||||
}
|
||||
|
||||
class UnderOverSetter {
|
||||
private readonly _type;
|
||||
|
||||
constructor(type: TagTypes) {
|
||||
this._type = type;
|
||||
}
|
||||
|
||||
apply(content: string, accent: string) {
|
||||
return latexAccents.includes(accent) ? `${accent}{${content}}` : `${this._defaultCommand}{${accent}}{${content}}`;
|
||||
}
|
||||
|
||||
private get _defaultCommand(): string {
|
||||
if (this._type === TagTypes.Under) return '\\underset';
|
||||
return '\\overset';
|
||||
}
|
||||
}
|
||||
|
||||
enum TagTypes {
|
||||
Under,
|
||||
Over,
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class MAction extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('maction', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this._isToggle) return this._mapChildrenToLaTeX().join(' \\Longrightarrow ');
|
||||
return this._mapChildrenToLaTeX()[0];
|
||||
}
|
||||
|
||||
private get _isToggle(): boolean {
|
||||
return this._attributes.actiontype === 'toggle' || !this._attributes.actiontype;
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class MError extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('merror', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return `\\color{red}{${this._mapChildrenToLaTeX().join(' ')}}`;
|
||||
}
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { InvalidNumberOfChild } from '../../../../../../errors';
|
||||
import { ParenthesisWrapper } from '../../../../../../utils/wrappers';
|
||||
|
||||
export class MFrac extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mfrac', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this._children.length !== 2) throw new InvalidNumberOfChild(this.name, 2, this._children.length);
|
||||
|
||||
const num = this._children[0].convert();
|
||||
const den = this._children[1].convert();
|
||||
|
||||
if (this._isBevelled) return `${this._wrapIfMoreThanOneChar(num)}/${this._wrapIfMoreThanOneChar(den)}`;
|
||||
|
||||
return `\\frac{${num}}{${den}}`;
|
||||
}
|
||||
|
||||
private _wrapIfMoreThanOneChar(str: string): string {
|
||||
return new ParenthesisWrapper().wrapIfMoreThanOneChar(str);
|
||||
}
|
||||
|
||||
private get _isBevelled(): boolean {
|
||||
return !!this._attributes.bevelled;
|
||||
}
|
||||
}
|
@ -1,56 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { ParenthesisWrapper } from '../../../../../../utils/wrappers';
|
||||
import { InvalidNumberOfChild } from '../../../../../../errors';
|
||||
|
||||
export class MMultiscripts extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mmultiscripts', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this._children.length < 3) throw new InvalidNumberOfChild(this.name, 3, this._children.length, 'at least');
|
||||
|
||||
const base = this._children[0];
|
||||
|
||||
return this._prescriptLatex() + this._wrapInParenthesisIfThereIsSpace(base.convert()) + this._postscriptLatex();
|
||||
}
|
||||
|
||||
private _prescriptLatex(): string {
|
||||
let sub;
|
||||
let sup;
|
||||
|
||||
if (this._isPrescripts(this._children[1])) {
|
||||
sub = this._children[2];
|
||||
sup = this._children[3];
|
||||
} else if (this._isPrescripts(this._children[3])) {
|
||||
sub = this._children[4];
|
||||
sup = this._children[5];
|
||||
} else return '';
|
||||
|
||||
const subLatex = sub ? sub.convert() : '';
|
||||
const supLatex = sup ? sup.convert() : '';
|
||||
|
||||
return `\\_{${subLatex}}^{${supLatex}}`;
|
||||
}
|
||||
|
||||
private _postscriptLatex(): string {
|
||||
if (this._isPrescripts(this._children[1])) return '';
|
||||
|
||||
const sub = this._children[1];
|
||||
const sup = this._children[2];
|
||||
|
||||
const subLatex = sub ? sub.convert() : '';
|
||||
const supLatex = sup ? sup.convert() : '';
|
||||
|
||||
return `_{${subLatex}}^{${supLatex}}`;
|
||||
}
|
||||
|
||||
private _wrapInParenthesisIfThereIsSpace(str: string): string {
|
||||
if (!str.match(/\s+/g)) return str;
|
||||
return new ParenthesisWrapper().wrap(str);
|
||||
}
|
||||
|
||||
private _isPrescripts(child: MathMLTag): boolean {
|
||||
return child?.name === 'mprescripts';
|
||||
}
|
||||
}
|
12
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/MN.ts
12
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/MN.ts
@ -1,12 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class MN extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mn', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const normalizedValue = this._normalizeWhiteSpaces(this._value);
|
||||
return normalizedValue.trim();
|
||||
}
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class MPhantom extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mphantom', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return '';
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { InvalidNumberOfChild } from '../../../../../../errors';
|
||||
|
||||
export class MRoot extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mroot', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this._children.length !== 2) throw new InvalidNumberOfChild(this.name, 2, this._children.length);
|
||||
|
||||
const content = this._children[0].convert();
|
||||
const rootIndex = this._children[1].convert();
|
||||
|
||||
return `\\sqrt[${rootIndex}]{${content}}`;
|
||||
}
|
||||
}
|
@ -1,12 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class MSqrt extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('msqrt', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const content = this._mapChildrenToLaTeX().join(' ');
|
||||
return `\\sqrt{${content}}`;
|
||||
}
|
||||
}
|
18
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/MSub.ts
18
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/MSub.ts
@ -1,18 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { BracketWrapper, ParenthesisWrapper } from '../../../../../../utils/wrappers';
|
||||
import { InvalidNumberOfChild } from '../../../../../../errors';
|
||||
|
||||
export class MSub extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('msub', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this._children.length !== 2) throw new InvalidNumberOfChild(this.name, 2, this._children.length);
|
||||
|
||||
const base = this._children[0].convert();
|
||||
const exponent = this._children[1].convert();
|
||||
|
||||
return `${new ParenthesisWrapper().wrapIfMoreThanOneChar(base)}_${new BracketWrapper().wrap(exponent)}`;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { BracketWrapper, ParenthesisWrapper } from '../../../../../../utils/wrappers';
|
||||
import { InvalidNumberOfChild } from '../../../../../../errors';
|
||||
|
||||
export class MSubsup extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('msubsup', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this._children.length !== 3) throw new InvalidNumberOfChild(this.name, 2, this._children.length);
|
||||
|
||||
const base = this._children[0].convert();
|
||||
const sub = this._children[1].convert();
|
||||
const sup = this._children[2].convert();
|
||||
|
||||
const wrappedSub = new BracketWrapper().wrap(sub);
|
||||
const wrappedSup = new BracketWrapper().wrap(sup);
|
||||
|
||||
return `${this._wrapInParenthesisIfThereIsSpace(base)}_${wrappedSub}^${wrappedSup}`;
|
||||
}
|
||||
|
||||
private _wrapInParenthesisIfThereIsSpace(str: string): string {
|
||||
if (!str.match(/\s+/g)) return str;
|
||||
return new ParenthesisWrapper().wrap(str);
|
||||
}
|
||||
}
|
18
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/MSup.ts
18
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/MSup.ts
@ -1,18 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { BracketWrapper, ParenthesisWrapper } from '../../../../../../utils/wrappers';
|
||||
import { InvalidNumberOfChild } from '../../../../../../errors';
|
||||
|
||||
export class MSup extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('msup', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this._children.length !== 2) throw new InvalidNumberOfChild(this.name, 2, this._children.length);
|
||||
|
||||
const base = this._children[0].convert();
|
||||
const exponent = this._children[1].convert();
|
||||
|
||||
return `${new ParenthesisWrapper().wrapIfMoreThanOneChar(base)}^${new BracketWrapper().wrap(exponent)}`;
|
||||
}
|
||||
}
|
@ -1,17 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class MTable extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mtable', value, attributes, children);
|
||||
this.addFlagRecursiveIfClassName(this.constructor.name, 'innerTable');
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
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}`;
|
||||
}
|
||||
}
|
11
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/MTr.ts
11
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/MTr.ts
@ -1,11 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class MTr extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mtr', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return this._mapChildrenToLaTeX().join(' & ');
|
||||
}
|
||||
}
|
@ -1,18 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { InvalidNumberOfChild } from '../../../../../../errors';
|
||||
|
||||
export class MUnderover extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('munderover', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this._children.length !== 3) throw new InvalidNumberOfChild(this.name, 3, this._children.length);
|
||||
|
||||
const base = this._children[0].convert();
|
||||
const underContent = this._children[1].convert();
|
||||
const overContent = this._children[2].convert();
|
||||
|
||||
return `${base}_{${underContent}}^{${overContent}}`;
|
||||
}
|
||||
}
|
11
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/Math.ts
11
src/converters/xml-mathml-to-latex/xml-to-mathml/mathml-to-latex/mathml-to-latex/mathml-tags/Math.ts
@ -1,11 +0,0 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
|
||||
export class Math extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('math', value, attributes, children);
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return this._normalizeWhiteSpaces(this._mapChildrenToLaTeX().join(''));
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
export class MathMLTag {
|
||||
readonly name: string;
|
||||
protected _value: string;
|
||||
protected _attributes: Record<string, string>;
|
||||
protected _children: MathMLTag[];
|
||||
protected _flags: string[] = [];
|
||||
|
||||
constructor(name: string, value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
this.name = name;
|
||||
this._value = value;
|
||||
this._attributes = attributes;
|
||||
this._children = children;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return this._mapChildrenToLaTeX().join('');
|
||||
}
|
||||
|
||||
protected _mapChildrenToLaTeX(): string[] {
|
||||
return this._children.map((mathMLTag) => mathMLTag.convert());
|
||||
}
|
||||
|
||||
protected _normalizeWhiteSpaces(str: string): string {
|
||||
return str.replace(/\s+/g, ' ');
|
||||
}
|
||||
|
||||
isThere(className: string): boolean {
|
||||
const firstChild = this._children[0];
|
||||
if (!firstChild) return false;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -1,23 +0,0 @@
|
||||
export { Math } from './Math';
|
||||
export { MathMLTag } from './MathMLTag';
|
||||
export { MI } from './MI';
|
||||
export { MO } from './MO';
|
||||
export { MN } from './MN';
|
||||
export { MSqrt } from './MSqrt';
|
||||
export { MFenced } from './MFenced';
|
||||
export { MFrac } from './MFrac';
|
||||
export { MRoot } from './MRoot';
|
||||
export { MAction } from './MAction';
|
||||
export { MEnclose } from './MEnclose';
|
||||
export { MError } from './MError';
|
||||
export { MPhantom } from './MPhantom';
|
||||
export { MSup } from './MSup';
|
||||
export { MSub } from './MSub';
|
||||
export { MSubsup } from './MSubsup';
|
||||
export { MMultiscripts } from './MMultiscripts';
|
||||
export { MText } from './MText';
|
||||
export { MUnderover } from './MUnderover';
|
||||
export { MTable } from './MTable';
|
||||
export { MTr } from './MTr';
|
||||
export { GenericContentWrapperTag } from './GenericContentWrapperTag';
|
||||
export { GenericUnderOverTag } from './GenericUnderOverTag';
|
4
src/data/helpers/index.ts
Normal file
4
src/data/helpers/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export * from './wrappers';
|
||||
export * from './join-with-many-separators';
|
||||
export * from './mathml-element-to-latex-converter';
|
||||
export * from './normalize-whitespace';
|
0
src/utils/Separators.ts → src/data/helpers/join-with-many-separators.ts
Executable file → Normal file
0
src/utils/Separators.ts → src/data/helpers/join-with-many-separators.ts
Executable file → Normal file
6
src/data/helpers/mathml-element-to-latex-converter.ts
Normal file
6
src/data/helpers/mathml-element-to-latex-converter.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { MathMLElement } from '@/data/protocols/mathml-element';
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElementToLatexConverterAdapter } from '../usecases/mathml-to-latex-convertion/mathml-element-to-latex-converter-adapter';
|
||||
|
||||
export const mathMLElementToLaTeXConverter = (mathMLElement: MathMLElement): ToLaTeXConverter =>
|
||||
new MathMLElementToLatexConverterAdapter(mathMLElement).toLatexConverter();
|
3
src/data/helpers/normalize-whitespace.ts
Normal file
3
src/data/helpers/normalize-whitespace.ts
Normal file
@ -0,0 +1,3 @@
|
||||
export const normalizeWhiteSpaces = (str: string): string => {
|
||||
return str.replace(/\s+/g, ' ');
|
||||
};
|
10
src/data/helpers/wrappers/bracket.ts
Executable file
10
src/data/helpers/wrappers/bracket.ts
Executable file
@ -0,0 +1,10 @@
|
||||
import { Wrapper } from './wrapper';
|
||||
|
||||
export class BracketWrapper {
|
||||
protected _open = '{';
|
||||
protected _close = '}';
|
||||
|
||||
wrap(str: string): string {
|
||||
return new Wrapper(this._open, this._close).wrap(str);
|
||||
}
|
||||
}
|
@ -1,12 +1,15 @@
|
||||
import { Wrapper } from './Wrapper';
|
||||
import { Wrapper } from './wrapper';
|
||||
|
||||
export class GenericWrapper extends Wrapper {
|
||||
export class GenericWrapper {
|
||||
protected _open: string;
|
||||
protected _close: string;
|
||||
|
||||
constructor(open: string, close: string) {
|
||||
super();
|
||||
this._open = '\\left' + open;
|
||||
this._close = '\\right' + close;
|
||||
}
|
||||
|
||||
wrap(str: string): string {
|
||||
return new Wrapper(this._open, this._close).wrap(str);
|
||||
}
|
||||
}
|
3
src/data/helpers/wrappers/index.ts
Executable file
3
src/data/helpers/wrappers/index.ts
Executable file
@ -0,0 +1,3 @@
|
||||
export { BracketWrapper } from './bracket';
|
||||
export { ParenthesisWrapper } from './parenthesis';
|
||||
export { GenericWrapper } from './generic';
|
15
src/data/helpers/wrappers/parenthesis.ts
Executable file
15
src/data/helpers/wrappers/parenthesis.ts
Executable file
@ -0,0 +1,15 @@
|
||||
import { Wrapper } from './wrapper';
|
||||
|
||||
export class ParenthesisWrapper {
|
||||
protected _open = '\\left(';
|
||||
protected _close = '\\right)';
|
||||
|
||||
wrap(str: string): string {
|
||||
return new Wrapper(this._open, this._close).wrap(str);
|
||||
}
|
||||
|
||||
wrapIfMoreThanOneChar(str: string): string {
|
||||
if (str.length <= 1) return str;
|
||||
return this.wrap(str);
|
||||
}
|
||||
}
|
13
src/data/helpers/wrappers/wrapper.ts
Executable file
13
src/data/helpers/wrappers/wrapper.ts
Executable file
@ -0,0 +1,13 @@
|
||||
export class Wrapper {
|
||||
protected _open: string;
|
||||
protected _close: string;
|
||||
|
||||
constructor(open: string, close: string) {
|
||||
this._open = open;
|
||||
this._close = close;
|
||||
}
|
||||
|
||||
wrap(str: string): string {
|
||||
return this._open + str + this._close;
|
||||
}
|
||||
}
|
6
src/data/protocols/mathml-element.ts
Normal file
6
src/data/protocols/mathml-element.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export interface MathMLElement {
|
||||
readonly name: string;
|
||||
readonly value: string;
|
||||
readonly children: MathMLElement[];
|
||||
attributes: Record<string, string>;
|
||||
}
|
14
src/data/usecases/mathml-element-to-latex-converter.ts
Normal file
14
src/data/usecases/mathml-element-to-latex-converter.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../protocols/mathml-element';
|
||||
|
||||
export class MathMLElementToLaTexConverter implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return 'a';
|
||||
}
|
||||
}
|
18
src/data/usecases/mathml-to-latex-convertion/converters/generic-no-spacing-wrapper.ts
Executable file
18
src/data/usecases/mathml-to-latex-convertion/converters/generic-no-spacing-wrapper.ts
Executable file
@ -0,0 +1,18 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers';
|
||||
|
||||
export class GenericNoSpacingWrapper implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join('');
|
||||
}
|
||||
}
|
18
src/data/usecases/mathml-to-latex-convertion/converters/generic-spacing-wrapper.ts
Executable file
18
src/data/usecases/mathml-to-latex-convertion/converters/generic-spacing-wrapper.ts
Executable file
@ -0,0 +1,18 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers';
|
||||
|
||||
export class GenericSpacingWrapper implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join(' ');
|
||||
}
|
||||
}
|
@ -0,0 +1,52 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers/mathml-element-to-latex-converter';
|
||||
import { InvalidNumberOfChild } from '../../../errors';
|
||||
import { latexAccents } from '@/syntax/latexAccents';
|
||||
|
||||
export class GenericUnderOver implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { name, children } = this._mathmlElement;
|
||||
const childrenLength = children.length;
|
||||
|
||||
if (childrenLength !== 2) throw new InvalidNumberOfChild(name, 2, childrenLength);
|
||||
|
||||
const content = mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
const accent = mathMLElementToLaTeXConverter(children[1]).convert();
|
||||
|
||||
return this._applyCommand(content, accent);
|
||||
}
|
||||
|
||||
private _applyCommand(content: string, accent: string): string {
|
||||
const type = this._mathmlElement.name.match(/under/) ? TagTypes.Under : TagTypes.Over;
|
||||
return new UnderOverSetter(type).apply(content, accent);
|
||||
}
|
||||
}
|
||||
|
||||
class UnderOverSetter {
|
||||
private readonly _type;
|
||||
|
||||
constructor(type: TagTypes) {
|
||||
this._type = type;
|
||||
}
|
||||
|
||||
apply(content: string, accent: string) {
|
||||
return latexAccents.includes(accent) ? `${accent}{${content}}` : `${this._defaultCommand}{${accent}}{${content}}`;
|
||||
}
|
||||
|
||||
private get _defaultCommand(): string {
|
||||
if (this._type === TagTypes.Under) return '\\underset';
|
||||
return '\\overset';
|
||||
}
|
||||
}
|
||||
|
||||
enum TagTypes {
|
||||
Under,
|
||||
Over,
|
||||
}
|
23
src/data/usecases/mathml-to-latex-convertion/converters/index.ts
Executable file
23
src/data/usecases/mathml-to-latex-convertion/converters/index.ts
Executable file
@ -0,0 +1,23 @@
|
||||
export { Math } from './math';
|
||||
export { MI } from './mi';
|
||||
export { MO } from './mo';
|
||||
export { MN } from './mn';
|
||||
export { MSqrt } from './msqrt';
|
||||
export { MFenced } from './mfenced';
|
||||
export { MFrac } from './mfrac';
|
||||
export { MRoot } from './mroot';
|
||||
export { MAction } from './maction';
|
||||
export { MEnclose } from './menclose';
|
||||
export { MError } from './merror';
|
||||
export { MPhantom } from './mphantom';
|
||||
export { MSup } from './msup';
|
||||
export { MSub } from './msub';
|
||||
export { MSubsup } from './msubsup';
|
||||
export { MMultiscripts } from './mmultiscripts';
|
||||
export { MText } from './mtext';
|
||||
export { MUnderover } from './munderover';
|
||||
export { MTable } from './mtable';
|
||||
export { MTr } from './mtr';
|
||||
export { GenericSpacingWrapper } from './generic-spacing-wrapper';
|
||||
export { GenericNoSpacingWrapper } from './generic-no-spacing-wrapper';
|
||||
export { GenericUnderOver } from './generic-under-over';
|
28
src/data/usecases/mathml-to-latex-convertion/converters/maction.ts
Executable file
28
src/data/usecases/mathml-to-latex-convertion/converters/maction.ts
Executable file
@ -0,0 +1,28 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers/mathml-element-to-latex-converter';
|
||||
|
||||
export class MAction implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { children } = this._mathmlElement;
|
||||
|
||||
if (this._isToggle())
|
||||
return children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join(' \\Longrightarrow ');
|
||||
|
||||
return mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
}
|
||||
|
||||
private _isToggle(): boolean {
|
||||
const { actiontype } = this._mathmlElement.attributes;
|
||||
return actiontype === 'toggle' || !actiontype;
|
||||
}
|
||||
}
|
21
src/data/usecases/mathml-to-latex-convertion/converters/math.ts
Executable file
21
src/data/usecases/mathml-to-latex-convertion/converters/math.ts
Executable file
@ -0,0 +1,21 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers/mathml-element-to-latex-converter';
|
||||
import { normalizeWhiteSpaces } from '../../../helpers/normalize-whitespace';
|
||||
|
||||
export class Math implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const unnormalizedLatex = this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join('');
|
||||
|
||||
return normalizeWhiteSpaces(unnormalizedLatex);
|
||||
}
|
||||
}
|
@ -1,12 +1,19 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers/mathml-element-to-latex-converter';
|
||||
|
||||
export class MEnclose extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('menclose', value, attributes, children);
|
||||
export class MEnclose implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const latexJoinedChildren = this._mapChildrenToLaTeX().join(' ');
|
||||
const latexJoinedChildren = this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join(' ');
|
||||
|
||||
if (this._notation === 'actuarial') return `\\overline{\\left.${latexJoinedChildren}\\right|}`;
|
||||
if (this._notation === 'radical') return `\\sqrt{${latexJoinedChildren}}`;
|
||||
@ -26,8 +33,6 @@ export class MEnclose extends MathMLTag {
|
||||
}
|
||||
|
||||
private get _notation(): string {
|
||||
if (!this._attributes.notation) return 'longdiv';
|
||||
|
||||
return this._attributes.notation;
|
||||
return this._mathmlElement.attributes.notation || 'longdiv';
|
||||
}
|
||||
}
|
20
src/data/usecases/mathml-to-latex-convertion/converters/merror.ts
Executable file
20
src/data/usecases/mathml-to-latex-convertion/converters/merror.ts
Executable file
@ -0,0 +1,20 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers/mathml-element-to-latex-converter';
|
||||
|
||||
export class MError implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const latexJoinedChildren = this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join(' ');
|
||||
|
||||
return `\\color{red}{${latexJoinedChildren}}`;
|
||||
}
|
||||
}
|
@ -1,24 +1,36 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { GenericWrapper } from '../../../../../../utils/wrappers';
|
||||
import { JoinWithManySeparators } from '../../../../../../utils';
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers/mathml-element-to-latex-converter';
|
||||
import { GenericWrapper, JoinWithManySeparators } from '../../../helpers';
|
||||
|
||||
export class MFenced extends MathMLTag {
|
||||
export class MFenced implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
private readonly _open: string;
|
||||
private readonly _close: string;
|
||||
private readonly _separators: string[];
|
||||
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mfenced', value, attributes, children);
|
||||
|
||||
this._open = this._attributes.open || '';
|
||||
this._close = this._attributes.close || '';
|
||||
this._separators = Array.from(this._attributes.separators || '');
|
||||
constructor(mathmlElement: MathMLElement) {
|
||||
this._mathmlElement = mathmlElement;
|
||||
this._open = this._mathmlElement.attributes.open || '';
|
||||
this._close = this._mathmlElement.attributes.close || '';
|
||||
this._separators = Array.from(this._mathmlElement.attributes.separators || '');
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
if (this.isThere('MTable')) return new Matrix(this._open, this._close).apply(this._mapChildrenToLaTeX().join());
|
||||
const latexChildren = this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert());
|
||||
|
||||
return new Vector(this._open, this._close, this._separators).apply(this._mapChildrenToLaTeX());
|
||||
if (this._isThereRelativeOfName(this._mathmlElement.children, 'mtable'))
|
||||
return new Matrix(this._open, this._close).apply(latexChildren);
|
||||
|
||||
return new Vector(this._open, this._close, this._separators).apply(latexChildren);
|
||||
}
|
||||
|
||||
private _isThereRelativeOfName(mathmlElements: MathMLElement[], elementName: string): boolean {
|
||||
return mathmlElements.some(
|
||||
(child) => child.name === elementName || this._isThereRelativeOfName(child.children, elementName),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -48,9 +60,9 @@ class Matrix {
|
||||
this._separators = new Separators(open, close);
|
||||
}
|
||||
|
||||
apply(latex: string): string {
|
||||
apply(latexContents: string[]): string {
|
||||
const command = this._command;
|
||||
const matrix = `\\begin{${command}}\n${latex}\n\\end{${command}}`;
|
||||
const matrix = `\\begin{${command}}\n${latexContents.join('')}\n\\end{${command}}`;
|
||||
|
||||
return command === this._genericCommand ? this._separators.wrap(matrix) : matrix;
|
||||
}
|
34
src/data/usecases/mathml-to-latex-convertion/converters/mfrac.ts
Executable file
34
src/data/usecases/mathml-to-latex-convertion/converters/mfrac.ts
Executable file
@ -0,0 +1,34 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { InvalidNumberOfChild } from '../../../errors';
|
||||
import { ParenthesisWrapper, mathMLElementToLaTeXConverter } from '../../../helpers';
|
||||
|
||||
export class MFrac implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { children, name } = this._mathmlElement;
|
||||
const childrenLength = children.length;
|
||||
|
||||
if (childrenLength !== 2) throw new InvalidNumberOfChild(name, 2, childrenLength);
|
||||
|
||||
const num = mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
const den = mathMLElementToLaTeXConverter(children[1]).convert();
|
||||
|
||||
if (this._isBevelled()) return `${this._wrapIfMoreThanOneChar(num)}/${this._wrapIfMoreThanOneChar(den)}`;
|
||||
|
||||
return `\\frac{${num}}{${den}}`;
|
||||
}
|
||||
|
||||
private _wrapIfMoreThanOneChar(str: string): string {
|
||||
return new ParenthesisWrapper().wrapIfMoreThanOneChar(str);
|
||||
}
|
||||
|
||||
private _isBevelled(): boolean {
|
||||
return !!this._mathmlElement.attributes.bevelled;
|
||||
}
|
||||
}
|
@ -1,13 +1,17 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { allMathSymbolsByChar, allMathSymbolsByGlyph } from '../../../../../../syntax';
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { normalizeWhiteSpaces } from '../../../helpers';
|
||||
import { allMathSymbolsByChar, allMathSymbolsByGlyph } from '@/syntax';
|
||||
|
||||
export class MI extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mi', value, attributes, children);
|
||||
export class MI implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const normalizedValue = this._normalizeWhiteSpaces(this._value);
|
||||
const normalizedValue = normalizeWhiteSpaces(this._mathmlElement.value);
|
||||
if (normalizedValue === ' ') return Character.apply(normalizedValue);
|
||||
|
||||
const trimmedValue = normalizedValue.trim();
|
64
src/data/usecases/mathml-to-latex-convertion/converters/mmultiscripts.ts
Executable file
64
src/data/usecases/mathml-to-latex-convertion/converters/mmultiscripts.ts
Executable file
@ -0,0 +1,64 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter, ParenthesisWrapper } from '../../../helpers';
|
||||
import { InvalidNumberOfChild } from '../../../errors';
|
||||
|
||||
export class MMultiscripts implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { name, children } = this._mathmlElement;
|
||||
const childrenLength = children.length;
|
||||
|
||||
if (childrenLength < 3) throw new InvalidNumberOfChild(name, 3, childrenLength, 'at least');
|
||||
|
||||
const baseContent = mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
|
||||
return this._prescriptLatex() + this._wrapInParenthesisIfThereIsSpace(baseContent) + this._postscriptLatex();
|
||||
}
|
||||
|
||||
private _prescriptLatex(): string {
|
||||
const { children } = this._mathmlElement;
|
||||
let sub;
|
||||
let sup;
|
||||
|
||||
if (this._isPrescripts(children[1])) {
|
||||
sub = children[2];
|
||||
sup = children[3];
|
||||
} else if (this._isPrescripts(children[3])) {
|
||||
sub = children[4];
|
||||
sup = children[5];
|
||||
} else return '';
|
||||
|
||||
const subLatex = sub ? mathMLElementToLaTeXConverter(sub).convert() : '';
|
||||
const supLatex = sup ? mathMLElementToLaTeXConverter(sup).convert() : '';
|
||||
|
||||
return `\\_{${subLatex}}^{${supLatex}}`;
|
||||
}
|
||||
|
||||
private _postscriptLatex(): string {
|
||||
const { children } = this._mathmlElement;
|
||||
if (this._isPrescripts(children[1])) return '';
|
||||
|
||||
const sub = children[1];
|
||||
const sup = children[2];
|
||||
|
||||
const subLatex = sub ? mathMLElementToLaTeXConverter(sub).convert() : '';
|
||||
const supLatex = sup ? mathMLElementToLaTeXConverter(sup).convert() : '';
|
||||
|
||||
return `_{${subLatex}}^{${supLatex}}`;
|
||||
}
|
||||
|
||||
private _wrapInParenthesisIfThereIsSpace(str: string): string {
|
||||
if (!str.match(/\s+/g)) return str;
|
||||
return new ParenthesisWrapper().wrap(str);
|
||||
}
|
||||
|
||||
private _isPrescripts(child: MathMLElement): boolean {
|
||||
return child?.name === 'mprescripts';
|
||||
}
|
||||
}
|
16
src/data/usecases/mathml-to-latex-convertion/converters/mn.ts
Executable file
16
src/data/usecases/mathml-to-latex-convertion/converters/mn.ts
Executable file
@ -0,0 +1,16 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { normalizeWhiteSpaces } from '../../../helpers';
|
||||
|
||||
export class MN implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const normalizedValue = normalizeWhiteSpaces(this._mathmlElement.value);
|
||||
return normalizedValue.trim();
|
||||
}
|
||||
}
|
@ -1,13 +1,17 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { allMathOperatorsByChar, allMathOperatorsByGlyph } from '../../../../../../syntax';
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { normalizeWhiteSpaces } from '../../../helpers';
|
||||
import { allMathOperatorsByChar, allMathOperatorsByGlyph } from '@/syntax';
|
||||
|
||||
export class MO extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mo', value, attributes, children);
|
||||
export class MO implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const normalizedValue = this._normalizeWhiteSpaces(this._value);
|
||||
const normalizedValue = normalizeWhiteSpaces(this._mathmlElement.value);
|
||||
const trimmedValue = normalizedValue.trim();
|
||||
|
||||
return Operator.operate(trimmedValue);
|
@ -0,0 +1,14 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
|
||||
export class MPhantom implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return '';
|
||||
}
|
||||
}
|
24
src/data/usecases/mathml-to-latex-convertion/converters/mroot.ts
Executable file
24
src/data/usecases/mathml-to-latex-convertion/converters/mroot.ts
Executable file
@ -0,0 +1,24 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers';
|
||||
import { InvalidNumberOfChild } from '../../../errors';
|
||||
|
||||
export class MRoot implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { name, children } = this._mathmlElement;
|
||||
const childrenLength = children.length;
|
||||
|
||||
if (childrenLength !== 2) throw new InvalidNumberOfChild(name, 2, childrenLength);
|
||||
|
||||
const content = mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
const rootIndex = mathMLElementToLaTeXConverter(children[1]).convert();
|
||||
|
||||
return `\\sqrt[${rootIndex}]{${content}}`;
|
||||
}
|
||||
}
|
20
src/data/usecases/mathml-to-latex-convertion/converters/msqrt.ts
Executable file
20
src/data/usecases/mathml-to-latex-convertion/converters/msqrt.ts
Executable file
@ -0,0 +1,20 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers';
|
||||
|
||||
export class MSqrt implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const latexJoinedChildren = this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join(' ');
|
||||
|
||||
return `\\sqrt{${latexJoinedChildren}}`;
|
||||
}
|
||||
}
|
24
src/data/usecases/mathml-to-latex-convertion/converters/msub.ts
Executable file
24
src/data/usecases/mathml-to-latex-convertion/converters/msub.ts
Executable file
@ -0,0 +1,24 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter, ParenthesisWrapper, BracketWrapper } from '../../../helpers';
|
||||
import { InvalidNumberOfChild } from '../../../errors';
|
||||
|
||||
export class MSub implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { name, children } = this._mathmlElement;
|
||||
const childrenLength = children.length;
|
||||
|
||||
if (childrenLength !== 2) throw new InvalidNumberOfChild(name, 2, childrenLength);
|
||||
|
||||
const base = mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
const subscript = mathMLElementToLaTeXConverter(children[1]).convert();
|
||||
|
||||
return `${new ParenthesisWrapper().wrapIfMoreThanOneChar(base)}_${new BracketWrapper().wrap(subscript)}`;
|
||||
}
|
||||
}
|
33
src/data/usecases/mathml-to-latex-convertion/converters/msubsup.ts
Executable file
33
src/data/usecases/mathml-to-latex-convertion/converters/msubsup.ts
Executable file
@ -0,0 +1,33 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter, ParenthesisWrapper, BracketWrapper } from '../../../helpers';
|
||||
import { InvalidNumberOfChild } from '../../../errors';
|
||||
|
||||
export class MSubsup implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { name, children } = this._mathmlElement;
|
||||
const childrenLength = children.length;
|
||||
|
||||
if (childrenLength !== 3) throw new InvalidNumberOfChild(name, 3, childrenLength);
|
||||
|
||||
const base = mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
const sub = mathMLElementToLaTeXConverter(children[1]).convert();
|
||||
const sup = mathMLElementToLaTeXConverter(children[2]).convert();
|
||||
|
||||
const wrappedSub = new BracketWrapper().wrap(sub);
|
||||
const wrappedSup = new BracketWrapper().wrap(sup);
|
||||
|
||||
return `${this._wrapInParenthesisIfThereIsSpace(base)}_${wrappedSub}^${wrappedSup}`;
|
||||
}
|
||||
|
||||
private _wrapInParenthesisIfThereIsSpace(str: string): string {
|
||||
if (!str.match(/\s+/g)) return str;
|
||||
return new ParenthesisWrapper().wrap(str);
|
||||
}
|
||||
}
|
24
src/data/usecases/mathml-to-latex-convertion/converters/msup.ts
Executable file
24
src/data/usecases/mathml-to-latex-convertion/converters/msup.ts
Executable file
@ -0,0 +1,24 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter, ParenthesisWrapper, BracketWrapper } from '../../../helpers';
|
||||
import { InvalidNumberOfChild } from '../../../errors';
|
||||
|
||||
export class MSup implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { name, children } = this._mathmlElement;
|
||||
const childrenLength = children.length;
|
||||
|
||||
if (childrenLength !== 2) throw new InvalidNumberOfChild(name, 2, childrenLength);
|
||||
|
||||
const base = mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
const exponent = mathMLElementToLaTeXConverter(children[1]).convert();
|
||||
|
||||
return `${new ParenthesisWrapper().wrapIfMoreThanOneChar(base)}^${new BracketWrapper().wrap(exponent)}`;
|
||||
}
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers';
|
||||
|
||||
export class MTable implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
this._addFlagRecursiveIfName(this._mathmlElement.children, 'mtable', 'innerTable');
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const tableContent = this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join(' \\\\\n');
|
||||
|
||||
return this._hasFlag('innerTable') ? this._wrap(tableContent) : tableContent;
|
||||
}
|
||||
|
||||
private _wrap(latex: string): string {
|
||||
return `\\begin{matrix}${latex}\\end{matrix}`;
|
||||
}
|
||||
|
||||
private _addFlagRecursiveIfName(mathmlElements: MathMLElement[], name: string, flag: string): void {
|
||||
mathmlElements.forEach((mathmlElement) => {
|
||||
if (mathmlElement.name === name) mathmlElement.attributes[flag] = flag;
|
||||
this._addFlagRecursiveIfName(mathmlElement.children, name, flag);
|
||||
});
|
||||
}
|
||||
|
||||
private _hasFlag(flag: string): boolean {
|
||||
return !!this._mathmlElement.attributes[flag];
|
||||
}
|
||||
}
|
||||
|
||||
export class GenericMathMlElementWrapper implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join(' ');
|
||||
}
|
||||
}
|
@ -1,14 +1,17 @@
|
||||
import { MathMLTag } from './MathMLTag';
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
|
||||
export class MText extends MathMLTag {
|
||||
constructor(value: string, attributes: Record<string, string>, children: MathMLTag[]) {
|
||||
super('mtext', value, attributes, children);
|
||||
export class MText implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const textCommand = new TextCommand(this._attributes.mathvariant);
|
||||
const { attributes, value } = this._mathmlElement;
|
||||
|
||||
return textCommand.apply(this._value);
|
||||
return new TextCommand(attributes.mathvariant).apply(value);
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,18 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers';
|
||||
|
||||
export class MTr implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
return this._mathmlElement.children
|
||||
.map((child) => mathMLElementToLaTeXConverter(child))
|
||||
.map((converter) => converter.convert())
|
||||
.join(' & ');
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
import { ToLaTeXConverter } from '@/domain/usecases/to-latex-converter';
|
||||
import { MathMLElement } from '../../../protocols/mathml-element';
|
||||
import { mathMLElementToLaTeXConverter } from '../../../helpers';
|
||||
import { InvalidNumberOfChild } from '../../../errors';
|
||||
|
||||
export class MUnderover implements ToLaTeXConverter {
|
||||
private readonly _mathmlElement: MathMLElement;
|
||||
|
||||
constructor(mathElement: MathMLElement) {
|
||||
this._mathmlElement = mathElement;
|
||||
}
|
||||
|
||||
convert(): string {
|
||||
const { name, children } = this._mathmlElement;
|
||||
const childrenLength = children.length;
|
||||
|
||||
if (childrenLength !== 3) throw new InvalidNumberOfChild(name, 3, childrenLength);
|
||||
|
||||
const base = mathMLElementToLaTeXConverter(children[0]).convert();
|
||||
const underContent = mathMLElementToLaTeXConverter(children[1]).convert();
|
||||
const overContent = mathMLElementToLaTeXConverter(children[2]).convert();
|
||||
|
||||
return `${base}_{${underContent}}^{${overContent}}`;
|
||||
}
|
||||
}
|
45
src/data/usecases/mathml-to-latex-convertion/mathml-element-to-latex-converter-adapter.ts
Normal file
45
src/data/usecases/mathml-to-latex-convertion/mathml-element-to-latex-converter-adapter.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import * as ToLatexConverters from './converters';
|
||||
import { MathMLElement } from '@/data/protocols/mathml-element';
|
||||
import { ToLaTeXConverter, ToLaTeXConverterClass } from '@/domain/usecases/to-latex-converter';
|
||||
|
||||
export class MathMLElementToLatexConverterAdapter {
|
||||
private readonly _mathMLElement: MathMLElement;
|
||||
|
||||
constructor(mathMLElement: MathMLElement) {
|
||||
this._mathMLElement = mathMLElement;
|
||||
}
|
||||
|
||||
toLatexConverter(): ToLaTeXConverter {
|
||||
const { name } = this._mathMLElement;
|
||||
const Converter = fromMathMLElementToLatexConverter[name] || ToLatexConverters.GenericNoSpacingWrapper;
|
||||
|
||||
return new Converter(this._mathMLElement);
|
||||
}
|
||||
}
|
||||
|
||||
const fromMathMLElementToLatexConverter: Record<string, ToLaTeXConverterClass> = {
|
||||
math: ToLatexConverters.Math,
|
||||
mi: ToLatexConverters.MI,
|
||||
mo: ToLatexConverters.MO,
|
||||
mn: ToLatexConverters.MN,
|
||||
msqrt: ToLatexConverters.MSqrt,
|
||||
mfenced: ToLatexConverters.MFenced,
|
||||
mfrac: ToLatexConverters.MFrac,
|
||||
mroot: ToLatexConverters.MRoot,
|
||||
maction: ToLatexConverters.MAction,
|
||||
menclose: ToLatexConverters.MEnclose,
|
||||
merror: ToLatexConverters.MError,
|
||||
mphantom: ToLatexConverters.MPhantom,
|
||||
msup: ToLatexConverters.MSup,
|
||||
msub: ToLatexConverters.MSub,
|
||||
msubsup: ToLatexConverters.MSubsup,
|
||||
mmultiscripts: ToLatexConverters.MMultiscripts,
|
||||
mtext: ToLatexConverters.MText,
|
||||
munderover: ToLatexConverters.MUnderover,
|
||||
mtable: ToLatexConverters.MTable,
|
||||
mtr: ToLatexConverters.MTr,
|
||||
mover: ToLatexConverters.GenericUnderOver,
|
||||
munder: ToLatexConverters.GenericUnderOver,
|
||||
mrow: ToLatexConverters.GenericSpacingWrapper,
|
||||
mpadded: ToLatexConverters.GenericSpacingWrapper,
|
||||
};
|
7
src/domain/usecases/to-latex-converter.ts
Normal file
7
src/domain/usecases/to-latex-converter.ts
Normal file
@ -0,0 +1,7 @@
|
||||
export interface ToLaTeXConverter {
|
||||
convert(): string;
|
||||
}
|
||||
|
||||
export interface ToLaTeXConverterClass {
|
||||
new (...args: any): ToLaTeXConverter;
|
||||
}
|
@ -1,3 +1,3 @@
|
||||
import MathMLToLaTeX from './converters/xml-mathml-to-latex';
|
||||
import { MathMLToLaTeX } from '@/main';
|
||||
|
||||
export default MathMLToLaTeX;
|
||||
|
0
src/converters/xml-mathml-to-latex/xml-to-mathml/ErrorHandler.ts → src/infra/usecases/xmldom-to-mathml-elements/error-handler.ts
Executable file → Normal file
0
src/converters/xml-mathml-to-latex/xml-to-mathml/ErrorHandler.ts → src/infra/usecases/xmldom-to-mathml-elements/error-handler.ts
Executable file → Normal file
1
src/infra/usecases/xmldom-to-mathml-elements/index.ts
Normal file
1
src/infra/usecases/xmldom-to-mathml-elements/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './xmldom-to-mathml-element-adapter';
|
@ -1,16 +1,18 @@
|
||||
import { MathML } from '../../protocols/MathML';
|
||||
import { MathMLElement } from '@/data/protocols/mathml-element';
|
||||
|
||||
export class ElementsToMathMLAdapter {
|
||||
convert(els: Element[]): MathML[] {
|
||||
convert(els: Element[]): MathMLElement[] {
|
||||
return els.filter((el: Element) => el.tagName !== undefined).map((el: Element) => this._convertElement(el));
|
||||
}
|
||||
|
||||
private _convertElement(el: Element): MathML {
|
||||
private _convertElement(el: Element): MathMLElement {
|
||||
return {
|
||||
name: el.tagName,
|
||||
attributes: el.attributes ? this._convertElementAttributes(el.attributes) : {},
|
||||
value: this._hasElementChild(el) ? '' : el.textContent || '',
|
||||
children: this._hasElementChild(el) ? this.convert(Array.from(el.childNodes) as Element[]) : ([] as MathML[]),
|
||||
children: this._hasElementChild(el)
|
||||
? this.convert(Array.from(el.childNodes) as Element[])
|
||||
: ([] as MathMLElement[]),
|
||||
};
|
||||
}
|
||||
|
@ -1,17 +1,18 @@
|
||||
import xmldom = require('xmldom');
|
||||
|
||||
import { DOMParser } from 'xmldom';
|
||||
import { ErrorHandler } from './ErrorHandler';
|
||||
import { MathML } from '../../protocols/MathML';
|
||||
import { ElementsToMathMLAdapter } from './ElementsToMathMLAdapter';
|
||||
import { ElementsToMathMLAdapter } from './xmldom-elements-to-mathml-elements-adapter';
|
||||
import { ErrorHandler } from './error-handler';
|
||||
import { MathMLElement } from '@/data/protocols/mathml-element';
|
||||
|
||||
export class XmlToMathMLAdapter {
|
||||
private _xmlDOM: DOMParser;
|
||||
private _errorHandler: ErrorHandler;
|
||||
private _elementsConvertor: ElementsToMathMLAdapter;
|
||||
private _xml: string;
|
||||
private readonly _xmlDOM: DOMParser;
|
||||
private readonly _errorHandler: ErrorHandler;
|
||||
private readonly _elementsConvertor: ElementsToMathMLAdapter;
|
||||
|
||||
constructor(private _xml: string) {
|
||||
this._xml = this._removeLineBreaks(_xml);
|
||||
constructor(xml: string) {
|
||||
this._xml = this._removeLineBreaks(xml);
|
||||
|
||||
this._elementsConvertor = new ElementsToMathMLAdapter();
|
||||
this._errorHandler = new ErrorHandler();
|
||||
@ -22,7 +23,7 @@ export class XmlToMathMLAdapter {
|
||||
});
|
||||
}
|
||||
|
||||
convert(): MathML[] {
|
||||
convert(): MathMLElement[] {
|
||||
return this._elementsConvertor.convert(this._mathMLElements);
|
||||
}
|
||||
|
1
src/main/index.ts
Normal file
1
src/main/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export * from './mathml-to-latex';
|
12
src/main/mathml-to-latex.ts
Normal file
12
src/main/mathml-to-latex.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { MathMLElementToLatexConverterAdapter } from '@/data/usecases/mathml-to-latex-convertion/mathml-element-to-latex-converter-adapter';
|
||||
import { XmlToMathMLAdapter } from '@/infra/usecases/xmldom-to-mathml-elements';
|
||||
|
||||
export class MathMLToLaTeX {
|
||||
static convert(mathml: string): string {
|
||||
const mathmlElements = new XmlToMathMLAdapter(mathml).convert();
|
||||
const mathmlElementsToLaTeXConverters = mathmlElements.map((mathMLElement) =>
|
||||
new MathMLElementToLatexConverterAdapter(mathMLElement).toLatexConverter(),
|
||||
);
|
||||
return mathmlElementsToLaTeXConverters.map((toLatexConverters) => toLatexConverters.convert()).join('');
|
||||
}
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
export interface MathML {
|
||||
name: string;
|
||||
attributes: Record<string, string>;
|
||||
value: string;
|
||||
children: MathML[];
|
||||
}
|
@ -1 +0,0 @@
|
||||
export { MathML } from './MathML';
|
@ -1,2 +0,0 @@
|
||||
export { JoinWithManySeparators } from './Separators';
|
||||
export * from './wrappers';
|
@ -1,6 +0,0 @@
|
||||
import { Wrapper } from './Wrapper';
|
||||
|
||||
export class BracketWrapper extends Wrapper {
|
||||
protected _open = '{';
|
||||
protected _close = '}';
|
||||
}
|
@ -1,6 +0,0 @@
|
||||
import { Wrapper } from './Wrapper';
|
||||
|
||||
export class ParenthesisWrapper extends Wrapper {
|
||||
protected _open = '\\left(';
|
||||
protected _close = '\\right)';
|
||||
}
|
@ -1,13 +0,0 @@
|
||||
export abstract class Wrapper {
|
||||
protected abstract _open: string;
|
||||
protected abstract _close: string;
|
||||
|
||||
wrap(str: string): string {
|
||||
return this._open + str + this._close;
|
||||
}
|
||||
|
||||
wrapIfMoreThanOneChar(str: string): string {
|
||||
if (str.length <= 1) return str;
|
||||
return this.wrap(str);
|
||||
}
|
||||
}
|
@ -1,3 +0,0 @@
|
||||
export { BracketWrapper } from './BracketWrapper';
|
||||
export { ParenthesisWrapper } from './ParenthesisWrapper';
|
||||
export { GenericWrapper } from './GenericWrapper';
|
Loading…
Reference in New Issue
Block a user