Skip to content

Commit

Permalink
fix: Remove circular dependency
Browse files Browse the repository at this point in the history
When bundling mathjax - you are warned that there is a circular
dependency:

```shell
code: CIRCULAR_DEPENDENCY, message: Circular dependency: node_modules/mathjax-full/js/input/tex/TexParser.js -> node_modules/mathjax-full/js/input/tex/ParseUtil.js -> node_modules/mathjax-full/js/input/tex/TexParser.js
```

This can lead to runtime errors as the bundler has to guess which module
to define first.

This commit removes this circular dependency by moving the functions in
ParseUtil that TexParser used into 2 new namespaces.

+ DimensionUtil -> matchDimen
+ StringUtil -> trimSpaces

I'm trying to be consistent with how the modules are laid out.
  • Loading branch information
edeustace committed Sep 6, 2021
1 parent 41565a9 commit dad5b94
Show file tree
Hide file tree
Showing 4 changed files with 141 additions and 81 deletions.
97 changes: 97 additions & 0 deletions ts/input/tex/DimensionUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*************************************************************
*
* Copyright (c) 2009-2021 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace DimensionUtil {
// TODO (VS): Combine some of this with lengths in util.
const emPerInch = 7.2;
const pxPerInch = 72;
// Note, the following are TeX CM font values.
const UNIT_CASES: { [key: string]: (m: number) => number } = {
em: (m) => m,
ex: (m) => m * 0.43,
pt: (m) => m / 10, // 10 pt to an em
pc: (m) => m * 1.2, // 12 pt to a pc
px: (m) => (m * emPerInch) / pxPerInch,
in: (m) => m * emPerInch,
cm: (m) => (m * emPerInch) / 2.54, // 2.54 cm to an inch
mm: (m) => (m * emPerInch) / 25.4, // 10 mm to a cm
mu: (m) => m / 18,
};
const num = '([-+]?([.,]\\d+|\\d+([.,]\\d*)?))';
const unit = '(pt|em|ex|mu|px|mm|cm|in|pc)';
const dimenEnd = RegExp('^\\s*' + num + '\\s*' + unit + '\\s*$');
const dimenRest = RegExp('^\\s*' + num + '\\s*' + unit + ' ?');
/**
* Matches for a dimension argument.
* @param {string} dim The argument.
* @param {boolean} rest Allow for trailing garbage in the dimension string.
* @return {[string, string, number]} The match result as (Anglosaxon) value,
* unit name, length of matched string. The latter is interesting in the
* case of trailing garbage.
*/
export function matchDimen(
dim: string,
rest: boolean = false
): [string, string, number] {
let match = dim.match(rest ? dimenRest : dimenEnd);
return match
? muReplace([match[1].replace(/,/, '.'), match[4], match[0].length])
: [null, null, 0];
}

/**
* Convert a dimension string into standard em dimension.
* @param {string} dim The attribute string.
* @return {number} The numerical value.
*/
export function dimen2em(dim: string): number {
let [value, unit] = matchDimen(dim);
let m = parseFloat(value || '1');
let func = UNIT_CASES[unit];
return func ? func(m) : 0;
}

/**
* Transforms mu dimension to em if necessary.
* @param {[string, string, number]} [value, unit, length] The dimension triple.
* @return {[string, string, number]} [value, unit, length] The transformed triple.
*/
function muReplace([value, unit, length]: [string, string, number]): [
string,
string,
number
] {
if (unit !== 'mu') {
return [value, unit, length];
}
let em = Em(UNIT_CASES[unit](parseFloat(value || '1')));
return [em.slice(0, -2), 'em', length];
}

/**
* Turns a number into an em value.
* @param {number} m The number.
* @return {string} The em dimension string.
*/
export function Em(m: number): string {
if (Math.abs(m) < 0.0006) {
return '0em';
}
return m.toFixed(3).replace(/\.?0+$/, '') + 'em';
}
}

export default DimensionUtil;
82 changes: 5 additions & 77 deletions ts/input/tex/ParseUtil.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,87 +31,15 @@ import TexParser from './TexParser.js';
import TexError from './TexError.js';
import {entities} from '../../util/Entities.js';
import {MmlMunderover} from '../../core/MmlTree/MmlNodes/munderover.js';

import DimensionUtil from './DimensionUtil';

namespace ParseUtil {

// TODO (VS): Combine some of this with lengths in util.
const emPerInch = 7.2;
const pxPerInch = 72;
// Note, the following are TeX CM font values.
const UNIT_CASES: {[key: string]: ((m: number) => number)} = {
'em': m => m,
'ex': m => m * .43,
'pt': m => m / 10, // 10 pt to an em
'pc': m => m * 1.2, // 12 pt to a pc
'px': m => m * emPerInch / pxPerInch,
'in': m => m * emPerInch,
'cm': m => m * emPerInch / 2.54, // 2.54 cm to an inch
'mm': m => m * emPerInch / 25.4, // 10 mm to a cm
'mu': m => m / 18,
};
const num = '([-+]?([.,]\\d+|\\d+([.,]\\d*)?))';
const unit = '(pt|em|ex|mu|px|mm|cm|in|pc)';
const dimenEnd = RegExp('^\\s*' + num + '\\s*' + unit + '\\s*$');
const dimenRest = RegExp('^\\s*' + num + '\\s*' + unit + ' ?');


/**
* Matches for a dimension argument.
* @param {string} dim The argument.
* @param {boolean} rest Allow for trailing garbage in the dimension string.
* @return {[string, string, number]} The match result as (Anglosaxon) value,
* unit name, length of matched string. The latter is interesting in the
* case of trailing garbage.
*/
export function matchDimen(
dim: string, rest: boolean = false): [string, string, number] {
let match = dim.match(rest ? dimenRest : dimenEnd);
return match ?
muReplace([match[1].replace(/,/, '.'), match[4], match[0].length]) :
[null, null, 0];
}


/**
* Transforms mu dimension to em if necessary.
* @param {[string, string, number]} [value, unit, length] The dimension triple.
* @return {[string, string, number]} [value, unit, length] The transformed triple.
*/
function muReplace([value, unit, length]: [string, string, number]): [string, string, number] {
if (unit !== 'mu') {
return [value, unit, length];
}
let em = Em(UNIT_CASES[unit](parseFloat(value || '1')));
return [em.slice(0, -2), 'em', length];
}


/**
* Convert a dimension string into standard em dimension.
* @param {string} dim The attribute string.
* @return {number} The numerical value.
*/
export function dimen2em(dim: string): number {
let [value, unit] = matchDimen(dim);
let m = parseFloat(value || '1');
let func = UNIT_CASES[unit];
return func ? func(m) : 0;
}


/**
* Turns a number into an em value.
* @param {number} m The number.
* @return {string} The em dimension string.
*/
export function Em(m: number): string {
if (Math.abs(m) < .0006) {
return '0em';
}
return m.toFixed(3).replace(/\.?0+$/, '') + 'em';
}
export const matchDimen = DimensionUtil.matchDimen;

export const dimen2em = DimensionUtil.dimen2em;

export const Em = DimensionUtil.Em;

/**
* Takes an array of numbers and returns a space-separated string of em values.
Expand Down
34 changes: 34 additions & 0 deletions ts/input/tex/StringUtil.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*************************************************************
*
* Copyright (c) 2009-2021 The MathJax Consortium
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace StringUtil {
/**
* Trim spaces from a string.
* @param {string} text The string to clean.
* @return {string} The string with leading and trailing whitespace removed.
*/
export function trimSpaces(text: string): string {
if (typeof text !== 'string') {
return text;
}
let TEXT = text.trim();
if (TEXT.match(/\\$/) && text.match(/ $/)) {
TEXT += ' ';
}
return TEXT;
}
}
export default StringUtil;
9 changes: 5 additions & 4 deletions ts/input/tex/TexParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@
* @author [email protected] (Volker Sorge)
*/

import ParseUtil from './ParseUtil.js';
import DimensionUtil from './DimensionUtil';
import StringUtil from './StringUtil';
import {HandlerType} from './MapHandler.js';
import Stack from './Stack.js';
import StackItemFactory from './StackItemFactory.js';
Expand Down Expand Up @@ -392,15 +393,15 @@ export default class TexParser {
public GetDimen(name: string): string {
if (this.GetNext() === '{') {
let dimen = this.GetArgument(name);
let [value, unit] = ParseUtil.matchDimen(dimen);
let [value, unit] = DimensionUtil.matchDimen(dimen);
if (value) {
// @test Raise In Line, Lower 2, (Raise|Lower) Negative
return value + unit;
}
} else {
// @test Above, Raise, Lower, Modulo, Above With Delims
let dimen = this.string.slice(this.i);
let [value, unit, length] = ParseUtil.matchDimen(dimen, true);
let [value, unit, length] = DimensionUtil.matchDimen(dimen, true);
if (value) {
this.i += length;
return value + unit;
Expand Down Expand Up @@ -475,7 +476,7 @@ export default class TexParser {
* @return {string} The delimiter.
*/
public GetDelimiterArg(name: string): string {
let c = ParseUtil.trimSpaces(this.GetArgument(name));
let c = StringUtil.trimSpaces(this.GetArgument(name));
if (c === '') {
return null;
}
Expand Down

0 comments on commit dad5b94

Please sign in to comment.