├── .gitignore ├── .gitmodules ├── .travis.yml ├── LICENSE ├── README.md ├── lib ├── main.js └── patch │ └── jsdom.js ├── package-lock.json ├── package.json └── test ├── assets └── test.js ├── base-config-extensions.js ├── base-config-fonturl.js ├── base-errors-startup.js ├── base-mathjax.js ├── base-typeset-promise.js ├── base-warnings.js ├── config-third-party-extensions.js ├── css.js ├── issue104.js ├── issue175.js ├── issue207.js ├── issue215.js ├── issue219.js ├── issue220.js ├── issue223.js ├── issue241.js ├── issue260.js ├── issue276.js ├── issue277.js ├── issue288.js ├── issue289.js ├── mathjax-config-combined.js ├── output-html-linebreaks-manual.js ├── pass_data.js ├── svg-full-width-chars.js ├── svg-metadata.js ├── useFontCache.js ├── userconfig-autoload.js └── userconfig-jax.js /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | mathjax/* 4 | !mathjax/README.md 5 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mathjax/MathJax-node/040b3f1f467edc2a9ada5dd066b0bf7f9db07412/.gitmodules -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - '10' 4 | - '11' 5 | - '12' 6 | - '13' 7 | - stable 8 | sudo: false 9 | script: 10 | - npm install 11 | - npm test 12 | deploy: 13 | provider: npm 14 | email: manager@mathjax.org 15 | api_key: 16 | secure: VyQLfUM+kLK4qNVdu6eqGO5Z5/raIuPL/fvnDvbf0KR4asHb3ieb9Q6YrHCMSKWGrVDx7sMn5xnk2TmcxL+9z3C1+wZIB+pBFTkcIZLMj+l/bwukJ0onTdfnOZPFxnBukgkgiXLpEzEIwJ6R+ULq0UsFhYni1eS9bp7hRn1+7Q4= 17 | on: 18 | tags: true 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # mathjax-node [![Build Status](https://travis-ci.org/mathjax/MathJax-node.svg?branch=develop)](https://travis-ci.org/mathjax/MathJax-node) 2 | 3 | This repository contains a library that provides an API to call [MathJax](https://github.com/mathjax/mathjax) from Node.js programs. The API converts individual math expressions (in any of MathJax's input formats) into HTML (with CSS), SVG, or MathML code. 4 | 5 | Use 6 | 7 | ``` 8 | npm install mathjax-node 9 | ``` 10 | 11 | to install mathjax-node and its dependencies. 12 | 13 | **Note:** 14 | The current version of mathjax-node requires Node.js v6 or later, and uses jsdom version 11. 15 | 16 | ## Getting started 17 | 18 | mathjax-node provides a library, `./lib/main.js`. Below is a very minimal example for using it - the tests and the examples mentioned above provide more advanced examples. 19 | 20 | ```javascript 21 | // a simple TeX-input example 22 | var mjAPI = require("mathjax-node"); 23 | mjAPI.config({ 24 | MathJax: { 25 | // traditional MathJax configuration 26 | } 27 | }); 28 | mjAPI.start(); 29 | 30 | var yourMath = 'E = mc^2'; 31 | 32 | mjAPI.typeset({ 33 | math: yourMath, 34 | format: "TeX", // or "inline-TeX", "MathML" 35 | mml:true, // or svg:true, or html:true 36 | }, function (data) { 37 | if (!data.errors) {console.log(data.mml)} 38 | // will produce: 39 | // 40 | // E 41 | // = 42 | // m 43 | // 44 | // c 45 | // 2 46 | // 47 | // 48 | }); 49 | ``` 50 | 51 | ## Documentation 52 | 53 | mathjax-node exports three methods, `config`, `start`, `typeset`. 54 | 55 | ### `config(options)` 56 | 57 | The `config` method is used to set _global_ configuration options. Its default options are 58 | 59 | ```javascript 60 | { 61 | displayMessages: false, // determines whether Message.Set() calls are logged 62 | displayErrors: true, // determines whether error messages are shown on the console 63 | undefinedCharError: false, // determines whether "unknown characters" (i.e., no glyph in the configured fonts) are saved in the error array 64 | extensions: '', // a convenience option to add MathJax extensions 65 | fontURL: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/fonts/HTML-CSS', // for webfont urls in the CSS for HTML output 66 | paths: {}, // configures custom path variables (e.g., for third party extensions, cf. test/config-third-party-extensions.js) 67 | MathJax: { } // standard MathJax configuration options, see https://docs.mathjax.org for more detail. 68 | } 69 | ``` 70 | 71 | **Note.** Changes to these options require a restart of the API using the `start()` method (see below). 72 | 73 | ### `start()` 74 | 75 | The `start` method start (and restarts) mathjax-node. This allows reconfiguration. 76 | 77 | **Note.** This is done automatically when `typeset` is first called (see below). 78 | 79 | ### `typeset(options[, callback])` 80 | 81 | The `typeset` method is the main method of mathjax-node. It expects a configuration object `options` and optionally a callback. 82 | 83 | If no `callback` is passed, it will return a Promise. 84 | 85 | Once called, `typeset` can be called repeatedly and will optionally store information across calls (see `state` below). 86 | 87 | The following are the default input options. 88 | 89 | ```javascript 90 | { 91 | ex: 6, // ex-size in pixels 92 | width: 100, // width of container (in ex) for linebreaking and tags 93 | useFontCache: true, // use and in svg output? 94 | useGlobalCache: false, // use common for all equations? 95 | linebreaks: false, // automatic linebreaking 96 | equationNumbers: "none", // automatic equation numbering ("none", "AMS" or "all") 97 | cjkCharWidth: 13, // width of CJK character 98 | 99 | math: "", // the math string to typeset 100 | format: "TeX", // the input format (TeX, inline-TeX, AsciiMath, or MathML) 101 | xmlns: "mml", // the namespace to use for MathML 102 | 103 | html: false, // generate HTML output 104 | htmlNode: false, // generate HTML output as jsdom node 105 | css: false, // generate CSS for HTML output 106 | mml: false, // generate MathML output 107 | mmlNode: false, // generate MathML output as jsdom node 108 | svg: false, // generate SVG output 109 | svgNode: false, // generate SVG output as jsdom node 110 | 111 | speakText: true, // add textual alternative (for TeX/asciimath the input string, for MathML a dummy string) 112 | 113 | state: {}, // an object to store information from multiple calls (e.g., if useGlobalCache, counter for equation numbering if equationNumbers ar ) 114 | timeout: 10 * 1000, // 10 second timeout before restarting MathJax 115 | } 116 | ``` 117 | 118 | ### `Promise.resolve(result,options)` / `Promise.reject(errors)` / `callback(result, options)` 119 | 120 | mathjax-node returns two objects to `Promise.resolve` or `callback`: a `result` object and the original input `options`. 121 | 122 | The `result` object will contain (at most) the following structure: 123 | 124 | ```javascript 125 | { 126 | errors: // an array of MathJax error messages if any errors occurred 127 | mml: // a string of MathML markup if requested 128 | mmlNode: // a jsdom node of MathML markup if requested 129 | html: // a string of HTML markup if requested 130 | htmlNode: // a jsdom node of HTML markup if requested 131 | css: // a string of CSS if HTML was requested 132 | svg: // a string of SVG markup if requested 133 | svgNode: // a jsdom node of SVG markup if requested 134 | style: // a string of CSS inline style if SVG requested 135 | height: // a string containing the height of the SVG output if SVG was requested 136 | width: // a string containing the width of the SVG output if SVG was requested 137 | speakText: // a string of speech text if requested 138 | 139 | state: { // the state object (if useGlobalCache or equationNumbers is set) 140 | glyphs: // a collection of glyph data 141 | defs : // a string containing SVG def elements 142 | AMS: { 143 | startNumber: // the current starting equation number 144 | labels: // the set of labels 145 | IDs: // IDs used in previous equations 146 | } 147 | } 148 | } 149 | ``` 150 | 151 | If the `errors` array is non-empty, the Promise will reject, and be passed the `errors` array. 152 | 153 | The `options` contains the configuration object passed to `typeset`; this can be useful for passing other data along or for identifying which `typeset()` call is associated with this (`callback`) call (in case you use the same `callback` function for more than one `typeset()`). 154 | 155 | ## Change History 156 | 157 | ### Breaking Changes in v2.0: 158 | 159 | mathjax-node v2.0 makes breaking changes as follows: 160 | 161 | - [CHANGED] mathjax-node now requires version 6 of Node.js (the minimum used to be Node.js version 4). 162 | - [CHANGED] mathjax-node now uses version 10 of jsdom. Since the jsdom API changed from 9 to 10, that means if you used jsdom in your code that calls mathjax-node, you may need to update how you call jsdom. 163 | 164 | 165 | ### Breaking Changes in v1.0: 166 | 167 | mathjax-node v1.0 makes breaking changes to the following features from the pre-releases. 168 | 169 | - [CHANGED] `lib/mj-single.js` has been renamed to `lib/main.js` (and set as `main` in `package.json`, i.e., `require('mathjax-node')` will load it. 170 | - [REMOVED] `lib/mj-page.js` (API for processing HTML-fragments) and related CLI tools 171 | - [REMOVED] speech-rule-engine integration 172 | - [REMOVED] PNG generation 173 | - [REMOVED] CLI tools in `bin/` 174 | 175 | These features can easily be recreated in separate modules for greater flexibility. For examples, see 176 | 177 | - [mathjax-node-cli](https://github.com/mathjax/mathjax-node-cli/) 178 | - [mathjax-node-page](https://github.com/pkra/mathjax-node-page/) 179 | - [mathjax-node-sre](https://github.com/pkra/mathjax-node-sre) 180 | - [mathjax-node-svg2png](https://github.com/pkra/mathjax-node-svg2png) 181 | 182 | --- 183 | 184 | Be sure to also check out other [projects on NPM that depend on mathjax-node](https://www.npmjs.com/browse/depended/mathjax-node). 185 | 186 | -------------------------------------------------------------------------------- /lib/main.js: -------------------------------------------------------------------------------- 1 | /********************************************************************* 2 | * 3 | * main.js 4 | * 5 | * Implements an API to MathJax in Node.js so that MathJax can be 6 | * used server-side to generate HTML+CSS, SVG, or MathML. 7 | * 8 | * This API converts single math expressions while giving control 9 | * over the input format, the SVG font caching, and a number of other 10 | * features. 11 | * 12 | * ---------------------------------------------------------------------- 13 | * 14 | * Copyright (c) 2014--2016 The MathJax Consortium 15 | * 16 | * Licensed under the Apache License, Version 2.0 (the "License"); 17 | * you may not use this file except in compliance with the License. 18 | * You may obtain a copy of the License at 19 | * 20 | * http://www.apache.org/licenses/LICENSE-2.0 21 | * 22 | * Unless required by applicable law or agreed to in writing, software 23 | * distributed under the License is distributed on an "AS IS" BASIS, 24 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 25 | * See the License for the specific language governing permissions and 26 | * limitations under the License. 27 | */ 28 | 29 | var http = require('http'); 30 | var fs = require('fs'); 31 | var path = require('path'); 32 | var url = require('url'); 33 | var jsdom = require('jsdom'); 34 | var JSDOM = jsdom.JSDOM; 35 | var isFullwidthCodePoint = require('is-fullwidth-code-point'); 36 | 37 | require('./patch/jsdom.js').patch(JSDOM); // Fix some bugs in jsdom 38 | 39 | var displayMessages = false; // don't log Message.Set() calls 40 | var displayErrors = true; // show error messages on the console 41 | var undefinedChar = false; // unknown characters are not saved in the error array 42 | var extensions = ''; // no additional extensions used 43 | var paths = {}; // additional paths (for third party extensions) 44 | var fontURL = ''; // location of web fonts for CHTML 45 | 46 | var defaults = { 47 | ex: 6, // ex-size in pixels 48 | width: 100, // width of container (in ex) for linebreaking and tags 49 | useFontCache: true, // use and in svg output? 50 | useGlobalCache: false, // use common for all equations? 51 | linebreaks: false, // do linebreaking? 52 | equationNumbers: "none", // or "AMS" or "all" 53 | cjkCharWidth: 13, // width of CJK character 54 | 55 | math: "", // the math to typeset 56 | format: "TeX", // the input format (TeX, inline-TeX, AsciiMath, or MathML) 57 | xmlns: "mml", // the namespace to use for MathML 58 | 59 | html: false, // return HTML output? 60 | htmlNode: false, // DOM element for HTML output? 61 | css: false, // return CSS for HTML output? 62 | mml: false, // return mml output? 63 | mmlNode: false, // DOM element for MML output? 64 | svg: false, // return svg output? 65 | svgNode: false, // DOM element for SVG output? 66 | speakText: true, // add spoken annotations 67 | timeout: 10 * 1000, // 10 second timeout before restarting MathJax 68 | }; 69 | 70 | // 71 | // The MathJax server states 72 | // 73 | var STATE = { 74 | STOPPED: 1, // no DOM or MathJax available 75 | STARTED: 2, // DOM loaded, MathJax starting up 76 | READY: 3, // MathJax initialized and ready to process math 77 | BUSY: 4, // MathJax currently processing math 78 | RESTART: 5, // start() called while MathJax is starting up 79 | }; 80 | 81 | // 82 | // The MathJaxPath is normaized against file:/// so that Windows paths are correct 83 | // 84 | var MathJaxPath = url.resolve("file:///","file:"+require.resolve('mathjax')); 85 | var MathJaxConfig; // configuration for when starting MathJax 86 | var MathJax; // filled in once MathJax is loaded 87 | var serverState = STATE.STOPPED; // nothing loaded yet 88 | var timer; // used to reset MathJax if it runs too long 89 | 90 | var document, window, content, html; // the DOM elements 91 | 92 | var queue = []; // queue of typesetting requests of the form [data,callback] 93 | var data, callback, originalData; // the current queue item 94 | var errors = []; // errors collected durring the typesetting 95 | var sErrors = []; // errors collected durring MathJax startup 96 | var ID = 0; // id for this SVG element 97 | 98 | // 99 | // The delimiters used for each of the input formats 100 | // 101 | var TYPES = { 102 | TeX: "tex; mode=display", 103 | "inline-TeX": "tex", 104 | AsciiMath: "asciimath", 105 | MathML: "mml" 106 | }; 107 | 108 | var CHTMLSTYLES; // filled in when CommonHTML is loaded 109 | 110 | /********************************************************************/ 111 | 112 | // 113 | // Create the DOM window and set up the console wtihin it 114 | // Add an error handler to trap unexpected errors (requires 115 | // modifying jsdom) 116 | // Add a
where we can put the math to be typeset 117 | // and typeset math in the three formats we use (to force 118 | // the jax to be loaded completely) 119 | // 120 | function GetWindow() { 121 | var virtualConsole = new jsdom.VirtualConsole(); 122 | virtualConsole.sendTo(console); 123 | window = new JSDOM('',{ 124 | virtualConsole: virtualConsole, 125 | userAgent: "Node.js", 126 | runScripts: "dangerously", 127 | resources: "usable" 128 | }).window; 129 | document = window.document; 130 | html = document.firstChild; 131 | window.addEventListener("error",function (event) {AddError("Error: "+event.error.stack)}); 132 | content = document.body.appendChild(document.createElement("div")); 133 | content.id = "MathJax_Content"; 134 | content.innerHTML = '' + 135 | '' + 136 | ''; 137 | } 138 | 139 | // 140 | // Set up a Mathjax configuration within the window 141 | // 142 | function ConfigureMathJax() { 143 | window.MathJax = { 144 | // 145 | // Load all input jax and preprocessors 146 | // Load AMS extensions and the autoload extension for TeX 147 | // Create stand-alone SVG elements with font caches by default 148 | // (users can override that) 149 | // 150 | jax: ["input/TeX", "input/MathML", "input/AsciiMath", "output/SVG", "output/CommonHTML"], 151 | extensions: ["toMathML.js"], 152 | TeX: {extensions: window.Array("AMSmath.js","AMSsymbols.js","autoload-all.js")}, 153 | SVG: {useFontCache: true, useGlobalCache: false, EqnChunk: 1000000, EqnDelay: 0}, 154 | CommonHTML: {EqnChunk: 1000000, EqnDelay: 0, undefinedFamily:"monospace"}, 155 | 156 | // 157 | // This gets run before MathJax queues any actions 158 | // 159 | AuthorInit: function () { 160 | MathJax = window.MathJax; 161 | 162 | // Add custom paths to configuration 163 | for (let key in paths) { 164 | MathJax.Ajax.config.path[key] = paths[key]; 165 | } 166 | 167 | delete MathJax.Hub.config.styles; // don't need any styles 168 | MathJax.Hub.Startup.MenuZoom = function () {}; // don't load menu or zoom code 169 | MathJax.Extension.MathEvents = { 170 | Event:{}, Touch:{}, Hover:{} // fake structure to avid errors 171 | }; 172 | MathJax.Ajax.loaded[MathJax.Ajax.fileURL("[MathJax]/extensions/MathEvents.js")] = true; 173 | 174 | // 175 | // When creating stylesheets, no need to wait for them 176 | // to become active, so just do the callback 177 | // 178 | MathJax.Ajax.timer.create = function (callback,node) { 179 | callback = MathJax.Callback(callback); 180 | callback(this.STATUS.OK); 181 | return callback; 182 | }; 183 | 184 | // 185 | // Use the console for messages, if we are requesting them 186 | // 187 | MathJax.Message.Set = function (text,n,delay) { 188 | if (displayMessages && n !== 0) { 189 | if (text instanceof window.Array) 190 | {text = MathJax.Localization._.apply(MathJax.Localization,text)} 191 | console.error(text); 192 | } 193 | }; 194 | MathJax.Message.Clear = function () {}; 195 | MathJax.Message.Remove = function () {}; 196 | MathJax.Message.Init = function () {}; 197 | 198 | // 199 | // Trap Math Processing Errors 200 | // 201 | MathJax.Hub.Register.MessageHook("Math Processing Error",function (message) { 202 | AddError("Math Processing Error: "+message[2].message); 203 | }); 204 | MathJax.Hub.Register.MessageHook("SVG Jax - unknown char",function (message) { 205 | AddError("SVG - Unknown character: U+"+message[1].toString(16).toUpperCase()+ 206 | " in "+(message[2].fonts||["unknown"]).join(","),!undefinedChar); 207 | }); 208 | MathJax.Hub.Register.MessageHook("CommonHTML Jax - unknown char",function (message) { 209 | AddError("CHTML - Unknown character: U+"+message[1].toString(16).toUpperCase()+ 210 | " in "+(message[2].fonts||["unknown"]).join(","),!undefinedChar); 211 | }); 212 | MathJax.Hub.Register.MessageHook("MathML Jax - unknown node type",function (message) { 213 | AddError("MathML - Unknown node type: "+message[1]); 214 | }); 215 | MathJax.Hub.Register.MessageHook("MathML Jax - parse error",function (message) { 216 | AddError("MathML - "+message[1]); 217 | }); 218 | MathJax.Hub.Register.MessageHook("AsciiMath Jax - parse error",function (message) { 219 | AddError("AsciiMath parse error: "+message[1]); 220 | }); 221 | MathJax.Hub.Register.MessageHook("TeX Jax - parse error",function (message) { 222 | AddError("TeX parse error: "+message[1]); 223 | }); 224 | MathJax.Hub.Register.MessageHook("file load error",function (message) { 225 | AddError("File load error: "+message[1]); 226 | }); 227 | 228 | // 229 | // Set the delays to 0 (we don't need to update the screen) 230 | // 231 | MathJax.Hub.processSectionDelay = 0; 232 | MathJax.Hub.processUpdateTime = 10000000; // don't interrupt processing of output 233 | MathJax.Hub.processUpdateDelay = 0; 234 | 235 | // 236 | // Adjust the SVG output jax 237 | // 238 | MathJax.Hub.Register.StartupHook("SVG Jax Config",function () { 239 | var SVG = MathJax.OutputJax.SVG, HTML = MathJax.HTML; 240 | 241 | // 242 | // Don't need the styles 243 | // 244 | delete SVG.config.styles 245 | 246 | SVG.Augment({ 247 | // 248 | // Set up the default ex-size and width 249 | // 250 | InitializeSVG: function () { 251 | this.pxPerInch = 96; 252 | this.defaultEx = 6; 253 | this.defaultWidth = 100; 254 | }, 255 | // 256 | // Adjust preTranslate() to not try to find the ex-size or 257 | // the container widths. 258 | // 259 | preTranslate: function (state) { 260 | var scripts = state.jax[this.id], i, m = scripts.length, 261 | script, prev, span, div, jax, ex, em, 262 | maxwidth = 100000, relwidth = false, cwidth, 263 | linebreak = this.config.linebreaks.automatic, 264 | width = this.config.linebreaks.width; 265 | // 266 | // Loop through the scripts 267 | // 268 | for (i = 0; i < m; i++) { 269 | script = scripts[i]; if (!script.parentNode) continue; 270 | // 271 | // Remove any existing output 272 | // 273 | prev = script.previousSibling; 274 | if (prev && String(prev.className).match(/^MathJax(_SVG)?(_Display)?( MathJax(_SVG)?_Processing)?$/)) 275 | {prev.parentNode.removeChild(prev)} 276 | // 277 | // Add the span, and a div if in display mode, 278 | // then mark it as being processed 279 | // 280 | jax = script.MathJax.elementJax; if (!jax) continue; 281 | jax.SVG = {display: (jax.root.Get("display") === "block")} 282 | span = div = HTML.Element("span",{ 283 | style: {"font-size": this.config.scale+"%", display:"inline-block"}, 284 | className:"MathJax_SVG", id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id 285 | }); 286 | if (jax.SVG.display) { 287 | div = HTML.Element("div",{className:"MathJax_SVG_Display"}); 288 | div.appendChild(span); 289 | } 290 | div.className += " MathJax_SVG_Processing"; 291 | script.parentNode.insertBefore(div,script); 292 | // 293 | // Set SVG data for jax 294 | // 295 | jax.SVG.ex = ex = (data||defaults).ex; 296 | jax.SVG.em = em = ex / SVG.TeX.x_height * 1000; // scale ex to x_height 297 | jax.SVG.cwidth = width / em * 1000; 298 | jax.SVG.lineWidth = (linebreak ? width / em * 1000 : SVG.BIGDIMEN); 299 | } 300 | // 301 | // Set state variables used for displaying equations in chunks 302 | // 303 | state.SVGeqn = state.SVGlast = 0; state.SVGi = -1; 304 | state.SVGchunk = this.config.EqnChunk; 305 | state.SVGdelay = false; 306 | } 307 | }); 308 | 309 | // 310 | // TEXT boxes use getBBox, which isn't implemented, so 311 | // use a monspace font and fake the size. Since these 312 | // are used only for error messages and undefined characters, 313 | // this should be good enough for now. 314 | // 315 | SVG.BBOX.TEXT.Augment({ 316 | Init: function (scale,text,def) { 317 | if (!def) {def = {}}; def.stroke = "none"; 318 | if (def["font-style"] === "") delete def["font-style"]; 319 | if (def["font-weight"] === "") delete def["font-weight"]; 320 | this.SUPER(arguments).Init.call(this,def); 321 | SVG.addText(this.element,text); 322 | // tweaking font fallback behavior: https://github.com/mathjax/MathJax-node/issues/299 323 | var textWidth = text.split('') 324 | .map(function(c) { return isFullwidthCodePoint(c.codePointAt()) ? data.cjkCharWidth : 8.5 }) 325 | .reduce(function(a, b) { return a + b }, 0); 326 | var bbox = {width: textWidth, height: 18, y: -12}; 327 | scale *= 1000/SVG.em; 328 | this.element.setAttribute("font-family","monospace"); 329 | this.element.setAttribute("transform","scale("+scale+") matrix(1 0 0 -1 0 0)"); 330 | this.w = this.r = bbox.width*scale; this.l = 0; 331 | this.h = this.H = -bbox.y*scale; 332 | this.d = this.D = (bbox.height + bbox.y)*scale; 333 | } 334 | }); 335 | 336 | // 337 | // Don't have mglyph load images 338 | // 339 | MathJax.Hub.Register.StartupHook("SVG mglyph Ready",function () { 340 | var MML = MathJax.ElementJax.mml; 341 | var MGLYPH = MML.mglyph; 342 | var TOSVG = MGLYPH.prototype.toSVG; 343 | MGLYPH.Augment({ 344 | toSVG: function (variant,scale) { 345 | var values = this.getValues("src","width","height"); 346 | if (values.src !== "" && !MGLYPH.GLYPH[values.src]) { 347 | if (!values.width || !values.height) { 348 | AddError("mglyphs must have explicit width and height in mathjax-node"); 349 | } 350 | MGLYPH.GLYPH[values.src] = { 351 | img: {SRC: values.src, width: 0, height: 0}, 352 | status: "OK" 353 | }; 354 | } 355 | return TOSVG.apply(this,arguments); 356 | } 357 | }); 358 | }); 359 | 360 | }); 361 | 362 | // 363 | // Adjust the CommonHTML output jax 364 | // 365 | MathJax.Hub.Register.StartupHook("CommonHTML Jax Config",function () { 366 | var CHTML = MathJax.OutputJax.CommonHTML, HTML = MathJax.HTML; 367 | 368 | // 369 | // Don't need these styles 370 | // 371 | var STYLES = CHTML.config.styles; 372 | delete STYLES["#MathJax_CHTML_Tooltip"]; 373 | delete STYLES[".MJXc-processing"]; 374 | delete STYLES[".MJXc-processed"]; 375 | delete STYLES[".mjx-chartest"]; 376 | delete STYLES[".mjx-chartest .mjx-char"]; 377 | delete STYLES[".mjx-chartest .mjx-box"]; 378 | delete STYLES[".mjx-test"]; 379 | delete STYLES[".mjx-ex-boxtest"]; 380 | // fontURL to current MathJax version 381 | if (!fontURL){ 382 | fontURL = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/' + MathJax.version + '/fonts/HTML-CSS'; 383 | } 384 | CHTML.Augment({ 385 | webfontDir: fontURL, 386 | // 387 | // Set up the default ex-size and width 388 | // 389 | getDefaultExEm: function () { 390 | var styles = document.head.getElementsByTagName("style"); 391 | CHTMLSTYLES = styles[styles.length-1].innerHTML; 392 | this.pxPerInch = 96; 393 | this.defaultEx = 6; 394 | this.defaultEm = 6 / CHTML.TEX.x_height * 1000; 395 | this.defaultWidth = 100; 396 | }, 397 | // 398 | // Adjust preTranslate() to not try to find the ex-size or 399 | // the container widths. 400 | // 401 | preTranslate: function (state) { 402 | var scripts = state.jax[this.id], i, m = scripts.length, 403 | script, prev, node, jax, ex, em, 404 | maxwidth = 100000, relwidth = false, cwidth = 0, 405 | linebreak = this.config.linebreaks.automatic, 406 | width = this.config.linebreaks.width; 407 | // 408 | // Loop through the scripts 409 | // 410 | for (i = 0; i < m; i++) { 411 | script = scripts[i]; if (!script.parentNode) continue; 412 | // 413 | // Remove any existing output 414 | // 415 | prev = script.previousSibling; 416 | if (prev && prev.className && String(prev.className).substr(0,9) === "mjx-chtml") 417 | prev.parentNode.removeChild(prev); 418 | // 419 | // Add the node for the math and mark it as being processed 420 | // 421 | jax = script.MathJax.elementJax; if (!jax) continue; 422 | jax.CHTML = {display: (jax.root.Get("display") === "block")} 423 | node = CHTML.Element("mjx-chtml",{ 424 | id:jax.inputID+"-Frame", isMathJax:true, jaxID:this.id 425 | }); 426 | if (jax.CHTML.display) { 427 | // 428 | // Zoom box requires an outer container to get the positioning right. 429 | // 430 | var NODE = CHTML.Element("mjx-chtml",{className:"MJXc-display",isMathJax:false}); 431 | NODE.appendChild(node); node = NODE; 432 | } 433 | 434 | node.className += " MJXc-processing"; 435 | script.parentNode.insertBefore(node,script); 436 | // 437 | // Set CHTML data for jax 438 | // 439 | jax.CHTML.ex = ex = (data||defaults).ex; 440 | jax.CHTML.em = jax.CHTML.outerEm = em = ex / CHTML.TEX.x_height; // scale ex to x_height 441 | jax.CHTML.cwidth = width / em; 442 | jax.CHTML.lineWidth = (linebreak ? width / em : 1000000); 443 | jax.CHTML.scale = 1; jax.CHTML.fontsize = "100%"; 444 | } 445 | // 446 | // Set state variables used for displaying equations in chunks 447 | // 448 | state.CHTMLeqn = state.CHTMLlast = 0; state.CHTMLi = -1; 449 | state.CHTMLchunk = this.config.EqnChunk; 450 | state.CHTMLdelay = false; 451 | }, 452 | 453 | // 454 | // We are using a monospaced font, so fake the size 455 | // 456 | getHDW: function (c,name,styles) { 457 | return {h:.8, d:.2, w:c.length*.5}; 458 | } 459 | 460 | }); 461 | 462 | // 463 | // Don't have mglyph load images 464 | // 465 | MathJax.Hub.Register.StartupHook("CommonHTML mglyph Ready",function () { 466 | var MML = MathJax.ElementJax.mml; 467 | var MGLYPH = MML.mglyph; 468 | var TOCHTML = MGLYPH.prototype.toCommonHTML; 469 | MGLYPH.Augment({ 470 | toCommonHTML: function (node,options) { 471 | var values = this.getValues("src","width","height"); 472 | if (values.src !== "" && !MGLYPH.GLYPH[values.src]) { 473 | if (!values.width || !values.height) { 474 | AddError("mglyphs must have explicit width and height in mathjax-node"); 475 | } 476 | MGLYPH.GLYPH[values.src] = { 477 | img: {SRC: values.src, width: 0, height: 0}, 478 | status: "OK" 479 | }; 480 | } 481 | return TOCHTML.apply(this,arguments); 482 | } 483 | }); 484 | }); 485 | 486 | }); 487 | 488 | // 489 | // Set up None output jax (for when only MathML output is needed) 490 | // 491 | MathJax.Hub.Register.StartupHook("End Jax", function () { 492 | MathJax.OutputJax.None = MathJax.OutputJax({ 493 | id: "None", 494 | preTranslate: function () {}, 495 | Translate: function () {}, 496 | postTranslate: function () {} 497 | }); 498 | MathJax.OutputJax.None.loadComplete("jax.js"); 499 | MathJax.OutputJax.None.Register("jax/mml"); 500 | }); 501 | 502 | // 503 | // Reset the color extension after `autoload-all` 504 | // 505 | if (MathJax.AuthorConfig.extensions.indexOf("TeX/color.js") == -1 && MathJax.AuthorConfig.extensions.indexOf("TeX/autoload-all.js") == -1) { 506 | MathJax.Hub.Register.StartupHook("TeX autoload-all Ready",function () { 507 | var macros = MathJax.InputJax.TeX.Definitions.macros; 508 | macros.color = "Color"; 509 | delete macros.textcolor; 510 | delete macros.colorbox; 511 | delete macros.fcolorbox; 512 | delete macros.definecolor; 513 | }); 514 | } 515 | 516 | // 517 | // Start the typesetting queue when MathJax is ready 518 | // (reseting the counters so that the initial math doesn't affect them) 519 | // 520 | MathJax.Hub.Register.StartupHook("End",function () { 521 | if (MathJax.OutputJax.SVG.resetGlyphs) MathJax.OutputJax.SVG.resetGlyphs(true); 522 | MathJax.ElementJax.mml.ID = 0; 523 | if (serverState === STATE.RESTART) { 524 | setTimeout(RestartMathJax, 100); 525 | } else { 526 | serverState = STATE.READY; 527 | MathJax.Hub.Queue( 528 | function () {sErrors = errors}, 529 | StartQueue 530 | ); 531 | } 532 | }); 533 | } 534 | }; 535 | 536 | if (extensions) { 537 | // 538 | // Parse added extensions list and add to standard ones 539 | // 540 | var extensionList = extensions.split(/\s*,\s*/); 541 | for (var i = 0; i < extensionList.length; i++) { 542 | var matches = extensionList[i].match(/^(.*?)(\.js)?$/); 543 | window.MathJax.extensions.push(matches[1] + '.js'); 544 | } 545 | } 546 | 547 | // 548 | // Turn arrays into jsdom window arrays 549 | // (so "instanceof Array" will identify them properly) 550 | // 551 | var adjustArrays = function (obj) { 552 | for (var id in obj) {if (obj.hasOwnProperty(id)) { 553 | if (obj[id] instanceof Array) { 554 | var A = window.Array(); 555 | obj[id] = A.concat.apply(A,obj[id]); 556 | } else if (typeof obj[id] === "object") { 557 | adjustArrays(obj[id]); 558 | } 559 | }} 560 | } 561 | if (MathJaxConfig) { 562 | adjustArrays(MathJaxConfig); 563 | // merge the defaults into the user configuration (to sanitize) 564 | window.MathJax = Insert(Insert({},MathJaxConfig),window.MathJax); 565 | if (MathJaxConfig.extensions) { 566 | window.MathJax.extensions = window.MathJax.extensions.concat(MathJaxConfig.extensions); 567 | } 568 | } 569 | } 570 | 571 | // 572 | // Insert one objects into another 573 | // 574 | function Insert(dst,src) { 575 | for (var id in src) {if (src.hasOwnProperty(id)) { 576 | // allow for concatenation of arrays? 577 | if (typeof src[id] === 'object' && !(src[id] instanceof Array) && 578 | (typeof dst[id] === 'object' || typeof dst[id] === 'function')) 579 | {Insert(dst[id],src[id])} else {dst[id] = src[id]} 580 | }} 581 | return dst; 582 | } 583 | 584 | // 585 | // Load MathJax into the DOM 586 | // 587 | function StartMathJax() { 588 | serverState = STATE.STARTED; 589 | var script = document.createElement("script"); 590 | script.src = MathJaxPath; 591 | script.onerror = function () {AddError("Can't load MathJax.js from "+MathJaxPath)}; 592 | document.head.appendChild(script); 593 | } 594 | 595 | /********************************************************************/ 596 | 597 | // 598 | // Return an error value (and report it to console) 599 | // 600 | function ReportError(message,currentCallback) { 601 | AddError(message); 602 | (currentCallback||callback)({errors: errors}); 603 | } 604 | 605 | // 606 | // Add an error to the error list and display it on the console 607 | // 608 | function AddError(message,nopush) { 609 | if (displayErrors) console.error(message); 610 | if (!nopush) errors.push(message); 611 | } 612 | 613 | 614 | /********************************************************************/ 615 | 616 | // 617 | // Creates the MathML output (taking MathJax resets 618 | // into account) 619 | // 620 | function GetMML(result) { 621 | if (!data.mml && !data.mmlNode) return; 622 | var jax = MathJax.Hub.getAllJax()[0]; 623 | if (data.speakText && !jax.root.alttext) { 624 | jax.root.alttext = result.speakText; 625 | var attrNames = jax.root.attrNames; 626 | if (attrNames && attrNames.indexOf("alttext") === -1) { 627 | attrNames.push("alttext"); 628 | } 629 | } 630 | try { 631 | var mml = jax.root.toMathML('',jax); 632 | } catch(err) { 633 | if (!err.restart) {throw err;} // an actual error 634 | return MathJax.Callback.After(window.Array(GetMML,result),err.restart); 635 | } 636 | if (data.mml) result.mml = mml; 637 | if (data.mmlNode) result.mmlNode = JSDOM.fragment(mml).firstChild; 638 | } 639 | 640 | // 641 | // Creates speech string and updates the MathML to include it, if needed 642 | // 643 | function GetSpeech(result) { 644 | if (!data.speakText) return; 645 | result.speakText = "Equation"; 646 | if (data.format !== "MathML") result.speakText = data.math; 647 | else { 648 | var jax = MathJax.Hub.getAllJax()[0]; 649 | if (jax.root.alttext) result.speakText = jax.root.alttext; 650 | } 651 | } 652 | 653 | // 654 | // Create HTML and CSS output, if requested 655 | // 656 | function GetHTML(result) { 657 | if (data.css) result.css = CHTMLSTYLES; 658 | if (!data.html && !data.htmlNode) return; 659 | var jax = MathJax.Hub.getAllJax()[0]; if (!jax) return; 660 | var script = jax.SourceElement(), html = script.previousSibling; 661 | 662 | // add speech text if there isn't one 663 | if (data.speakText){ 664 | var labelTarget = html.querySelector('.mjx-math'); 665 | for (child of labelTarget.childNodes) child.setAttribute("aria-hidden",true); 666 | if (!labelTarget.getAttribute("aria-label")){ 667 | labelTarget.setAttribute("aria-label",result.speakText); 668 | } 669 | } 670 | // remove automatically generated IDs 671 | var ids = html.querySelectorAll('[id^="MJXc-Node-"]'); 672 | for (var i = 0; i < ids.length; i++){ 673 | ids[i].removeAttribute("id"); 674 | } 675 | // remove extreneous frame element 676 | var frame = html.querySelector('[id^="MathJax-Element-"]'); 677 | if (frame){ 678 | // in display-mode, the frame is inside the display-style wrapper 679 | html.insertBefore(frame.firstChild, frame); 680 | html.removeChild(frame); 681 | } 682 | else{ 683 | // otherwise (inline-mode) the frame is the root element 684 | html.removeAttribute("id"); 685 | } 686 | if (data.html) result.html = html.outerHTML; 687 | if (data.htmlNode) result.htmlNode = html; 688 | } 689 | 690 | // 691 | // Create SVG output, if requested 692 | // 693 | function GetSVG(result) { 694 | if (!data.svg && !data.svgNode) return; 695 | var jax = MathJax.Hub.getAllJax()[0]; if (!jax) return; 696 | var script = jax.SourceElement(), 697 | svg = script.previousSibling.getElementsByTagName("svg")[0]; 698 | svg.setAttribute("xmlns","http://www.w3.org/2000/svg"); 699 | 700 | // 701 | // Add the speech text and mark the SVG appropriately 702 | // 703 | if (data.speakText){ 704 | for (var i=0, m=svg.childNodes.length; i < m; i++) 705 | svg.childNodes[i].setAttribute("aria-hidden",true); 706 | // Note: if aria-label exists, getSpeech preserved it in speakText 707 | // remove aria-label since labelled-by title is preferred 708 | svg.removeAttribute("aria-label"); 709 | ID++; var id = "MathJax-SVG-"+ID+"-Title"; 710 | svg.setAttribute("aria-labelledby",id); 711 | var node = MathJax.HTML.Element("title",{id:id},[result.speakText]); 712 | svg.insertBefore(node,svg.firstChild); 713 | } 714 | 715 | if (data.svg){ 716 | // 717 | // SVG data is modified to add linebreaks for readability, 718 | // and to put back the xlink namespace that is removed in HTML5 719 | // 720 | var svgdata = svg.outerHTML.replace(/><([^/])/g,">\n<$1") 721 | .replace(/(<\/[a-z]*>)(?=<\/)/g,"$1\n") 722 | .replace(/(<(?:use|image) [^>]*)(href=)/g,' $1xlink:$2'); 723 | 724 | // 725 | // Add the requested data to the results 726 | // 727 | result.svg = svgdata; 728 | } 729 | if (data.svgNode) result.svgNode = svg; 730 | result.width = svg.getAttribute("width"); 731 | result.height = svg.getAttribute("height"); 732 | result.style = svg.style.cssText; 733 | } 734 | 735 | /********************************************************************/ 736 | 737 | // 738 | // Start typesetting the queued expressions 739 | // 740 | function StartQueue() { 741 | data = callback = originalData = null; // clear existing equation, if any 742 | errors = sErrors; sErrors = []; // clear any errors 743 | if (!queue.length) return; // return if nothing to do 744 | 745 | serverState = STATE.BUSY; 746 | var result = {}, $$ = window.Array; 747 | 748 | // 749 | // Get the math data and callback 750 | // and set the content with the proper script type 751 | // 752 | var item = queue.shift(); 753 | data = item[0]; callback = item[1]; originalData = item[2]; 754 | content.innerHTML = ""; 755 | MathJax.HTML.addElement(content,"script",{type: "math/"+TYPES[data.format]},[data.math]); 756 | html.setAttribute("xmlns:"+data.xmlns,"http://www.w3.org/1998/Math/MathML"); 757 | 758 | // 759 | // Set the SVG and TeX parameters 760 | // according to the requested data 761 | // 762 | var CHTML = MathJax.OutputJax.CommonHTML, 763 | SVG = MathJax.OutputJax.SVG, 764 | TEX = MathJax.InputJax.TeX, 765 | HUB = MathJax.Hub; 766 | 767 | SVG.defaultEx = CHTML.defaultEx = data.ex; 768 | SVG.defaultWidth = CHTMLdefaultWidth = data.width * data.ex; 769 | SVG.config.linebreaks.automatic = CHTML.config.linebreaks.automatic = data.linebreaks; 770 | SVG.config.linebreaks.width = CHTML.config.linebreaks.width = data.width * data.ex; 771 | SVG.config.useFontCache = data.useFontCache; 772 | SVG.config.useGlobalCache = data.useGlobalCache; 773 | TEX.config.equationNumbers.autoNumber = data.equationNumbers; 774 | 775 | // 776 | // Set the state from data.state or clear it 777 | // 778 | GetState(data.state); 779 | 780 | // 781 | // Get the renderer to use 782 | // 783 | var renderer = ( 784 | (data.html || data.htmlNode || data.css) ? "CommonHTML" : 785 | (data.svg || data.svgNode) ? "SVG" : "None" 786 | ); 787 | 788 | // 789 | // Set up a timeout timer to restart MathJax if it runs too long, 790 | // Then push the Typeset call, the MathML, speech, and SVG calls, 791 | // and our TypesetDone routine 792 | // 793 | timer = setTimeout(RestartMathJax,data.timeout); 794 | HUB.Queue( 795 | $$(SetRenderer,renderer), 796 | $$("Process",HUB), 797 | $$(TypesetDone,result), 798 | $$(GetSpeech,result), 799 | $$(GetMML,result), 800 | $$(GetHTML,result), 801 | $$(RerenderSVG,result), 802 | $$(GetSVG,result), 803 | $$(ReturnResult,result) 804 | ); 805 | } 806 | 807 | // 808 | // Update the MathJax values from the state, 809 | // or clear them if there is no state. 810 | // 811 | function GetState(state) { 812 | var SVG = MathJax.OutputJax.SVG, 813 | TEX = MathJax.InputJax.TeX, 814 | MML = MathJax.ElementJax.mml, 815 | AMS = MathJax.Extension["TeX/AMSmath"], 816 | HUB = MathJax.Hub, HTML = MathJax.HTML, 817 | GLYPH = (SVG.BBOX||{}).GLYPH; 818 | 819 | if (state && state.AMS) { 820 | AMS.startNumber = state.AMS.startNumber; 821 | AMS.labels = state.AMS.labels; 822 | AMS.IDs = state.AMS.IDs; 823 | MML.SUPER.ID = state.mmlID; 824 | GLYPH.glyphs = state.glyphs; 825 | GLYPH.defs = state.defs; 826 | GLYPH.n = state.n; 827 | ID = state.ID; 828 | } else { 829 | if (state) {state.AMS = {}} 830 | if (SVG.resetGlyphs) SVG.resetGlyphs(true); 831 | if (data.useGlobalCache) { 832 | state.glyphs = {}; 833 | state.defs = HTML.Element("defs"); 834 | state.n = 0; 835 | } 836 | if (TEX.resetEquationNumbers) TEX.resetEquationNumbers(); 837 | MML.SUPER.ID = ID = 0; 838 | MathJax.OutputJax.CommonHTML.ID = 0; 839 | } 840 | } 841 | 842 | // 843 | // When the expression is typeset, 844 | // clear the timeout timer, if any, 845 | // and update the MathJax state, 846 | // 847 | function TypesetDone(result) { 848 | if (timer) {clearTimeout(timer); timer = null} 849 | html.removeAttribute("xmlns:"+data.xmlns); 850 | } 851 | 852 | // 853 | // Return the result object, and 854 | // do the next queued expression 855 | // 856 | function ReturnResult(result) { 857 | if (errors.length) { 858 | result.errors = errors; 859 | } 860 | var state = data.state; 861 | if (state) { 862 | var AMS = MathJax.Extension["TeX/AMSmath"]; 863 | var GLYPH = (MathJax.OutputJax.SVG||{}).BBOX.GLYPH; 864 | state.AMS.startNumber = AMS.startNumber; 865 | state.AMS.labels = AMS.labels; 866 | state.AMS.IDs = AMS.IDs; 867 | state.mmlID = MathJax.ElementJax.mml.SUPER.ID; 868 | state.glyphs = GLYPH.glyphs; 869 | state.defs = GLYPH.defs; 870 | state.n = GLYPH.n; 871 | state.ID = ID; 872 | } 873 | serverState = STATE.READY; 874 | callback(result, originalData); 875 | if (serverState === STATE.READY) StartQueue(); 876 | } 877 | 878 | // 879 | // Set the MathJax renderer 880 | // 881 | function SetRenderer(renderer) { 882 | return MathJax.Hub.setRenderer(renderer); 883 | } 884 | 885 | function RerenderSVG(result) { 886 | if ((data.html || data.htmlNode || data.css) && (data.svg || data.svgNode)) { 887 | timer = setTimeout(RestartMathJax,data.timeout); 888 | var queue = MathJax.Callback.Queue(), $$ = window.Array; 889 | return queue.Push( 890 | $$(SetRenderer,"SVG"), 891 | $$("Rerender",MathJax.Hub), 892 | $$(TypesetDone,result) 893 | ); 894 | } 895 | } 896 | 897 | 898 | /********************************************************************/ 899 | 900 | // 901 | // If MathJax times out, discard the DOM 902 | // and load a new one (get a fresh MathJax) 903 | // 904 | function RestartMathJax() { 905 | if (timer) { 906 | MathJax.Hub.queue.queue = []; // clear MathJax queue, so pending operations won't fire 907 | MathJax = timer = window = document = html = content = null; 908 | ReportError("Timeout waiting for MathJax: restarting"); 909 | } 910 | serverState = STATE.STOPPED; 911 | GetWindow(); 912 | ConfigureMathJax(); 913 | StartMathJax(); 914 | } 915 | 916 | /********************************************************************/ 917 | 918 | // 919 | // The API call to typeset an equation 920 | // 921 | // %%% cache results? 922 | // %%% check types and values of parameters 923 | // 924 | 925 | // callback API for compatibility with MathJax 926 | var cbTypeset = function (data, callback) { 927 | if (!callback || typeof(callback) !== "function") { 928 | if (displayErrors) console.error("Missing callback"); 929 | return; 930 | } 931 | var options = {}; 932 | for (var id in defaults) {if (defaults.hasOwnProperty(id)) { 933 | options[id] = (data.hasOwnProperty(id) ? data[id]: defaults[id]); 934 | }} 935 | if (data.state) {options.state = data.state} 936 | if (!TYPES[options.format]) {ReportError("Unknown format: "+options.format,callback); return} 937 | queue.push([options,callback,Object.assign({},data)]); 938 | if (serverState == STATE.STOPPED) {RestartMathJax()} 939 | if (serverState == STATE.READY) StartQueue(); 940 | } 941 | 942 | // main API, callback and promise compatible 943 | exports.typeset = function (data, callback) { 944 | if (callback) cbTypeset(data, callback); 945 | else return new Promise(function (resolve, reject) { 946 | cbTypeset(data, function (output, input) { 947 | if (output.errors) reject(output.errors); 948 | else resolve(output, input); 949 | }); 950 | }); 951 | }; 952 | 953 | // 954 | // Manually start MathJax (this is done automatically 955 | // when the first typeset() call is made), but delay 956 | // restart if we are already starting up (prevents 957 | // multiple calls to start() from causing confusion). 958 | // 959 | exports.start = function () { 960 | if (serverState === STATE.STARTED) { 961 | serverState = STATE.RESTART; 962 | } else if (serverState !== STATE.ABORT) { 963 | RestartMathJax(); 964 | } 965 | } 966 | 967 | // 968 | // Configure MathJax and the API 969 | // You can pass additional configuration options to MathJax using the 970 | // MathJax property, and can set displayErrors and displayMessages 971 | // that control the display of error messages, and extensions to add 972 | // additional MathJax extensions to the base or to sub-categories. 973 | // 974 | // E.g. 975 | // mjAPI.config({ 976 | // MathJax: {SVG: {font: "STIX-Web"}}, 977 | // displayErrors: false, 978 | // extensions: 'Safe,TeX/noUndefined' 979 | // }); 980 | // 981 | exports.config = function (config) { 982 | if (config.displayMessages != null) {displayMessages = config.displayMessages} 983 | if (config.displayErrors != null) {displayErrors = config.displayErrors} 984 | if (config.undefinedCharError != null) {undefinedChar = config.undefinedCharError} 985 | if (config.extensions != null) {extensions = config.extensions} 986 | if (config.paths != null) {paths = config.paths} 987 | if (config.fontURL != null) {fontURL = config.fontURL} 988 | if (config.MathJax) { 989 | // strip MathJax config blocks to avoid errors 990 | if (config.MathJax.config) delete config.MathJax.config 991 | MathJaxConfig = config.MathJax 992 | } 993 | } 994 | -------------------------------------------------------------------------------- /lib/patch/jsdom.js: -------------------------------------------------------------------------------- 1 | // 2 | // We need to load cssstyle's parsers.js, but its location differs 3 | // between node 4 and node 5, so check which one we have. 4 | // 5 | 6 | var PARSERS = 'cssstyle/lib/parsers.js'; 7 | 8 | // 9 | // Patch for CSSStyleDeclaration lengthRegEx so that it includes ex units 10 | // (plus a number of other units that are left out) 11 | // 12 | var FixValueType = function () { 13 | var parsers = require(PARSERS); 14 | 15 | var integerRegEx = /^[\-+]?[0-9]+$/; 16 | var numberRegEx = /^[\-+]?[0-9]*\.[0-9]+$/; 17 | var lengthRegEx = /^(0|[\-+]?[0-9]*\.?[0-9]+(in|cm|mm|pt|pc|px|em|ex|ch|rem|vh|vw|vmin|vmax))$/; 18 | var percentRegEx = /^[\-+]?[0-9]*\.?[0-9]+%$/; 19 | var urlRegEx = /^url\(\s*([^\)]*)\s*\)$/; 20 | var stringRegEx = /^(\"[^\"]*\"|\'[^\']*\')$/; 21 | var colorRegEx1 = /^#[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]([0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])?$/; 22 | var colorRegEx2 = /^rgb\(([^\)]*)\)$/; 23 | var colorRegEx3 = /^rgba\(([^\)]*)\)$/; 24 | var angleRegEx = /^([\-+]?[0-9]*\.?[0-9]+)(deg|grad|rad)$/; 25 | 26 | parsers.valueType = function valueType(val) { 27 | var TYPES = parsers.TYPES; 28 | if (val === '' || val === null) return TYPES.NULL_OR_EMPTY_STR; 29 | if (typeof val === 'number') val = val.toString(); 30 | if (typeof val !== 'string') return undefined; 31 | 32 | if (integerRegEx.test(val)) return TYPES.INTEGER; 33 | if (numberRegEx.test(val)) return TYPES.NUMBER; 34 | if (lengthRegEx.test(val)) return TYPES.LENGTH; 35 | if (percentRegEx.test(val)) return TYPES.PERCENT; 36 | if (urlRegEx.test(val)) return TYPES.URL; 37 | if (stringRegEx.test(val)) return TYPES.STRING; 38 | if (angleRegEx.test(val)) return TYPES.ANGLE; 39 | if (colorRegEx1.test(val)) return TYPES.COLOR; 40 | var res = colorRegEx2.exec(val); 41 | var parts; 42 | if (res !== null) { 43 | parts = res[1].split(/\s*,\s*/); 44 | if (parts.length !== 3) return undefined; 45 | if (parts.every(percentRegEx.test.bind(percentRegEx)) || 46 | parts.every(integerRegEx.test.bind(integerRegEx))) return TYPES.COLOR; 47 | return undefined; 48 | } 49 | res = colorRegEx3.exec(val); 50 | if (res !== null) { 51 | parts = res[1].split(/\s*,\s*/); 52 | if (parts.length !== 4) return undefined; 53 | if (parts.slice(0, 3).every(percentRegEx.test.bind(percentRegEx)) || 54 | parts.every(integerRegEx.test.bind(integerRegEx))) { 55 | if (numberRegEx.test(parts[3])) return TYPES.COLOR; 56 | } 57 | return undefined; 58 | } 59 | val = val.toLowerCase(); 60 | switch (val) { 61 | case 'maroon': 62 | case 'red': 63 | case 'orange': 64 | case 'yellow': 65 | case 'olive': 66 | case 'purple': 67 | case 'fuchsia': 68 | case 'white': 69 | case 'lime': 70 | case 'green': 71 | case 'navy': 72 | case 'blue': 73 | case 'aqua': 74 | case 'teal': 75 | case 'black': 76 | case 'silver': 77 | case 'gray': 78 | // the following are deprecated in CSS3 79 | case 'activeborder': 80 | case 'activecaption': 81 | case 'appworkspace': 82 | case 'background': 83 | case 'buttonface': 84 | case 'buttonhighlight': 85 | case 'buttonshadow': 86 | case 'buttontext': 87 | case 'captiontext': 88 | case 'graytext': 89 | case 'highlight': 90 | case 'highlighttext': 91 | case 'inactiveborder': 92 | case 'inactivecaption': 93 | case 'inactivecaptiontext': 94 | case 'infobackground': 95 | case 'infotext': 96 | case 'menu': 97 | case 'menutext': 98 | case 'scrollbar': 99 | case 'threeddarkshadow': 100 | case 'threedface': 101 | case 'threedhighlight': 102 | case 'threedlightshadow': 103 | case 'threedshadow': 104 | case 'window': 105 | case 'windowframe': 106 | case 'windowtext': 107 | return TYPES.COLOR; 108 | default: 109 | return TYPES.KEYWORD; 110 | } 111 | }; 112 | } 113 | 114 | 115 | // 116 | // Patch jsdom functions 117 | // 118 | exports.patch = function (JSDOM) { 119 | var window = new JSDOM('').window; 120 | var document = window.document; 121 | 122 | var div = document.createElement("div"); 123 | 124 | // 125 | // Check if units of ex are allowed 126 | // 127 | div.style.marginTop = "3ex"; 128 | if (div.style.marginTop !== "3ex") FixValueType(); 129 | } 130 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mathjax-node", 3 | "version": "2.1.1", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "abab": { 8 | "version": "2.0.0", 9 | "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.0.tgz", 10 | "integrity": "sha512-sY5AXXVZv4Y1VACTtR11UJCPHHudgY5i26Qj5TypE6DKlIApbwb5uqhXcJ5UUGbvZNRh7EeIoW+LrJumBsKp7w==" 11 | }, 12 | "acorn": { 13 | "version": "5.7.4", 14 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.4.tgz", 15 | "integrity": "sha512-1D++VG7BhrtvQpNbBzovKNc1FLGGEE/oGe7b9xJm/RFHMBeUaUGpluV9RLjZa47YFdPcDAenEYuq9pQPcMdLJg==" 16 | }, 17 | "acorn-globals": { 18 | "version": "4.3.0", 19 | "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.0.tgz", 20 | "integrity": "sha512-hMtHj3s5RnuhvHPowpBYvJVj3rAar82JiDQHvGs1zO0l10ocX/xEdBShNHTJaboucJUsScghp74pH3s7EnHHQw==", 21 | "requires": { 22 | "acorn": "^6.0.1", 23 | "acorn-walk": "^6.0.1" 24 | }, 25 | "dependencies": { 26 | "acorn": { 27 | "version": "6.4.1", 28 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", 29 | "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==" 30 | } 31 | } 32 | }, 33 | "acorn-walk": { 34 | "version": "6.1.1", 35 | "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.1.1.tgz", 36 | "integrity": "sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw==" 37 | }, 38 | "ajv": { 39 | "version": "6.12.6", 40 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", 41 | "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", 42 | "requires": { 43 | "fast-deep-equal": "^3.1.1", 44 | "fast-json-stable-stringify": "^2.0.0", 45 | "json-schema-traverse": "^0.4.1", 46 | "uri-js": "^4.2.2" 47 | }, 48 | "dependencies": { 49 | "fast-deep-equal": { 50 | "version": "3.1.3", 51 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", 52 | "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" 53 | } 54 | } 55 | }, 56 | "array-equal": { 57 | "version": "1.0.0", 58 | "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", 59 | "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=" 60 | }, 61 | "asn1": { 62 | "version": "0.2.4", 63 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", 64 | "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", 65 | "requires": { 66 | "safer-buffer": "~2.1.0" 67 | } 68 | }, 69 | "assert-plus": { 70 | "version": "1.0.0", 71 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", 72 | "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=" 73 | }, 74 | "async-limiter": { 75 | "version": "1.0.0", 76 | "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.0.tgz", 77 | "integrity": "sha512-jp/uFnooOiO+L211eZOoSyzpOITMXx1rBITauYykG3BRYPu8h0UcxsPNB04RR5vo4Tyz3+ay17tR6JVf9qzYWg==" 78 | }, 79 | "asynckit": { 80 | "version": "0.4.0", 81 | "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", 82 | "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" 83 | }, 84 | "aws-sign2": { 85 | "version": "0.7.0", 86 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", 87 | "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=" 88 | }, 89 | "aws4": { 90 | "version": "1.8.0", 91 | "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", 92 | "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==" 93 | }, 94 | "balanced-match": { 95 | "version": "1.0.0", 96 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", 97 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", 98 | "dev": true 99 | }, 100 | "bcrypt-pbkdf": { 101 | "version": "1.0.2", 102 | "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", 103 | "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", 104 | "requires": { 105 | "tweetnacl": "^0.14.3" 106 | } 107 | }, 108 | "brace-expansion": { 109 | "version": "1.1.11", 110 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", 111 | "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", 112 | "dev": true, 113 | "requires": { 114 | "balanced-match": "^1.0.0", 115 | "concat-map": "0.0.1" 116 | } 117 | }, 118 | "browser-process-hrtime": { 119 | "version": "0.1.3", 120 | "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", 121 | "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==" 122 | }, 123 | "caseless": { 124 | "version": "0.12.0", 125 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", 126 | "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=" 127 | }, 128 | "combined-stream": { 129 | "version": "1.0.7", 130 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.7.tgz", 131 | "integrity": "sha512-brWl9y6vOB1xYPZcpZde3N9zDByXTosAeMDo4p1wzo6UMOX4vumB+TP1RZ76sfE6Md68Q0NJSrE/gbezd4Ul+w==", 132 | "requires": { 133 | "delayed-stream": "~1.0.0" 134 | } 135 | }, 136 | "concat-map": { 137 | "version": "0.0.1", 138 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", 139 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 140 | "dev": true 141 | }, 142 | "core-util-is": { 143 | "version": "1.0.2", 144 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", 145 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 146 | }, 147 | "cssom": { 148 | "version": "0.3.6", 149 | "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.6.tgz", 150 | "integrity": "sha512-DtUeseGk9/GBW0hl0vVPpU22iHL6YB5BUX7ml1hB+GMpo0NX5G4voX3kdWiMSEguFtcW3Vh3djqNF4aIe6ne0A==" 151 | }, 152 | "cssstyle": { 153 | "version": "1.2.1", 154 | "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.2.1.tgz", 155 | "integrity": "sha512-7DYm8qe+gPx/h77QlCyFmX80+fGaE/6A/Ekl0zaszYOubvySO2saYFdQ78P29D0UsULxFKCetDGNaNRUdSF+2A==", 156 | "requires": { 157 | "cssom": "0.3.x" 158 | } 159 | }, 160 | "dashdash": { 161 | "version": "1.14.1", 162 | "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", 163 | "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", 164 | "requires": { 165 | "assert-plus": "^1.0.0" 166 | } 167 | }, 168 | "data-urls": { 169 | "version": "1.1.0", 170 | "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", 171 | "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", 172 | "requires": { 173 | "abab": "^2.0.0", 174 | "whatwg-mimetype": "^2.2.0", 175 | "whatwg-url": "^7.0.0" 176 | }, 177 | "dependencies": { 178 | "whatwg-url": { 179 | "version": "7.0.0", 180 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.0.0.tgz", 181 | "integrity": "sha512-37GeVSIJ3kn1JgKyjiYNmSLP1yzbpb29jdmwBSgkD9h40/hyrR/OifpVUndji3tmwGgD8qpw7iQu3RSbCrBpsQ==", 182 | "requires": { 183 | "lodash.sortby": "^4.7.0", 184 | "tr46": "^1.0.1", 185 | "webidl-conversions": "^4.0.2" 186 | } 187 | } 188 | } 189 | }, 190 | "deep-equal": { 191 | "version": "1.0.1", 192 | "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", 193 | "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=", 194 | "dev": true 195 | }, 196 | "deep-is": { 197 | "version": "0.1.3", 198 | "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", 199 | "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=" 200 | }, 201 | "define-properties": { 202 | "version": "1.1.3", 203 | "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 204 | "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", 205 | "dev": true, 206 | "requires": { 207 | "object-keys": "^1.0.12" 208 | } 209 | }, 210 | "defined": { 211 | "version": "1.0.0", 212 | "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", 213 | "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", 214 | "dev": true 215 | }, 216 | "delayed-stream": { 217 | "version": "1.0.0", 218 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", 219 | "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" 220 | }, 221 | "domexception": { 222 | "version": "1.0.1", 223 | "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", 224 | "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", 225 | "requires": { 226 | "webidl-conversions": "^4.0.2" 227 | } 228 | }, 229 | "ecc-jsbn": { 230 | "version": "0.1.2", 231 | "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", 232 | "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", 233 | "requires": { 234 | "jsbn": "~0.1.0", 235 | "safer-buffer": "^2.1.0" 236 | } 237 | }, 238 | "es-abstract": { 239 | "version": "1.13.0", 240 | "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", 241 | "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", 242 | "dev": true, 243 | "requires": { 244 | "es-to-primitive": "^1.2.0", 245 | "function-bind": "^1.1.1", 246 | "has": "^1.0.3", 247 | "is-callable": "^1.1.4", 248 | "is-regex": "^1.0.4", 249 | "object-keys": "^1.0.12" 250 | } 251 | }, 252 | "es-to-primitive": { 253 | "version": "1.2.0", 254 | "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", 255 | "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", 256 | "dev": true, 257 | "requires": { 258 | "is-callable": "^1.1.4", 259 | "is-date-object": "^1.0.1", 260 | "is-symbol": "^1.0.2" 261 | } 262 | }, 263 | "escodegen": { 264 | "version": "1.11.1", 265 | "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.11.1.tgz", 266 | "integrity": "sha512-JwiqFD9KdGVVpeuRa68yU3zZnBEOcPs0nKW7wZzXky8Z7tffdYUHbe11bPCV5jYlK6DVdKLWLm0f5I/QlL0Kmw==", 267 | "requires": { 268 | "esprima": "^3.1.3", 269 | "estraverse": "^4.2.0", 270 | "esutils": "^2.0.2", 271 | "optionator": "^0.8.1", 272 | "source-map": "~0.6.1" 273 | } 274 | }, 275 | "esprima": { 276 | "version": "3.1.3", 277 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", 278 | "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=" 279 | }, 280 | "estraverse": { 281 | "version": "4.2.0", 282 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz", 283 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=" 284 | }, 285 | "esutils": { 286 | "version": "2.0.2", 287 | "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 288 | "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=" 289 | }, 290 | "extend": { 291 | "version": "3.0.2", 292 | "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", 293 | "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==" 294 | }, 295 | "extsprintf": { 296 | "version": "1.3.0", 297 | "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", 298 | "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=" 299 | }, 300 | "fast-json-stable-stringify": { 301 | "version": "2.0.0", 302 | "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", 303 | "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=" 304 | }, 305 | "fast-levenshtein": { 306 | "version": "2.0.6", 307 | "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", 308 | "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" 309 | }, 310 | "for-each": { 311 | "version": "0.3.3", 312 | "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", 313 | "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", 314 | "dev": true, 315 | "requires": { 316 | "is-callable": "^1.1.3" 317 | } 318 | }, 319 | "forever-agent": { 320 | "version": "0.6.1", 321 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", 322 | "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=" 323 | }, 324 | "form-data": { 325 | "version": "2.3.3", 326 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", 327 | "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", 328 | "requires": { 329 | "asynckit": "^0.4.0", 330 | "combined-stream": "^1.0.6", 331 | "mime-types": "^2.1.12" 332 | } 333 | }, 334 | "fs.realpath": { 335 | "version": "1.0.0", 336 | "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", 337 | "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", 338 | "dev": true 339 | }, 340 | "function-bind": { 341 | "version": "1.1.1", 342 | "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", 343 | "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", 344 | "dev": true 345 | }, 346 | "getpass": { 347 | "version": "0.1.7", 348 | "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", 349 | "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", 350 | "requires": { 351 | "assert-plus": "^1.0.0" 352 | } 353 | }, 354 | "glob": { 355 | "version": "7.1.3", 356 | "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 357 | "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", 358 | "dev": true, 359 | "requires": { 360 | "fs.realpath": "^1.0.0", 361 | "inflight": "^1.0.4", 362 | "inherits": "2", 363 | "minimatch": "^3.0.4", 364 | "once": "^1.3.0", 365 | "path-is-absolute": "^1.0.0" 366 | } 367 | }, 368 | "har-schema": { 369 | "version": "2.0.0", 370 | "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", 371 | "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=" 372 | }, 373 | "har-validator": { 374 | "version": "5.1.3", 375 | "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", 376 | "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", 377 | "requires": { 378 | "ajv": "^6.5.5", 379 | "har-schema": "^2.0.0" 380 | } 381 | }, 382 | "has": { 383 | "version": "1.0.3", 384 | "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", 385 | "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", 386 | "dev": true, 387 | "requires": { 388 | "function-bind": "^1.1.1" 389 | } 390 | }, 391 | "has-symbols": { 392 | "version": "1.0.0", 393 | "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", 394 | "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", 395 | "dev": true 396 | }, 397 | "html-encoding-sniffer": { 398 | "version": "1.0.2", 399 | "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", 400 | "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", 401 | "requires": { 402 | "whatwg-encoding": "^1.0.1" 403 | } 404 | }, 405 | "http-signature": { 406 | "version": "1.2.0", 407 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", 408 | "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", 409 | "requires": { 410 | "assert-plus": "^1.0.0", 411 | "jsprim": "^1.2.2", 412 | "sshpk": "^1.7.0" 413 | } 414 | }, 415 | "iconv-lite": { 416 | "version": "0.4.24", 417 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", 418 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", 419 | "requires": { 420 | "safer-buffer": ">= 2.1.2 < 3" 421 | } 422 | }, 423 | "inflight": { 424 | "version": "1.0.6", 425 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", 426 | "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", 427 | "dev": true, 428 | "requires": { 429 | "once": "^1.3.0", 430 | "wrappy": "1" 431 | } 432 | }, 433 | "inherits": { 434 | "version": "2.0.3", 435 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 436 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 437 | "dev": true 438 | }, 439 | "is-callable": { 440 | "version": "1.1.4", 441 | "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", 442 | "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", 443 | "dev": true 444 | }, 445 | "is-date-object": { 446 | "version": "1.0.1", 447 | "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", 448 | "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", 449 | "dev": true 450 | }, 451 | "is-fullwidth-code-point": { 452 | "version": "2.0.0", 453 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", 454 | "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=" 455 | }, 456 | "is-regex": { 457 | "version": "1.0.4", 458 | "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", 459 | "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", 460 | "dev": true, 461 | "requires": { 462 | "has": "^1.0.1" 463 | } 464 | }, 465 | "is-symbol": { 466 | "version": "1.0.2", 467 | "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", 468 | "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", 469 | "dev": true, 470 | "requires": { 471 | "has-symbols": "^1.0.0" 472 | } 473 | }, 474 | "is-typedarray": { 475 | "version": "1.0.0", 476 | "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", 477 | "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=" 478 | }, 479 | "isstream": { 480 | "version": "0.1.2", 481 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", 482 | "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=" 483 | }, 484 | "jsbn": { 485 | "version": "0.1.1", 486 | "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", 487 | "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=" 488 | }, 489 | "jsdom": { 490 | "version": "11.12.0", 491 | "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", 492 | "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", 493 | "requires": { 494 | "abab": "^2.0.0", 495 | "acorn": "^5.5.3", 496 | "acorn-globals": "^4.1.0", 497 | "array-equal": "^1.0.0", 498 | "cssom": ">= 0.3.2 < 0.4.0", 499 | "cssstyle": "^1.0.0", 500 | "data-urls": "^1.0.0", 501 | "domexception": "^1.0.1", 502 | "escodegen": "^1.9.1", 503 | "html-encoding-sniffer": "^1.0.2", 504 | "left-pad": "^1.3.0", 505 | "nwsapi": "^2.0.7", 506 | "parse5": "4.0.0", 507 | "pn": "^1.1.0", 508 | "request": "^2.87.0", 509 | "request-promise-native": "^1.0.5", 510 | "sax": "^1.2.4", 511 | "symbol-tree": "^3.2.2", 512 | "tough-cookie": "^2.3.4", 513 | "w3c-hr-time": "^1.0.1", 514 | "webidl-conversions": "^4.0.2", 515 | "whatwg-encoding": "^1.0.3", 516 | "whatwg-mimetype": "^2.1.0", 517 | "whatwg-url": "^6.4.1", 518 | "ws": "^5.2.0", 519 | "xml-name-validator": "^3.0.0" 520 | } 521 | }, 522 | "json-schema": { 523 | "version": "0.2.3", 524 | "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", 525 | "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=" 526 | }, 527 | "json-schema-traverse": { 528 | "version": "0.4.1", 529 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", 530 | "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" 531 | }, 532 | "json-stringify-safe": { 533 | "version": "5.0.1", 534 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", 535 | "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=" 536 | }, 537 | "jsprim": { 538 | "version": "1.4.1", 539 | "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", 540 | "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", 541 | "requires": { 542 | "assert-plus": "1.0.0", 543 | "extsprintf": "1.3.0", 544 | "json-schema": "0.2.3", 545 | "verror": "1.10.0" 546 | } 547 | }, 548 | "left-pad": { 549 | "version": "1.3.0", 550 | "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", 551 | "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==" 552 | }, 553 | "levn": { 554 | "version": "0.3.0", 555 | "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", 556 | "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", 557 | "requires": { 558 | "prelude-ls": "~1.1.2", 559 | "type-check": "~0.3.2" 560 | } 561 | }, 562 | "lodash": { 563 | "version": "4.17.21", 564 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", 565 | "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" 566 | }, 567 | "lodash.sortby": { 568 | "version": "4.7.0", 569 | "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", 570 | "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=" 571 | }, 572 | "mathjax": { 573 | "version": "2.7.5", 574 | "resolved": "https://registry.npmjs.org/mathjax/-/mathjax-2.7.5.tgz", 575 | "integrity": "sha512-OzsJNitEHAJB3y4IIlPCAvS0yoXwYjlo2Y4kmm9KQzyIBZt2d8yKRalby3uTRNN4fZQiGL2iMXjpdP1u2Rq2DQ==" 576 | }, 577 | "mime-db": { 578 | "version": "1.38.0", 579 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.38.0.tgz", 580 | "integrity": "sha512-bqVioMFFzc2awcdJZIzR3HjZFX20QhilVS7hytkKrv7xFAn8bM1gzc/FOX2awLISvWe0PV8ptFKcon+wZ5qYkg==" 581 | }, 582 | "mime-types": { 583 | "version": "2.1.22", 584 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.22.tgz", 585 | "integrity": "sha512-aGl6TZGnhm/li6F7yx82bJiBZwgiEa4Hf6CNr8YO+r5UHr53tSTYZb102zyU50DOWWKeOv0uQLRL0/9EiKWCog==", 586 | "requires": { 587 | "mime-db": "~1.38.0" 588 | } 589 | }, 590 | "minimatch": { 591 | "version": "3.0.4", 592 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 593 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", 594 | "dev": true, 595 | "requires": { 596 | "brace-expansion": "^1.1.7" 597 | } 598 | }, 599 | "minimist": { 600 | "version": "1.2.6", 601 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", 602 | "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", 603 | "dev": true 604 | }, 605 | "nwsapi": { 606 | "version": "2.1.1", 607 | "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.1.1.tgz", 608 | "integrity": "sha512-T5GaA1J/d34AC8mkrFD2O0DR17kwJ702ZOtJOsS8RpbsQZVOC2/xYFb1i/cw+xdM54JIlMuojjDOYct8GIWtwg==" 609 | }, 610 | "oauth-sign": { 611 | "version": "0.9.0", 612 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", 613 | "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==" 614 | }, 615 | "object-inspect": { 616 | "version": "1.6.0", 617 | "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", 618 | "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", 619 | "dev": true 620 | }, 621 | "object-keys": { 622 | "version": "1.1.0", 623 | "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.0.tgz", 624 | "integrity": "sha512-6OO5X1+2tYkNyNEx6TsCxEqFfRWaqx6EtMiSbGrw8Ob8v9Ne+Hl8rBAgLBZn5wjEz3s/s6U1WXFUFOcxxAwUpg==", 625 | "dev": true 626 | }, 627 | "once": { 628 | "version": "1.4.0", 629 | "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", 630 | "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", 631 | "dev": true, 632 | "requires": { 633 | "wrappy": "1" 634 | } 635 | }, 636 | "optionator": { 637 | "version": "0.8.2", 638 | "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", 639 | "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", 640 | "requires": { 641 | "deep-is": "~0.1.3", 642 | "fast-levenshtein": "~2.0.4", 643 | "levn": "~0.3.0", 644 | "prelude-ls": "~1.1.2", 645 | "type-check": "~0.3.2", 646 | "wordwrap": "~1.0.0" 647 | } 648 | }, 649 | "parse5": { 650 | "version": "4.0.0", 651 | "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", 652 | "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==" 653 | }, 654 | "path-is-absolute": { 655 | "version": "1.0.1", 656 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", 657 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 658 | "dev": true 659 | }, 660 | "path-parse": { 661 | "version": "1.0.7", 662 | "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", 663 | "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", 664 | "dev": true 665 | }, 666 | "performance-now": { 667 | "version": "2.1.0", 668 | "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", 669 | "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" 670 | }, 671 | "pn": { 672 | "version": "1.1.0", 673 | "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", 674 | "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" 675 | }, 676 | "prelude-ls": { 677 | "version": "1.1.2", 678 | "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", 679 | "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=" 680 | }, 681 | "psl": { 682 | "version": "1.1.31", 683 | "resolved": "https://registry.npmjs.org/psl/-/psl-1.1.31.tgz", 684 | "integrity": "sha512-/6pt4+C+T+wZUieKR620OpzN/LlnNKuWjy1iFLQ/UG35JqHlR/89MP1d96dUfkf6Dne3TuLQzOYEYshJ+Hx8mw==" 685 | }, 686 | "punycode": { 687 | "version": "2.1.1", 688 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", 689 | "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==" 690 | }, 691 | "qs": { 692 | "version": "6.5.2", 693 | "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", 694 | "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" 695 | }, 696 | "request": { 697 | "version": "2.88.0", 698 | "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", 699 | "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", 700 | "requires": { 701 | "aws-sign2": "~0.7.0", 702 | "aws4": "^1.8.0", 703 | "caseless": "~0.12.0", 704 | "combined-stream": "~1.0.6", 705 | "extend": "~3.0.2", 706 | "forever-agent": "~0.6.1", 707 | "form-data": "~2.3.2", 708 | "har-validator": "~5.1.0", 709 | "http-signature": "~1.2.0", 710 | "is-typedarray": "~1.0.0", 711 | "isstream": "~0.1.2", 712 | "json-stringify-safe": "~5.0.1", 713 | "mime-types": "~2.1.19", 714 | "oauth-sign": "~0.9.0", 715 | "performance-now": "^2.1.0", 716 | "qs": "~6.5.2", 717 | "safe-buffer": "^5.1.2", 718 | "tough-cookie": "~2.4.3", 719 | "tunnel-agent": "^0.6.0", 720 | "uuid": "^3.3.2" 721 | }, 722 | "dependencies": { 723 | "punycode": { 724 | "version": "1.4.1", 725 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", 726 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" 727 | }, 728 | "tough-cookie": { 729 | "version": "2.4.3", 730 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", 731 | "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", 732 | "requires": { 733 | "psl": "^1.1.24", 734 | "punycode": "^1.4.1" 735 | } 736 | } 737 | } 738 | }, 739 | "request-promise-core": { 740 | "version": "1.1.2", 741 | "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.2.tgz", 742 | "integrity": "sha512-UHYyq1MO8GsefGEt7EprS8UrXsm1TxEvFUX1IMTuSLU2Rh7fTIdFtl8xD7JiEYiWU2dl+NYAjCTksTehQUxPag==", 743 | "requires": { 744 | "lodash": "^4.17.11" 745 | } 746 | }, 747 | "request-promise-native": { 748 | "version": "1.0.7", 749 | "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.7.tgz", 750 | "integrity": "sha512-rIMnbBdgNViL37nZ1b3L/VfPOpSi0TqVDQPAvO6U14lMzOLrt5nilxCQqtDKhZeDiW0/hkCXGoQjhgJd/tCh6w==", 751 | "requires": { 752 | "request-promise-core": "1.1.2", 753 | "stealthy-require": "^1.1.1", 754 | "tough-cookie": "^2.3.3" 755 | } 756 | }, 757 | "resolve": { 758 | "version": "1.10.0", 759 | "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.0.tgz", 760 | "integrity": "sha512-3sUr9aq5OfSg2S9pNtPA9hL1FVEAjvfOC4leW0SNf/mpnaakz2a9femSd6LqAww2RaFctwyf1lCqnTHuF1rxDg==", 761 | "dev": true, 762 | "requires": { 763 | "path-parse": "^1.0.6" 764 | } 765 | }, 766 | "resumer": { 767 | "version": "0.0.0", 768 | "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", 769 | "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", 770 | "dev": true, 771 | "requires": { 772 | "through": "~2.3.4" 773 | } 774 | }, 775 | "safe-buffer": { 776 | "version": "5.1.2", 777 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 778 | "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" 779 | }, 780 | "safer-buffer": { 781 | "version": "2.1.2", 782 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", 783 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" 784 | }, 785 | "sax": { 786 | "version": "1.2.4", 787 | "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", 788 | "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" 789 | }, 790 | "source-map": { 791 | "version": "0.6.1", 792 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", 793 | "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", 794 | "optional": true 795 | }, 796 | "sshpk": { 797 | "version": "1.16.1", 798 | "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", 799 | "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", 800 | "requires": { 801 | "asn1": "~0.2.3", 802 | "assert-plus": "^1.0.0", 803 | "bcrypt-pbkdf": "^1.0.0", 804 | "dashdash": "^1.12.0", 805 | "ecc-jsbn": "~0.1.1", 806 | "getpass": "^0.1.1", 807 | "jsbn": "~0.1.0", 808 | "safer-buffer": "^2.0.2", 809 | "tweetnacl": "~0.14.0" 810 | } 811 | }, 812 | "stealthy-require": { 813 | "version": "1.1.1", 814 | "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", 815 | "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=" 816 | }, 817 | "string.prototype.trim": { 818 | "version": "1.1.2", 819 | "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz", 820 | "integrity": "sha1-0E3iyJ4Tf019IG8Ia17S+ua+jOo=", 821 | "dev": true, 822 | "requires": { 823 | "define-properties": "^1.1.2", 824 | "es-abstract": "^1.5.0", 825 | "function-bind": "^1.0.2" 826 | } 827 | }, 828 | "symbol-tree": { 829 | "version": "3.2.2", 830 | "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz", 831 | "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=" 832 | }, 833 | "tape": { 834 | "version": "4.10.1", 835 | "resolved": "https://registry.npmjs.org/tape/-/tape-4.10.1.tgz", 836 | "integrity": "sha512-G0DywYV1jQeY3axeYnXUOt6ktnxS9OPJh97FGR3nrua8lhWi1zPflLxcAHavZ7Jf3qUfY7cxcVIVFa4mY2IY1w==", 837 | "dev": true, 838 | "requires": { 839 | "deep-equal": "~1.0.1", 840 | "defined": "~1.0.0", 841 | "for-each": "~0.3.3", 842 | "function-bind": "~1.1.1", 843 | "glob": "~7.1.3", 844 | "has": "~1.0.3", 845 | "inherits": "~2.0.3", 846 | "minimist": "~1.2.0", 847 | "object-inspect": "~1.6.0", 848 | "resolve": "~1.10.0", 849 | "resumer": "~0.0.0", 850 | "string.prototype.trim": "~1.1.2", 851 | "through": "~2.3.8" 852 | } 853 | }, 854 | "through": { 855 | "version": "2.3.8", 856 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", 857 | "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", 858 | "dev": true 859 | }, 860 | "tough-cookie": { 861 | "version": "2.5.0", 862 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", 863 | "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", 864 | "requires": { 865 | "psl": "^1.1.28", 866 | "punycode": "^2.1.1" 867 | } 868 | }, 869 | "tr46": { 870 | "version": "1.0.1", 871 | "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", 872 | "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", 873 | "requires": { 874 | "punycode": "^2.1.0" 875 | } 876 | }, 877 | "tunnel-agent": { 878 | "version": "0.6.0", 879 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", 880 | "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", 881 | "requires": { 882 | "safe-buffer": "^5.0.1" 883 | } 884 | }, 885 | "tweetnacl": { 886 | "version": "0.14.5", 887 | "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", 888 | "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=" 889 | }, 890 | "type-check": { 891 | "version": "0.3.2", 892 | "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", 893 | "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", 894 | "requires": { 895 | "prelude-ls": "~1.1.2" 896 | } 897 | }, 898 | "uri-js": { 899 | "version": "4.2.2", 900 | "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", 901 | "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", 902 | "requires": { 903 | "punycode": "^2.1.0" 904 | } 905 | }, 906 | "uuid": { 907 | "version": "3.3.2", 908 | "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", 909 | "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==" 910 | }, 911 | "verror": { 912 | "version": "1.10.0", 913 | "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", 914 | "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", 915 | "requires": { 916 | "assert-plus": "^1.0.0", 917 | "core-util-is": "1.0.2", 918 | "extsprintf": "^1.2.0" 919 | } 920 | }, 921 | "w3c-hr-time": { 922 | "version": "1.0.1", 923 | "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", 924 | "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", 925 | "requires": { 926 | "browser-process-hrtime": "^0.1.2" 927 | } 928 | }, 929 | "webidl-conversions": { 930 | "version": "4.0.2", 931 | "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", 932 | "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==" 933 | }, 934 | "whatwg-encoding": { 935 | "version": "1.0.5", 936 | "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", 937 | "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", 938 | "requires": { 939 | "iconv-lite": "0.4.24" 940 | } 941 | }, 942 | "whatwg-mimetype": { 943 | "version": "2.3.0", 944 | "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", 945 | "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==" 946 | }, 947 | "whatwg-url": { 948 | "version": "6.5.0", 949 | "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", 950 | "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", 951 | "requires": { 952 | "lodash.sortby": "^4.7.0", 953 | "tr46": "^1.0.1", 954 | "webidl-conversions": "^4.0.2" 955 | } 956 | }, 957 | "wordwrap": { 958 | "version": "1.0.0", 959 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", 960 | "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=" 961 | }, 962 | "wrappy": { 963 | "version": "1.0.2", 964 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", 965 | "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", 966 | "dev": true 967 | }, 968 | "ws": { 969 | "version": "5.2.3", 970 | "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.3.tgz", 971 | "integrity": "sha512-jZArVERrMsKUatIdnLzqvcfydI85dvd/Fp1u/VOpfdDWQ4c9qWXe+VIeAbQ5FrDwciAkr+lzofXLz3Kuf26AOA==", 972 | "requires": { 973 | "async-limiter": "~1.0.0" 974 | } 975 | }, 976 | "xml-name-validator": { 977 | "version": "3.0.0", 978 | "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", 979 | "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==" 980 | } 981 | } 982 | } 983 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mathjax-node", 3 | "version": "2.1.1", 4 | "description": "API's for calling MathJax from node.js", 5 | "keywords": [ 6 | "MathJax", 7 | "math", 8 | "svg", 9 | "HTML", 10 | "MathML", 11 | "TeX", 12 | "AsciiMath" 13 | ], 14 | "maintainers": [ 15 | "MathJax Consortium (http://www.mathjax.org)" 16 | ], 17 | "bugs": { 18 | "url": "http://github.com/mathjax/MathJax-node/issues" 19 | }, 20 | "license": "Apache-2.0", 21 | "repository": { 22 | "type": "git", 23 | "url": "git://github.com/mathjax/MathJax-node.git" 24 | }, 25 | "dependencies": { 26 | "is-fullwidth-code-point": "^2.0.0", 27 | "jsdom": "^11.0.0", 28 | "lodash": "^4.17.20", 29 | "mathjax": "^2.7.2" 30 | }, 31 | "engines": { 32 | "node": ">=6.0.0" 33 | }, 34 | "scripts": { 35 | "test": "tape test/*.js" 36 | }, 37 | "main": "./lib/main.js", 38 | "devDependencies": { 39 | "tape": "^4.0.3" 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /test/assets/test.js: -------------------------------------------------------------------------------- 1 | MathJax.Hub.Register.StartupHook("TeX Jax Ready", function () { 2 | MathJax.InputJax.TeX.Definitions.Add({ 3 | macros: { 4 | test: ["Macro", "\text{This is a Test}"] 5 | } 6 | }); 7 | }); 8 | 9 | MathJax.Ajax.loadComplete("[test]/test.js"); 10 | -------------------------------------------------------------------------------- /test/base-config-extensions.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require('../lib/main.js'); 3 | 4 | tape('Options "extension": multiple extensions', function(t) { 5 | t.plan(1); 6 | mjAPI.config({ 7 | extensions: 'TeX/autoload-all.js, TeX/color.js' 8 | }); 9 | mjAPI.typeset( 10 | { 11 | math: 'E = mc^2', 12 | format: 'TeX', 13 | mml: true 14 | }, 15 | function(data) { 16 | t.notOk( 17 | data.errors, 18 | 'Config block with multiple extensions throws no error' 19 | ); 20 | } 21 | ); 22 | }); 23 | -------------------------------------------------------------------------------- /test/base-config-fonturl.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var mjVersion = require('../package-lock.json').dependencies['mathjax'].version 4 | 5 | tape('basic configuration: check fontURL', function (t) { 6 | t.plan(2); 7 | 8 | var tex = 'a'; 9 | 10 | mjAPI.typeset({ 11 | math: tex, 12 | format: "TeX", 13 | css: true, 14 | htmlNode: true 15 | }, function (result, data) { 16 | var mjVersion = result.htmlNode.ownerDocument.defaultView.MathJax.version; 17 | var URL = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/' + mjVersion + '/fonts/HTML-CSS'; 18 | t.ok(result.css.indexOf(URL) > -1, 'Default fontURL'); 19 | 20 | // 21 | // reconfigure 22 | // 23 | mjAPI.config({ 24 | fontURL: 'https://example.com' 25 | }); 26 | mjAPI.start(); 27 | 28 | // 29 | // Next test 30 | // 31 | 32 | mjAPI.typeset({ 33 | math: 'a', 34 | format: "TeX", 35 | css: true, 36 | }, function (result, data) { 37 | t.ok(result.css.indexOf('https://example.com') > -1, 'Configuring fontURL'); 38 | // 39 | // reconfigure 40 | // 41 | mjAPI.config({fontURL: ''}); 42 | mjAPI.start(); 43 | }); 44 | 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/base-errors-startup.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require('../lib/main.js'); 3 | 4 | tape('Catch errors during startup phase', function(t) { 5 | t.plan(1); 6 | mjAPI.config({ 7 | extensions: 'blargh' 8 | }); 9 | mjAPI.start(); 10 | mjAPI.typeset( 11 | { 12 | math: 'x', 13 | format: 'TeX', 14 | mml: true 15 | }, 16 | function(data) { 17 | t.ok( 18 | data.errors, 19 | 'Error (loading non-existent extension) is caught in output' 20 | ); 21 | // reset configuration 22 | mjAPI.config({ 23 | extensions: '' 24 | }); 25 | mjAPI.start(); 26 | } 27 | ); 28 | }); 29 | -------------------------------------------------------------------------------- /test/base-mathjax.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('basic test: check MathJax core', function(t) { 5 | t.plan(2); 6 | 7 | var tex = ''; 8 | 9 | mjAPI.typeset({ 10 | math: tex, 11 | format: "TeX", 12 | mml: true 13 | }, function(result,data) { 14 | t.ok(result.mml, 'MathJax core seems ok'); 15 | t.ok(data.format, 'MathJax input preserved'); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/base-typeset-promise.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('basic test: check typeset promise API', function (t) { 5 | t.plan(2); 6 | 7 | mjAPI.config({displayErrors: false}); 8 | 9 | var tex = ''; 10 | 11 | // 12 | // promise resolved 13 | // 14 | mjAPI.typeset({ 15 | math: tex, 16 | format: "TeX", 17 | mml: true 18 | }).then((result) => t.ok(result.mml, 'Typset promise resolved on success')); 19 | 20 | // 21 | // promise frejected 22 | // 23 | mjAPI.typeset({ 24 | math: tex, 25 | format: "MathML", 26 | mml: true 27 | }).catch((error) => t.ok(error, 'Typeset promise rejected on error')); 28 | 29 | // 30 | // reset configuration 31 | // 32 | mjAPI.typeset({math: '', format: 'TeX', mml: true}, () => { 33 | mjAPI.config({displayErrors: true}); 34 | }); 35 | 36 | }); 37 | -------------------------------------------------------------------------------- /test/base-warnings.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | mjAPI.config({undefinedCharError: true}); 4 | 5 | tape('basic test: check warnings', function (t) { 6 | t.plan(2); 7 | 8 | mjAPI.config({displayErrors: false}); 9 | 10 | mjAPI.typeset({math:'\u5475', html:true}) 11 | .catch(errors => t.ok(errors, 'CommonHTML output reports error')); 12 | mjAPI.typeset({math:'\u5475', svg:true}) 13 | .catch(errors => t.ok(errors, 'SVG output reports error')); 14 | 15 | // 16 | // reset configuration 17 | // 18 | mjAPI.typeset({math: '', format: 'TeX', mml: true}, () => { 19 | mjAPI.config({displayErrors: true}); 20 | }); 21 | 22 | }); 23 | -------------------------------------------------------------------------------- /test/config-third-party-extensions.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | const path = require('path'); 4 | 5 | tape('Configuring third party extensions', function(t) { 6 | t.plan(1); 7 | 8 | mjAPI.config( { 9 | extensions: '[test]/test.js', 10 | paths: { 11 | 'test': path.join(__dirname,'assets/') 12 | } 13 | }); 14 | mjAPI.start(); 15 | 16 | var tex = '\\test'; 17 | 18 | mjAPI.typeset({ 19 | math: tex, 20 | format: "TeX", 21 | mmlNode: true 22 | }, function(data) { 23 | t.notOk(data.errors, 'No error loading the extension'); 24 | // 25 | // reset configuration 26 | // 27 | mjAPI.config({extensions: '', paths: {}}); 28 | mjAPI.start(); 29 | }); 30 | 31 | }); 32 | -------------------------------------------------------------------------------- /test/css.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('CSS output', function(t) { 5 | t.plan(3); 6 | 7 | mjAPI.typeset({ 8 | math: tex, 9 | format: "TeX", 10 | css: true 11 | }, function(data) { 12 | t.ok(data.css, 'css output while no other output'); 13 | }); 14 | 15 | var tex = 'x'; 16 | 17 | mjAPI.typeset({ 18 | math: tex, 19 | format: "TeX", 20 | css: true, 21 | svg: true 22 | }, function(data) { 23 | t.ok(data.css, 'css output created alongside SVG output'); 24 | t.ok(data.svg, 'svg output is created'); 25 | }); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/issue104.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var JSDOM = require('jsdom').JSDOM; 4 | 5 | tape('the SVG width should match the default', function(t) { 6 | t.plan(1); 7 | 8 | var tex = 'a \\\\ b'; 9 | var expected = '100ex'; 10 | 11 | mjAPI.typeset({ 12 | math: tex, 13 | format: "TeX", 14 | svg: true 15 | }, function(data) { 16 | var window = new JSDOM(data.svg).window; 17 | var document = window.document; 18 | var element = window.document.getElementsByTagName("svg")[0]; 19 | var width = element.getAttribute('width'); 20 | t.equal(width, expected); 21 | }); 22 | 23 | }); 24 | -------------------------------------------------------------------------------- /test/issue175.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var JSDOM = require('jsdom').JSDOM; 4 | 5 | tape('color extension should be reset', function(t) { 6 | t.plan(3); 7 | 8 | mjAPI.config({displayErrors: false}); 9 | 10 | var tex = '\\colorbox{green}{x}'; 11 | var tex2 = '\\color{red}{x}x'; 12 | 13 | mjAPI.typeset({ 14 | math: tex, 15 | format: "TeX", 16 | mml: true 17 | }, function(data) { 18 | t.ok(data.errors, 'Color extension disabled'); 19 | }); 20 | 21 | mjAPI.typeset({ 22 | math: tex2, 23 | format: "TeX", 24 | mml: true 25 | }, function(data) { 26 | var document = new JSDOM(data.mml).window.document; 27 | var mstyle = document.querySelector('mstyle'); 28 | t.ok(document.querySelectorAll('mi')[0].parentNode === mstyle, 'Color macro behaves correctly (1 of 2)'); 29 | t.notOk(document.querySelectorAll('mi')[1].parentNode === mstyle, 'Color macro behaves correctly (2 of 2)'); 30 | mjAPI.config({displayErrors: true}); // reset configuration 31 | }); 32 | 33 | }); 34 | -------------------------------------------------------------------------------- /test/issue207.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var JSDOM = require('jsdom').JSDOM; 4 | 5 | tape('Generate dummy speechText', function(t) { 6 | t.plan(9); 7 | 8 | var input1 = 'source'; 9 | var input2 = 'x'; 10 | var input3 = 'x'; 11 | var expected1 = 'source'; 12 | var expected2 = 'alttext'; 13 | var expected3 = 'Equation'; 14 | var desc1 = 'source'; 15 | var desc2 = 'original MathML alttext'; 16 | var desc3 = 'default dummy value'; 17 | 18 | mjSpeechTest = function(data, expected, desc) { 19 | var document = new JSDOM(data.html).window.document; 20 | var element = document.querySelector('.mjx-math'); 21 | var actual = element.getAttribute('aria-label'); 22 | t.equal(actual, expected, 'HTML output contains speechText from ' + desc); 23 | document = new JSDOM(data.mml).window.document; 24 | element = document.querySelector('math'); 25 | actual = element.getAttribute('alttext'); 26 | t.equal(actual, expected, 'MathML output contains speechText from ' + desc); 27 | document = new JSDOM(data.svg).window.document; 28 | var svgTitle = document.querySelector('title'); 29 | actual = svgTitle.innerHTML; 30 | t.equal(actual, expected, 'SVG output contains speechText from ' + desc); 31 | }; 32 | 33 | // 34 | // TeX source 35 | // 36 | mjAPI.typeset({ 37 | math: input1, 38 | format: "TeX", 39 | html: true, 40 | svg: true, 41 | mml: true 42 | }, function(data) {mjSpeechTest(data, expected1, desc1)}); 43 | 44 | // 45 | // MathML alttext 46 | // 47 | mjAPI.typeset({ 48 | math: input2, 49 | format: "MathML", 50 | html: true, 51 | svg: true, 52 | mml: true 53 | }, function(data) {mjSpeechTest(data, expected2, desc2)}); 54 | 55 | // 56 | // MathML without alttext 57 | // 58 | mjAPI.typeset({ 59 | math: input3, 60 | format: "MathML", 61 | html: true, 62 | svg: true, 63 | mml: true 64 | }, function(data) {mjSpeechTest(data, expected3, desc3)}); 65 | 66 | }); 67 | -------------------------------------------------------------------------------- /test/issue215.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var JSDOM = require('jsdom').JSDOM; 4 | 5 | tape('HTML output should remove automatically generated IDs', function(t) { 6 | t.plan(2); 7 | 8 | var tex = 'a \\\\ b'; 9 | var expected = '100ex'; 10 | 11 | mjAPI.typeset({ 12 | math: tex, 13 | format: "TeX", 14 | html: true 15 | }, function(data) { 16 | var document = new JSDOM(data.html).window.document; 17 | var id = document.querySelector('[id^="MJXc-Node-"]'); 18 | var frame = document.querySelector('[id^="MathJax-Element-"]'); 19 | t.notOk(id, 'automatic ids successfully removed'); 20 | t.notOk(frame, 'MathJax-Element-[n]-frame id successfully removed'); 21 | }); 22 | 23 | }); 24 | -------------------------------------------------------------------------------- /test/issue219.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var JSDOM = require('jsdom').JSDOM; 4 | 5 | tape('Basic Check: pass jsdom object to output', function(t) { 6 | t.plan(3); 7 | 8 | var tex = 'x'; 9 | 10 | mjAPI.typeset({ 11 | math: tex, 12 | format: "TeX", 13 | html: true, 14 | htmlNode: true, 15 | svg: true, 16 | svgNode: true, 17 | mml: true, 18 | mmlNode: true 19 | }, function(data) { 20 | var window = new JSDOM().window; 21 | t.ok(data.htmlNode instanceof window.HTMLElement, 'htmlNode is an HTMLElement'); 22 | t.ok(data.svgNode instanceof window.SVGElement, 'svgNode is an SVGElement'); 23 | t.ok(data.mmlNode instanceof window.Element, 'mmlNode is an Element'); 24 | }); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /test/issue220.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var JSDOM = require('jsdom').JSDOM; 4 | 5 | tape('displayAlign:left in HTML output', function(t) { 6 | t.plan(1); 7 | 8 | mjAPI.config({MathJax: {"displayAlign": "left"}}); 9 | mjAPI.start(); 10 | 11 | var tex = 'x'; 12 | var expected = "text-align: left;"; 13 | 14 | mjAPI.typeset({ 15 | math: tex, 16 | format: "TeX", 17 | html: true 18 | }, function(data) { 19 | var document = new JSDOM(data.html).window.document; 20 | var element = document.getElementsByClassName("MJXc-display")[0]; 21 | var result = element.getAttribute('style'); 22 | t.equal(result, expected); 23 | // 24 | // reset configuration 25 | // 26 | mjAPI.config({MathJax: {}}); 27 | mjAPI.start(); 28 | }); 29 | 30 | }); 31 | -------------------------------------------------------------------------------- /test/issue223.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var JSDOM = require('jsdom').JSDOM; 4 | 5 | tape('displayIndent:left in HTML output', function(t) { 6 | t.plan(2); 7 | 8 | mjAPI.config({MathJax: {displayIndent: '10em'}}); 9 | mjAPI.start(); 10 | 11 | var first = 'x'; 12 | var second = 'x \\tag{1}' 13 | expected = "10em"; 14 | 15 | // 16 | // basic text 17 | // 18 | mjAPI.typeset({ 19 | math: first, 20 | format: "TeX", 21 | html: true 22 | }, function(data) { 23 | var document = new JSDOM(data.html).window.document; 24 | var element = document.getElementsByClassName('MJXc-display')[0]; 25 | var result = element.style.marginLeft; 26 | t.ok((result === expected), 'style includes a margin'); 27 | }); 28 | 29 | // 30 | // test for mlabeledtr 31 | // 32 | mjAPI.typeset({ 33 | math: second, 34 | format: "TeX", 35 | html: true 36 | }, function(data) { 37 | var document = new JSDOM(data.html).window.document; 38 | var element = document.getElementsByClassName('mjx-table')[0]; 39 | var result = element.style.marginLeft; 40 | t.ok((result === expected), 'style includes a margin'); 41 | // 42 | // reset configuration 43 | // 44 | mjAPI.config({MathJax: {}}); 45 | mjAPI.start(); 46 | }); 47 | 48 | }); 49 | -------------------------------------------------------------------------------- /test/issue241.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('SVG output: add xlink to href in ', function(t) { 5 | t.plan(1); 6 | 7 | var mml = ''; 8 | var expected = /xlink:href/; 9 | 10 | mjAPI.typeset({ 11 | math: mml, 12 | format: "MathML", 13 | svg: true 14 | }, function(data) { 15 | t.ok(data.svg.match(expected)); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/issue260.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require('../lib/main.js'); 3 | 4 | tape('getSVG should increment state.ID', function(t) { 5 | t.plan(1); 6 | 7 | var mml = '1'; 8 | var state = {}; 9 | 10 | mjAPI.typeset({ 11 | math: mml, 12 | format: 'MathML', 13 | speakText: true, 14 | svg: true, 15 | state: state}, function(data) {}); 16 | mjAPI.typeset({ 17 | math: mml, 18 | format: 'MathML', 19 | speakText: true, 20 | svg: true, 21 | state: state 22 | }, function(data) { 23 | t.equal(state.ID, 2, 'state.ID incremented') 24 | }); 25 | 26 | }); 27 | -------------------------------------------------------------------------------- /test/issue276.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var JSDOM = require('jsdom').JSDOM; 4 | 5 | tape('SVG output: physical units', function(t) { 6 | t.plan(1); 7 | 8 | var mml = ''; 9 | 10 | mjAPI.typeset({ 11 | math: mml, 12 | format: "MathML", 13 | svg: true 14 | }, function(data) { 15 | var document = new JSDOM(data.svg).window.document; 16 | var width = document.querySelector('svg').getAttribute('width'); 17 | t.notEqual(width, '0', ''); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/issue277.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('mmlNode should not produce mml', function(t) { 5 | t.plan(1); 6 | 7 | var tex = 'x'; 8 | 9 | mjAPI.typeset({ 10 | math: tex, 11 | format: "TeX", 12 | mmlNode: true 13 | }, function(data) { 14 | t.ok(data.mml === undefined, 'mml not generated'); 15 | }); 16 | 17 | }); 18 | -------------------------------------------------------------------------------- /test/issue288.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('HTML output when requesting both SVG and HTML', function(t) { 5 | t.plan(2); 6 | 7 | var tex = 'x'; 8 | 9 | mjAPI.typeset({ 10 | math: tex, 11 | format: "TeX", 12 | htmlNode: true, 13 | svgNode: true 14 | }, function(data) { 15 | t.equal(data.htmlNode.className, 'mjx-chtml MJXc-display', 'htmlNode output is correct'); 16 | }); 17 | 18 | mjAPI.typeset({ 19 | math: tex, 20 | format: "TeX", 21 | html: true, 22 | svgNode: true 23 | }, function(data) { 24 | t.ok(data.html, 'html output is present') 25 | }); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/issue289.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('HTML output: add aria-label to correct childnode', function(t) { 5 | t.plan(1); 6 | 7 | var mml = '1'; 8 | 9 | mjAPI.typeset({ 10 | math: mml, 11 | format: "MathML", 12 | htmlNode: true, 13 | html: true 14 | }, function(data) { 15 | t.equal(data.htmlNode.parentNode.querySelectorAll('[aria-label]').length, 1, 'Aria-label is unique'); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/mathjax-config-combined.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('MathJax configuration: strip config block', function (t) { 5 | t.plan(1); 6 | 7 | mjAPI.config({ 8 | MathJax: { 9 | config: ["TeX-AMS_SVG.js"] 10 | } 11 | }); 12 | mjAPI.start(); 13 | 14 | mjAPI.typeset({ 15 | math: 'E = mc^2', 16 | format: "TeX", 17 | mml: true, 18 | }, function (data) { 19 | t.ok(data, 'Config block did not cause errors'); 20 | // 21 | // reset configuration 22 | // 23 | mjAPI.config({MathJax: {}}); 24 | mjAPI.start(); 25 | }); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/output-html-linebreaks-manual.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('Output, HTML: linebreaks, manual', function(t) { 5 | t.plan(1); 6 | 7 | var tex = 'A \\\\ B'; 8 | var expected = '' 9 | 10 | mjAPI.typeset({ 11 | math: tex, 12 | format: "TeX", 13 | html: true 14 | }, function(data) { 15 | t.equal(data.html, expected, 'HTML output as expected'); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/pass_data.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('Passing data along', function(t) { 5 | t.plan(1); 6 | 7 | var tex = 'x'; 8 | 9 | mjAPI.typeset({ 10 | math: tex, 11 | format: "TeX", 12 | css: true, 13 | something: 'expected', 14 | }, function(data, input) { 15 | t.equal(input.something, 'expected', 'Data was passed along to output'); 16 | }); 17 | 18 | }); 19 | -------------------------------------------------------------------------------- /test/svg-full-width-chars.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('the SVG output should renders full-width characters correctly', function(t) { 5 | t.plan(1); 6 | 7 | mjAPI.config({displayErrors: false}); 8 | 9 | var tex = '\\text{\u62FE\u96F6}^i'; 10 | 11 | mjAPI.typeset({ 12 | math: tex, 13 | format: "TeX", 14 | svg: true 15 | }, function(data) { 16 | t.ok(data.width, '5.133ex', 'Width is correct'); 17 | mjAPI.config({displayErrors: true}); // reset configuration 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/svg-metadata.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | var jsdom = require('jsdom').jsdom; 4 | 5 | tape('the SVG output should add dimensions and styles', function(t) { 6 | t.plan(3); 7 | 8 | var tex = 'a + b'; 9 | 10 | mjAPI.typeset({ 11 | math: tex, 12 | format: "TeX", 13 | svg: true 14 | }, function(data) { 15 | t.ok(data.width, 'Width is present'); 16 | t.ok(data.height, 'Height is present'); 17 | t.ok(data.style, 'Style is present'); 18 | }); 19 | 20 | }); 21 | -------------------------------------------------------------------------------- /test/useFontCache.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('basic configuration: useFontCache', function (t) { 5 | t.plan(2); 6 | 7 | var tex = 'a'; 8 | 9 | mjAPI.typeset({ 10 | math: tex, 11 | format: "TeX", 12 | svg: true, 13 | useFontCache: false 14 | }, function (result, data) { 15 | t.ok(result.svg.indexOf(' -1, 'useFontCache set to true'); 25 | }); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/userconfig-autoload.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require("../lib/main.js"); 3 | 4 | tape('User config: autoload-all should enable color extension', function(t) { 5 | t.plan(1); 6 | 7 | mjAPI.config( { 8 | extensions: 'TeX/autoload-all', // a convenience option to add MathJax extensions 9 | }); 10 | mjAPI.start(); 11 | 12 | var tex = '\\definecolor{myorange}{RGB}{255,165,100}\\color{myorange}e^{i \\pi}\\color{Black} = -1'; 13 | 14 | mjAPI.typeset({ 15 | math: tex, 16 | format: "inline-TeX", 17 | mml: true 18 | }, function(data) { 19 | t.ok(!data.errors, 'definecolor should be a known function'); 20 | // 21 | // reset configuration 22 | // 23 | mjAPI.config({extenstion: ''}); 24 | mjAPI.start(); 25 | }); 26 | 27 | }); 28 | -------------------------------------------------------------------------------- /test/userconfig-jax.js: -------------------------------------------------------------------------------- 1 | var tape = require('tape'); 2 | var mjAPI = require('../lib/main.js'); 3 | 4 | tape('User configuration with jax array', function (t) { 5 | t.plan(1); 6 | 7 | mjAPI.config({ 8 | MathJax: { 9 | jax: ["input/MathML", "output/SVG"] 10 | } 11 | }); 12 | mjAPI.start(); 13 | 14 | mjAPI.typeset({ 15 | math: '1', 16 | format: 'MathML', 17 | svg: true 18 | }, function (data) { 19 | t.ok(!data.errors, 'No errors'); 20 | // 21 | // reset configuration 22 | // 23 | mjAPI.config({MathJax: {}}); 24 | mjAPI.start(); 25 | }); 26 | 27 | }); 28 | --------------------------------------------------------------------------------