Socket
Socket
Sign inDemoInstall

katex

Package Overview
Dependencies
Maintainers
2
Versions
77
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

katex - npm Package Compare versions

Comparing version 0.3.0 to 0.4.0

src/environments.js

22

cli.js

@@ -8,9 +8,25 @@ #!/usr/bin/env node

// Skip the first two args, which are just "node" and "cli.js"
var args = process.argv.slice(2);
if (args.indexOf("--help") != -1) {
console.log(process.argv[0] + " " + process.argv[1] +
" [ --help ]" +
" [ --display-mode ]");
console.log("\n" +
"Options:");
console.log(" --help Display this help message");
console.log(" --display-mode Render in display mode (not inline mode)");
process.exit();
}
process.stdin.on("data", function(chunk) {
input += chunk.toString();
input += chunk.toString();
});
process.stdin.on("end", function() {
var output = katex.renderToString(input);
console.log(output);
var options = { displayMode: args.indexOf("--display-mode") != -1 };
var output = katex.renderToString(input, options);
console.log(output);
});

@@ -55,6 +55,20 @@ /**

/**
* Parse an expression and return the parse tree.
*/
var generateParseTree = function(expression, options) {
var settings = new Settings(options);
return parseTree(expression, settings);
};
module.exports = {
render: render,
renderToString: renderToString,
/**
* NOTE: This method is not currently recommended for public use.
* The internal tree representation is unstable and is very likely
* to change. Use at your own risk.
*/
__parse: generateParseTree,
ParseError: ParseError
};

5

package.json
{
"name": "katex",
"version": "0.3.0",
"version": "0.4.0",
"description": "Fast math typesetting for the web.",

@@ -28,3 +28,6 @@ "main": "katex.js",

"test": "make lint test"
},
"dependencies": {
"match-at": "^0.1.0"
}
}

@@ -17,4 +17,4 @@ # [<img src="https://khan.github.io/KaTeX/katex-logo.svg" width="130" alt="KaTeX">](https://khan.github.io/KaTeX/) [![Build Status](https://travis-ci.org/Khan/KaTeX.svg?branch=master)](https://travis-ci.org/Khan/KaTeX)

```html
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.2.0/katex.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.2.0/katex.min.js"></script>
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.3.0/katex.min.js"></script>
```

@@ -30,2 +30,4 @@

If KaTeX can't parse the expression, it throws a `katex.ParseError` error.
#### Server side rendering or rendering to a string

@@ -40,3 +42,3 @@

Make sure to include the CSS and font files, but there is no need to include the JavaScript.
Make sure to include the CSS and font files, but there is no need to include the JavaScript. Like `render`, `renderToString` throws if it can't parse the expression.

@@ -43,0 +45,0 @@ #### Rendering options

@@ -46,2 +46,3 @@ /**

genfrac: "minner",
array: "minner",
spacing: "mord",

@@ -502,2 +503,104 @@ punct: "mpunct",

array: function(group, options, prev) {
var r, c;
var nr = group.value.body.length;
var nc = 0;
var body = new Array(nr);
// Horizontal spacing
var pt = 1 / fontMetrics.metrics.ptPerEm;
var arraycolsep = 5 * pt; // \arraycolsep in article.cls
// Vertical spacing
var baselineskip = 12 * pt; // see size10.clo
var arraystretch = 1; // factor, see lttab.dtx
var arrayskip = arraystretch * baselineskip;
var arstrutHeight = 0.7 * arrayskip; // \strutbox in ltfsstrc.dtx and
var arstrutDepth = 0.3 * arrayskip; // \@arstrutbox in lttab.dtx
var totalHeight = 0;
for (r = 0; r < group.value.body.length; ++r) {
var inrow = group.value.body[r];
var height = arstrutHeight; // \@array adds an \@arstrut
var depth = arstrutDepth; // to each tow (via the template)
if (nc < inrow.length) {
nc = inrow.length;
}
var outrow = new Array(inrow.length);
for (c = 0; c < inrow.length; ++c) {
var elt = buildGroup(inrow[c], options);
if (depth < elt.depth) {
depth = elt.depth;
}
if (height < elt.height) {
height = elt.height;
}
outrow[c] = elt;
}
var gap = 0;
if (group.value.rowGaps[r]) {
gap = group.value.rowGaps[r].value;
switch (gap.unit) {
case "em":
gap = gap.number;
break;
case "ex":
gap = gap.number * fontMetrics.metrics.emPerEx;
break;
default:
console.error("Can't handle unit " + gap.unit);
gap = 0;
}
if (gap > 0) { // \@argarraycr
gap += arstrutDepth;
if (depth < gap) {
depth = gap; // \@xargarraycr
}
gap = 0;
}
}
outrow.height = height;
outrow.depth = depth;
totalHeight += height;
outrow.pos = totalHeight;
totalHeight += depth + gap; // \@yargarraycr
body[r] = outrow;
}
var offset = totalHeight / 2 + fontMetrics.metrics.axisHeight;
var colalign = group.value.colalign || [];
var cols = [];
var colsep;
for (c = 0; c < nc; ++c) {
if (c > 0 || group.value.hskipBeforeAndAfter) {
colsep = makeSpan(["arraycolsep"], []);
colsep.style.width = arraycolsep + "em";
cols.push(colsep);
}
var col = [];
for (r = 0; r < nr; ++r) {
var row = body[r];
var elem = row[c];
if (!elem) {
continue;
}
var shift = row.pos - offset;
elem.depth = row.depth;
elem.height = row.height;
col.push({type: "elem", elem: elem, shift: shift});
}
col = buildCommon.makeVList(col, "individualShift", null, options);
col = makeSpan(
["col-align-" + (colalign[c] || "c")],
[col]);
cols.push(col);
if (c < nc - 1 || group.value.hskipBeforeAndAfter) {
colsep = makeSpan(["arraycolsep"], []);
colsep.style.width = arraycolsep + "em";
cols.push(colsep);
}
}
body = makeSpan(["mtable"], cols);
return makeSpan(["minner"], [body], options.getColor());
},
spacing: function(group, options, prev) {

@@ -817,3 +920,33 @@ if (group.value === "\\ " || group.value === "\\space" ||

return makeSpan(["sqrt", "mord"], [delim, body]);
if (!group.value.index) {
return makeSpan(["sqrt", "mord"], [delim, body]);
} else {
// Handle the optional root index
// The index is always in scriptscript style
var root = buildGroup(
group.value.index,
options.withStyle(Style.SCRIPTSCRIPT));
var rootWrap = makeSpan(
[options.style.reset(), Style.SCRIPTSCRIPT.cls()],
[root]);
// Figure out the height and depth of the inner part
var innerRootHeight = Math.max(delim.height, body.height);
var innerRootDepth = Math.max(delim.depth, body.depth);
// The amount the index is shifted by. This is taken from the TeX
// source, in the definition of `\r@@t`.
var toShift = 0.6 * (innerRootHeight - innerRootDepth);
// Build a VList with the superscript shifted up correctly
var rootVList = buildCommon.makeVList(
[{type: "elem", elem: rootWrap}],
"shift", -toShift, options);
// Add a class surrounding it so we can add on the appropriate
// kerning
var rootVListWrap = makeSpan(["root"], [rootVList]);
return makeSpan(["sqrt", "mord"], [rootVListWrap, delim, body]);
}
},

@@ -1133,2 +1266,6 @@

var buildHTML = function(tree, settings) {
// buildExpression is destructive, so we need to make a clone
// of the incoming tree so that it isn't accidentally changed
tree = JSON.parse(JSON.stringify(tree));
var startStyle = Style.TEXT;

@@ -1135,0 +1272,0 @@ if (settings.displayMode) {

@@ -189,5 +189,25 @@ /**

array: function(group) {
return new mathMLTree.MathNode(
"mtable", group.value.body.map(function(row) {
return new mathMLTree.MathNode(
"mtr", row.map(function(cell) {
return new mathMLTree.MathNode(
"mtd", [buildGroup(cell)]);
}));
}));
},
sqrt: function(group) {
var node = new mathMLTree.MathNode(
"msqrt", [buildGroup(group.value.body)]);
var node;
if (group.value.index) {
node = new mathMLTree.MathNode(
"mroot", [
buildGroup(group.value.body),
buildGroup(group.value.index)
]);
} else {
node = new mathMLTree.MathNode(
"msqrt", [buildGroup(group.value.body)]);
}

@@ -194,0 +214,0 @@ return node;

@@ -234,25 +234,22 @@ /**

var bottomHeightTotal = bottomMetrics.height + bottomMetrics.depth;
var middleMetrics, middleHeightTotal;
var middleHeightTotal = 0;
var middleFactor = 1;
if (middle !== null) {
middleMetrics = getMetrics(middle, font);
var middleMetrics = getMetrics(middle, font);
middleHeightTotal = middleMetrics.height + middleMetrics.depth;
middleFactor = 2; // repeat symmetrically above and below middle
}
// Calcuate the real height that the delimiter will have. It is at least the
// size of the top, bottom, and optional middle combined.
var realHeightTotal = topHeightTotal + bottomHeightTotal;
if (middle !== null) {
realHeightTotal += middleHeightTotal;
}
// Calcuate the minimal height that the delimiter can have.
// It is at least the size of the top, bottom, and optional middle combined.
var minHeight = topHeightTotal + bottomHeightTotal + middleHeightTotal;
// Then add repeated pieces until we reach the specified height.
while (realHeightTotal < heightTotal) {
realHeightTotal += repeatHeightTotal;
if (middle !== null) {
// If there is a middle section, we need an equal number of pieces
// on the top and bottom.
realHeightTotal += repeatHeightTotal;
}
}
// Compute the number of copies of the repeat symbol we will need
var repeatCount = Math.ceil(
(heightTotal - minHeight) / (middleFactor * repeatHeightTotal));
// Compute the total height of the delimiter including all the symbols
var realHeightTotal =
minHeight + repeatCount * middleFactor * repeatHeightTotal;
// The center of the delimiter is placed at the center of the axis. Note

@@ -279,8 +276,4 @@ // that in this context, "center" means that the delimiter should be

if (middle === null) {
// Calculate the number of repeated symbols we need
var repeatHeight = realHeightTotal - topHeightTotal - bottomHeightTotal;
var symbolCount = Math.ceil(repeatHeight / repeatHeightTotal);
// Add that many symbols
for (i = 0; i < symbolCount; i++) {
for (i = 0; i < repeatCount; i++) {
inners.push(makeInner(repeat, font, mode));

@@ -291,24 +284,7 @@ }

// sections
// Calculate the number of symbols needed for the top and bottom
// repeated parts
var topRepeatHeight =
realHeightTotal / 2 - topHeightTotal - middleHeightTotal / 2;
var topSymbolCount = Math.ceil(topRepeatHeight / repeatHeightTotal);
var bottomRepeatHeight =
realHeightTotal / 2 - topHeightTotal - middleHeightTotal / 2;
var bottomSymbolCount =
Math.ceil(bottomRepeatHeight / repeatHeightTotal);
// Add the top repeated part
for (i = 0; i < topSymbolCount; i++) {
for (i = 0; i < repeatCount; i++) {
inners.push(makeInner(repeat, font, mode));
}
// Add the middle piece
inners.push(makeInner(middle, font, mode));
// Add the bottom repeated part
for (i = 0; i < bottomSymbolCount; i++) {
for (i = 0; i < repeatCount; i++) {
inners.push(makeInner(repeat, font, mode));

@@ -315,0 +291,0 @@ }

@@ -74,12 +74,7 @@ var utils = require("./utils");

numOptionalArgs: 1,
handler: function(func, optional, body, positions) {
if (optional != null) {
throw new ParseError(
"Optional arguments to \\sqrt aren't supported yet",
this.lexer, positions[1] - 1);
}
handler: function(func, index, body, positions) {
return {
type: "sqrt",
body: body
body: body,
index: index
};

@@ -235,3 +230,14 @@ }

"\\blue", "\\orange", "\\pink", "\\red",
"\\green", "\\gray", "\\purple"
"\\green", "\\gray", "\\purple",
"\\blueA", "\\blueB", "\\blueC", "\\blueD", "\\blueE",
"\\tealA", "\\tealB", "\\tealC", "\\tealD", "\\tealE",
"\\greenA", "\\greenB", "\\greenC", "\\greenD", "\\greenE",
"\\goldA", "\\goldB", "\\goldC", "\\goldD", "\\goldE",
"\\redA", "\\redB", "\\redC", "\\redD", "\\redE",
"\\maroonA", "\\maroonB", "\\maroonC", "\\maroonD", "\\maroonE",
"\\purpleA", "\\purpleB", "\\purpleC", "\\purpleD", "\\purpleE",
"\\mintA", "\\mintB", "\\mintC",
"\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
"\\grayF", "\\grayG", "\\grayH", "\\grayI",
"\\kaBlue", "\\kaGreen"
],

@@ -516,2 +522,43 @@ data: {

}
},
// Row breaks for aligned data
{
funcs: ["\\\\", "\\cr"],
data: {
numArgs: 0,
numOptionalArgs: 1,
argTypes: ["size"],
handler: function(func, size) {
return {
type: "cr",
size: size
};
}
}
},
// Environment delimiters
{
funcs: ["\\begin", "\\end"],
data: {
numArgs: 1,
argTypes: ["text"],
handler: function(func, nameGroup, positions) {
if (nameGroup.type !== "ordgroup") {
throw new ParseError(
"Invalid environment name",
this.lexer, positions[1]);
}
var name = "";
for (var i = 0; i < nameGroup.value.length; ++i) {
name += nameGroup.value[i].value;
}
return {
type: "environment",
name: name,
namepos: positions[1]
};
}
}
}

@@ -518,0 +565,0 @@ ];

@@ -14,2 +14,4 @@ /**

var matchAt = require("match-at");
var ParseError = require("./ParseError");

@@ -32,10 +34,12 @@

var mathNormals = [
/^[/|@.""`0-9a-zA-Z]/, // ords
/^[*+-]/, // bins
/^[=<>:]/, // rels
/^[,;]/, // punctuation
/^['\^_{}]/, // misc
/^[(\[]/, // opens
/^[)\]?!]/, // closes
/^~/ // spacing
/[/|@.""`0-9a-zA-Z]/, // ords
/[*+-]/, // bins
/[=<>:]/, // rels
/[,;]/, // punctuation
/['\^_{}]/, // misc
/[(\[]/, // opens
/[)\]?!]/, // closes
/~/, // spacing
/&/, // horizontal alignment
/\\\\/ // line break
];

@@ -46,14 +50,16 @@

var textNormals = [
/^[a-zA-Z0-9`!@*()-=+\[\]'";:?\/.,]/, // ords
/^[{}]/, // grouping
/^~/ // spacing
/[a-zA-Z0-9`!@*()-=+\[\]'";:?\/.,]/, // ords
/[{}]/, // grouping
/~/, // spacing
/&/, // horizontal alignment
/\\\\/ // line break
];
// Regexes for matching whitespace
var whitespaceRegex = /^\s*/;
var whitespaceConcatRegex = /^( +|\\ +)/;
var whitespaceRegex = /\s*/;
var whitespaceConcatRegex = / +|\\ +/;
// This regex matches any other TeX function, which is a backslash followed by a
// word or a single symbol
var anyFunc = /^\\(?:[a-zA-Z]+|.)/;
var anyFunc = /\\(?:[a-zA-Z]+|.)/;

@@ -66,3 +72,3 @@ /**

Lexer.prototype._innerLex = function(pos, normals, ignoreWhitespace) {
var input = this._input.slice(pos);
var input = this._input;
var whitespace;

@@ -72,8 +78,7 @@

// Get rid of whitespace.
whitespace = input.match(whitespaceRegex)[0];
whitespace = matchAt(whitespaceRegex, input, pos)[0];
pos += whitespace.length;
input = input.slice(whitespace.length);
} else {
// Do the funky concatenation of whitespace that happens in text mode.
whitespace = input.match(whitespaceConcatRegex);
whitespace = matchAt(whitespaceConcatRegex, input, pos);
if (whitespace !== null) {

@@ -85,3 +90,3 @@ return new Token(" ", null, pos + whitespace[0].length);

// If there's no more input to parse, return an EOF token
if (input.length === 0) {
if (pos === input.length) {
return new Token("EOF", null, pos);

@@ -91,3 +96,3 @@ }

var match;
if ((match = input.match(anyFunc))) {
if ((match = matchAt(anyFunc, input, pos))) {
// If we match a function token, return it

@@ -101,3 +106,3 @@ return new Token(match[0], null, pos + match[0].length);

if ((match = input.match(normal))) {
if ((match = matchAt(normal, input, pos))) {
// If it is, return it

@@ -110,8 +115,9 @@ return new Token(

throw new ParseError("Unexpected character: '" + input[0] +
"'", this, pos);
throw new ParseError(
"Unexpected character: '" + input[pos] + "'",
this, pos);
};
// A regex to match a CSS color (like #ffffff or BlueViolet)
var cssColor = /^(#[a-z0-9]+|[a-z]+)/i;
var cssColor = /#[a-z0-9]+|[a-z]+/i;

@@ -122,11 +128,10 @@ /**

Lexer.prototype._innerLexColor = function(pos) {
var input = this._input.slice(pos);
var input = this._input;
// Ignore whitespace
var whitespace = input.match(whitespaceRegex)[0];
var whitespace = matchAt(whitespaceRegex, input, pos)[0];
pos += whitespace.length;
input = input.slice(whitespace.length);
var match;
if ((match = input.match(cssColor))) {
if ((match = matchAt(cssColor, input, pos))) {
// If we look like a color, return a color

@@ -141,3 +146,3 @@ return new Token(match[0], null, pos + match[0].length);

// "1.2em" or ".4pt" or "1 ex"
var sizeRegex = /^(-?)\s*(\d+(?:\.\d*)?|\.\d+)\s*([a-z]{2})/;
var sizeRegex = /(-?)\s*(\d+(?:\.\d*)?|\.\d+)\s*([a-z]{2})/;

@@ -148,11 +153,10 @@ /**

Lexer.prototype._innerLexSize = function(pos) {
var input = this._input.slice(pos);
var input = this._input;
// Ignore whitespace
var whitespace = input.match(whitespaceRegex)[0];
var whitespace = matchAt(whitespaceRegex, input, pos)[0];
pos += whitespace.length;
input = input.slice(whitespace.length);
var match;
if ((match = input.match(sizeRegex))) {
if ((match = matchAt(sizeRegex, input, pos))) {
var unit = match[3];

@@ -176,8 +180,8 @@ // We only currently handle "em" and "ex" units

Lexer.prototype._innerLexWhitespace = function(pos) {
var input = this._input.slice(pos);
var input = this._input;
var whitespace = input.match(whitespaceRegex)[0];
var whitespace = matchAt(whitespaceRegex, input, pos)[0];
pos += whitespace.length;
return new Token(whitespace, null, pos);
return new Token(whitespace[0], null, pos);
};

@@ -184,0 +188,0 @@

@@ -114,3 +114,52 @@ /**

"katex-gray": "gray",
"katex-purple": "#9d38bd"
"katex-purple": "#9d38bd",
"katex-blueA": "#c7e9f1",
"katex-blueB": "#9cdceb",
"katex-blueC": "#58c4dd",
"katex-blueD": "#29abca",
"katex-blueE": "#1c758a",
"katex-tealA": "#acead7",
"katex-tealB": "#76ddc0",
"katex-tealC": "#5cd0b3",
"katex-tealD": "#55c1a7",
"katex-tealE": "#49a88f",
"katex-greenA": "#c9e2ae",
"katex-greenB": "#a6cf8c",
"katex-greenC": "#83c167",
"katex-greenD": "#77b05d",
"katex-greenE": "#699c52",
"katex-goldA": "#f7c797",
"katex-goldB": "#f9b775",
"katex-goldC": "#f0ac5f",
"katex-goldD": "#e1a158",
"katex-goldE": "#c78d46",
"katex-redA": "#f7a1a3",
"katex-redB": "#ff8080",
"katex-redC": "#fc6255",
"katex-redD": "#e65a4c",
"katex-redE": "#cf5044",
"katex-maroonA": "#ecabc1",
"katex-maroonB": "#ec92ab",
"katex-maroonC": "#c55f73",
"katex-maroonD": "#a24d61",
"katex-maroonE": "#94424f",
"katex-purpleA": "#caa3e8",
"katex-purpleB": "#b189c6",
"katex-purpleC": "#9a72ac",
"katex-purpleD": "#715582",
"katex-purpleE": "#644172",
"katex-mintA": "#f5f9e8",
"katex-mintB": "#edf2df",
"katex-mintC": "#e0e5cc",
"katex-grayA": "#fdfdfd",
"katex-grayB": "#f7f7f7",
"katex-grayC": "#eeeeee",
"katex-grayD": "#dddddd",
"katex-grayE": "#cccccc",
"katex-grayF": "#aaaaaa",
"katex-grayG": "#999999",
"katex-grayH": "#555555",
"katex-grayI": "#333333",
"katex-kaBlue": "#314453",
"katex-kaGreen": "#639b24"
};

@@ -117,0 +166,0 @@

var functions = require("./functions");
var environments = require("./environments");
var Lexer = require("./Lexer");

@@ -6,2 +7,3 @@ var symbols = require("./symbols");

var parseData = require("./parseData");
var ParseError = require("./ParseError");

@@ -54,20 +56,6 @@

/**
* The resulting parse tree nodes of the parse tree.
*/
function ParseNode(type, value, mode) {
this.type = type;
this.value = value;
this.mode = mode;
}
var ParseNode = parseData.ParseNode;
var ParseResult = parseData.ParseResult;
/**
* A result and final position returned by the `.parse...` functions.
*/
function ParseResult(result, newPosition) {
this.result = result;
this.position = newPosition;
}
/**
* An initial function (without its arguments), or an argument to a function.

@@ -111,9 +99,10 @@ * The `result` argument should be a ParseResult.

// Parse an expression
var expression = this.parseExpression(pos, mode, false, null);
var expression = this.parseExpression(pos, mode, false);
// If we succeeded, make sure there's an EOF at the end
var EOF = this.lexer.lex(expression.position, mode);
this.expect(EOF, "EOF");
this.expect(expression.peek, "EOF");
return expression;
};
var endOfExpression = ["}", "\\end", "\\right", "&", "\\\\", "\\cr"];
/**

@@ -133,9 +122,13 @@ * Parses an "expression", which is a list of atoms.

var body = [];
var lex = null;
// Keep adding atoms to the body until we can't parse any more atoms (either
// we reached the end, a }, or a \right)
while (true) {
var lex = this.lexer.lex(pos, mode);
if (breakOnToken != null && lex.text === breakOnToken) {
lex = this.lexer.lex(pos, mode);
if (endOfExpression.indexOf(lex.text) !== -1) {
break;
}
if (breakOnToken && lex.text === breakOnToken) {
break;
}
var atom = this.parseAtom(pos, mode);

@@ -151,3 +144,5 @@ if (!atom) {

}
return new ParseResult(this.handleInfixNodes(body, mode), pos);
var res = new ParseResult(this.handleInfixNodes(body, mode), pos);
res.peek = lex;
return res;
};

@@ -361,27 +356,44 @@

// Parse out the implicit body
body = this.parseExpression(left.position, mode, false, "}");
body = this.parseExpression(left.position, mode, false);
// Check the next token
var rightLex = this.parseSymbol(body.position, mode);
if (rightLex && rightLex.result.result === "\\right") {
// If it's a \right, parse the entire right function (including the delimiter)
var right = this.parseFunction(body.position, mode);
return new ParseResult(
new ParseNode("leftright", {
body: body.result,
left: left.result.value.value,
right: right.result.value.value
}, mode),
right.position);
} else {
throw new ParseError("Missing \\right", this.lexer, body.position);
this.expect(body.peek, "\\right");
var right = this.parseFunction(body.position, mode);
return new ParseResult(
new ParseNode("leftright", {
body: body.result,
left: left.result.value.value,
right: right.result.value.value
}, mode),
right.position);
} else if (func === "\\begin") {
// begin...end is similar to left...right
var begin = this.parseFunction(pos, mode);
var envName = begin.result.value.name;
if (!environments.hasOwnProperty(envName)) {
throw new ParseError(
"No such environment: " + envName,
this.lexer, begin.result.value.namepos);
}
} else if (func === "\\right") {
// If we see a right, explicitly fail the parsing here so the \left
// handling ends the group
return null;
// Build the environment object. Arguments and other information will
// be made available to the begin and end methods using properties.
var env = environments[envName];
var args = [null, mode, envName];
var newPos = this.parseArguments(
begin.position, mode, "\\begin{" + envName + "}", env, args);
args[0] = newPos;
var result = env.handler.apply(this, args);
var endLex = this.lexer.lex(result.position, mode);
this.expect(endLex, "\\end");
var end = this.parseFunction(result.position, mode);
if (end.result.value.name !== envName) {
throw new ParseError(
"Mismatch: \\begin{" + envName + "} matched " +
"by \\end{" + end.result.value.name + "}",
this.lexer, end.namepos);
}
result.position = end.position;
return result;
} else if (utils.contains(sizeFuncs, func)) {
// If we see a sizing function, parse out the implict body
body = this.parseExpression(start.result.position, mode, false, "}");
body = this.parseExpression(start.result.position, mode, false);
return new ParseResult(

@@ -396,3 +408,3 @@ new ParseNode("sizing", {

// If we see a styling function, parse out the implict body
body = this.parseExpression(start.result.position, mode, true, "}");
body = this.parseExpression(start.result.position, mode, true);
return new ParseResult(

@@ -430,67 +442,6 @@ new ParseNode("styling", {

var newPos = baseGroup.result.position;
var result;
var totalArgs = funcData.numArgs + funcData.numOptionalArgs;
if (totalArgs > 0) {
var baseGreediness = funcData.greediness;
var args = [func];
var positions = [newPos];
for (var i = 0; i < totalArgs; i++) {
var argType = funcData.argTypes && funcData.argTypes[i];
var arg;
if (i < funcData.numOptionalArgs) {
if (argType) {
arg = this.parseSpecialGroup(newPos, argType, mode, true);
} else {
arg = this.parseOptionalGroup(newPos, mode);
}
if (!arg) {
args.push(null);
positions.push(newPos);
continue;
}
} else {
if (argType) {
arg = this.parseSpecialGroup(newPos, argType, mode);
} else {
arg = this.parseGroup(newPos, mode);
}
if (!arg) {
throw new ParseError(
"Expected group after '" + baseGroup.result.result +
"'",
this.lexer, newPos);
}
}
var argNode;
if (arg.isFunction) {
var argGreediness =
functions.funcs[arg.result.result].greediness;
if (argGreediness > baseGreediness) {
argNode = this.parseFunction(newPos, mode);
} else {
throw new ParseError(
"Got function '" + arg.result.result + "' as " +
"argument to function '" +
baseGroup.result.result + "'",
this.lexer, arg.result.position - 1);
}
} else {
argNode = arg.result;
}
args.push(argNode.result);
positions.push(argNode.position);
newPos = argNode.position;
}
args.push(positions);
result = functions.funcs[func].handler.apply(this, args);
} else {
result = functions.funcs[func].handler.apply(this, [func]);
}
var args = [func];
var newPos = this.parseArguments(
baseGroup.result.position, mode, func, funcData, args);
var result = functions.funcs[func].handler.apply(this, args);
return new ParseResult(

@@ -507,3 +458,74 @@ new ParseNode(result.type, result, mode),

/**
* Parses the arguments of a function or environment
*
* @param {string} func "\name" or "\begin{name}"
* @param {{numArgs:number,numOptionalArgs:number|undefined}} funcData
* @param {Array} args list of arguments to which new ones will be pushed
* @return the position after all arguments have been parsed
*/
Parser.prototype.parseArguments = function(pos, mode, func, funcData, args) {
var totalArgs = funcData.numArgs + funcData.numOptionalArgs;
if (totalArgs === 0) {
return pos;
}
var newPos = pos;
var baseGreediness = funcData.greediness;
var positions = [newPos];
for (var i = 0; i < totalArgs; i++) {
var argType = funcData.argTypes && funcData.argTypes[i];
var arg;
if (i < funcData.numOptionalArgs) {
if (argType) {
arg = this.parseSpecialGroup(newPos, argType, mode, true);
} else {
arg = this.parseOptionalGroup(newPos, mode);
}
if (!arg) {
args.push(null);
positions.push(newPos);
continue;
}
} else {
if (argType) {
arg = this.parseSpecialGroup(newPos, argType, mode);
} else {
arg = this.parseGroup(newPos, mode);
}
if (!arg) {
throw new ParseError(
"Expected group after '" + func + "'",
this.lexer, newPos);
}
}
var argNode;
if (arg.isFunction) {
var argGreediness =
functions.funcs[arg.result.result].greediness;
if (argGreediness > baseGreediness) {
argNode = this.parseFunction(newPos, mode);
} else {
throw new ParseError(
"Got function '" + arg.result.result + "' as " +
"argument to '" + func + "'",
this.lexer, arg.result.position - 1);
}
} else {
argNode = arg.result;
}
args.push(argNode.result);
positions.push(argNode.position);
newPos = argNode.position;
}
args.push(positions);
return newPos;
};
/**
* Parses a group when the mode is changing. Takes a position, a new mode, and

@@ -568,3 +590,3 @@ * an outer mode that is used to parse the outside.

// If we get a brace, parse an expression
var expression = this.parseExpression(start.position, mode, false, "}");
var expression = this.parseExpression(start.position, mode, false);
// Make sure we get a close brace

@@ -638,2 +660,4 @@ var closeBrace = this.lexer.lex(expression.position, mode);

Parser.prototype.ParseNode = ParseNode;
module.exports = Parser;

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc