Migrate to eslint

Summary
We'd like contributors to use the same linter and lint rules that we use
internally.  This diff swaps out eslint for jshint and fixes all lint failures
except for the max-len failures in the test suites.

Test Plan:
- ka-lint src
- make lint
- make test

Reviewers: emily
This commit is contained in:
Kevin Barabash 2015-11-30 20:52:22 -08:00
parent 1a082e81d9
commit 14a58adb90
34 changed files with 2271 additions and 2206 deletions

86
.eslintrc Normal file
View File

@ -0,0 +1,86 @@
{
"rules": {
"arrow-spacing": 2,
"brace-style": [2, "1tbs", { "allowSingleLine": true }],
// We'd possibly like to remove the 'properties': 'never' one day.
"camelcase": [2, { "properties": "never" }],
"comma-dangle": [2, "always-multiline"],
"comma-spacing": [2, { "before": false, "after": true }],
"constructor-super": 2,
"curly": 2,
"eol-last": 2,
"eqeqeq": [2, "allow-null"],
"guard-for-in": 2,
"indent": [2, 4, {"SwitchCase": 1}],
"linebreak-style": [2, "unix"],
"max-len": [2, 80, 4, { "ignoreUrls": true, "ignorePattern": "\\brequire\\([\"']|eslint-disable" }],
"no-alert": 2,
"no-array-constructor": 2,
"no-console": 2,
"no-const-assign": 2,
"no-debugger": 2,
"no-dupe-class-members": 2,
"no-dupe-keys": 2,
"no-extra-bind": 2,
"no-new": 2,
"no-new-func": 2,
"no-new-object": 2,
"no-spaced-func": 2,
"no-this-before-super": 2,
"no-throw-literal": 2,
"no-trailing-spaces": 2,
"no-undef": 2,
"no-unexpected-multiline": 2,
"no-unreachable": 2,
"no-unused-vars": [2, {"args": "none", "varsIgnorePattern": "^_*$"}],
"no-useless-call": 2,
"no-with": 2,
"one-var": [2, "never"],
"prefer-const": 2,
"prefer-spread": 2,
"semi": [2, "always"],
"space-after-keywords": 2,
"space-before-blocks": 2,
"space-before-function-paren": [2, "never"],
"space-before-keywords": 2,
"space-infix-ops": 2,
"space-return-throw-case": 2,
"space-unary-ops": 2,
// ---------------------------------------
// Stuff we explicitly disable.
// We turned this off because it complains when you have a
// multi-line string, which I think is going too far.
"prefer-template": 0,
// We've decided explicitly not to care about this.
"arrow-parens": 0,
// ---------------------------------------
// Stuff that's disabled for now, but maybe shouldn't be.
// disabled because KaTeX doesn't use ES6
"no-var": 0,
// TODO(csilvers): enable these if/when community agrees on it.
"prefer-arrow-callback": 0,
"object-curly-spacing": [0, "always"],
// Might be nice to turn this on one day, but since we don't
// use jsdoc anywhere it seems silly to require it yet.
"valid-jsdoc": 0,
"require-jsdoc": 0
},
"ecmaFeatures": {
"arrowFunctions": true,
"blockBindings": true,
"classes": true,
"destructuring": true,
"experimentalObjectRestSpread": true,
"forOf": true,
"jsx": true,
"restParams": true,
"spread": true,
"templateStrings": true
},
"env": {
// "es6": true,
"node": true,
"browser": true
},
"extends": "eslint:recommended"
}

View File

@ -1,68 +0,0 @@
{
"bitwise" : true,
"camelcase" : true,
"curly" : true,
"eqeqeq" : false,
"es3" : true,
"forin" : false,
"immed" : true,
"indent" : 4,
"latedef" : false,
"newcap" : true,
"noarg" : true,
"noempty" : true,
"nonbsp" : true,
"nonew" : true,
"plusplus" : false,
"quotmark" : "double",
"undef" : true,
"unused" : "vars",
"strict" : false,
"trailing" : true,
"maxparams" : 7,
"maxdepth" : 6,
"asi" : false,
"boss" : false,
"debug" : false,
"eqnull" : true,
"esnext" : false,
"evil" : false,
"expr" : true,
"funcscope" : false,
"globalstrict" : false,
"iterator" : false,
"lastsemic" : false,
"laxbreak" : true,
"laxcomma" : false,
"loopfunc" : false,
"maxerr" : 50,
"multistr" : false,
"notypeof" : false,
"proto" : true,
"scripturl" : false,
"smarttabs" : false,
"shadow" : false,
"sub" : false,
"supernew" : false,
"validthis" : false,
"noyield" : false,
"browser" : true,
"couch" : false,
"devel" : false,
"dojo" : false,
"jquery" : false,
"mootools" : false,
"node" : true,
"nonstandard" : false,
"prototypejs" : false,
"rhino" : false,
"worker" : false,
"wsh" : false,
"yui" : false,
"globals": {
"JSON": false,
"console": true
}
}

View File

@ -17,7 +17,7 @@ setup:
npm install npm install
lint: katex.js server.js cli.js $(wildcard src/*.js) $(wildcard test/*.js) $(wildcard contrib/*/*.js) $(wildcard dockers/*/*.js) lint: katex.js server.js cli.js $(wildcard src/*.js) $(wildcard test/*.js) $(wildcard contrib/*/*.js) $(wildcard dockers/*/*.js)
./node_modules/.bin/jshint $^ ./node_modules/.bin/eslint --fix $^
build/katex.js: katex.js $(wildcard src/*.js) build/katex.js: katex.js $(wildcard src/*.js)
$(BROWSERIFY) $< --standalone katex > $@ $(BROWSERIFY) $< --standalone katex > $@

5
cli.js
View File

@ -1,6 +1,7 @@
#!/usr/bin/env node #!/usr/bin/env node
// Simple CLI for KaTeX. // Simple CLI for KaTeX.
// Reads TeX from stdin, outputs HTML to stdout. // Reads TeX from stdin, outputs HTML to stdout.
/* eslint no-console:0 */
var katex = require("./"); var katex = require("./");
var input = ""; var input = "";
@ -8,7 +9,7 @@ var input = "";
// Skip the first two args, which are just "node" and "cli.js" // Skip the first two args, which are just "node" and "cli.js"
var args = process.argv.slice(2); var args = process.argv.slice(2);
if (args.indexOf("--help") != -1) { if (args.indexOf("--help") !== -1) {
console.log(process.argv[0] + " " + process.argv[1] + console.log(process.argv[0] + " " + process.argv[1] +
" [ --help ]" + " [ --help ]" +
" [ --display-mode ]"); " [ --display-mode ]");
@ -25,7 +26,7 @@ process.stdin.on("data", function(chunk) {
}); });
process.stdin.on("end", function() { process.stdin.on("end", function() {
var options = { displayMode: args.indexOf("--display-mode") != -1 }; var options = { displayMode: args.indexOf("--display-mode") !== -1 };
var output = katex.renderToString(input, options); var output = katex.renderToString(input, options);
console.log(output); console.log(output);
}); });

View File

@ -13,12 +13,13 @@ beforeEach(function() {
compare: function(actual, left, right, result) { compare: function(actual, left, right, result) {
var message = { var message = {
pass: true, pass: true,
message: "'" + actual + "' split correctly" message: "'" + actual + "' split correctly",
}; };
var startData = [{type: "text", data: actual}]; var startData = [{type: "text", data: actual}];
var split = splitAtDelimiters(startData, left, right, false); var split =
splitAtDelimiters(startData, left, right, false);
if (split.length !== result.length) { if (split.length !== result.length) {
message.pass = false; message.pass = false;
@ -58,9 +59,9 @@ beforeEach(function() {
} }
return message; return message;
} },
}; };
} },
}); });
}); });
@ -69,12 +70,12 @@ describe("A delimiter splitter", function() {
expect("hello").toSplitInto("(", ")", [{type: "text", data: "hello"}]); expect("hello").toSplitInto("(", ")", [{type: "text", data: "hello"}]);
}); });
it("doesn't create a math node when there's only a left delimiter", function() { it("doesn't create a math node with only one left delimiter", function() {
expect("hello ( world").toSplitInto( expect("hello ( world").toSplitInto(
"(", ")", "(", ")",
[ [
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "text", data: "( world"} {type: "text", data: "( world"},
]); ]);
}); });
@ -82,7 +83,7 @@ describe("A delimiter splitter", function() {
expect("hello ) world").toSplitInto( expect("hello ) world").toSplitInto(
"(", ")", "(", ")",
[ [
{type: "text", data: "hello ) world"} {type: "text", data: "hello ) world"},
]); ]);
}); });
@ -93,7 +94,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "math", data: " world ", {type: "math", data: " world ",
rawData: "( world )", display: false}, rawData: "( world )", display: false},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
}); });
@ -104,7 +105,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "math", data: " world ", {type: "math", data: " world ",
rawData: "[[ world ]]", display: false}, rawData: "[[ world ]]", display: false},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
}); });
@ -118,7 +119,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: " boo "}, {type: "text", data: " boo "},
{type: "math", data: " more ", {type: "math", data: " more ",
rawData: "( more )", display: false}, rawData: "( more )", display: false},
{type: "text", data: " stuff"} {type: "text", data: " stuff"},
]); ]);
}); });
@ -130,7 +131,7 @@ describe("A delimiter splitter", function() {
{type: "math", data: " world ", {type: "math", data: " world ",
rawData: "( world )", display: false}, rawData: "( world )", display: false},
{type: "text", data: " boo "}, {type: "text", data: " boo "},
{type: "text", data: "( left"} {type: "text", data: "( left"},
]); ]);
}); });
@ -141,7 +142,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "math", data: " world { ) } ", {type: "math", data: " world { ) } ",
rawData: "( world { ) } )", display: false}, rawData: "( world { ) } )", display: false},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
expect("hello ( world { { } ) } ) boo").toSplitInto( expect("hello ( world { { } ) } ) boo").toSplitInto(
@ -150,7 +151,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "math", data: " world { { } ) } ", {type: "math", data: " world { { } ) } ",
rawData: "( world { { } ) } )", display: false}, rawData: "( world { { } ) } )", display: false},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
}); });
@ -161,7 +162,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "math", data: " world \\) ", {type: "math", data: " world \\) ",
rawData: "( world \\) )", display: false}, rawData: "( world \\) )", display: false},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
/* TODO(emily): make this work maybe? /* TODO(emily): make this work maybe?
@ -171,7 +172,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello \\( "}, {type: "text", data: "hello \\( "},
{type: "math", data: " world ", {type: "math", data: " world ",
rawData: "( world )", display: false}, rawData: "( world )", display: false},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
*/ */
}); });
@ -183,7 +184,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "math", data: " world ", {type: "math", data: " world ",
rawData: "$ world $", display: false}, rawData: "$ world $", display: false},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
}); });
@ -195,7 +196,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "math", data: " world ", {type: "math", data: " world ",
rawData: "( world )", display: true}, rawData: "( world )", display: true},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
}); });
@ -203,7 +204,7 @@ describe("A delimiter splitter", function() {
var startData = [ var startData = [
{type: "text", data: "hello ( world ) boo"}, {type: "text", data: "hello ( world ) boo"},
{type: "math", data: "math", rawData: "(math)", display: true}, {type: "math", data: "math", rawData: "(math)", display: true},
{type: "text", data: "hello ( world ) boo"} {type: "text", data: "hello ( world ) boo"},
]; ];
expect(splitAtDelimiters(startData, "(", ")", false)).toEqual( expect(splitAtDelimiters(startData, "(", ")", false)).toEqual(
@ -216,7 +217,7 @@ describe("A delimiter splitter", function() {
{type: "text", data: "hello "}, {type: "text", data: "hello "},
{type: "math", data: " world ", {type: "math", data: " world ",
rawData: "( world )", display: false}, rawData: "( world )", display: false},
{type: "text", data: " boo"} {type: "text", data: " boo"},
]); ]);
}); });
@ -224,7 +225,7 @@ describe("A delimiter splitter", function() {
var startData = [ var startData = [
{type: "text", data: "hello ( world ) boo"}, {type: "text", data: "hello ( world ) boo"},
{type: "math", data: "hello ( world ) boo", {type: "math", data: "hello ( world ) boo",
rawData: "(hello ( world ) boo)", display: true} rawData: "(hello ( world ) boo)", display: true},
]; ];
expect(splitAtDelimiters(startData, "(", ")", false)).toEqual( expect(splitAtDelimiters(startData, "(", ")", false)).toEqual(
@ -234,7 +235,7 @@ describe("A delimiter splitter", function() {
rawData: "( world )", display: false}, rawData: "( world )", display: false},
{type: "text", data: " boo"}, {type: "text", data: " boo"},
{type: "math", data: "hello ( world ) boo", {type: "math", data: "hello ( world ) boo",
rawData: "(hello ( world ) boo)", display: true} rawData: "(hello ( world ) boo)", display: true},
]); ]);
}); });
}); });

View File

@ -1,3 +1,4 @@
/* eslint no-console:0 */
/* global katex */ /* global katex */
var splitAtDelimiters = require("./splitAtDelimiters"); var splitAtDelimiters = require("./splitAtDelimiters");
@ -26,7 +27,7 @@ var renderMathInText = function(text, delimiters) {
var math = data[i].data; var math = data[i].data;
try { try {
katex.render(math, span, { katex.render(math, span, {
displayMode: data[i].display displayMode: data[i].display,
}); });
} catch (e) { } catch (e) {
if (!(e instanceof katex.ParseError)) { if (!(e instanceof katex.ParseError)) {
@ -72,19 +73,20 @@ var defaultOptions = {
delimiters: [ delimiters: [
{left: "$$", right: "$$", display: true}, {left: "$$", right: "$$", display: true},
{left: "\\[", right: "\\]", display: true}, {left: "\\[", right: "\\]", display: true},
{left: "\\(", right: "\\)", display: false} {left: "\\(", right: "\\)", display: false},
// LaTeX uses this, but it ruins the display of normal `$` in text: // LaTeX uses this, but it ruins the display of normal `$` in text:
// {left: "$", right: "$", display: false} // {left: "$", right: "$", display: false},
], ],
ignoredTags: [ ignoredTags: [
"script", "noscript", "style", "textarea", "pre", "code" "script", "noscript", "style", "textarea", "pre", "code",
] ],
}; };
var extend = function(obj) { var extend = function(obj) {
// Adapted from underscore.js' `_.extend`. See LICENSE.txt for license. // Adapted from underscore.js' `_.extend`. See LICENSE.txt for license.
var source, prop; var source;
var prop;
for (var i = 1, length = arguments.length; i < length; i++) { for (var i = 1, length = arguments.length; i < length; i++) {
source = arguments[i]; source = arguments[i];
for (prop in source) { for (prop in source) {

View File

@ -1,3 +1,4 @@
/* eslint no-constant-condition:0 */
var findEndOfMath = function(delimiter, text, startIndex) { var findEndOfMath = function(delimiter, text, startIndex) {
// Adapted from // Adapted from
// https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx // https://github.com/Khan/perseus/blob/master/src/perseus-markdown.jsx
@ -42,7 +43,7 @@ var splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
currIndex = nextIndex; currIndex = nextIndex;
finalData.push({ finalData.push({
type: "text", type: "text",
data: text.slice(0, currIndex) data: text.slice(0, currIndex),
}); });
lookingForLeft = false; lookingForLeft = false;
} }
@ -56,7 +57,7 @@ var splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
finalData.push({ finalData.push({
type: "text", type: "text",
data: text.slice(currIndex, nextIndex) data: text.slice(currIndex, nextIndex),
}); });
currIndex = nextIndex; currIndex = nextIndex;
@ -77,7 +78,7 @@ var splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
rawData: text.slice( rawData: text.slice(
currIndex, currIndex,
nextIndex + rightDelim.length), nextIndex + rightDelim.length),
display: display display: display,
}); });
currIndex = nextIndex + rightDelim.length; currIndex = nextIndex + rightDelim.length;
@ -88,7 +89,7 @@ var splitAtDelimiters = function(startData, leftDelim, rightDelim, display) {
finalData.push({ finalData.push({
type: "text", type: "text",
data: text.slice(currIndex) data: text.slice(currIndex),
}); });
} else { } else {
finalData.push(startData[i]); finalData.push(startData[i]);

View File

@ -1,3 +1,4 @@
/* eslint no-console:0, prefer-spread:0 */
"use strict"; "use strict";
var childProcess = require("child_process"); var childProcess = require("child_process");
@ -23,50 +24,50 @@ var opts = require("nomnom")
.option("browser", { .option("browser", {
abbr: "b", abbr: "b",
"default": "firefox", "default": "firefox",
help: "Name of the browser to use" help: "Name of the browser to use",
}) })
.option("container", { .option("container", {
abbr: "c", abbr: "c",
type: "string", type: "string",
help: "Name or ID of a running docker container to contact" help: "Name or ID of a running docker container to contact",
}) })
.option("seleniumURL", { .option("seleniumURL", {
full: "selenium-url", full: "selenium-url",
help: "Full URL of the Selenium web driver" help: "Full URL of the Selenium web driver",
}) })
.option("seleniumIP", { .option("seleniumIP", {
full: "selenium-ip", full: "selenium-ip",
help: "IP address of the Selenium web driver" help: "IP address of the Selenium web driver",
}) })
.option("seleniumPort", { .option("seleniumPort", {
full: "selenium-port", full: "selenium-port",
"default": 4444, "default": 4444,
help: "Port number of the Selenium web driver" help: "Port number of the Selenium web driver",
}) })
.option("katexURL", { .option("katexURL", {
full: "katex-url", full: "katex-url",
help: "Full URL of the KaTeX development server" help: "Full URL of the KaTeX development server",
}) })
.option("katexIP", { .option("katexIP", {
full: "katex-ip", full: "katex-ip",
"default": "localhost", "default": "localhost",
help: "Full URL of the KaTeX development server" help: "Full URL of the KaTeX development server",
}) })
.option("katexPort", { .option("katexPort", {
full: "katex-port", full: "katex-port",
help: "Port number of the KaTeX development server" help: "Port number of the KaTeX development server",
}) })
.option("include", { .option("include", {
abbr: "i", abbr: "i",
help: "Comma-separated list of test cases to process" help: "Comma-separated list of test cases to process",
}) })
.option("exclude", { .option("exclude", {
abbr: "x", abbr: "x",
help: "Comma-separated list of test cases to exclude" help: "Comma-separated list of test cases to exclude",
}) })
.option("verify", { .option("verify", {
flag: true, flag: true,
help: "Check whether screenshot matches current file content" help: "Check whether screenshot matches current file content",
}) })
.parse(); .parse();
@ -121,7 +122,7 @@ if (!seleniumURL && opts.container) {
process.exit(2); process.exit(2);
} }
katexIP = config[1]; katexIP = config[1];
} catch(e) { } catch (e) {
seleniumIP = katexIP = dockerCmd( seleniumIP = katexIP = dockerCmd(
"inspect", "-f", "{{.NetworkSettings.Gateway}}", opts.container); "inspect", "-f", "{{.NetworkSettings.Gateway}}", opts.container);
} }
@ -185,7 +186,7 @@ function tryConnect() {
} }
var sock = net.connect({ var sock = net.connect({
host: seleniumIP, host: seleniumIP,
port: +seleniumPort port: +seleniumPort,
}); });
sock.on("connect", function() { sock.on("connect", function() {
sock.end(); sock.end();
@ -223,7 +224,8 @@ function buildDriver() {
////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////
// Set the screen size // Set the screen size
var targetW = 1024, targetH = 768; var targetW = 1024;
var targetH = 768;
function setSize(reqW, reqH) { function setSize(reqW, reqH) {
return driver.manage().window().setSize(reqW, reqH).then(function() { return driver.manage().window().setSize(reqW, reqH).then(function() {
return driver.takeScreenshot(); return driver.takeScreenshot();
@ -247,7 +249,7 @@ function imageDimensions(img) {
return { return {
buf: buf, buf: buf,
width: buf.readUInt32BE(16), width: buf.readUInt32BE(16),
height: buf.readUInt32BE(20) height: buf.readUInt32BE(20),
}; };
} }
@ -310,7 +312,7 @@ function takeScreenshot(key) {
} }
} }
var opt = new jspngopt.Optimizer({ var opt = new jspngopt.Optimizer({
pako: pako pako: pako,
}); });
var buf = opt.bufferSync(img.buf); var buf = opt.bufferSync(img.buf);
if (loadExpected) { if (loadExpected) {

View File

@ -1,3 +1,4 @@
/* eslint no-console:0 */
"use strict"; "use strict";
var childProcess = require("child_process"); var childProcess = require("child_process");
@ -47,7 +48,7 @@ Q.all([
readFile(path.join(ssDir, "test.tex"), "utf-8"), readFile(path.join(ssDir, "test.tex"), "utf-8"),
ensureDir(tmpDir), ensureDir(tmpDir),
ensureDir(teximgDir), ensureDir(teximgDir),
ensureDir(diffDir) ensureDir(diffDir),
]).spread(function(data) { ]).spread(function(data) {
template = data; template = data;
// dirs have been created, template has been read, now rasterize. // dirs have been created, template has been read, now rasterize.
@ -78,14 +79,14 @@ function processTestCase(key) {
var fftLatex = writeFile(texFile, tex).then(function() { var fftLatex = writeFile(texFile, tex).then(function() {
// Step 2: call "pdflatex key" to create key.pdf // Step 2: call "pdflatex key" to create key.pdf
return execFile("pdflatex", [ return execFile("pdflatex", [
"-interaction", "nonstopmode", key "-interaction", "nonstopmode", key,
], {cwd: tmpDir}); ], {cwd: tmpDir});
}).then(function() { }).then(function() {
console.log("Typeset " + key); console.log("Typeset " + key);
// Step 3: call "convert ... key.pdf key.png" to create key.png // Step 3: call "convert ... key.pdf key.png" to create key.png
return execFile("convert", [ return execFile("convert", [
"-density", dpi, "-units", "PixelsPerInch", "-flatten", "-density", dpi, "-units", "PixelsPerInch", "-flatten",
pdfFile, pngFile pdfFile, pngFile,
]); ]);
}).then(function() { }).then(function() {
console.log("Rasterized " + key); console.log("Rasterized " + key);
@ -96,10 +97,11 @@ function processTestCase(key) {
var fftBrowser = readPNG(browserFile).then(fftImage); var fftBrowser = readPNG(browserFile).then(fftImage);
return Q.all([fftBrowser, fftLatex]).spread(function(browser, latex) { return Q.all([fftBrowser, fftLatex]).spread(function(browser, latex) {
// Now we have the FFT result from both // Now we have the FFT result from both
// Step 6: find alignment which maximizes overlap. // Step 6: find alignment which maximizes overlap.
// This uses a FFT-based correlation computation. // This uses a FFT-based correlation computation.
var x, y; var x;
var y;
var real = createMatrix(); var real = createMatrix();
var imag = createMatrix(); var imag = createMatrix();
@ -164,8 +166,8 @@ function processTestCase(key) {
"(", "-clone", "0-1", "-compose", "darken", "-composite", ")", "(", "-clone", "0-1", "-compose", "darken", "-composite", ")",
// First image is red, second green, third blue channel of result // First image is red, second green, third blue channel of result
"-channel", "RGB", "-combine", "-channel", "RGB", "-combine",
"-trim", // remove everything that has the same color as the corners "-trim", // remove everything with the same color as the corners
diffFile // output file name diffFile, // output file name
]); ]);
}).then(function() { }).then(function() {
console.log("Compared " + key); console.log("Compared " + key);
@ -241,7 +243,7 @@ function fftImage(image) {
real: real, real: real,
imag: imag, imag: imag,
width: image.width, width: image.width,
height: image.height height: image.height,
}; };
} }

View File

@ -1,3 +1,4 @@
/* eslint no-console:0 */
/** /**
* This is the main entry point for KaTeX. Here, we expose functions for * This is the main entry point for KaTeX. Here, we expose functions for
* rendering expressions either to DOM nodes or to markup strings. * rendering expressions either to DOM nodes or to markup strings.
@ -69,5 +70,5 @@ module.exports = {
* to change. Use at your own risk. * to change. Use at your own risk.
*/ */
__parse: generateParseTree, __parse: generateParseTree,
ParseError: ParseError ParseError: ParseError,
}; };

View File

@ -10,17 +10,17 @@ if len(sys.argv) > 1:
props.append('width') props.append('width')
data = json.load(sys.stdin) data = json.load(sys.stdin)
sep = "module.exports = {\n" sep = "module.exports = {\n "
for font in sorted(data): for font in sorted(data):
sys.stdout.write(sep + json.dumps(font)) sys.stdout.write(sep + json.dumps(font))
sep = ": {\n " sep = ": {\n "
for glyph in sorted(data[font], key=int): for glyph in sorted(data[font], key=int):
sys.stdout.write(sep + json.dumps(glyph) + ": ") sys.stdout.write(sep + json.dumps(glyph) + ": ")
values = [value if value != 0.0 else 0 for value in values = [value if value != 0.0 else 0 for value in
[data[font][glyph][key] for key in props]] [data[font][glyph][key] for key in props]]
sys.stdout.write(json.dumps(values)) sys.stdout.write(json.dumps(values))
sep = ",\n " sep = ",\n "
sep = "\n},\n" sep = ",\n },\n "
sys.stdout.write("\n}};\n") sys.stdout.write(",\n },\n};\n")

View File

@ -16,12 +16,12 @@
"devDependencies": { "devDependencies": {
"browserify": "^10.2.4", "browserify": "^10.2.4",
"clean-css": "~2.2.15", "clean-css": "~2.2.15",
"eslint": "^1.10.2",
"express": "~3.3.3", "express": "~3.3.3",
"glob": "^5.0.15", "glob": "^5.0.15",
"jasmine": "^2.3.2", "jasmine": "^2.3.2",
"jasmine-core": "^2.3.4", "jasmine-core": "^2.3.4",
"js-yaml": "^3.3.1", "js-yaml": "^3.3.1",
"jshint": "^2.5.6",
"jspngopt": "^0.1.0", "jspngopt": "^0.1.0",
"less": "~1.7.5", "less": "~1.7.5",
"nomnom": "^1.8.1", "nomnom": "^1.8.1",

View File

@ -1,3 +1,4 @@
/* eslint no-console:0 */
var fs = require("fs"); var fs = require("fs");
var path = require("path"); var path = require("path");
@ -41,7 +42,13 @@ var serveBrowserified = function(file, standaloneName) {
}; };
app.get("/katex.js", serveBrowserified("./katex", "katex")); app.get("/katex.js", serveBrowserified("./katex", "katex"));
app.use("/test/jasmine", express["static"](path.dirname(require.resolve("jasmine-core/lib/jasmine-core/jasmine.js")))); app.use("/test/jasmine",
express["static"](
path.dirname(
require.resolve("jasmine-core/lib/jasmine-core/jasmine.js")
)
)
);
app.get("/test/katex-spec.js", serveBrowserified("./test/*[Ss]pec.js")); app.get("/test/katex-spec.js", serveBrowserified("./test/*[Ss]pec.js"));
app.get("/contrib/auto-render/auto-render.js", app.get("/contrib/auto-render/auto-render.js",
serveBrowserified("./contrib/auto-render/auto-render", serveBrowserified("./contrib/auto-render/auto-render",
@ -56,7 +63,7 @@ app.get("/katex.css", function(req, res, next) {
var parser = new less.Parser({ var parser = new less.Parser({
paths: ["./static"], paths: ["./static"],
filename: "katex.less" filename: "katex.less",
}); });
parser.parse(data, function(err, tree) { parser.parse(data, function(err, tree) {

View File

@ -60,7 +60,7 @@ var whitespaceRegex = /\s*/;
*/ */
Lexer.prototype._innerLex = function(pos, ignoreWhitespace) { Lexer.prototype._innerLex = function(pos, ignoreWhitespace) {
var input = this._input; var input = this._input;
if (pos == input.length) { if (pos === input.length) {
return new Token("EOF", null, pos); return new Token("EOF", null, pos);
} }
var match = matchAt(tokenRegex, input, pos); var match = matchAt(tokenRegex, input, pos);
@ -121,9 +121,9 @@ Lexer.prototype._innerLexSize = function(pos) {
throw new ParseError("Invalid unit: '" + unit + "'", this, pos); throw new ParseError("Invalid unit: '" + unit + "'", this, pos);
} }
return new Token(match[0], { return new Token(match[0], {
number: +(match[1] + match[2]), number: +(match[1] + match[2]),
unit: unit unit: unit,
}, pos + match[0].length); }, pos + match[0].length);
} }
throw new ParseError("Invalid size", this, pos); throw new ParseError("Invalid size", this, pos);

View File

@ -46,7 +46,7 @@ Options.prototype.extend = function(extension) {
parentStyle: this.style, parentStyle: this.style,
parentSize: this.size, parentSize: this.size,
phantom: this.phantom, phantom: this.phantom,
font: this.font font: this.font,
}; };
for (var key in extension) { for (var key in extension) {
@ -63,7 +63,7 @@ Options.prototype.extend = function(extension) {
*/ */
Options.prototype.withStyle = function(style) { Options.prototype.withStyle = function(style) {
return this.extend({ return this.extend({
style: style style: style,
}); });
}; };
@ -72,7 +72,7 @@ Options.prototype.withStyle = function(style) {
*/ */
Options.prototype.withSize = function(size) { Options.prototype.withSize = function(size) {
return this.extend({ return this.extend({
size: size size: size,
}); });
}; };
@ -81,7 +81,7 @@ Options.prototype.withSize = function(size) {
*/ */
Options.prototype.withColor = function(color) { Options.prototype.withColor = function(color) {
return this.extend({ return this.extend({
color: color color: color,
}); });
}; };
@ -90,7 +90,7 @@ Options.prototype.withColor = function(color) {
*/ */
Options.prototype.withPhantom = function() { Options.prototype.withPhantom = function() {
return this.extend({ return this.extend({
phantom: true phantom: true,
}); });
}; };
@ -99,7 +99,7 @@ Options.prototype.withPhantom = function() {
*/ */
Options.prototype.withFont = function(font) { Options.prototype.withFont = function(font) {
return this.extend({ return this.extend({
font: font font: font,
}); });
}; };
@ -171,7 +171,7 @@ var colorMap = {
"katex-grayH": "#555555", "katex-grayH": "#555555",
"katex-grayI": "#333333", "katex-grayI": "#333333",
"katex-kaBlue": "#314453", "katex-kaBlue": "#314453",
"katex-kaGreen": "#639b24" "katex-kaGreen": "#639b24",
}; };
/** /**

View File

@ -1,3 +1,4 @@
/* eslint no-constant-condition:0 */
var functions = require("./functions"); var functions = require("./functions");
var environments = require("./environments"); var environments = require("./environments");
var Lexer = require("./Lexer"); var Lexer = require("./Lexer");
@ -175,9 +176,8 @@ Parser.prototype.parseExpression = function(breakOnInfix, breakOnToken) {
* *
* @returns {Array} * @returns {Array}
*/ */
Parser.prototype.handleInfixNodes = function (body) { Parser.prototype.handleInfixNodes = function(body) {
var overIndex = -1; var overIndex = -1;
var func;
var funcName; var funcName;
for (var i = 0; i < body.length; i++) { for (var i = 0; i < body.length; i++) {
@ -189,12 +189,12 @@ Parser.prototype.handleInfixNodes = function (body) {
} }
overIndex = i; overIndex = i;
funcName = node.value.replaceWith; funcName = node.value.replaceWith;
func = functions[funcName];
} }
} }
if (overIndex !== -1) { if (overIndex !== -1) {
var numerNode, denomNode; var numerNode;
var denomNode;
var numerBody = body.slice(0, overIndex); var numerBody = body.slice(0, overIndex);
var denomBody = body.slice(overIndex + 1); var denomBody = body.slice(overIndex + 1);
@ -236,7 +236,10 @@ Parser.prototype.handleSupSubscript = function(name) {
return this.handleUnsupportedCmd(); return this.handleUnsupportedCmd();
} else { } else {
throw new ParseError( throw new ParseError(
"Expected group after '" + symbol + "'", this.lexer, symPos + 1); "Expected group after '" + symbol + "'",
this.lexer,
symPos + 1
);
} }
} else if (group.isFunction) { } else if (group.isFunction) {
// ^ and _ have a greediness, so handle interactions with functions' // ^ and _ have a greediness, so handle interactions with functions'
@ -259,34 +262,34 @@ Parser.prototype.handleSupSubscript = function(name) {
* Converts the textual input of an unsupported command into a text node * Converts the textual input of an unsupported command into a text node
* contained within a color node whose color is determined by errorColor * contained within a color node whose color is determined by errorColor
*/ */
Parser.prototype.handleUnsupportedCmd = function() { Parser.prototype.handleUnsupportedCmd = function() {
var text = this.nextToken.text; var text = this.nextToken.text;
var textordArray = []; var textordArray = [];
for (var i = 0; i < text.length; i++) { for (var i = 0; i < text.length; i++) {
textordArray.push(new ParseNode("textord", text[i], "text")); textordArray.push(new ParseNode("textord", text[i], "text"));
} }
var textNode = new ParseNode( var textNode = new ParseNode(
"text", "text",
{ {
body: textordArray, body: textordArray,
type: "text" type: "text",
}, },
this.mode); this.mode);
var colorNode = new ParseNode( var colorNode = new ParseNode(
"color", "color",
{ {
color: this.settings.errorColor, color: this.settings.errorColor,
value: [textNode], value: [textNode],
type: "color" type: "color",
}, },
this.mode); this.mode);
this.consume(); this.consume();
return colorNode; return colorNode;
}; };
/** /**
* Parses a group with optional super/subscripts. * Parses a group with optional super/subscripts.
@ -314,10 +317,10 @@ Parser.prototype.parseAtom = function() {
if (lex.text === "\\limits" || lex.text === "\\nolimits") { if (lex.text === "\\limits" || lex.text === "\\nolimits") {
// We got a limit control // We got a limit control
if (!base || base.type !== "op") { if (!base || base.type !== "op") {
throw new ParseError("Limit controls must follow a math operator", throw new ParseError(
"Limit controls must follow a math operator",
this.lexer, this.pos); this.lexer, this.pos);
} } else {
else {
var limits = lex.text === "\\limits"; var limits = lex.text === "\\limits";
base.value.limits = limits; base.value.limits = limits;
base.value.alwaysHandleSupSub = true; base.value.alwaysHandleSupSub = true;
@ -363,7 +366,7 @@ Parser.prototype.parseAtom = function() {
return new ParseNode("supsub", { return new ParseNode("supsub", {
base: base, base: base,
sup: superscript, sup: superscript,
sub: subscript sub: subscript,
}, this.mode); }, this.mode);
} else { } else {
// Otherwise return the original body // Otherwise return the original body
@ -374,12 +377,12 @@ Parser.prototype.parseAtom = function() {
// A list of the size-changing functions, for use in parseImplicitGroup // A list of the size-changing functions, for use in parseImplicitGroup
var sizeFuncs = [ var sizeFuncs = [
"\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize", "\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\normalsize",
"\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge" "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge",
]; ];
// A list of the style-changing functions, for use in parseImplicitGroup // A list of the style-changing functions, for use in parseImplicitGroup
var styleFuncs = [ var styleFuncs = [
"\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle" "\\displaystyle", "\\textstyle", "\\scriptstyle", "\\scriptscriptstyle",
]; ];
/** /**
@ -416,7 +419,7 @@ Parser.prototype.parseImplicitGroup = function() {
return new ParseNode("leftright", { return new ParseNode("leftright", {
body: body, body: body,
left: left.value.value, left: left.value.value,
right: right.value.value right: right.value.value,
}, this.mode); }, this.mode);
} else if (func === "\\begin") { } else if (func === "\\begin") {
// begin...end is similar to left...right // begin...end is similar to left...right
@ -436,7 +439,7 @@ Parser.prototype.parseImplicitGroup = function() {
envName: envName, envName: envName,
parser: this, parser: this,
lexer: this.lexer, lexer: this.lexer,
positions: args.pop() positions: args.pop(),
}; };
var result = env.handler(context, args); var result = env.handler(context, args);
this.expect("\\end", false); this.expect("\\end", false);
@ -457,7 +460,7 @@ Parser.prototype.parseImplicitGroup = function() {
return new ParseNode("sizing", { return new ParseNode("sizing", {
// Figure out what size to use based on the list of functions above // Figure out what size to use based on the list of functions above
size: "size" + (utils.indexOf(sizeFuncs, func) + 1), size: "size" + (utils.indexOf(sizeFuncs, func) + 1),
value: body value: body,
}, this.mode); }, this.mode);
} else if (utils.contains(styleFuncs, func)) { } else if (utils.contains(styleFuncs, func)) {
// If we see a styling function, parse out the implict body // If we see a styling function, parse out the implict body
@ -466,7 +469,7 @@ Parser.prototype.parseImplicitGroup = function() {
// Figure out what style to use by pulling out the style from // Figure out what style to use by pulling out the style from
// the function name // the function name
style: func.slice(1, func.length - 5), style: func.slice(1, func.length - 5),
value: body value: body,
}, this.mode); }, this.mode);
} else { } else {
// Defer to parseFunction if it's not a function we handle // Defer to parseFunction if it's not a function we handle
@ -516,7 +519,7 @@ Parser.prototype.callFunction = function(name, args, positions) {
funcName: name, funcName: name,
parser: this, parser: this,
lexer: this.lexer, lexer: this.lexer,
positions: positions positions: positions,
}; };
return functions[name].handler(context, args); return functions[name].handler(context, args);
}; };

View File

@ -86,7 +86,7 @@ var sizeNames = [
"displaystyle textstyle", "displaystyle textstyle",
"textstyle", "textstyle",
"scriptstyle", "scriptstyle",
"scriptscriptstyle" "scriptscriptstyle",
]; ];
// Reset names for the different sizes // Reset names for the different sizes
@ -94,7 +94,7 @@ var resetNames = [
"reset-textstyle", "reset-textstyle",
"reset-textstyle", "reset-textstyle",
"reset-scriptstyle", "reset-scriptstyle",
"reset-scriptscriptstyle" "reset-scriptscriptstyle",
]; ];
// Instances of the different styles // Instances of the different styles
@ -106,7 +106,7 @@ var styles = [
new Style(S, 2, 0.7, false), new Style(S, 2, 0.7, false),
new Style(Sc, 2, 0.7, true), new Style(Sc, 2, 0.7, true),
new Style(SS, 3, 0.5, false), new Style(SS, 3, 0.5, false),
new Style(SSc, 3, 0.5, true) new Style(SSc, 3, 0.5, true),
]; ];
// Lookup tables for switching from one style to another // Lookup tables for switching from one style to another
@ -122,5 +122,5 @@ module.exports = {
DISPLAY: styles[D], DISPLAY: styles[D],
TEXT: styles[T], TEXT: styles[T],
SCRIPT: styles[S], SCRIPT: styles[S],
SCRIPTSCRIPT: styles[SS] SCRIPTSCRIPT: styles[SS],
}; };

View File

@ -1,3 +1,4 @@
/* eslint no-console:0 */
/** /**
* This module contains general functions that can be used for building * This module contains general functions that can be used for building
* different kinds of domTree nodes in a consistent manner. * different kinds of domTree nodes in a consistent manner.
@ -19,12 +20,12 @@ var greekCapitals = [
"\\Upsilon", "\\Upsilon",
"\\Phi", "\\Phi",
"\\Psi", "\\Psi",
"\\Omega" "\\Omega",
]; ];
var dotlessLetters = [ var dotlessLetters = [
"\u0131", // dotless i, \imath "\u0131", // dotless i, \imath
"\u0237" // dotless j, \jmath "\u0237", // dotless j, \jmath
]; ];
/** /**
@ -130,7 +131,8 @@ var makeOrd = function(group, options, type) {
} else { } else {
var fontName = fontMap[font].fontName; var fontName = fontMap[font].fontName;
if (fontMetrics.getCharacterMetrics(value, fontName)) { if (fontMetrics.getCharacterMetrics(value, fontName)) {
return makeSymbol(value, fontName, mode, color, classes.concat([font])); return makeSymbol(
value, fontName, mode, color, classes.concat([font]));
} else { } else {
return mathDefault(value, mode, color, classes, type); return mathDefault(value, mode, color, classes, type);
} }
@ -201,7 +203,8 @@ var makeFragment = function(children) {
*/ */
var makeFontSizer = function(options, fontSize) { var makeFontSizer = function(options, fontSize) {
var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]); var fontSizeInner = makeSpan([], [new domTree.symbolNode("\u200b")]);
fontSizeInner.style.fontSize = (fontSize / options.style.sizeMultiplier) + "em"; fontSizeInner.style.fontSize =
(fontSize / options.style.sizeMultiplier) + "em";
var fontSizer = makeSpan( var fontSizer = makeSpan(
["fontsize-ensurer", "reset-" + options.size, "size5"], ["fontsize-ensurer", "reset-" + options.size, "size5"],
@ -350,7 +353,7 @@ var sizingMultiplier = {
size7: 1.44, size7: 1.44,
size8: 1.73, size8: 1.73,
size9: 2.07, size9: 2.07,
size10: 2.49 size10: 2.49,
}; };
// A map of spacing functions to their attributes, like size and corresponding // A map of spacing functions to their attributes, like size and corresponding
@ -358,32 +361,32 @@ var sizingMultiplier = {
var spacingFunctions = { var spacingFunctions = {
"\\qquad": { "\\qquad": {
size: "2em", size: "2em",
className: "qquad" className: "qquad",
}, },
"\\quad": { "\\quad": {
size: "1em", size: "1em",
className: "quad" className: "quad",
}, },
"\\enspace": { "\\enspace": {
size: "0.5em", size: "0.5em",
className: "enspace" className: "enspace",
}, },
"\\;": { "\\;": {
size: "0.277778em", size: "0.277778em",
className: "thickspace" className: "thickspace",
}, },
"\\:": { "\\:": {
size: "0.22222em", size: "0.22222em",
className: "mediumspace" className: "mediumspace",
}, },
"\\,": { "\\,": {
size: "0.16667em", size: "0.16667em",
className: "thinspace" className: "thinspace",
}, },
"\\!": { "\\!": {
size: "-0.16667em", size: "-0.16667em",
className: "negativethinspace" className: "negativethinspace",
} },
}; };
/** /**
@ -396,11 +399,11 @@ var fontMap = {
// styles // styles
"mathbf": { "mathbf": {
variant: "bold", variant: "bold",
fontName: "Main-Bold" fontName: "Main-Bold",
}, },
"mathrm": { "mathrm": {
variant: "normal", variant: "normal",
fontName: "Main-Regular" fontName: "Main-Regular",
}, },
// "mathit" is missing because it requires the use of two fonts: Main-Italic // "mathit" is missing because it requires the use of two fonts: Main-Italic
@ -410,28 +413,28 @@ var fontMap = {
// families // families
"mathbb": { "mathbb": {
variant: "double-struck", variant: "double-struck",
fontName: "AMS-Regular" fontName: "AMS-Regular",
}, },
"mathcal": { "mathcal": {
variant: "script", variant: "script",
fontName: "Caligraphic-Regular" fontName: "Caligraphic-Regular",
}, },
"mathfrak": { "mathfrak": {
variant: "fraktur", variant: "fraktur",
fontName: "Fraktur-Regular" fontName: "Fraktur-Regular",
}, },
"mathscr": { "mathscr": {
variant: "script", variant: "script",
fontName: "Script-Regular" fontName: "Script-Regular",
}, },
"mathsf": { "mathsf": {
variant: "sans-serif", variant: "sans-serif",
fontName: "SansSerif-Regular" fontName: "SansSerif-Regular",
}, },
"mathtt": { "mathtt": {
variant: "monospace", variant: "monospace",
fontName: "Typewriter-Regular" fontName: "Typewriter-Regular",
} },
}; };
module.exports = { module.exports = {
@ -443,5 +446,5 @@ module.exports = {
makeVList: makeVList, makeVList: makeVList,
makeOrd: makeOrd, makeOrd: makeOrd,
sizingMultiplier: sizingMultiplier, sizingMultiplier: sizingMultiplier,
spacingFunctions: spacingFunctions spacingFunctions: spacingFunctions,
}; };

View File

@ -1,3 +1,4 @@
/* eslint no-console:0 */
/** /**
* This file does the main work of building a domTree structure from a parse * This file does the main work of building a domTree structure from a parse
* tree. The entry point is the `buildHTML` function, which takes a parse tree. * tree. The entry point is the `buildHTML` function, which takes a parse tree.
@ -53,7 +54,7 @@ var groupToType = {
rule: "mord", rule: "mord",
leftright: "minner", leftright: "minner",
sqrt: "mord", sqrt: "mord",
accent: "mord" accent: "mord",
}; };
/** /**
@ -104,7 +105,8 @@ var shouldHandleSupSub = function(group, options) {
// Operators handle supsubs differently when they have limits // Operators handle supsubs differently when they have limits
// (e.g. `\displaystyle\sum_2^3`) // (e.g. `\displaystyle\sum_2^3`)
return group.value.limits && return group.value.limits &&
(options.style.size === Style.DISPLAY.size || group.value.alwaysHandleSupSub); (options.style.size === Style.DISPLAY.size ||
group.value.alwaysHandleSupSub);
} else if (group.type === "accent") { } else if (group.type === "accent") {
return isCharacterBox(group.value.base); return isCharacterBox(group.value.base);
} else { } else {
@ -160,7 +162,7 @@ var makeNullDelimiter = function(options) {
return makeSpan([ return makeSpan([
"sizing", "reset-" + options.size, "size5", "sizing", "reset-" + options.size, "size5",
options.style.reset(), Style.TEXT.cls(), options.style.reset(), Style.TEXT.cls(),
"nulldelimiter" "nulldelimiter",
]); ]);
}; };
@ -263,7 +265,10 @@ groupTypes.supsub = function(group, options, prev) {
} }
var base = buildGroup(group.value.base, options.reset()); var base = buildGroup(group.value.base, options.reset());
var supmid, submid, sup, sub; var supmid;
var submid;
var sup;
var sub;
if (group.value.sup) { if (group.value.sup) {
sup = buildGroup(group.value.sup, sup = buildGroup(group.value.sup,
@ -280,7 +285,8 @@ groupTypes.supsub = function(group, options, prev) {
} }
// Rule 18a // Rule 18a
var supShift, subShift; var supShift;
var subShift;
if (isCharacterBox(group.value.base)) { if (isCharacterBox(group.value.base)) {
supShift = 0; supShift = 0;
subShift = 0; subShift = 0;
@ -314,7 +320,7 @@ groupTypes.supsub = function(group, options, prev) {
sub.height - 0.8 * fontMetrics.metrics.xHeight); sub.height - 0.8 * fontMetrics.metrics.xHeight);
supsub = buildCommon.makeVList([ supsub = buildCommon.makeVList([
{type: "elem", elem: submid} {type: "elem", elem: submid},
], "shift", subShift, options); ], "shift", subShift, options);
supsub.children[0].style.marginRight = scriptspace; supsub.children[0].style.marginRight = scriptspace;
@ -331,7 +337,7 @@ groupTypes.supsub = function(group, options, prev) {
sup.depth + 0.25 * fontMetrics.metrics.xHeight); sup.depth + 0.25 * fontMetrics.metrics.xHeight);
supsub = buildCommon.makeVList([ supsub = buildCommon.makeVList([
{type: "elem", elem: supmid} {type: "elem", elem: supmid},
], "shift", -supShift, options); ], "shift", -supShift, options);
supsub.children[0].style.marginRight = scriptspace; supsub.children[0].style.marginRight = scriptspace;
@ -357,7 +363,7 @@ groupTypes.supsub = function(group, options, prev) {
supsub = buildCommon.makeVList([ supsub = buildCommon.makeVList([
{type: "elem", elem: submid, shift: subShift}, {type: "elem", elem: submid, shift: subShift},
{type: "elem", elem: supmid, shift: -supShift} {type: "elem", elem: supmid, shift: -supShift},
], "individualShift", null, options); ], "individualShift", null, options);
// See comment above about subscripts not being shifted // See comment above about subscripts not being shifted
@ -436,7 +442,7 @@ groupTypes.genfrac = function(group, options, prev) {
frac = buildCommon.makeVList([ frac = buildCommon.makeVList([
{type: "elem", elem: denomreset, shift: denomShift}, {type: "elem", elem: denomreset, shift: denomShift},
{type: "elem", elem: numerreset, shift: -numShift} {type: "elem", elem: numerreset, shift: -numShift},
], "individualShift", null, options); ], "individualShift", null, options);
} else { } else {
// Rule 15d // Rule 15d
@ -467,7 +473,7 @@ groupTypes.genfrac = function(group, options, prev) {
frac = buildCommon.makeVList([ frac = buildCommon.makeVList([
{type: "elem", elem: denomreset, shift: denomShift}, {type: "elem", elem: denomreset, shift: denomShift},
{type: "elem", elem: mid, shift: midShift}, {type: "elem", elem: mid, shift: midShift},
{type: "elem", elem: numerreset, shift: -numShift} {type: "elem", elem: numerreset, shift: -numShift},
], "individualShift", null, options); ], "individualShift", null, options);
} }
@ -484,7 +490,8 @@ groupTypes.genfrac = function(group, options, prev) {
delimSize = fontMetrics.metrics.getDelim2(fstyle); delimSize = fontMetrics.metrics.getDelim2(fstyle);
} }
var leftDelim, rightDelim; var leftDelim;
var rightDelim;
if (group.value.leftDelim == null) { if (group.value.leftDelim == null) {
leftDelim = makeNullDelimiter(options); leftDelim = makeNullDelimiter(options);
} else { } else {
@ -507,7 +514,8 @@ groupTypes.genfrac = function(group, options, prev) {
}; };
groupTypes.array = function(group, options, prev) { groupTypes.array = function(group, options, prev) {
var r, c; var r;
var c;
var nr = group.value.body.length; var nr = group.value.body.length;
var nc = 0; var nc = 0;
var body = new Array(nr); var body = new Array(nr);
@ -551,15 +559,15 @@ groupTypes.array = function(group, options, prev) {
if (group.value.rowGaps[r]) { if (group.value.rowGaps[r]) {
gap = group.value.rowGaps[r].value; gap = group.value.rowGaps[r].value;
switch (gap.unit) { switch (gap.unit) {
case "em": case "em":
gap = gap.number; gap = gap.number;
break; break;
case "ex": case "ex":
gap = gap.number * fontMetrics.metrics.emPerEx; gap = gap.number * fontMetrics.metrics.emPerEx;
break; break;
default: default:
console.error("Can't handle unit " + gap.unit); console.error("Can't handle unit " + gap.unit);
gap = 0; gap = 0;
} }
if (gap > 0) { // \@argarraycr if (gap > 0) { // \@argarraycr
gap += arstrutDepth; gap += arstrutDepth;
@ -719,7 +727,7 @@ groupTypes.op = function(group, options, prev) {
// Most operators have a large successor symbol, but these don't. // Most operators have a large successor symbol, but these don't.
var noSuccessor = [ var noSuccessor = [
"\\smallint" "\\smallint",
]; ];
var large = false; var large = false;
@ -769,7 +777,10 @@ groupTypes.op = function(group, options, prev) {
// in a new span so it is an inline, and works. // in a new span so it is an inline, and works.
base = makeSpan([], [base]); base = makeSpan([], [base]);
var supmid, supKern, submid, subKern; var supmid;
var supKern;
var submid;
var subKern;
// We manually have to handle the superscripts and subscripts. This, // We manually have to handle the superscripts and subscripts. This,
// aside from the kern calculations, is copied from supsub. // aside from the kern calculations, is copied from supsub.
if (supGroup) { if (supGroup) {
@ -797,7 +808,9 @@ groupTypes.op = function(group, options, prev) {
// Build the final group as a vlist of the possible subscript, base, // Build the final group as a vlist of the possible subscript, base,
// and possible superscript. // and possible superscript.
var finalGroup, top, bottom; var finalGroup;
var top;
var bottom;
if (!supGroup) { if (!supGroup) {
top = base.height - baseShift; top = base.height - baseShift;
@ -805,7 +818,7 @@ groupTypes.op = function(group, options, prev) {
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5}, {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
{type: "elem", elem: submid}, {type: "elem", elem: submid},
{type: "kern", size: subKern}, {type: "kern", size: subKern},
{type: "elem", elem: base} {type: "elem", elem: base},
], "top", top, options); ], "top", top, options);
// Here, we shift the limits by the slant of the symbol. Note // Here, we shift the limits by the slant of the symbol. Note
@ -820,7 +833,7 @@ groupTypes.op = function(group, options, prev) {
{type: "elem", elem: base}, {type: "elem", elem: base},
{type: "kern", size: supKern}, {type: "kern", size: supKern},
{type: "elem", elem: supmid}, {type: "elem", elem: supmid},
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5} {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
], "bottom", bottom, options); ], "bottom", bottom, options);
// See comment above about slants // See comment above about slants
@ -843,7 +856,7 @@ groupTypes.op = function(group, options, prev) {
{type: "elem", elem: base}, {type: "elem", elem: base},
{type: "kern", size: supKern}, {type: "kern", size: supKern},
{type: "elem", elem: supmid}, {type: "elem", elem: supmid},
{type: "kern", size: fontMetrics.metrics.bigOpSpacing5} {type: "kern", size: fontMetrics.metrics.bigOpSpacing5},
], "bottom", bottom, options); ], "bottom", bottom, options);
// See comment above about slants // See comment above about slants
@ -909,7 +922,7 @@ groupTypes.overline = function(group, options, prev) {
{type: "elem", elem: innerGroup}, {type: "elem", elem: innerGroup},
{type: "kern", size: 3 * ruleWidth}, {type: "kern", size: 3 * ruleWidth},
{type: "elem", elem: line}, {type: "elem", elem: line},
{type: "kern", size: ruleWidth} {type: "kern", size: ruleWidth},
], "firstBaseline", null, options); ], "firstBaseline", null, options);
return makeSpan(["overline", "mord"], [vlist], options.getColor()); return makeSpan(["overline", "mord"], [vlist], options.getColor());
@ -977,7 +990,7 @@ groupTypes.sqrt = function(group, options, prev) {
{type: "elem", elem: inner}, {type: "elem", elem: inner},
{type: "kern", size: lineClearance}, {type: "kern", size: lineClearance},
{type: "elem", elem: line}, {type: "elem", elem: line},
{type: "kern", size: ruleWidth} {type: "kern", size: ruleWidth},
], "firstBaseline", null, options); ], "firstBaseline", null, options);
} }
@ -1041,7 +1054,7 @@ groupTypes.styling = function(group, options, prev) {
"display": Style.DISPLAY, "display": Style.DISPLAY,
"text": Style.TEXT, "text": Style.TEXT,
"script": Style.SCRIPT, "script": Style.SCRIPT,
"scriptscript": Style.SCRIPTSCRIPT "scriptscript": Style.SCRIPTSCRIPT,
}; };
var newStyle = style[group.value.style]; var newStyle = style[group.value.style];
@ -1243,7 +1256,7 @@ groupTypes.accent = function(group, options, prev) {
accentBody = buildCommon.makeVList([ accentBody = buildCommon.makeVList([
{type: "elem", elem: body}, {type: "elem", elem: body},
{type: "kern", size: -clearance}, {type: "kern", size: -clearance},
{type: "elem", elem: accentBody} {type: "elem", elem: accentBody},
], "firstBaseline", null, options); ], "firstBaseline", null, options);
// Shift the accent over by the skew. Note we shift by twice the skew // Shift the accent over by the skew. Note we shift by twice the skew

View File

@ -249,7 +249,7 @@ groupTypes.sqrt = function(group, options) {
node = new mathMLTree.MathNode( node = new mathMLTree.MathNode(
"mroot", [ "mroot", [
buildGroup(group.value.body, options), buildGroup(group.value.body, options),
buildGroup(group.value.index, options) buildGroup(group.value.index, options),
]); ]);
} else { } else {
node = new mathMLTree.MathNode( node = new mathMLTree.MathNode(
@ -381,7 +381,7 @@ groupTypes.styling = function(group, options) {
"display": ["0", "true"], "display": ["0", "true"],
"text": ["0", "false"], "text": ["0", "false"],
"script": ["1", "false"], "script": ["1", "false"],
"scriptscript": ["2", "false"] "scriptscript": ["2", "false"],
}; };
var attr = styleAttributes[group.value.style]; var attr = styleAttributes[group.value.style];

View File

@ -18,7 +18,7 @@ var buildTree = function(tree, expression, settings) {
// Setup the default options // Setup the default options
var options = new Options({ var options = new Options({
style: startStyle, style: startStyle,
size: "size5" size: "size5",
}); });
// `buildHTML` sometimes messes with the parse tree (like turning bins -> // `buildHTML` sometimes messes with the parse tree (like turning bins ->
@ -27,7 +27,7 @@ var buildTree = function(tree, expression, settings) {
var htmlNode = buildHTML(tree, options); var htmlNode = buildHTML(tree, options);
var katexNode = makeSpan(["katex"], [ var katexNode = makeSpan(["katex"], [
mathMLNode, htmlNode mathMLNode, htmlNode,
]); ]);
if (settings.displayMode) { if (settings.displayMode) {

View File

@ -144,7 +144,10 @@ var makeInner = function(symbol, font, mode) {
var makeStackedDelim = function(delim, heightTotal, center, options, mode) { var makeStackedDelim = function(delim, heightTotal, center, options, mode) {
// There are four parts, the top, an optional middle, a repeated part, and a // There are four parts, the top, an optional middle, a repeated part, and a
// bottom. // bottom.
var top, middle, repeat, bottom; var top;
var middle;
var repeat;
var bottom;
top = repeat = bottom = delim; top = repeat = bottom = delim;
middle = null; middle = null;
// Also keep track of what font the delimiters are in // Also keep track of what font the delimiters are in
@ -325,7 +328,7 @@ var stackLargeDelimiters = [
"(", ")", "[", "\\lbrack", "]", "\\rbrack", "(", ")", "[", "\\lbrack", "]", "\\rbrack",
"\\{", "\\lbrace", "\\}", "\\rbrace", "\\{", "\\lbrace", "\\}", "\\rbrace",
"\\lfloor", "\\rfloor", "\\lceil", "\\rceil", "\\lfloor", "\\rfloor", "\\lceil", "\\rceil",
"\\surd" "\\surd",
]; ];
// delimiters that always stack // delimiters that always stack
@ -334,12 +337,12 @@ var stackAlwaysDelimiters = [
"\\Uparrow", "\\Downarrow", "\\Updownarrow", "\\Uparrow", "\\Downarrow", "\\Updownarrow",
"|", "\\|", "\\vert", "\\Vert", "|", "\\|", "\\vert", "\\Vert",
"\\lvert", "\\rvert", "\\lVert", "\\rVert", "\\lvert", "\\rvert", "\\lVert", "\\rVert",
"\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache" "\\lgroup", "\\rgroup", "\\lmoustache", "\\rmoustache",
]; ];
// and delimiters that never stack // and delimiters that never stack
var stackNeverDelimiters = [ var stackNeverDelimiters = [
"<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt" "<", ">", "\\langle", "\\rangle", "/", "\\backslash", "\\lt", "\\gt",
]; ];
// Metrics of the different sizes. Found by looking at TeX's output of // Metrics of the different sizes. Found by looking at TeX's output of
@ -390,7 +393,7 @@ var stackNeverDelimiterSequence = [
{type: "large", size: 1}, {type: "large", size: 1},
{type: "large", size: 2}, {type: "large", size: 2},
{type: "large", size: 3}, {type: "large", size: 3},
{type: "large", size: 4} {type: "large", size: 4},
]; ];
// Delimiters that always stack try the small delimiters first, then stack // Delimiters that always stack try the small delimiters first, then stack
@ -398,7 +401,7 @@ var stackAlwaysDelimiterSequence = [
{type: "small", style: Style.SCRIPTSCRIPT}, {type: "small", style: Style.SCRIPTSCRIPT},
{type: "small", style: Style.SCRIPT}, {type: "small", style: Style.SCRIPT},
{type: "small", style: Style.TEXT}, {type: "small", style: Style.TEXT},
{type: "stack"} {type: "stack"},
]; ];
// Delimiters that stack when large try the small and then large delimiters, and // Delimiters that stack when large try the small and then large delimiters, and
@ -411,7 +414,7 @@ var stackLargeDelimiterSequence = [
{type: "large", size: 2}, {type: "large", size: 2},
{type: "large", size: 3}, {type: "large", size: 3},
{type: "large", size: 4}, {type: "large", size: 4},
{type: "stack"} {type: "stack"},
]; ];
/** /**
@ -535,5 +538,5 @@ var makeLeftRightDelim = function(delim, height, depth, options, mode) {
module.exports = { module.exports = {
sizedDelim: makeSizedDelim, sizedDelim: makeSizedDelim,
customSizedDelim: makeCustomSizedDelim, customSizedDelim: makeCustomSizedDelim,
leftRightDelim: makeLeftRightDelim leftRightDelim: makeLeftRightDelim,
}; };

View File

@ -265,5 +265,5 @@ symbolNode.prototype.toMarkup = function() {
module.exports = { module.exports = {
span: span, span: span,
documentFragment: documentFragment, documentFragment: documentFragment,
symbolNode: symbolNode symbolNode: symbolNode,
}; };

View File

@ -1,3 +1,4 @@
/* eslint no-constant-condition:0 */
var fontMetrics = require("./fontMetrics"); var fontMetrics = require("./fontMetrics");
var parseData = require("./parseData"); var parseData = require("./parseData");
var ParseError = require("./ParseError"); var ParseError = require("./ParseError");
@ -10,7 +11,9 @@ var ParseNode = parseData.ParseNode;
* with one group per cell. * with one group per cell.
*/ */
function parseArray(parser, result) { function parseArray(parser, result) {
var row = [], body = [row], rowGaps = []; var row = [];
var body = [row];
var rowGaps = [];
while (true) { while (true) {
var cell = parser.parseExpression(false, null); var cell = parser.parseExpression(false, null);
row.push(new ParseNode("ordgroup", cell, parser.mode)); row.push(new ParseNode("ordgroup", cell, parser.mode));
@ -74,7 +77,7 @@ function defineEnvironment(names, props, handler) {
greediness: 1, greediness: 1,
allowedInText: !!props.allowedInText, allowedInText: !!props.allowedInText,
numOptionalArgs: props.numOptionalArgs || 0, numOptionalArgs: props.numOptionalArgs || 0,
handler: handler handler: handler,
}; };
for (var i = 0; i < names.length; ++i) { for (var i = 0; i < names.length; ++i) {
module.exports[names[i]] = data; module.exports[names[i]] = data;
@ -84,7 +87,7 @@ function defineEnvironment(names, props, handler) {
// Arrays are part of LaTeX, defined in lttab.dtx so its documentation // Arrays are part of LaTeX, defined in lttab.dtx so its documentation
// is part of the source2e.pdf file of LaTeX2e source documentation. // is part of the source2e.pdf file of LaTeX2e source documentation.
defineEnvironment("array", { defineEnvironment("array", {
numArgs: 1 numArgs: 1,
}, function(context, args) { }, function(context, args) {
var colalign = args[0]; var colalign = args[0];
colalign = colalign.value.map ? colalign.value : [colalign]; colalign = colalign.value.map ? colalign.value : [colalign];
@ -93,12 +96,12 @@ defineEnvironment("array", {
if ("lcr".indexOf(ca) !== -1) { if ("lcr".indexOf(ca) !== -1) {
return { return {
type: "align", type: "align",
align: ca align: ca,
}; };
} else if (ca === "|") { } else if (ca === "|") {
return { return {
type: "separator", type: "separator",
separator: "|" separator: "|",
}; };
} }
throw new ParseError( throw new ParseError(
@ -108,7 +111,7 @@ defineEnvironment("array", {
var res = { var res = {
type: "array", type: "array",
cols: cols, cols: cols,
hskipBeforeAndAfter: true // \@preamble in lttab.dtx hskipBeforeAndAfter: true, // \@preamble in lttab.dtx
}; };
res = parseArray(context.parser, res); res = parseArray(context.parser, res);
return res; return res;
@ -122,7 +125,7 @@ defineEnvironment([
"bmatrix", "bmatrix",
"Bmatrix", "Bmatrix",
"vmatrix", "vmatrix",
"Vmatrix" "Vmatrix",
], { ], {
}, function(context) { }, function(context) {
var delimiters = { var delimiters = {
@ -131,18 +134,18 @@ defineEnvironment([
"bmatrix": ["[", "]"], "bmatrix": ["[", "]"],
"Bmatrix": ["\\{", "\\}"], "Bmatrix": ["\\{", "\\}"],
"vmatrix": ["|", "|"], "vmatrix": ["|", "|"],
"Vmatrix": ["\\Vert", "\\Vert"] "Vmatrix": ["\\Vert", "\\Vert"],
}[context.envName]; }[context.envName];
var res = { var res = {
type: "array", type: "array",
hskipBeforeAndAfter: false // \hskip -\arraycolsep in amsmath hskipBeforeAndAfter: false, // \hskip -\arraycolsep in amsmath
}; };
res = parseArray(context.parser, res); res = parseArray(context.parser, res);
if (delimiters) { if (delimiters) {
res = new ParseNode("leftright", { res = new ParseNode("leftright", {
body: [res], body: [res],
left: delimiters[0], left: delimiters[0],
right: delimiters[1] right: delimiters[1],
}, context.mode); }, context.mode);
} }
return res; return res;
@ -160,19 +163,19 @@ defineEnvironment("cases", {
type: "align", type: "align",
align: "l", align: "l",
pregap: 0, pregap: 0,
postgap: fontMetrics.metrics.quad postgap: fontMetrics.metrics.quad,
}, { }, {
type: "align", type: "align",
align: "l", align: "l",
pregap: 0, pregap: 0,
postgap: 0 postgap: 0,
}] }],
}; };
res = parseArray(context.parser, res); res = parseArray(context.parser, res);
res = new ParseNode("leftright", { res = new ParseNode("leftright", {
body: [res], body: [res],
left: "\\{", left: "\\{",
right: "." right: ".",
}, context.mode); }, context.mode);
return res; return res;
}); });
@ -185,7 +188,7 @@ defineEnvironment("aligned", {
}, function(context) { }, function(context) {
var res = { var res = {
type: "array", type: "array",
cols: [] cols: [],
}; };
res = parseArray(context.parser, res); res = parseArray(context.parser, res);
var emptyGroup = new ParseNode("ordgroup", [], context.mode); var emptyGroup = new ParseNode("ordgroup", [], context.mode);
@ -211,7 +214,7 @@ defineEnvironment("aligned", {
type: "align", type: "align",
align: align, align: align,
pregap: pregap, pregap: pregap,
postgap: 0 postgap: 0,
}; };
} }
return res; return res;

View File

@ -1,4 +1,4 @@
/* jshint unused:false */ /* eslint no-unused-vars:0 */
var Style = require("./Style"); var Style = require("./Style");
@ -112,7 +112,7 @@ var metrics = {
return sigma21ScriptScript; return sigma21ScriptScript;
} }
throw new Error("Unexpected style size: " + style.size); throw new Error("Unexpected style size: " + style.size);
} },
}; };
// This map contains a mapping from font name and character code to character // This map contains a mapping from font name and character code to character
@ -124,7 +124,7 @@ var metricMap = require("./fontMetricsData");
/** /**
* This function is a convenience function for looking up information in the * This function is a convenience function for looking up information in the
* metricMap table. It takes a character as a string, and a style. * metricMap table. It takes a character as a string, and a style.
* *
* Note: the `width` property may be undefined if fontMetricsData.js wasn't * Note: the `width` property may be undefined if fontMetricsData.js wasn't
* built using `Make extended_metrics`. * built using `Make extended_metrics`.
*/ */
@ -136,12 +136,12 @@ var getCharacterMetrics = function(character, style) {
height: metrics[1], height: metrics[1],
italic: metrics[2], italic: metrics[2],
skew: metrics[3], skew: metrics[3],
width: metrics[4] width: metrics[4],
}; };
} }
}; };
module.exports = { module.exports = {
metrics: metrics, metrics: metrics,
getCharacterMetrics: getCharacterMetrics getCharacterMetrics: getCharacterMetrics,
}; };

File diff suppressed because it is too large Load Diff

View File

@ -91,7 +91,7 @@ function defineFunction(names, props, handler) {
greediness: (props.greediness === undefined) ? 1 : props.greediness, greediness: (props.greediness === undefined) ? 1 : props.greediness,
allowedInText: !!props.allowedInText, allowedInText: !!props.allowedInText,
numOptionalArgs: props.numOptionalArgs || 0, numOptionalArgs: props.numOptionalArgs || 0,
handler: handler handler: handler,
}; };
for (var i = 0; i < names.length; ++i) { for (var i = 0; i < names.length; ++i) {
module.exports[names[i]] = data; module.exports[names[i]] = data;
@ -101,14 +101,14 @@ function defineFunction(names, props, handler) {
// A normal square root // A normal square root
defineFunction("\\sqrt", { defineFunction("\\sqrt", {
numArgs: 1, numArgs: 1,
numOptionalArgs: 1 numOptionalArgs: 1,
}, function(context, args) { }, function(context, args) {
var index = args[0]; var index = args[0];
var body = args[1]; var body = args[1];
return { return {
type: "sqrt", type: "sqrt",
body: body, body: body,
index: index index: index,
}; };
}); });
@ -116,7 +116,7 @@ defineFunction("\\sqrt", {
defineFunction("\\text", { defineFunction("\\text", {
numArgs: 1, numArgs: 1,
argTypes: ["text"], argTypes: ["text"],
greediness: 2 greediness: 2,
}, function(context, args) { }, function(context, args) {
var body = args[0]; var body = args[0];
// Since the corresponding buildHTML/buildMathML function expects a // Since the corresponding buildHTML/buildMathML function expects a
@ -131,7 +131,7 @@ defineFunction("\\text", {
return { return {
type: "text", type: "text",
body: inner body: inner,
}; };
}); });
@ -140,7 +140,7 @@ defineFunction("\\color", {
numArgs: 2, numArgs: 2,
allowedInText: true, allowedInText: true,
greediness: 3, greediness: 3,
argTypes: ["color", "original"] argTypes: ["color", "original"],
}, function(context, args) { }, function(context, args) {
var color = args[0]; var color = args[0];
var body = args[1]; var body = args[1];
@ -155,18 +155,18 @@ defineFunction("\\color", {
return { return {
type: "color", type: "color",
color: color.value, color: color.value,
value: inner value: inner,
}; };
}); });
// An overline // An overline
defineFunction("\\overline", { defineFunction("\\overline", {
numArgs: 1 numArgs: 1,
}, function(context, args) { }, function(context, args) {
var body = args[0]; var body = args[0];
return { return {
type: "overline", type: "overline",
body: body body: body,
}; };
}); });
@ -174,7 +174,7 @@ defineFunction("\\overline", {
defineFunction("\\rule", { defineFunction("\\rule", {
numArgs: 2, numArgs: 2,
numOptionalArgs: 1, numOptionalArgs: 1,
argTypes: ["size", "size", "size"] argTypes: ["size", "size", "size"],
}, function(context, args) { }, function(context, args) {
var shift = args[0]; var shift = args[0];
var width = args[1]; var width = args[1];
@ -183,21 +183,21 @@ defineFunction("\\rule", {
type: "rule", type: "rule",
shift: shift && shift.value, shift: shift && shift.value,
width: width.value, width: width.value,
height: height.value height: height.value,
}; };
}); });
// A KaTeX logo // A KaTeX logo
defineFunction("\\KaTeX", { defineFunction("\\KaTeX", {
numArgs: 0 numArgs: 0,
}, function(context) { }, function(context) {
return { return {
type: "katex" type: "katex",
}; };
}); });
defineFunction("\\phantom", { defineFunction("\\phantom", {
numArgs: 1 numArgs: 1,
}, function(context, args) { }, function(context, args) {
var body = args[0]; var body = args[0];
var inner; var inner;
@ -209,7 +209,7 @@ defineFunction("\\phantom", {
return { return {
type: "phantom", type: "phantom",
value: inner value: inner,
}; };
}); });
@ -230,7 +230,7 @@ var delimiterSizes = {
"\\big" : {type: "textord", size: 1}, "\\big" : {type: "textord", size: 1},
"\\Big" : {type: "textord", size: 2}, "\\Big" : {type: "textord", size: 2},
"\\bigg" : {type: "textord", size: 3}, "\\bigg" : {type: "textord", size: 3},
"\\Bigg" : {type: "textord", size: 4} "\\Bigg" : {type: "textord", size: 4},
}; };
var delimiters = [ var delimiters = [
@ -245,13 +245,13 @@ var delimiters = [
"\\uparrow", "\\Uparrow", "\\uparrow", "\\Uparrow",
"\\downarrow", "\\Downarrow", "\\downarrow", "\\Downarrow",
"\\updownarrow", "\\Updownarrow", "\\updownarrow", "\\Updownarrow",
"." ".",
]; ];
var fontAliases = { var fontAliases = {
"\\Bbb": "\\mathbb", "\\Bbb": "\\mathbb",
"\\bold": "\\mathbf", "\\bold": "\\mathbf",
"\\frak": "\\mathfrak" "\\frak": "\\mathfrak",
}; };
// Single-argument color functions // Single-argument color functions
@ -268,11 +268,11 @@ defineFunction([
"\\mintA", "\\mintB", "\\mintC", "\\mintA", "\\mintB", "\\mintC",
"\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE", "\\grayA", "\\grayB", "\\grayC", "\\grayD", "\\grayE",
"\\grayF", "\\grayG", "\\grayH", "\\grayI", "\\grayF", "\\grayG", "\\grayH", "\\grayI",
"\\kaBlue", "\\kaGreen" "\\kaBlue", "\\kaGreen",
], { ], {
numArgs: 1, numArgs: 1,
allowedInText: true, allowedInText: true,
greediness: 3 greediness: 3,
}, function(context, args) { }, function(context, args) {
var body = args[0]; var body = args[0];
var atoms; var atoms;
@ -285,7 +285,7 @@ defineFunction([
return { return {
type: "color", type: "color",
color: "katex-" + context.funcName.slice(1), color: "katex-" + context.funcName.slice(1),
value: atoms value: atoms,
}; };
}); });
@ -298,44 +298,44 @@ defineFunction([
"\\arcsin", "\\arccos", "\\arctan", "\\arg", "\\cos", "\\cosh", "\\arcsin", "\\arccos", "\\arctan", "\\arg", "\\cos", "\\cosh",
"\\cot", "\\coth", "\\csc", "\\deg", "\\dim", "\\exp", "\\hom", "\\cot", "\\coth", "\\csc", "\\deg", "\\dim", "\\exp", "\\hom",
"\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh", "\\ker", "\\lg", "\\ln", "\\log", "\\sec", "\\sin", "\\sinh",
"\\tan","\\tanh" "\\tan", "\\tanh",
], { ], {
numArgs: 0 numArgs: 0,
}, function(context) { }, function(context) {
return { return {
type: "op", type: "op",
limits: false, limits: false,
symbol: false, symbol: false,
body: context.funcName body: context.funcName,
}; };
}); });
// Limits, not symbols // Limits, not symbols
defineFunction([ defineFunction([
"\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max", "\\det", "\\gcd", "\\inf", "\\lim", "\\liminf", "\\limsup", "\\max",
"\\min", "\\Pr", "\\sup" "\\min", "\\Pr", "\\sup",
], { ], {
numArgs: 0 numArgs: 0,
}, function(context) { }, function(context) {
return { return {
type: "op", type: "op",
limits: true, limits: true,
symbol: false, symbol: false,
body: context.funcName body: context.funcName,
}; };
}); });
// No limits, symbols // No limits, symbols
defineFunction([ defineFunction([
"\\int", "\\iint", "\\iiint", "\\oint" "\\int", "\\iint", "\\iiint", "\\oint",
], { ], {
numArgs: 0 numArgs: 0,
}, function(context) { }, function(context) {
return { return {
type: "op", type: "op",
limits: false, limits: false,
symbol: true, symbol: true,
body: context.funcName body: context.funcName,
}; };
}); });
@ -343,25 +343,25 @@ defineFunction([
defineFunction([ defineFunction([
"\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap", "\\coprod", "\\bigvee", "\\bigwedge", "\\biguplus", "\\bigcap",
"\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes", "\\bigcup", "\\intop", "\\prod", "\\sum", "\\bigotimes",
"\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint" "\\bigoplus", "\\bigodot", "\\bigsqcup", "\\smallint",
], { ], {
numArgs: 0 numArgs: 0,
}, function(context) { }, function(context) {
return { return {
type: "op", type: "op",
limits: true, limits: true,
symbol: true, symbol: true,
body: context.funcName body: context.funcName,
}; };
}); });
// Fractions // Fractions
defineFunction([ defineFunction([
"\\dfrac", "\\frac", "\\tfrac", "\\dfrac", "\\frac", "\\tfrac",
"\\dbinom", "\\binom", "\\tbinom" "\\dbinom", "\\binom", "\\tbinom",
], { ], {
numArgs: 2, numArgs: 2,
greediness: 2 greediness: 2,
}, function(context, args) { }, function(context, args) {
var numer = args[0]; var numer = args[0];
var denom = args[1]; var denom = args[1];
@ -371,31 +371,31 @@ defineFunction([
var size = "auto"; var size = "auto";
switch (context.funcName) { switch (context.funcName) {
case "\\dfrac": case "\\dfrac":
case "\\frac": case "\\frac":
case "\\tfrac": case "\\tfrac":
hasBarLine = true; hasBarLine = true;
break; break;
case "\\dbinom": case "\\dbinom":
case "\\binom": case "\\binom":
case "\\tbinom": case "\\tbinom":
hasBarLine = false; hasBarLine = false;
leftDelim = "("; leftDelim = "(";
rightDelim = ")"; rightDelim = ")";
break; break;
default: default:
throw new Error("Unrecognized genfrac command"); throw new Error("Unrecognized genfrac command");
} }
switch (context.funcName) { switch (context.funcName) {
case "\\dfrac": case "\\dfrac":
case "\\dbinom": case "\\dbinom":
size = "display"; size = "display";
break; break;
case "\\tfrac": case "\\tfrac":
case "\\tbinom": case "\\tbinom":
size = "text"; size = "text";
break; break;
} }
return { return {
@ -405,19 +405,19 @@ defineFunction([
hasBarLine: hasBarLine, hasBarLine: hasBarLine,
leftDelim: leftDelim, leftDelim: leftDelim,
rightDelim: rightDelim, rightDelim: rightDelim,
size: size size: size,
}; };
}); });
// Left and right overlap functions // Left and right overlap functions
defineFunction(["\\llap", "\\rlap"], { defineFunction(["\\llap", "\\rlap"], {
numArgs: 1, numArgs: 1,
allowedInText: true allowedInText: true,
}, function(context, args) { }, function(context, args) {
var body = args[0]; var body = args[0];
return { return {
type: context.funcName.slice(1), type: context.funcName.slice(1),
body: body body: body,
}; };
}); });
@ -427,9 +427,9 @@ defineFunction([
"\\bigr", "\\Bigr", "\\biggr", "\\Biggr", "\\bigr", "\\Bigr", "\\biggr", "\\Biggr",
"\\bigm", "\\Bigm", "\\biggm", "\\Biggm", "\\bigm", "\\Bigm", "\\biggm", "\\Biggm",
"\\big", "\\Big", "\\bigg", "\\Bigg", "\\big", "\\Big", "\\bigg", "\\Bigg",
"\\left", "\\right" "\\left", "\\right",
], { ], {
numArgs: 1 numArgs: 1,
}, function(context, args) { }, function(context, args) {
var delim = args[0]; var delim = args[0];
if (!utils.contains(delimiters, delim.value)) { if (!utils.contains(delimiters, delim.value)) {
@ -444,14 +444,14 @@ defineFunction([
if (context.funcName === "\\left" || context.funcName === "\\right") { if (context.funcName === "\\left" || context.funcName === "\\right") {
return { return {
type: "leftright", type: "leftright",
value: delim.value value: delim.value,
}; };
} else { } else {
return { return {
type: "delimsizing", type: "delimsizing",
size: delimiterSizes[context.funcName].size, size: delimiterSizes[context.funcName].size,
delimType: delimiterSizes[context.funcName].type, delimType: delimiterSizes[context.funcName].type,
value: delim.value value: delim.value,
}; };
} }
}); });
@ -459,14 +459,14 @@ defineFunction([
// Sizing functions (handled in Parser.js explicitly, hence no handler) // Sizing functions (handled in Parser.js explicitly, hence no handler)
defineFunction([ defineFunction([
"\\tiny", "\\scriptsize", "\\footnotesize", "\\small", "\\tiny", "\\scriptsize", "\\footnotesize", "\\small",
"\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge" "\\normalsize", "\\large", "\\Large", "\\LARGE", "\\huge", "\\Huge",
], 0, null); ], 0, null);
// Style changing functions (handled in Parser.js explicitly, hence no // Style changing functions (handled in Parser.js explicitly, hence no
// handler) // handler)
defineFunction([ defineFunction([
"\\displaystyle", "\\textstyle", "\\scriptstyle", "\\displaystyle", "\\textstyle", "\\scriptstyle",
"\\scriptscriptstyle" "\\scriptscriptstyle",
], 0, null); ], 0, null);
defineFunction([ defineFunction([
@ -478,11 +478,11 @@ defineFunction([
"\\mathtt", "\\mathtt",
// aliases // aliases
"\\Bbb", "\\bold", "\\frak" "\\Bbb", "\\bold", "\\frak",
], { ], {
numArgs: 1, numArgs: 1,
greediness: 2 greediness: 2,
}, function (context, args) { }, function(context, args) {
var body = args[0]; var body = args[0];
var func = context.funcName; var func = context.funcName;
if (func in fontAliases) { if (func in fontAliases) {
@ -491,45 +491,45 @@ defineFunction([
return { return {
type: "font", type: "font",
font: func.slice(1), font: func.slice(1),
body: body body: body,
}; };
}); });
// Accents // Accents
defineFunction([ defineFunction([
"\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve", "\\acute", "\\grave", "\\ddot", "\\tilde", "\\bar", "\\breve",
"\\check", "\\hat", "\\vec", "\\dot" "\\check", "\\hat", "\\vec", "\\dot",
// We don't support expanding accents yet // We don't support expanding accents yet
// "\\widetilde", "\\widehat" // "\\widetilde", "\\widehat"
], { ], {
numArgs: 1 numArgs: 1,
}, function(context, args) { }, function(context, args) {
var base = args[0]; var base = args[0];
return { return {
type: "accent", type: "accent",
accent: context.funcName, accent: context.funcName,
base: base base: base,
}; };
}); });
// Infix generalized fractions // Infix generalized fractions
defineFunction(["\\over", "\\choose"], { defineFunction(["\\over", "\\choose"], {
numArgs: 0 numArgs: 0,
}, function (context) { }, function(context) {
var replaceWith; var replaceWith;
switch (context.funcName) { switch (context.funcName) {
case "\\over": case "\\over":
replaceWith = "\\frac"; replaceWith = "\\frac";
break; break;
case "\\choose": case "\\choose":
replaceWith = "\\binom"; replaceWith = "\\binom";
break; break;
default: default:
throw new Error("Unrecognized infix genfrac command"); throw new Error("Unrecognized infix genfrac command");
} }
return { return {
type: "infix", type: "infix",
replaceWith: replaceWith replaceWith: replaceWith,
}; };
}); });
@ -537,19 +537,19 @@ defineFunction(["\\over", "\\choose"], {
defineFunction(["\\\\", "\\cr"], { defineFunction(["\\\\", "\\cr"], {
numArgs: 0, numArgs: 0,
numOptionalArgs: 1, numOptionalArgs: 1,
argTypes: ["size"] argTypes: ["size"],
}, function(context, args) { }, function(context, args) {
var size = args[0]; var size = args[0];
return { return {
type: "cr", type: "cr",
size: size size: size,
}; };
}); });
// Environment delimiters // Environment delimiters
defineFunction(["\\begin", "\\end"], { defineFunction(["\\begin", "\\end"], {
numArgs: 1, numArgs: 1,
argTypes: ["text"] argTypes: ["text"],
}, function(context, args) { }, function(context, args) {
var nameGroup = args[0]; var nameGroup = args[0];
if (nameGroup.type !== "ordgroup") { if (nameGroup.type !== "ordgroup") {
@ -564,6 +564,6 @@ defineFunction(["\\begin", "\\end"], {
return { return {
type: "environment", type: "environment",
name: name, name: name,
namepos: context.positions[1] namepos: context.positions[1],
}; };
}); });

View File

@ -98,5 +98,5 @@ TextNode.prototype.toMarkup = function() {
module.exports = { module.exports = {
MathNode: MathNode, MathNode: MathNode,
TextNode: TextNode TextNode: TextNode,
}; };

View File

@ -8,6 +8,6 @@ function ParseNode(type, value, mode) {
} }
module.exports = { module.exports = {
ParseNode: ParseNode ParseNode: ParseNode,
}; };

View File

@ -18,20 +18,17 @@
module.exports = { module.exports = {
math: {}, math: {},
text: {} text: {},
}; };
function defineSymbol(mode, font, group, replace, name) { function defineSymbol(mode, font, group, replace, name) {
module.exports[mode][name] = { module.exports[mode][name] = {
font: font, font: font,
group: group, group: group,
replace: replace replace: replace,
}; };
} }
// (For some reason jshint believes open and close to be global symbols.)
/* globals -open, -close */
// Some abbreviations for commonly used strings. // Some abbreviations for commonly used strings.
// This helps minify the code, and also spotting typos using jshint. // This helps minify the code, and also spotting typos using jshint.
@ -597,25 +594,27 @@ defineSymbol(text, main, spacing, "\u00a0", " ");
defineSymbol(text, main, spacing, "\u00a0", "~"); defineSymbol(text, main, spacing, "\u00a0", "~");
// There are lots of symbols which are the same, so we add them in afterwards. // There are lots of symbols which are the same, so we add them in afterwards.
var i;
var ch;
// All of these are textords in math mode // All of these are textords in math mode
var mathTextSymbols = "0123456789/@.\""; var mathTextSymbols = "0123456789/@.\"";
for (var i = 0; i < mathTextSymbols.length; i++) { for (i = 0; i < mathTextSymbols.length; i++) {
var ch = mathTextSymbols.charAt(i); ch = mathTextSymbols.charAt(i);
defineSymbol(math, main, textord, ch, ch); defineSymbol(math, main, textord, ch, ch);
} }
// All of these are textords in text mode // All of these are textords in text mode
var textSymbols = "0123456789`!@*()-=+[]'\";:?/.,"; var textSymbols = "0123456789`!@*()-=+[]'\";:?/.,";
for (var i = 0; i < textSymbols.length; i++) { for (i = 0; i < textSymbols.length; i++) {
var ch = textSymbols.charAt(i); ch = textSymbols.charAt(i);
defineSymbol(text, main, textord, ch, ch); defineSymbol(text, main, textord, ch, ch);
} }
// All of these are textords in text mode, and mathords in math mode // All of these are textords in text mode, and mathords in math mode
var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; var letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (var i = 0; i < letters.length; i++) { for (i = 0; i < letters.length; i++) {
var ch = letters.charAt(i); ch = letters.charAt(i);
defineSymbol(math, main, mathord, ch, ch); defineSymbol(math, main, mathord, ch, ch);
defineSymbol(text, main, textord, ch, ch); defineSymbol(text, main, textord, ch, ch);
} }

View File

@ -15,7 +15,8 @@ var indexOf = function(list, elem) {
if (nativeIndexOf && list.indexOf === nativeIndexOf) { if (nativeIndexOf && list.indexOf === nativeIndexOf) {
return list.indexOf(elem); return list.indexOf(elem);
} }
var i = 0, l = list.length; var i = 0;
var l = list.length;
for (; i < l; i++) { for (; i < l; i++) {
if (list[i] === elem) { if (list[i] === elem) {
return i; return i;
@ -46,17 +47,17 @@ var hyphenate = function(str) {
}; };
var ESCAPE_LOOKUP = { var ESCAPE_LOOKUP = {
"&": "&amp;", "&": "&amp;",
">": "&gt;", ">": "&gt;",
"<": "&lt;", "<": "&lt;",
"\"": "&quot;", "\"": "&quot;",
"'": "&#x27;" "'": "&#x27;",
}; };
var ESCAPE_REGEX = /[&><"']/g; var ESCAPE_REGEX = /[&><"']/g;
function escaper(match) { function escaper(match) {
return ESCAPE_LOOKUP[match]; return ESCAPE_LOOKUP[match];
} }
/** /**
@ -66,7 +67,7 @@ function escaper(match) {
* @return {string} An escaped string. * @return {string} An escaped string.
*/ */
function escape(text) { function escape(text) {
return ("" + text).replace(ESCAPE_REGEX, escaper); return ("" + text).replace(ESCAPE_REGEX, escaper);
} }
/** /**
@ -101,5 +102,5 @@ module.exports = {
hyphenate: hyphenate, hyphenate: hyphenate,
indexOf: indexOf, indexOf: indexOf,
setTextContent: setTextContent, setTextContent: setTextContent,
clearNode: clearNode clearNode: clearNode,
}; };

View File

@ -19,13 +19,13 @@ beforeEach(function() {
parseTree(actual, defaultSettings); parseTree(actual, defaultSettings);
return { return {
pass: false, pass: false,
message: "'" + actual + "' parsed without error" message: "'" + actual + "' parsed without error",
}; };
} catch (e) { } catch (e) {
if (expected === undefined) { if (expected === undefined) {
return { return {
pass: true, pass: true,
message: "'" + actual + "' parsed with error" message: "'" + actual + "' parsed with error",
}; };
} }
var msg = e.message; var msg = e.message;
@ -34,27 +34,27 @@ beforeEach(function() {
return { return {
pass: true, pass: true,
message: "'" + actual + "'" + message: "'" + actual + "'" +
" parsed with error '" + expected + "'" " parsed with error '" + expected + "'",
}; };
} else if (msg.slice(0, 19) === prefix) { } else if (msg.slice(0, 19) === prefix) {
return { return {
pass: false, pass: false,
message: "'" + actual + "'" + message: "'" + actual + "'" +
" parsed with error '" + msg.slice(19) + " parsed with error '" + msg.slice(19) +
"' but expected '" + expected + "'" "' but expected '" + expected + "'",
}; };
} else { } else {
return { return {
pass: false, pass: false,
message: "'" + actual + "'" + message: "'" + actual + "'" +
" caused error '" + msg + " caused error '" + msg +
"' but expected '" + exp + "'" "' but expected '" + exp + "'",
}; };
} }
} }
} },
}; };
} },
}); });
}); });
@ -265,7 +265,7 @@ describe("environments.js:", function() {
}); });
it("rejects incorrectly scoped \\end", function() { it("rejects incorrectly scoped \\end", function() {
expect("{\\begin{matrix}1}\\end{matrix}").toFailWithParseError( expect("{\\begin{matrix}1}\\end{matrix}").toFailWithParseError(
"Expected & or \\\\\ or \\end at position 17:" + "Expected & or \\\\\ or \\end at position 17:" +
" begin{matrix}1}̲\\end{matrix}"); " begin{matrix}1}̲\\end{matrix}");
}); });
}); });

View File

@ -1,3 +1,4 @@
/* eslint max-len:0 */
/* global beforeEach: false */ /* global beforeEach: false */
/* global jasmine: false */ /* global jasmine: false */
/* global expect: false */ /* global expect: false */
@ -16,7 +17,7 @@ var Style = require("../src/Style");
var defaultSettings = new Settings({}); var defaultSettings = new Settings({});
var defaultOptions = new Options({ var defaultOptions = new Options({
style: Style.TEXT, style: Style.TEXT,
size: "size5" size: "size5",
}); });
var _getBuilt = function(expr, settings) { var _getBuilt = function(expr, settings) {
@ -65,7 +66,7 @@ beforeEach(function() {
var result = { var result = {
pass: true, pass: true,
message: "'" + actual + "' succeeded parsing" message: "'" + actual + "' succeeded parsing",
}; };
try { try {
@ -82,7 +83,7 @@ beforeEach(function() {
} }
return result; return result;
} },
}; };
}, },
@ -94,7 +95,7 @@ beforeEach(function() {
var result = { var result = {
pass: false, pass: false,
message: "Expected '" + actual + "' to fail " + message: "Expected '" + actual + "' to fail " +
"parsing, but it succeeded" "parsing, but it succeeded",
}; };
try { try {
@ -111,7 +112,7 @@ beforeEach(function() {
} }
return result; return result;
} },
}; };
}, },
@ -122,7 +123,7 @@ beforeEach(function() {
var result = { var result = {
pass: true, pass: true,
message: "'" + actual + "' succeeded in building" message: "'" + actual + "' succeeded in building",
}; };
expect(actual).toParse(usedSettings); expect(actual).toParse(usedSettings);
@ -141,9 +142,9 @@ beforeEach(function() {
} }
return result; return result;
} },
}; };
} },
}); });
}); });
@ -425,7 +426,7 @@ describe("A parser with limit controls", function() {
parsedInput = getParsed("\\int\\limits_2\\nolimits^2"); parsedInput = getParsed("\\int\\limits_2\\nolimits^2");
expect(parsedInput[0].value.base.value.limits).toBe(false); expect(parsedInput[0].value.base.value.limits).toBe(false);
}); });
}); });
describe("A group parser", function() { describe("A group parser", function() {
@ -562,7 +563,7 @@ describe("An over parser", function() {
var simpleOver = "1 \\over x"; var simpleOver = "1 \\over x";
var complexOver = "1+2i \\over 3+4i"; var complexOver = "1+2i \\over 3+4i";
it("should not fail", function () { it("should not fail", function() {
expect(simpleOver).toParse(); expect(simpleOver).toParse();
expect(complexOver).toParse(); expect(complexOver).toParse();
}); });
@ -583,21 +584,21 @@ describe("An over parser", function() {
expect(parse.value.denom).toBeDefined(); expect(parse.value.denom).toBeDefined();
}); });
it("should create a numerator from the atoms before \\over", function () { it("should create a numerator from the atoms before \\over", function() {
var parse = getParsed(complexOver)[0]; var parse = getParsed(complexOver)[0];
var numer = parse.value.numer; var numer = parse.value.numer;
expect(numer.value.length).toEqual(4); expect(numer.value.length).toEqual(4);
}); });
it("should create a demonimator from the atoms after \\over", function () { it("should create a demonimator from the atoms after \\over", function() {
var parse = getParsed(complexOver)[0]; var parse = getParsed(complexOver)[0];
var denom = parse.value.numer; var denom = parse.value.numer;
expect(denom.value.length).toEqual(4); expect(denom.value.length).toEqual(4);
}); });
it("should handle empty numerators", function () { it("should handle empty numerators", function() {
var emptyNumerator = "\\over x"; var emptyNumerator = "\\over x";
var parse = getParsed(emptyNumerator)[0]; var parse = getParsed(emptyNumerator)[0];
expect(parse.type).toEqual("genfrac"); expect(parse.type).toEqual("genfrac");
@ -605,7 +606,7 @@ describe("An over parser", function() {
expect(parse.value.denom).toBeDefined(); expect(parse.value.denom).toBeDefined();
}); });
it("should handle empty denominators", function () { it("should handle empty denominators", function() {
var emptyDenominator = "1 \\over"; var emptyDenominator = "1 \\over";
var parse = getParsed(emptyDenominator)[0]; var parse = getParsed(emptyDenominator)[0];
expect(parse.type).toEqual("genfrac"); expect(parse.type).toEqual("genfrac");
@ -613,7 +614,7 @@ describe("An over parser", function() {
expect(parse.value.denom).toBeDefined(); expect(parse.value.denom).toBeDefined();
}); });
it("should handle \\displaystyle correctly", function () { it("should handle \\displaystyle correctly", function() {
var displaystyleExpression = "\\displaystyle 1 \\over 2"; var displaystyleExpression = "\\displaystyle 1 \\over 2";
var parse = getParsed(displaystyleExpression)[0]; var parse = getParsed(displaystyleExpression)[0];
expect(parse.type).toEqual("genfrac"); expect(parse.type).toEqual("genfrac");
@ -621,7 +622,7 @@ describe("An over parser", function() {
expect(parse.value.denom).toBeDefined(); expect(parse.value.denom).toBeDefined();
}); });
it("should handle nested factions", function () { it("should handle nested factions", function() {
var nestedOverExpression = "{1 \\over 2} \\over 3"; var nestedOverExpression = "{1 \\over 2} \\over 3";
var parse = getParsed(nestedOverExpression)[0]; var parse = getParsed(nestedOverExpression)[0];
expect(parse.type).toEqual("genfrac"); expect(parse.type).toEqual("genfrac");
@ -632,7 +633,7 @@ describe("An over parser", function() {
expect(parse.value.denom.value[0].value).toEqual("3"); expect(parse.value.denom.value[0].value).toEqual("3");
}); });
it("should fail with multiple overs in the same group", function () { it("should fail with multiple overs in the same group", function() {
var badMultipleOvers = "1 \\over 2 + 3 \\over 4"; var badMultipleOvers = "1 \\over 2 + 3 \\over 4";
expect(badMultipleOvers).toNotParse(); expect(badMultipleOvers).toNotParse();
@ -757,7 +758,7 @@ describe("A color parser", function() {
expect(badCustomColorExpression).toNotParse(); expect(badCustomColorExpression).toNotParse();
}); });
it("should parse new colors from the branding guide", function(){ it("should parse new colors from the branding guide", function() {
expect(newColorExpression).toParse(); expect(newColorExpression).toParse();
}); });
@ -1025,7 +1026,7 @@ describe("A TeX-compliant parser", function() {
"\\rule{1em}", "\\rule{1em}",
"\\llap", "\\llap",
"\\bigl", "\\bigl",
"\\text" "\\text",
]; ];
for (var i = 0; i < missingGroups.length; i++) { for (var i = 0; i < missingGroups.length; i++) {
@ -1052,7 +1053,7 @@ describe("A TeX-compliant parser", function() {
// work // work
// "\\llap \\frac x y", // "\\llap \\frac x y",
"\\llap \\llap x", "\\llap \\llap x",
"\\sqrt \\llap x" "\\sqrt \\llap x",
]; ];
for (var i = 0; i < badArguments.length; i++) { for (var i = 0; i < badArguments.length; i++) {
@ -1070,7 +1071,7 @@ describe("A TeX-compliant parser", function() {
"\\frac x {\\llap y}", "\\frac x {\\llap y}",
"\\llap {\\frac x y}", "\\llap {\\frac x y}",
"\\llap {\\llap x}", "\\llap {\\llap x}",
"\\sqrt {\\llap x}" "\\sqrt {\\llap x}",
]; ];
for (var i = 0; i < goodArguments.length; i++) { for (var i = 0; i < goodArguments.length; i++) {
@ -1083,7 +1084,7 @@ describe("A TeX-compliant parser", function() {
"x^\\sqrt x", "x^\\sqrt x",
"x^\\llap x", "x^\\llap x",
"x_\\sqrt x", "x_\\sqrt x",
"x_\\llap x" "x_\\llap x",
]; ];
for (var i = 0; i < badSupSubscripts.length; i++) { for (var i = 0; i < badSupSubscripts.length; i++) {
@ -1096,7 +1097,7 @@ describe("A TeX-compliant parser", function() {
"x^{\\sqrt x}", "x^{\\sqrt x}",
"x^{\\llap x}", "x^{\\llap x}",
"x_{\\sqrt x}", "x_{\\sqrt x}",
"x_{\\llap x}" "x_{\\llap x}",
]; ];
for (var i = 0; i < goodSupSubscripts.length; i++) { for (var i = 0; i < goodSupSubscripts.length; i++) {
@ -1135,7 +1136,7 @@ describe("A TeX-compliant parser", function() {
"\\frac x \\left( y \\right)", "\\frac x \\left( y \\right)",
"\\llap \\left( x \\right)", "\\llap \\left( x \\right)",
"\\sqrt \\left( x \\right)", "\\sqrt \\left( x \\right)",
"x^\\left( x \\right)" "x^\\left( x \\right)",
]; ];
for (var i = 0; i < badLeftArguments.length; i++) { for (var i = 0; i < badLeftArguments.length; i++) {
@ -1149,7 +1150,7 @@ describe("A TeX-compliant parser", function() {
"\\frac x {\\left( y \\right)}", "\\frac x {\\left( y \\right)}",
"\\llap {\\left( x \\right)}", "\\llap {\\left( x \\right)}",
"\\sqrt {\\left( x \\right)}", "\\sqrt {\\left( x \\right)}",
"x^{\\left( x \\right)}" "x^{\\left( x \\right)}",
]; ];
for (var i = 0; i < goodLeftArguments.length; i++) { for (var i = 0; i < goodLeftArguments.length; i++) {
@ -1189,8 +1190,8 @@ describe("A style change parser", function() {
}); });
}); });
describe("A font parser", function () { describe("A font parser", function() {
it("should parse \\mathrm, \\mathbb, and \\mathit", function () { it("should parse \\mathrm, \\mathbb, and \\mathit", function() {
expect("\\mathrm x").toParse(); expect("\\mathrm x").toParse();
expect("\\mathbb x").toParse(); expect("\\mathbb x").toParse();
expect("\\mathit x").toParse(); expect("\\mathit x").toParse();
@ -1199,12 +1200,12 @@ describe("A font parser", function () {
expect("\\mathit {x + 1}").toParse(); expect("\\mathit {x + 1}").toParse();
}); });
it("should parse \\mathcal and \\mathfrak", function () { it("should parse \\mathcal and \\mathfrak", function() {
expect("\\mathcal{ABC123}").toParse(); expect("\\mathcal{ABC123}").toParse();
expect("\\mathfrak{abcABC123}").toParse(); expect("\\mathfrak{abcABC123}").toParse();
}); });
it("should produce the correct fonts", function () { it("should produce the correct fonts", function() {
var mathbbParse = getParsed("\\mathbb x")[0]; var mathbbParse = getParsed("\\mathbb x")[0];
expect(mathbbParse.value.font).toEqual("mathbb"); expect(mathbbParse.value.font).toEqual("mathbb");
expect(mathbbParse.value.type).toEqual("font"); expect(mathbbParse.value.type).toEqual("font");
@ -1226,7 +1227,7 @@ describe("A font parser", function () {
expect(mathfrakParse.value.type).toEqual("font"); expect(mathfrakParse.value.type).toEqual("font");
}); });
it("should parse nested font commands", function () { it("should parse nested font commands", function() {
var nestedParse = getParsed("\\mathbb{R \\neq \\mathrm{R}}")[0]; var nestedParse = getParsed("\\mathbb{R \\neq \\mathrm{R}}")[0];
expect(nestedParse.value.font).toEqual("mathbb"); expect(nestedParse.value.font).toEqual("mathbb");
expect(nestedParse.value.type).toEqual("font"); expect(nestedParse.value.type).toEqual("font");
@ -1240,7 +1241,7 @@ describe("A font parser", function () {
expect(bbBody[2].value.type).toEqual("font"); expect(bbBody[2].value.type).toEqual("font");
}); });
it("should work with \\color", function () { it("should work with \\color", function() {
var colorMathbbParse = getParsed("\\color{blue}{\\mathbb R}")[0]; var colorMathbbParse = getParsed("\\color{blue}{\\mathbb R}")[0];
expect(colorMathbbParse.value.type).toEqual("color"); expect(colorMathbbParse.value.type).toEqual("color");
expect(colorMathbbParse.value.color).toEqual("blue"); expect(colorMathbbParse.value.color).toEqual("blue");
@ -1250,11 +1251,11 @@ describe("A font parser", function () {
expect(body[0].value.font).toEqual("mathbb"); expect(body[0].value.font).toEqual("mathbb");
}); });
it("should not parse a series of font commands", function () { it("should not parse a series of font commands", function() {
expect("\\mathbb \\mathrm R").toNotParse(); expect("\\mathbb \\mathrm R").toNotParse();
}); });
it("should nest fonts correctly", function () { it("should nest fonts correctly", function() {
var bf = getParsed("\\mathbf{a\\mathrm{b}c}")[0]; var bf = getParsed("\\mathbf{a\\mathrm{b}c}")[0];
expect(bf.value.type).toEqual("font"); expect(bf.value.type).toEqual("font");
expect(bf.value.font).toEqual("mathbf"); expect(bf.value.font).toEqual("mathbf");
@ -1270,28 +1271,28 @@ describe("A font parser", function () {
}); });
}); });
describe("An HTML font tree-builder", function () { describe("An HTML font tree-builder", function() {
it("should render \\mathbb{R} with the correct font", function () { it("should render \\mathbb{R} with the correct font", function() {
var markup = katex.renderToString("\\mathbb{R}"); var markup = katex.renderToString("\\mathbb{R}");
expect(markup).toContain("<span class=\"mord mathbb\">R</span>"); expect(markup).toContain("<span class=\"mord mathbb\">R</span>");
}); });
it("should render \\mathrm{R} with the correct font", function () { it("should render \\mathrm{R} with the correct font", function() {
var markup = katex.renderToString("\\mathrm{R}"); var markup = katex.renderToString("\\mathrm{R}");
expect(markup).toContain("<span class=\"mord mathrm\">R</span>"); expect(markup).toContain("<span class=\"mord mathrm\">R</span>");
}); });
it("should render \\mathcal{R} with the correct font", function () { it("should render \\mathcal{R} with the correct font", function() {
var markup = katex.renderToString("\\mathcal{R}"); var markup = katex.renderToString("\\mathcal{R}");
expect(markup).toContain("<span class=\"mord mathcal\">R</span>"); expect(markup).toContain("<span class=\"mord mathcal\">R</span>");
}); });
it("should render \\mathfrak{R} with the correct font", function () { it("should render \\mathfrak{R} with the correct font", function() {
var markup = katex.renderToString("\\mathfrak{R}"); var markup = katex.renderToString("\\mathfrak{R}");
expect(markup).toContain("<span class=\"mord mathfrak\">R</span>"); expect(markup).toContain("<span class=\"mord mathfrak\">R</span>");
}); });
it("should render a combination of font and color changes", function () { it("should render a combination of font and color changes", function() {
var markup = katex.renderToString("\\color{blue}{\\mathbb R}"); var markup = katex.renderToString("\\color{blue}{\\mathbb R}");
var span = "<span class=\"mord mathbb\" style=\"color:blue;\">R</span>"; var span = "<span class=\"mord mathbb\" style=\"color:blue;\">R</span>";
expect(markup).toContain(span); expect(markup).toContain(span);
@ -1303,10 +1304,10 @@ describe("An HTML font tree-builder", function () {
}); });
describe("A MathML font tree-builder", function () { describe("A MathML font tree-builder", function() {
var contents = "Ax2k\\omega\\Omega\\imath+"; var contents = "Ax2k\\omega\\Omega\\imath+";
it("should render " + contents + " with the correct mathvariants", function () { it("should render " + contents + " with the correct mathvariants", function() {
var tree = getParsed(contents); var tree = getParsed(contents);
var markup = buildMathML(tree, contents, defaultOptions).toMarkup(); var markup = buildMathML(tree, contents, defaultOptions).toMarkup();
expect(markup).toContain("<mi>A</mi>"); expect(markup).toContain("<mi>A</mi>");
@ -1318,7 +1319,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render \\mathbb{" + contents + "} with the correct mathvariants", function () { it("should render \\mathbb{" + contents + "} with the correct mathvariants", function() {
var tex = "\\mathbb{" + contents + "}"; var tex = "\\mathbb{" + contents + "}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1331,7 +1332,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render \\mathrm{" + contents + "} with the correct mathvariants", function () { it("should render \\mathrm{" + contents + "} with the correct mathvariants", function() {
var tex = "\\mathrm{" + contents + "}"; var tex = "\\mathrm{" + contents + "}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1344,7 +1345,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render \\mathit{" + contents + "} with the correct mathvariants", function () { it("should render \\mathit{" + contents + "} with the correct mathvariants", function() {
var tex = "\\mathit{" + contents + "}"; var tex = "\\mathit{" + contents + "}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1357,7 +1358,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render \\mathbf{" + contents + "} with the correct mathvariants", function () { it("should render \\mathbf{" + contents + "} with the correct mathvariants", function() {
var tex = "\\mathbf{" + contents + "}"; var tex = "\\mathbf{" + contents + "}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1370,7 +1371,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render \\mathcal{" + contents + "} with the correct mathvariants", function () { it("should render \\mathcal{" + contents + "} with the correct mathvariants", function() {
var tex = "\\mathcal{" + contents + "}"; var tex = "\\mathcal{" + contents + "}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1385,7 +1386,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render \\mathfrak{" + contents + "} with the correct mathvariants", function () { it("should render \\mathfrak{" + contents + "} with the correct mathvariants", function() {
var tex = "\\mathfrak{" + contents + "}"; var tex = "\\mathfrak{" + contents + "}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1400,7 +1401,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render \\mathscr{" + contents + "} with the correct mathvariants", function () { it("should render \\mathscr{" + contents + "} with the correct mathvariants", function() {
var tex = "\\mathscr{" + contents + "}"; var tex = "\\mathscr{" + contents + "}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1415,7 +1416,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render \\mathsf{" + contents + "} with the correct mathvariants", function () { it("should render \\mathsf{" + contents + "} with the correct mathvariants", function() {
var tex = "\\mathsf{" + contents + "}"; var tex = "\\mathsf{" + contents + "}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1428,7 +1429,7 @@ describe("A MathML font tree-builder", function () {
expect(markup).toContain("<mo>+</mo>"); expect(markup).toContain("<mo>+</mo>");
}); });
it("should render a combination of font and color changes", function () { it("should render a combination of font and color changes", function() {
var tex = "\\color{blue}{\\mathbb R}"; var tex = "\\color{blue}{\\mathbb R}";
var tree = getParsed(tex); var tree = getParsed(tex);
var markup = buildMathML(tree, tex, defaultOptions).toMarkup(); var markup = buildMathML(tree, tex, defaultOptions).toMarkup();
@ -1504,17 +1505,17 @@ describe("A parse tree generator", function() {
"base": { "base": {
"type": "mathord", "type": "mathord",
"value": "\\sigma", "value": "\\sigma",
"mode": "math" "mode": "math",
}, },
"sup": { "sup": {
"type": "textord", "type": "textord",
"value": "2", "value": "2",
"mode": "math" "mode": "math",
}, },
"sub": undefined "sub": undefined,
}, },
"mode": "math" "mode": "math",
} },
])); ]));
}); });
}); });
@ -1600,8 +1601,8 @@ describe("A phantom builder", function() {
}); });
}); });
describe("A parser error", function () { describe("A parser error", function() {
it("should report the position of an error", function () { it("should report the position of an error", function() {
try { try {
parseTree("\\sqrt}", defaultSettings); parseTree("\\sqrt}", defaultSettings);
} catch (e) { } catch (e) {
@ -1643,7 +1644,7 @@ describe("An array environment", function() {
var parse = getParsed("\\begin{array}r1\\\\20\\end{array}"); var parse = getParsed("\\begin{array}r1\\\\20\\end{array}");
expect(parse[0].type).toBe("array"); expect(parse[0].type).toBe("array");
expect(parse[0].value.cols).toEqual([ expect(parse[0].value.cols).toEqual([
{ type: "align", align: "r" } { type: "align", align: "r" },
]); ]);
}); });
@ -1656,7 +1657,7 @@ describe("An array environment", function() {
{ type: "separator", separator: "|" }, { type: "separator", separator: "|" },
{ type: "separator", separator: "|" }, { type: "separator", separator: "|" },
{ type: "align", align: "c" }, { type: "align", align: "c" },
{ type: "separator", separator: "|" } { type: "separator", separator: "|" },
]); ]);
}); });
@ -1731,7 +1732,7 @@ describe("A parser that does not throw on unsupported commands", function() {
var errorColor = "#933"; var errorColor = "#933";
var noThrowSettings = new Settings({ var noThrowSettings = new Settings({
throwOnError: false, throwOnError: false,
errorColor: errorColor errorColor: errorColor,
}); });
it("should still parse on unrecognized control sequences", function() { it("should still parse on unrecognized control sequences", function() {

View File

@ -1,3 +1,4 @@
/* eslint no-console:0 */
"use strict"; "use strict";
var fs = require("fs"); var fs = require("fs");
@ -6,7 +7,7 @@ var childProcess = require("child_process");
var opts = require("nomnom") var opts = require("nomnom")
.option("spacing", { .option("spacing", {
flag: true, flag: true,
help: "Print mismatches involving spacing commands" help: "Print mismatches involving spacing commands",
}) })
.parse(); .parse();
@ -15,7 +16,7 @@ var keys = Object.keys(symbols.math);
keys.sort(); keys.sort();
var types = [ var types = [
"mathord", "op", "bin", "rel", "open", "close", "punct", "inner", "mathord", "op", "bin", "rel", "open", "close", "punct", "inner",
"spacing", "accent", "textord" "spacing", "accent", "textord",
]; ];
process.nextTick(writeTexFile); process.nextTick(writeTexFile);
@ -94,7 +95,8 @@ function evaluate(err, log) {
throw err; throw err;
} }
var match, nextIndex = 0; var match;
var nextIndex = 0;
while ((match = reMM.exec(log)) !== null) { while ((match = reMM.exec(log)) !== null) {
var list = match[1]; var list = match[1];
match = reParts.exec(list); match = reParts.exec(list);
@ -143,7 +145,8 @@ function evaluate(err, log) {
} }
function extractDigits(str) { function extractDigits(str) {
var match, res = ""; var match;
var res = "";
while ((match = reDigit.exec(str)) !== null) { while ((match = reDigit.exec(str)) !== null) {
res += match[1]; res += match[1];
} }