diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 000000000..040bc1b6e --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,54 @@ +name: Docs + +on: + push: + branches: + - develop + +# Allows you to run this workflow manually from the Actions tab + workflow_dispatch: + +# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages +permissions: + contents: read + pages: write + id-token: write + +# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued. +# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete. +concurrency: + group: "pages" + cancel-in-progress: false + +jobs: + docs: + environment: + name: github-pages + url: ${{ steps.deployment.outputs.page_url }} + runs-on: ubuntu-latest + name: Generate Code Docs + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + version: 10 + run_install: false + + - name: Install packages + run: pnpm i + + - name: Build docs + run: pnpm typedoc + + - name: Upload artifact + uses: actions/upload-pages-artifact@v3 + with: + # Upload docs folder + path: './docs' + + - name: Deploy to GitHub Pages + id: deployment + uses: actions/deploy-pages@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 000000000..3d4e9f906 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,43 @@ +name: Release + +on: + release: + types: [published] + +jobs: + setup: + runs-on: ubuntu-latest + name: Build and publish MathJax + permissions: + contents: read + id-token: write + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + version: 10 + run_install: false + registry-url: 'https://registry.npmjs.org' + + - name: Install packages + run: pnpm i + + - name: Build MathJax + run: | + ./components/bin/version + pnpm -s link:src + pnpm -s build-all + + - name: Temp fix to publish + run: | + echo "//registry.npmjs.org/:_authToken=${{ secrets.NPM_TOKEN }}" > ~/.npmrc + echo "always-auth=true" >> ~/.npmrc + + - name: Publish to npmjs + run: pnpm publish --access public --no-git-checks + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 000000000..4a0da0f71 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,49 @@ +name: Tests + +on: + push: + branches: + - develop + pull_request: + branches: + - develop + +jobs: + setup: + runs-on: ubuntu-latest + name: Compile and test MathJax + steps: + - name: Checkout + uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + name: Install pnpm + with: + version: 10 + run_install: false + + - name: Install packages + run: | + pnpm -r i + pnpm -s link:src + + - name: Compile MathJax + run: | + pnpm -s mjs:compile + components/bin/makeAll --mjs --terse --build components/mjs + pnpm -s cjs:compile + pnpm -s cjs:components:src:build + components/bin/makeAll --cjs --terse --build components/cjs + pnpm -s copy:pkg cjs + + - name: Build tests + run: pnpm tsc -p testsuite/tsconfig.json + + - name: Run tests + run: pnpm -s test:gh + + - name: Upload coverage reports to Codecov + uses: codecov/codecov-action@v5 + with: + token: ${{ secrets.CODECOV_TOKEN }} + slug: mathjax/MathJax-src diff --git a/.gitignore b/.gitignore index c6aca5c5a..b16c8614b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,11 @@ *~ node_modules -components/src/**/lib -js -es5 +coverage +/components/mjs/**/lib +/components/cjs +/cjs +/mjs +/bundle +/bundle-cjs +/testsuite/js +/lab/sre.js diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100755 index 000000000..cb2c84d5c --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +pnpm lint-staged diff --git a/.husky/pre-push b/.husky/pre-push new file mode 100755 index 000000000..ed4148f2c --- /dev/null +++ b/.husky/pre-push @@ -0,0 +1 @@ +# pnpm test diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..c1a6f6671 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,4 @@ +{ + "singleQuote": true, + "trailingComma": "es5" +} diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 807461f62..000000000 --- a/.travis.yml +++ /dev/null @@ -1,21 +0,0 @@ -dist: focal -language: node_js -node_js: -- stable -sudo: false -script: -- components/bin/version -- npm install -- npm run compile -- npm run make-components -branches: - only: - - "/^\\d+\\.\\d+/" -deploy: - provider: npm - email: manager@mathjax.org - api_key: - secure: iiJYaydsd6nypSMgjvQiTYIy+YF/oil5fqfVLmMkAQtykAqE5oS/HcJ6QxQa8DKHQCmNNhmUqMnD7H5jVhXGcbhEcx7dNxr7pXkrY2Vkyj8voYFIfZ05rwfaojQQPlPdrkwiLmAcUnz1v9gP20M6uVJrhVpBSe4bfHxSHbSUBjlRu4md8fXyA9cLJ3hu/QHV2ahjRDHL+axklCH8YFMW2bN7IRYALUaFeN6gZFWQvq6A4gT1zaFo0yTsej5z+PmyvDHYGzI1KfUioNa81KMWvSMIkRooJes2JrDFdo4HYXgYhZ/wb+7FLOJGeLLQejfQiVw+MS+7R+C6Ss/TcxddeBGg+x9+pZY4AvnVjuWfYW7WSh+iMZ1ujFE3xhqjVUI6WpowSfLK2lguY/8AZ1hKuWxnWw/UwCGcy6qOG0HMyE05mkl+VvPMITckkkeM/an4k7PeR+DY9L25Imp0jmpCyfk72KXMAEgVLAjnsy+l0EnZWK7oeYzDwEaw8HdOCmKKraRYFSetbqC+25g1iKc8ylTs1IxN7HXo0e0dTGSxwtU14L26GMHrC2pVsDdeR7+b5ll0C/6kevK794eQpzSEM50Addb1+fUJ3bn1y22H7OaglnJYxfuP44AYTENOn3fDJrIgcVG/yp273MImSYZiXL+xQBK8ZPEG5z36sH5/iAI= - on: - tags: true - skip_cleanup: true diff --git a/README.md b/README.md index 9b4ac4057..160e6de4a 100644 --- a/README.md +++ b/README.md @@ -3,13 +3,14 @@ ![GitHub release version](https://img.shields.io/github/v/release/mathjax/MathJax-src.svg?sort=semver) ![GitHub release version (v2)](https://img.shields.io/github/package-json/v/mathjax/MathJax/legacy-v2.svg?label=release-v2) ![NPM version](https://img.shields.io/npm/v/mathjax.svg?style=flat) -![powered by NumFOCUS](https://img.shields.io/badge/powered%20by-NumFOCUS-orange.svg?style=flat) ![jsdelivr rank](https://flat.badgen.net/jsdelivr/rank/npm/mathjax?color=green) ![jsDelivr hits (npm)](https://img.shields.io/jsdelivr/npm/hm/mathjax) ![npm monthly downloads (full)](https://img.shields.io/npm/dm/mathjax?label=npm) ![npm monthly downloads (full)](https://img.shields.io/npm/dm/mathjax-full?label=npm%20%28full%29) ![npm total downloads](https://img.shields.io/npm/dt/mathjax.svg?style=flat&label=npm%20total) ![npm total downloads](https://img.shields.io/npm/dt/mathjax-full.svg?style=flat&label=npm%20total%20%28full%29) +![test workflow](https://github.com/MathJax/MathJax-src/actions/workflows/test.js.yml/badge.svg?branch=develop) +[![codecov](https://codecov.io/gh/mathjax/mathjax-src/branch/develop/graph/badge.svg)](https://codecov.io/gh/mathjax/mathjax-src/tree/develop) ## Beautiful math in all browsers diff --git a/components/bin/build b/components/bin/build index d9a9d5836..68360eac4 100755 --- a/components/bin/build +++ b/components/bin/build @@ -2,7 +2,7 @@ /************************************************************* * - * Copyright (c) 2018 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,21 +35,31 @@ const INDENT = ' '; /** * The pattern to use when looking for explort commands to process */ -const EXPORTPATTERN = /(^export(?:\s+default)?(?:\s+abstract)?\s+[^ {*}]+\s+[a-zA-Z0-9_.$]+)/m; +const EXPORTPATTERN = + /(^export(?:\s+(?:default|abstract|async))?\s+(?:[^ {*}]+\s+(?:enum\s+)?[a-zA-Z0-9_.$]+|\{.* as .*\}))/m; const EXPORT_IGNORE = ['type', 'interface']; -const EXPORT_PROCESS = ['let', 'const', 'var', 'function', 'class', 'namespace']; +const EXPORT_PROCESS = ['let', 'const', 'var', 'function', 'class', 'namespace', 'enum', 'as']; /** - * The relative path to the MathJax directory + * The module type to use ('cjs' or 'mjs') */ -const mjPath = path.relative(process.cwd(), path.resolve(__dirname, '..', '..', 'js')); -const mjGlobal = path.join('..', mjPath, 'components', 'global.js'); +const target = (process.argv[2] || 'mjs'); /** * Read the configuration for the component */ -const config = JSON.parse(fs.readFileSync(process.argv[2] || 'build.json')); +const json = path.resolve(process.argv[3] || '.', 'config.json'); +const config = require(json).build; +if (!config) process.exit() +process.chdir(path.dirname(json)); + + +/** + * The relative path to the MathJax directory + */ +const mjPath = path.relative(process.cwd(), path.resolve(__dirname, '..', '..', target)); +const mjGlobal = path.join('..', mjPath, 'components', 'global.js'); function getType() { const component = config.component || 'part'; @@ -66,13 +76,14 @@ const COMPONENT = path.basename(config.component || 'part'); // n const ID = config.id || config.component || 'part'; // the ID of the component const TARGETS = config.targets || []; // the files to include in the component const EXCLUDE = new Map((config.exclude || []).map(name => [name, true])); // files to exclude from the component -const EXCLUDESUBDIRS = config.excludeSubdirs === 'true'; // exclude subdirectories or not +const EXCLUDESUBDIRS = !!config.excludeSubdirs; // exclude subdirectories or not const JS = config.js || config.mathjax || mjPath; // path to the compiled .js files const LIB = config.lib || './lib'; // path to the lib directory to create -const TS = config.ts || JS.replace(/js$/, 'ts'); // path to the .ts files +const TS = config.ts || path.join(JS, '..', 'ts'); // path to the .ts files const GLOBAL = config.global || mjGlobal; // path to the global.js file const VERSION = config.version || mjGlobal.replace(/global/, 'version'); // path to the version.js file const TYPE = config.type || getType(); // the module type +const PREFIX = config.prefix || ''; // directories to add to any ts files /** * The list of files that need to be added to the lib directory @@ -96,7 +107,7 @@ function processList(base, dir, list, top = true) { if (top || !EXCLUDESUBDIRS) { processDir(base, file); } - } else if (file.match(/\.ts$/)) { + } else if (file.match(/(? 3 ? words[n - 3] : words[n - 2]); + const name = words[n - 1].replace(/\}$/, ''); if (words[1] === 'default' || type === 'default') { objects.push('default'); @@ -165,24 +177,31 @@ function processParts(parts) { * Create the lines of the lib file using the object names from the file. * * @param {string} name The path of the file relative to the root .ts directory - * @param {string[]} objects Array of names of the object exported by the file + * @param {string[]} objects Array of names of the objects exported by the file * @return {string[]} Array of lines for the contents of the library file */ function processLines(file, objects) { if (objects.length === 0) return []; - const dir = path.dirname(file).replace(/^\.$/, ''); + const base = path.dirname(file).replace(/^\.$/, ''); + const dir = (PREFIX ? path.join(PREFIX, base) : base); const dots = dir.replace(/[^\/]+/g, '..') || '.'; const relative = path.join(dots, '..', JS, dir, path.basename(file)).replace(/\.ts$/, '.js'); const name = path.parse(file).name; - const lines = [ + const lines = (target === 'mjs' ? [] : [ '"use strict";', - `Object.defineProperty(exports, '__esModule', {value: true});` - ]; + `Object.defineProperty(exports, '__esModule', {value: true});`, + ]); let source = ((dir.replace(/\//g, '.') + '.' + name).replace(/^\./, '') + (exists(path.resolve(JS, file.replace(/\.ts$/, ''))) ? '_ts' : '')) - .replace(/\.[^.]*/g, (x) => (x.substr(1).match(/[^a-zA-Z_]/) ? '[\'' + x.substr(1) + '\']' : x)); + .replace(/\.[^.]*/g, (x) => (x.substring(1).match(/[^a-zA-Z_]/) ? '[\'' + x.substring(1) + '\']' : x)); + lines.push( + objects.indexOf('MathJax') >= 0 ? + `const g = (typeof window !== 'undefined' ? window : global);\nconst def = g.MathJax._.${source};` : + `const def = MathJax._.${source};` + ); for (const id of objects) { - lines.push(`exports.${id} = MathJax._.${source}.${id};`); + lines.push(target === 'cjs' ? `exports.${id} = def.${id};` : + id === 'default' ? `export default def.${id};` : `export const ${id} = def.${id};`); } return lines; } @@ -221,26 +240,51 @@ function makeDir(dir) { */ function makeFile(file, lines) { if (!lines.length) return; - const [dir, name] = [path.dirname(file), path.basename(file)]; + const basedir = path.dirname(file); + const [dir, name] = [PREFIX ? path.join(PREFIX, basedir) : basedir, path.basename(file)]; makeDir(dir); fs.writeFileSync(path.resolve(LIB, dir, name.replace(/\.ts$/, '.js')), lines.join('\n') + '\n'); } +/** + * @return {[string, string, string]} The needed nesting data for handking extra directories from a prefix + */ +function getExtraDirectories() { + if (PREFIX === '') return ['', INDENT, '']; + let prefix = ''; + let indent = INDENT; + let postfix = ''; + for (let name of PREFIX.split(/\//)) { + if (name.match(/[^a-zA-Z0-9]/)) { + name = `"${name}"`; + } + prefix += indent + name + ': {\n'; + postfix = '\n' + indent + '}' + postfix; + indent += INDENT; + } + return [prefix, indent, postfix]; +} + /** * Make the library file that adds all the exported objects into the MathJax global object */ function processGlobal() { console.info(' ' + COMPONENT + '.ts'); - const lines = [ + const lines = (target === 'cjs' ? [ + `const {combineWithMathJax} = require('${GLOBAL}')`, + `const {VERSION} = require('${VERSION}');`, + '', + ] : [ `import {combineWithMathJax} from '${GLOBAL}';`, `import {VERSION} from '${VERSION}';`, '', - ]; + ]); + const [prefix, indent, postfix] = getExtraDirectories(); const packages = []; PACKAGE = PACKAGE.sort(sortDir); while (PACKAGE.length) { const dir = path.dirname(PACKAGE[0]).split(path.sep)[0]; - packages.push(processPackage(lines, INDENT, dir)); + packages.push(processPackage(lines, indent, dir)); } const name = (ID.match(/[^a-zA-Z0-9_]/) ? `"${ID}"` : ID); lines.push( @@ -250,9 +294,10 @@ function processGlobal() { '}', '', `combineWithMathJax({_: {`, - INDENT + packages.join(',\n' + INDENT), + prefix + indent + packages.join(',\n' + indent) + postfix, '}});' ); + makeDir(''); fs.writeFileSync(path.join(LIB, COMPONENT + '.js'), lines.join('\n') + '\n'); } @@ -279,12 +324,12 @@ function processPackage(lines, space, dir) { // // Loop through the lines that are in the current directory // - while (PACKAGE.length && (PACKAGE[0].substr(0, dir.length) === dir || dir === '.')) { + while (PACKAGE.length && (PACKAGE[0].substring(0, dir.length) === dir || dir === '.')) { // // If the current package is in this directory (not a subdirectory) // Get the location of transpiled mathjax file // Get the name to use for the data from that file - // Create an entry for the file in the MathJax global that loads the reuired component + // Create an entry for the file in the MathJax global that loads the required component // Otherwise (its in a subdirectory) // Get the subdirectory name // Process the subdirectory using an additional indentation @@ -292,9 +337,13 @@ function processPackage(lines, space, dir) { if (path.dirname(PACKAGE[0]) === dir) { const file = PACKAGE.shift(); const name = path.basename(file); - const relativefile = path.join('..', JS, dir, name).replace(/\.ts$/, '.js'); + let relativefile = path.join('..', JS, dir, name).replace(/\.ts$/, '.js') const component = 'module' + (++importCount); - lines.push(`import * as ${component} from '${relativefile}';`); + lines.push( + target === 'cjs' ? + `const ${component} = require('${relativefile}');` : + `import * as ${component} from '${relativefile}';` + ); let property = name.replace(/\.ts$/, ''); if (property !== name && exists(path.resolve(JS, file.replace(/\.ts$/, '')))) { property += '_ts'; @@ -315,7 +364,11 @@ function processPackage(lines, space, dir) { // Create the string defining the object that loads all the needed files into the proper places // if (dir === '.') return packages.join(',\n '); - return path.basename(dir) + ': {\n' + INDENT + space + packages.join(',\n' + INDENT + space) + '\n' + space + '}'; + let name = path.basename(dir); + if (name.match(/[^a-zA-Z0-9]/)) { + name = `"${name}"`; + } + return name + ': {\n' + INDENT + space + packages.join(',\n' + INDENT + space) + '\n' + space + '}'; } /** diff --git a/components/bin/copy b/components/bin/copy index 6810045e4..8f41e5a08 100755 --- a/components/bin/copy +++ b/components/bin/copy @@ -2,7 +2,7 @@ /************************************************************* * - * Copyright (c) 2018 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,9 +33,26 @@ const path = require('path'); const INDENT = ' '; /** - * The configuration data for the copy operation + * The module type to use ('cjs' or 'mjs') */ -const config = JSON.parse(fs.readFileSync(process.argv[2] || 'copy.json')); +const target = (process.argv[2] || 'mjs'); + +/** + * The bundle directory name + */ +const bundle = (process.argv[3] || 'bundle'); + +/** + * The configuration data for the copy operation(s) + */ +const json = path.resolve(process.argv[4] || '.', 'config.json'); +let configs = require(json).copy; +if (!configs) process.exit(); +const wd = path.dirname(json); +process.chdir(wd); +if (!Array.isArray(configs)) { + configs = [configs]; +} /** * Get the directory for node modules (either the parent of the MathJax directory, @@ -68,11 +85,23 @@ function copyFile(from, to, name, space) { } /** - * Copy the given files + * Handle the copying for a given configuration + * + * @param {{from: string, to: string, copy: string[]}} config The configuration for the copy operation */ -const wd = process.cwd(); -const to = path.resolve(wd, config.to); -const from = path.resolve(wd, config.from.replace(/\[node\]/, nodeDir)); -for (const name of config.copy) { - copyFile(from, to, name, ''); +function processConfig(config) { + const to = path.resolve(wd, config.to.replace(/\/bundle(\/|$)/, '/' + bundle + '$1')); + const from = path.resolve(wd, config.from.replace(/\[node\]/, nodeDir)); + for (const name of config.copy) { + copyFile(from, to, name, ''); + } } + +/** + * Process all the configurations + */ +for (const config of configs) { + processConfig(config); +} + + diff --git a/components/bin/link-full b/components/bin/link-full new file mode 100644 index 000000000..b2a3c137f --- /dev/null +++ b/components/bin/link-full @@ -0,0 +1,9 @@ +const fs = require('fs'); +const path = require('path'); + +const dir = path.join(__dirname, '..', '..'); +const src = path.join(dir, 'node_modules', '@mathjax', 'src'); + +if (fs.existsSync(path.join(dir, 'node_modules')) && !fs.existsSync(src)) { + fs.symlinkSync(dir, src); +} diff --git a/components/bin/makeAll b/components/bin/makeAll index df879f584..b661d3696 100755 --- a/components/bin/makeAll +++ b/components/bin/makeAll @@ -2,7 +2,7 @@ /************************************************************* * - * Copyright (c) 2018 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -29,38 +29,120 @@ const fs = require('fs'); const path = require('path'); const {execSync} = require('child_process'); +/** + * The default options + */ const options = { - recursive: true + build: true, + copy: true, + pack: true, + recursive: true, + verbose: true, + target: 'mjs', + bundle: '' }; /** - * Get the directories to process and check for options + * Get the directories to process */ const dirs = process.argv.slice(2); -if (dirs[0] === '--no-subdirs') { - dirs.shift(); - options.recursive = false; +/** + * The options and their actions + */ +const optionActions = new Map([ + ['no-subdirs', () => {options.recursive = false}], + ['cjs', () => {options.target = 'cjs'}], + ['mjs', () => {options.target = 'mjs'}], + ['terse', () => {options.verbose = false}], + ['bundle-cjs', () => {options.bundle = 'bundle-cjs'}], + ['build', () => { + options.build = 1; + if (options.copy === true) { + options.copy = false; + } + if (options.pack === true) { + options.pack = false; + } + }], + ['copy', () => { + options.copy = 1; + if (options.build === true) { + options.build = false; + } + if (options.pack === true) { + options.pack = false; + } + }], + ['pack', () => { + options.pack = 1; + if (options.build === true) { + options.build = false; + } + if (options.copy === true) { + options.copy = false; + } + }] +]); + +/** + * Check for options + */ +while (dirs[0] && dirs[0].substring(0, 2) === '--') { + const option = dirs.shift().substring(2); + if (option === '') { + break; + } + const action = optionActions.get(option); + if (!action) { + console.error(`Invalid option --${option}`); + process.exit(); + } + action(); } +/** + * Make sure there is at least one directory + */ if (dirs.length === 0) { dirs.push('.'); } /** - * The commads to runb the bin/build scripts - * (on Unix, could be done without the 'node ' prefix, but - * for Windows, these are needed.) + * The commads to run the various scripts + * (on Unix, could be done without the 'node ' prefix, but for Windows, these are needed.) */ -const build = `node '${path.join(__dirname, 'build')}'`; -const copy = `node '${path.join(__dirname, 'copy')}'`; -const pack = `node '${path.join(__dirname, 'pack')}'`; +const build = `node '${path.join(__dirname, 'build')}' '${options.target}'`; +const copy = `node '${path.join(__dirname, 'copy')}' '${options.target}' '${options.bundle}'`; +const pack = `node '${path.join(__dirname, 'pack')}' '${options.target}' '${options.bundle}'`; + +/** + * @param {string} name The file name to turn into a Regular expression + * @return {RegExp} The regular expression for the name, + */ +function fileRegExp(name) { + return new RegExp(name.replace(/([\\.{}[\]()?*^$])/g, '\\$1'), 'g'); +} + +/** + * Get the current working directory + */ +const root = process.cwd(); /** * Regular expression for the components directory */ -const compRE = new RegExp(path.dirname(__dirname).replace(/([\\.{}[\]()?*^$])/g, '\\$1')); -const dirRE = new RegExp(process.cwd().replace(/([\\.{}[\]()?*^$])/g, '\\$1')); +const compRE = fileRegExp(path.dirname(__dirname)); +const dirRE = fileRegExp(root); + + +/** + * Read and process a configuration file + */ +function getConfig(dir) { + const file = path.join(dir, 'config.json'); + return fs.existsSync(file) ? JSON.parse(String(fs.readFileSync(file))) : null; +} /** * Process the contents of an array of directories @@ -69,10 +151,11 @@ const dirRE = new RegExp(process.cwd().replace(/([\\.{}[\]()?*^$])/g, '\\$1')); */ function processList(dirs) { for (const dir of dirs) { - const fulldir = path.resolve(dir); - processDir(fulldir, buildLib); - processDir(fulldir, webpackLib); - processDir(fulldir, copyLib); + const fulldir = path.resolve(root, dir); + const config = getConfig(fulldir); + processDir(fulldir, buildLib, config); + processDir(fulldir, copyLib, config); + processDir(fulldir, webpackLib, config); } } @@ -81,9 +164,12 @@ function processList(dirs) { * * @param {string} dir The directory to process * @param {Function} action The action to take + * @param {Object} config The configuration json data */ -function processDir(dir, action) { - action(dir); +function processDir(dir, action, config) { + if (config) { + action(dir, config); + } if (options.recursive) { processSubdirs(dir, action); } @@ -94,69 +180,77 @@ function processDir(dir, action) { * * @param {string} dir The directory whose subdirectories are to be processed * @param {Function} action The action to take + * @param {Object} config The configuration json data */ -function processSubdirs(dir, action) { +function processSubdirs(dir, action, config) { for (const name of fs.readdirSync(dir)) { const file = path.join(dir, name); if (fs.lstatSync(file).isDirectory()) { - processDir(file, action); + const config = getConfig(file); + processDir(file, action, config); } } } +/** + * Run a command on a given directory + */ +function run(cmd, dir) { + return execSync(cmd + ` '${path.relative('.', dir).replace(/'/g, '\\\'')}'`); +} + /** * Run bin/build if there is a configuration file for it * - * @param {string} dir The directory to check + * @param {string} dir The directory to check + * @param {Object} config The configuration json data */ -function buildLib(dir) { - const file = path.join(dir, 'build.json'); - if (!fs.existsSync(file)) return; +function buildLib(dir, config) { + if (!config.build || !options.build) return; console.info('Building ' + dir.replace(compRE, '').replace(dirRE, '.')); - const wd = process.cwd(); try { - process.chdir(dir); - const result = execSync(build); - console.info(' ' + String(result).replace(/\n/g, '\n ')); + const result = run(build, dir); + if (options.verbose) { + console.info(' ' + String(result).replace(/\n/g, '\n ')); + } } catch (err) { console.info(' ' + err.message); } - process.chdir(wd); } /** * Run webpack if there is a configuration file for it * - * @param {string} dir The directory to check + * @param {string} dir The directory to check + * @param {Object} config The configuration json data */ -function webpackLib(dir) { - const file = path.join(dir, 'webpack.config.js'); - if (!fs.existsSync(file)) return; +function webpackLib(dir, config) { + if (!config.webpack || !options.pack) return; console.info('Webpacking ' + dir.replace(compRE, '').replace(dirRE, '.')); - const wd = process.cwd(); try { - process.chdir(dir); - const result = execSync(pack); - console.info(' ' + String(result).replace(/\n/g, '\n ')); + const result = run(pack, dir); + if (options.verbose) { + console.info(' ' + String(result).replace(/\n/g, '\n ')); + } } catch (err) { console.info(' ' + err.message); } - process.chdir(wd); } /** * Copy the designated files if there is a configurtion file for it * - * @param {string} dir The directory to check + * @param {string} dir The directory to check + * @param {Object} config The configuration json data */ -function copyLib(dir) { - const file = path.join(dir, 'copy.json'); - if (!fs.existsSync(file)) return; - console.info('Copying ' + dir.replace(compRE, '')); +function copyLib(dir, config) { + if (!config.copy || !options.copy) return; + console.info('Copying ' + dir.replace(compRE, '').replace(dirRE, '.')); try { - process.chdir(dir); - const result = execSync(copy); - console.info(' ' + String(result).replace(/\n/g, '\n ')); + const result = run(copy, dir); + if (options.verbose) { + console.info(' ' + String(result).replace(/\n/g, '\n ')); + } } catch (err) { console.info(' ' + err.message); } diff --git a/components/bin/pack b/components/bin/pack index d0a67b06a..ebcf8a214 100755 --- a/components/bin/pack +++ b/components/bin/pack @@ -1,9 +1,8 @@ #! /usr/bin/env node - /************************************************************* * - * Copyright (c) 2018 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -24,17 +23,26 @@ * @author dpvc@mathjax.org (Davide Cervone) */ - const fs = require('fs'); const path = require('path'); -const {spawn} = require('child_process'); +const {spawn, execSync} = require('child_process'); + +/** + * The module type to use ('cjs' or 'mjs') + */ +const target = (process.argv[2] || 'mjs') + +/** + * The bundle directory name + */ +const bundle = (process.argv[3] || 'bundle'); /** * @param {string} name The file name to turn into a Regular expression * @return {RegExp} The regular expression for the name, */ function fileRegExp(name) { - return new RegExp(name.replace(/([\\.{}[\]()?*^$])/g, '\\$1'), 'g'); + return new RegExp(name.replace(/([\\.{}[\]()?*+^$])/g, '\\$1'), 'g'); } /** @@ -48,19 +56,42 @@ function fileSize(file) { /** * Regular expressions for the components directory and the MathJax .js location */ -const compRE = fileRegExp(path.dirname(__dirname)); -const rootRE = fileRegExp(path.join(path.dirname(path.dirname(__dirname)), 'js')); -const nodeRE = fileRegExp(path.join(path.dirname(path.dirname(__dirname)), 'node_modules')); +const compPath = path.dirname(__dirname); +const mjPath = path.dirname(compPath); +const jsPath = path.join(__dirname, '..', '..', target); +const compRE = fileRegExp(compPath); +const rootRE = fileRegExp(path.dirname(jsPath)); +const nodeRE = /^.*\/node_modules/; +const fontRE = new RegExp('^.*\\/(mathjax-[^\/-]*)(?:-font)?\/(build|[cm]js)'); /** + * Find the directory where npx runs (so we know where "npx webpack" will run) + * (We use npx rather than pnpm here as it seems that pnpm doesn't + * find the executable from a node_modules directory higher than the + * first package.json, and extensions and fonts can have their own + * package.json.) + */ +const packDir = String(execSync('npx node -e "console.log(process.cwd())"')); + +/** + * @param {string} dir The directory to pack * @return {JSON} The parsed JSON from webpack */ -async function readJSON() { +async function readJSON(dir) { return new Promise((ok, fail) => { const buffer = []; - const child = spawn('npx', ['webpack', '--json']); + const child = spawn('npx', [ + 'webpack', '--env', `dir=${path.relative(packDir, path.resolve(dir))}`, + '--env', `bundle=${bundle}`, '--json', + '-c', path.relative(packDir, path.join(compPath, 'webpack.config.' + target)) + ]); child.stdout.on('data', (data) => buffer.push(String(data))); - child.stdout.on('close', (code) => { + child.stderr.on('data', (data) => console.error(String(data))); + child.on('close', (code) => { + if (code !== 0) { + fail('Webpack failed with code ' + code); + return; + } const json = JSON.parse(buffer.join('')); if (json.errors && json.errors.length) { fail(json.errors[0].message); @@ -77,20 +108,22 @@ async function readJSON() { */ async function webpackLib(dir) { try { - process.chdir(dir); const dirRE = fileRegExp(path.resolve(dir)); // // Get js directory from the webpack.config.js file // - const jsdir = require(path.resolve(dir, 'webpack.config.js')).plugins[0].definitions.__JSDIR__; + let config = require(path.resolve(dir, 'config.json')).webpack; + if (!config) return; + const jsdir = (config.js ? path.resolve(dir, config.js).replace(/js$/, target) : jsPath); const jsRE = fileRegExp(jsdir); + const jsRE2 = (config.js ? fileRegExp(path.resolve(dir, config.js)) : /^$/); const libRE = fileRegExp(path.resolve(jsdir, '..', 'components')); // // Get the json from webpack and print the asset name and size // - const json = await readJSON(); + const json = await readJSON(dir); for (const asset of json.assets) { console.log(asset.name + fileSize(asset)); } @@ -105,13 +138,15 @@ async function webpackLib(dir) { } const list = []; for (const module of modules) { - if (module.moduleType.match(/javascript/)) { - let name = module.name + if (module.moduleType.match(/javascript|json/)) { + let name = (module.nameForCondition || module.name) .replace(compRE, '[components]') - .replace(rootRE, '[mathjax]') .replace(nodeRE, '[node]') + .replace(rootRE, '[mathjax]') + .replace(fontRE, '[$1]/$2') .replace(jsRE, '[js]') - .replace(libRE, '[lib]'); + .replace(jsRE2, '[js]') + .replace(libRE, '[build]'); if (name.charAt(0) !== '.' && name.charAt(0) !== '[') { name = path.relative(dir, name); } @@ -129,4 +164,4 @@ async function webpackLib(dir) { } } -webpackLib(process.argv[2] || '.'); +webpackLib(process.argv[4] || '.'); diff --git a/components/bin/package.json b/components/bin/package.json new file mode 100644 index 000000000..bb29aab3c --- /dev/null +++ b/components/bin/package.json @@ -0,0 +1,12 @@ +{ + "type": "commonjs", + "imports": { + "#js/*": "@mathjax/src/cjs/*", + "#source/*": "@mathjax/src/components/cjs/*", + "#root/*": "@mathjax/src/cjs/components/cjs/*", + "#menu/*": "mj-context-menu/cjs/*", + "#sre/*": "speech-rule-engine/cjs/*", + "#mhchem/*": "mhchemparser/dist/*", + "#default-font/*": "@mathjax/mathjax-newcm-font/cjs/*" + } +} diff --git a/components/bin/version b/components/bin/version index 5eb0c6dab..0aab5b08e 100755 --- a/components/bin/version +++ b/components/bin/version @@ -2,7 +2,7 @@ /************************************************************* * - * Copyright (c) 2022 The MathJax Consortium + * Copyright (c) 2022-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,7 +32,7 @@ const version = require(package).version; const lines = `/************************************************************* * - * Copyright (c) 2022 The MathJax Consortium + * Copyright (c) 2023 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -48,8 +48,8 @@ const lines = `/************************************************************* */ /** - * @fileoverview The version of MathJax (used to tell what version a component - * was compiled against). + * @file The version of MathJax (used to tell what version a component + * was compiled against). * * @author dpvc@mathjax.org (Davide Cervone) */ diff --git a/components/mjs/a11y/assistive-mml/assistive-mml.js b/components/mjs/a11y/assistive-mml/assistive-mml.js new file mode 100644 index 000000000..cb7b0719d --- /dev/null +++ b/components/mjs/a11y/assistive-mml/assistive-mml.js @@ -0,0 +1,17 @@ +import './lib/assistive-mml.js'; + +import {combineDefaults} from '#js/components/global.js'; +import {AssistiveMmlHandler} from '#js/a11y/assistive-mml.js'; + +if (MathJax.startup) { + if (MathJax.config.options && MathJax.config.options.enableAssistiveMml !== false) { + combineDefaults(MathJax.config, 'options', { + menuOptions: { + settings: { + assistiveMml: true + } + } + }); + } + MathJax.startup.extendHandler(handler => AssistiveMmlHandler(handler)); +} diff --git a/components/mjs/a11y/assistive-mml/config.json b/components/mjs/a11y/assistive-mml/config.json new file mode 100644 index 000000000..8861d0cfb --- /dev/null +++ b/components/mjs/a11y/assistive-mml/config.json @@ -0,0 +1,13 @@ +{ + "build": { + "component": "a11y/assistive-mml", + "targets": ["a11y/assistive-mml.ts"] + }, + "webpack": { + "name": "a11y/assistive-mml", + "libs": [ + "components/src/input/mml/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/a11y/complexity/complexity.js b/components/mjs/a11y/complexity/complexity.js similarity index 61% rename from components/src/a11y/complexity/complexity.js rename to components/mjs/a11y/complexity/complexity.js index 1fbc931a3..c80fc76af 100644 --- a/components/src/a11y/complexity/complexity.js +++ b/components/mjs/a11y/complexity/complexity.js @@ -1,7 +1,7 @@ import './lib/complexity.js'; -import {combineDefaults} from '../../../../js/components/global.js'; -import {ComplexityHandler} from '../../../../js/a11y/complexity.js'; +import {combineDefaults} from '#js/components/global.js'; +import {ComplexityHandler} from '#js/a11y/complexity.js'; if (MathJax.startup) { MathJax.startup.extendHandler(handler => ComplexityHandler(handler)); diff --git a/components/mjs/a11y/complexity/config.json b/components/mjs/a11y/complexity/config.json new file mode 100644 index 000000000..77e22a080 --- /dev/null +++ b/components/mjs/a11y/complexity/config.json @@ -0,0 +1,18 @@ +{ + "build": { + "component": "a11y/complexity", + "targets": [ + "a11y/complexity.ts", + "a11y/complexity", + "a11y/semantic-enrich.ts" + ] + }, + "webpack": { + "name": "a11y/complexity", + "libs": [ + "components/src/a11y/semantic-enrich/lib", + "components/src/input/mml/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/a11y/explorer/config.json b/components/mjs/a11y/explorer/config.json new file mode 100644 index 000000000..7ed079980 --- /dev/null +++ b/components/mjs/a11y/explorer/config.json @@ -0,0 +1,16 @@ +{ + "build": { + "component": "a11y/explorer", + "targets": ["a11y/explorer.ts", "a11y/explorer"] + }, + "webpack": { + "name": "a11y/explorer", + "libs": [ + "components/src/a11y/semantic-enrich/lib", + "components/src/a11y/speech/lib", + "components/src/a11y/sre/lib", + "components/src/input/mml/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/a11y/explorer/explorer.js b/components/mjs/a11y/explorer/explorer.js new file mode 100644 index 000000000..4c3a9c89e --- /dev/null +++ b/components/mjs/a11y/explorer/explorer.js @@ -0,0 +1,8 @@ +import './lib/explorer.js'; + +import {ExplorerHandler} from '#js/a11y/explorer.js'; +import {hasWindow} from '#js/util/context.js'; + +if (MathJax.startup && hasWindow) { + MathJax.startup.extendHandler(handler => ExplorerHandler(handler)); +} diff --git a/components/mjs/a11y/semantic-enrich/config.json b/components/mjs/a11y/semantic-enrich/config.json new file mode 100644 index 000000000..8889b4fb7 --- /dev/null +++ b/components/mjs/a11y/semantic-enrich/config.json @@ -0,0 +1,17 @@ +{ + "build": { + "component": "a11y/semantic-enrich", + "targets": [ + "a11y/semantic-enrich.ts" + ] + }, + "webpack": { + "name": "a11y/semantic-enrich", + "libs": [ + "components/src/input/mml/lib", + "components/src/core/lib", + "components/src/a11y/sre/lib", + "components/src/loader/lib" + ] + } +} diff --git a/components/mjs/a11y/semantic-enrich/semantic-enrich.js b/components/mjs/a11y/semantic-enrich/semantic-enrich.js new file mode 100644 index 000000000..9b15f1837 --- /dev/null +++ b/components/mjs/a11y/semantic-enrich/semantic-enrich.js @@ -0,0 +1,11 @@ +import './lib/semantic-enrich.js'; + +import {combineDefaults} from '#js/components/global.js'; +import {EnrichHandler} from '#js/a11y/semantic-enrich.js'; +import {MathML} from '#js/input/mathml.js'; + +if (MathJax.startup) { + MathJax.startup.extendHandler( + handler => EnrichHandler(handler, new MathML({allowHtmlInTokenNodes: true})) + ); +} diff --git a/components/mjs/a11y/speech/config.json b/components/mjs/a11y/speech/config.json new file mode 100644 index 000000000..c9f0dfdbd --- /dev/null +++ b/components/mjs/a11y/speech/config.json @@ -0,0 +1,16 @@ +{ + "build": { + "component": "a11y/speech", + "targets": ["a11y/speech.ts", "a11y/speech"], + "exclude": ["a11y/speech/SpeechMenu.ts"] + }, + "webpack": { + "name": "a11y/speech", + "libs": [ + "components/src/a11y/semantic-enrich/lib", + "components/src/a11y/sre/lib", + "components/src/input/mml/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/a11y/speech/speech.js b/components/mjs/a11y/speech/speech.js new file mode 100644 index 000000000..a4c474b4d --- /dev/null +++ b/components/mjs/a11y/speech/speech.js @@ -0,0 +1,30 @@ +import './lib/speech.js'; + +import {combineDefaults} from '#js/components/global.js'; +import {Package} from '#js/components/package.js'; +import {hasWindow} from '#js/util/context.js'; +import {SpeechHandler} from '#js/a11y/speech.js'; + +if (MathJax.loader) { + let path = Package.resolvePath('[sre]', false); + let maps = Package.resolvePath('[mathmaps]', false); + if (hasWindow) { + path = new URL(path, location).href; + maps = new URL(maps, location).href; + } else { + const REQUIRE = typeof require !== 'undefined' ? require : MathJax.config.loader.require; + if (REQUIRE?.resolve) { + path = REQUIRE.resolve(`${path}/require.mjs`).replace(/\/[^\/]*$/, ''); + maps = REQUIRE.resolve(`${maps}/base.json`).replace(/\/[^\/]*$/, ''); + } else { + path = maps = ''; + } + } + if (path) { + combineDefaults(MathJax.config, 'options', { worker: { path, maps } }); + } +} + +if (MathJax.startup) { + MathJax.startup.extendHandler(handler => SpeechHandler(handler)); +} diff --git a/components/mjs/a11y/sre/config.json b/components/mjs/a11y/sre/config.json new file mode 100644 index 000000000..35fad3f22 --- /dev/null +++ b/components/mjs/a11y/sre/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "component": "a11y/sre", + "targets": ["a11y/sre.ts"] + }, + "webpack": { + "name": "a11y/sre", + "libs": [ + "components/src/input/mml/lib", + "components/src/core/lib", + "components/src/startup/lib" + ] + } +} diff --git a/components/mjs/a11y/sre/sre.js b/components/mjs/a11y/sre/sre.js new file mode 100644 index 000000000..53582341c --- /dev/null +++ b/components/mjs/a11y/sre/sre.js @@ -0,0 +1,4 @@ +import './lib/sre.js'; +import * as Sre from '#js/a11y/sre.js'; + +export {Sre}; diff --git a/components/mjs/a11y/sre/worker/config.json b/components/mjs/a11y/sre/worker/config.json new file mode 100644 index 000000000..c1303a29f --- /dev/null +++ b/components/mjs/a11y/sre/worker/config.json @@ -0,0 +1,13 @@ +{ + "webpack": { + "name": "sre/speech-worker" + }, + "copy": { + "to": "../../../../../bundle/sre", + "from": "../../../../../ts/a11y/sre", + "copy": [ + "require.mjs", + "require.d.mts" + ] + } +} diff --git a/components/mjs/a11y/sre/worker/speech-worker.js b/components/mjs/a11y/sre/worker/speech-worker.js new file mode 100644 index 000000000..babf9cdcb --- /dev/null +++ b/components/mjs/a11y/sre/worker/speech-worker.js @@ -0,0 +1 @@ +import '#js/a11y/sre/speech-worker.js'; diff --git a/components/mjs/a11y/sre/worker/webpack.cjs b/components/mjs/a11y/sre/worker/webpack.cjs new file mode 100644 index 000000000..43ef657fa --- /dev/null +++ b/components/mjs/a11y/sre/worker/webpack.cjs @@ -0,0 +1,10 @@ +const webpack = require('webpack'); + +module.exports = (pkg) => { + pkg.plugins.push( + new webpack.optimize.LimitChunkCountPlugin({ + maxChunks: 1, + }) + ); + return pkg; +} diff --git a/components/mjs/a11y/util.js b/components/mjs/a11y/util.js new file mode 100644 index 000000000..6e2096ba7 --- /dev/null +++ b/components/mjs/a11y/util.js @@ -0,0 +1,13 @@ +import {Loader} from '#js/components/loader.js'; +import '../input/mml/init.js'; +import './sre/sre.js'; +import './semantic-enrich/semantic-enrich.js'; +import './speech/speech.js'; +import './explorer/explorer.js'; + +Loader.preLoaded( + 'a11y/sre', + 'a11y/semantic-enrich', + 'a11y/speech', + 'a11y/explorer' +); diff --git a/components/mjs/adaptors/jsdom/config.json b/components/mjs/adaptors/jsdom/config.json new file mode 100644 index 000000000..e93a68d85 --- /dev/null +++ b/components/mjs/adaptors/jsdom/config.json @@ -0,0 +1,10 @@ +{ + "build": { + "component": "adaptors/jsdom", + "targets": ["adaptors/jsdomAdaptor.ts"] + }, + "webpack": { + "name": "adaptors/jsdom", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/mjs/adaptors/jsdom/jsdom.js b/components/mjs/adaptors/jsdom/jsdom.js new file mode 100644 index 000000000..b483c07b6 --- /dev/null +++ b/components/mjs/adaptors/jsdom/jsdom.js @@ -0,0 +1,11 @@ +import './lib/jsdom.js'; + +import {jsdomAdaptor} from '#js/adaptors/jsdomAdaptor.js'; + +if (MathJax.startup) { + MathJax.startup.registerConstructor( + 'jsdomAdaptor', + (options) => jsdomAdaptor(MathJax.config.JSDOM, options) + ); + MathJax.startup.useAdaptor('jsdomAdaptor', true); +} diff --git a/components/mjs/adaptors/linkedom/config.json b/components/mjs/adaptors/linkedom/config.json new file mode 100644 index 000000000..02c61e63e --- /dev/null +++ b/components/mjs/adaptors/linkedom/config.json @@ -0,0 +1,10 @@ +{ + "build": { + "component": "adaptors/linkedom", + "targets": ["adaptors/linkedomAdaptor.ts"] + }, + "webpack": { + "name": "adaptors/linkedom", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/mjs/adaptors/linkedom/linkedom.js b/components/mjs/adaptors/linkedom/linkedom.js new file mode 100644 index 000000000..8f4961c0c --- /dev/null +++ b/components/mjs/adaptors/linkedom/linkedom.js @@ -0,0 +1,11 @@ +import './lib/linkedom.js'; + +import {linkedomAdaptor} from '#js/adaptors/linkedomAdaptor.js'; + +if (MathJax.startup) { + MathJax.startup.registerConstructor( + 'linkedomAdaptor', + (options) => linkedomAdaptor(MathJax.config.LINKEDOM, options) + ); + MathJax.startup.useAdaptor('linkedomAdaptor', true); +} diff --git a/components/mjs/adaptors/liteDOM/config.json b/components/mjs/adaptors/liteDOM/config.json new file mode 100644 index 000000000..ab347dba9 --- /dev/null +++ b/components/mjs/adaptors/liteDOM/config.json @@ -0,0 +1,10 @@ +{ + "build": { + "component": "adaptors/liteDOM", + "targets": ["adaptors/liteAdaptor.ts", "adaptors/lite"] + }, + "webpack": { + "name": "adaptors/liteDOM", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/src/adaptors/liteDOM/liteDOM.js b/components/mjs/adaptors/liteDOM/liteDOM.js similarity index 71% rename from components/src/adaptors/liteDOM/liteDOM.js rename to components/mjs/adaptors/liteDOM/liteDOM.js index d4b959bbf..a5a240cef 100644 --- a/components/src/adaptors/liteDOM/liteDOM.js +++ b/components/mjs/adaptors/liteDOM/liteDOM.js @@ -1,6 +1,6 @@ import './lib/liteDOM.js'; -import {liteAdaptor} from '../../../../js/adaptors/liteAdaptor.js'; +import {liteAdaptor} from '#js/adaptors/liteAdaptor.js'; if (MathJax.startup) { MathJax.startup.registerConstructor('liteAdaptor', liteAdaptor); diff --git a/components/mjs/core/config.json b/components/mjs/core/config.json new file mode 100644 index 000000000..7f032dbc4 --- /dev/null +++ b/components/mjs/core/config.json @@ -0,0 +1,22 @@ +{ + "build": { + "component": "core", + "targets": [ + "mathjax.ts", + "core", "util", "handlers", + "adaptors/HTMLAdaptor.ts", + "adaptors/browserAdaptor.ts", + "components/global.ts" + ], + "exclude": [ + "core/MmlTree/JsonMmlVisitor.ts", + "core/MmlTree/LegacyMmlVisitor.ts", + "core/MmlTree/TestMmlVisitor.ts", + "util/asyncLoad", + "util/entities" + ] + }, + "webpack": { + "name": "core" + } +} diff --git a/components/mjs/core/core.js b/components/mjs/core/core.js new file mode 100644 index 000000000..82dcdbd23 --- /dev/null +++ b/components/mjs/core/core.js @@ -0,0 +1,19 @@ +import './lib/core.js'; + +import {HTMLHandler} from '#js/handlers/html/HTMLHandler.js'; +import {browserAdaptor} from '#js/adaptors/browserAdaptor.js'; + +if (MathJax.startup) { + MathJax.startup.registerConstructor('HTMLHandler', HTMLHandler); + MathJax.startup.registerConstructor('browserAdaptor', browserAdaptor); + MathJax.startup.useHandler('HTMLHandler'); + MathJax.startup.useAdaptor('browserAdaptor'); +} +if (MathJax.loader) { + const config = MathJax.config.loader; + MathJax._.mathjax.mathjax.asyncLoad = ( + (name) => name.substring(0, 5) === 'node:' + ? config.require(name) + : MathJax.loader.load(name).then(result => result[0]) + ); +} diff --git a/components/src/dependencies.js b/components/mjs/dependencies.js similarity index 76% rename from components/src/dependencies.js rename to components/mjs/dependencies.js index 6a33e9e72..4d3c182ea 100644 --- a/components/src/dependencies.js +++ b/components/mjs/dependencies.js @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2019-2021 The MathJax Consortium + * Copyright (c) 2019-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,28 +17,35 @@ export const dependencies = { 'a11y/semantic-enrich': ['input/mml', 'a11y/sre'], + 'a11y/speech': ['a11y/semantic-enrich'], 'a11y/complexity': ['a11y/semantic-enrich'], - 'a11y/explorer': ['a11y/semantic-enrich', 'ui/menu'], + 'a11y/explorer': ['a11y/speech'], '[mml]/mml3': ['input/mml'], - '[tex]/all-packages': ['input/tex-base'], - '[tex]/action': ['input/tex-base', '[tex]/newcommand'], - '[tex]/autoload': ['input/tex-base', '[tex]/require'], - '[tex]/ams': ['input/tex-base'], + '[tex]/action': ['input/tex-base'], + '[tex]/ams': ['input/tex-base', '[tex]/newcommand'], '[tex]/amscd': ['input/tex-base'], - '[tex]/bbox': ['input/tex-base', '[tex]/ams', '[tex]/newcommand'], + '[tex]/autoload': ['input/tex-base', '[tex]/require'], + '[tex]/bbm': ['input/tex-base'], + '[tex]/bboldx': ['input/tex-base', '[tex]/textmacros'], + '[tex]/bbox': ['input/tex-base'], + '[tex]/begingroup': ['input/tex-base', '[tex]/newcommand'], '[tex]/boldsymbol': ['input/tex-base'], '[tex]/braket': ['input/tex-base'], '[tex]/bussproofs': ['input/tex-base'], '[tex]/cancel': ['input/tex-base', '[tex]/enclose'], + '[tex]/cases': ['[tex]/empheq'], '[tex]/centernot': ['input/tex-base'], '[tex]/color': ['input/tex-base'], - '[tex]/colorv2': ['input/tex-base'], '[tex]/colortbl': ['input/tex-base', '[tex]/color'], + '[tex]/colorv2': ['input/tex-base'], '[tex]/configmacros': ['input/tex-base', '[tex]/newcommand'], + '[tex]/dsfont': ['input/tex-base'], + '[tex]/empheq': ['input/tex-base', '[tex]/ams'], '[tex]/enclose': ['input/tex-base'], '[tex]/extpfeil': ['input/tex-base', '[tex]/newcommand', '[tex]/ams'], + '[tex]/gensymb': ['input/tex-base'], '[tex]/html': ['input/tex-base'], - '[tex]/mathtools': ['input/tex-base', '[tex]/newcommand', '[tex]/ams'], + '[tex]/mathtools': ['input/tex-base', '[tex]/newcommand', '[tex]/ams', '[tex]/boldsymbol'], '[tex]/mhchem': ['input/tex-base', '[tex]/ams'], '[tex]/newcommand': ['input/tex-base'], '[tex]/noerrors': ['input/tex-base'], @@ -47,43 +54,35 @@ export const dependencies = { '[tex]/require': ['input/tex-base'], '[tex]/setoptions': ['input/tex-base'], '[tex]/tagformat': ['input/tex-base'], + '[tex]/texhtml': ['input/tex-base'], '[tex]/textcomp': ['input/tex-base', '[tex]/textmacros'], '[tex]/textmacros': ['input/tex-base'], '[tex]/unicode': ['input/tex-base'], + '[tex]/units': ['input/tex-base'], + '[tex]/upgreek': ['input/tex-base'], '[tex]/verb': ['input/tex-base'], - '[tex]/cases': ['[tex]/empheq'], - '[tex]/empheq': ['input/tex-base', '[tex]/ams'] + 'ui/menu': ['a11y/sre'], }; export const paths = { tex: '[mathjax]/input/tex/extensions', mml: '[mathjax]/input/mml/extensions', - sre: '[mathjax]/sre/mathmaps' + sre: '[mathjax]/sre', + mathmaps: '[sre]/mathmaps', }; -const allPackages = Array.from(Object.keys(dependencies)) - .filter(name => name.substr(0,5) === '[tex]' && - name !== '[tex]/autoload' && - name !== '[tex]/colorv2' && - name !== '[tex]/all-packages'); - export const provides = { 'startup': ['loader'], 'input/tex': [ 'input/tex-base', '[tex]/ams', '[tex]/newcommand', + '[tex]/textmacros', '[tex]/noundefined', '[tex]/require', '[tex]/autoload', '[tex]/configmacros' - ], - 'input/tex-full': [ - 'input/tex-base', - '[tex]/all-packages', - ...allPackages - ], - '[tex]/all-packages': allPackages + ] }; // diff --git a/components/mjs/fullpath.cjs b/components/mjs/fullpath.cjs new file mode 100644 index 000000000..664e2a000 --- /dev/null +++ b/components/mjs/fullpath.cjs @@ -0,0 +1,41 @@ +/************************************************************* + * + * Copyright (c) 2023-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Gets the fully resolved path from a webpack request object using the + * correct package.json file to map pseudo-packages to the mjs/cjs directories. + * When this file is in the components/cjs directory, it will use the + * package.json in that directory, which maps them to the @mathjax/src/cjs files. + * When in the components/mjs directory, the main package.json file will be used. + */ + +let path = require('path'); + +/** + * @param {object} resource The module resource object from webpack + * @return {string} The full path to the module + */ +function fullPath(resource) { + const file = resource.request ? + (resource.request.charAt(0) === '.' ? + path.resolve(resource.path, resource.request) : + resource.request) : + resource.path; + return file.charAt(0) === '/' ? file : require.resolve(file); +} + +module.exports.fullPath = fullPath; diff --git a/components/src/input/asciimath/asciimath.js b/components/mjs/input/asciimath/asciimath.js similarity index 72% rename from components/src/input/asciimath/asciimath.js rename to components/mjs/input/asciimath/asciimath.js index a2b51375c..88d48fa85 100644 --- a/components/src/input/asciimath/asciimath.js +++ b/components/mjs/input/asciimath/asciimath.js @@ -1,6 +1,6 @@ import './lib/asciimath.js'; -import {AsciiMath} from '../../../../js/input/asciimath.js'; +import {AsciiMath} from '#js/input/asciimath.js'; if (MathJax.startup) { MathJax.startup.registerConstructor('asciimath', AsciiMath); diff --git a/components/mjs/input/asciimath/config.json b/components/mjs/input/asciimath/config.json new file mode 100644 index 000000000..d9679c77f --- /dev/null +++ b/components/mjs/input/asciimath/config.json @@ -0,0 +1,11 @@ +{ + "build": { + "component": "input/asciimath", + "targets": ["input/asciimath.ts", "input/asciimath"], + "excludeSubdirs": true + }, + "webpack": { + "name": "input/asciimath", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/mjs/input/mml/config.json b/components/mjs/input/mml/config.json new file mode 100644 index 000000000..444a4919b --- /dev/null +++ b/components/mjs/input/mml/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "component": "input/mml", + "targets": [ + "input/mathml.ts", + "input/mathml" + ], + "excludeSubdirs": true + }, + "webpack": { + "name": "input/mml", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/mjs/input/mml/entities/config.json b/components/mjs/input/mml/entities/config.json new file mode 100644 index 000000000..d4eff8e46 --- /dev/null +++ b/components/mjs/input/mml/entities/config.json @@ -0,0 +1,6 @@ +{ + "webpack": { + "name": "input/mml/entities", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/mjs/input/mml/entities/entities.js b/components/mjs/input/mml/entities/entities.js new file mode 100644 index 000000000..060280f30 --- /dev/null +++ b/components/mjs/input/mml/entities/entities.js @@ -0,0 +1,6 @@ +import '#js/util/entities/all.js'; +import {VERSION} from '#js/components/version.js'; + +if (MathJax.loader) { + MathJax.loader.checkVersion('input/mml/entities', VERSION, 'input/mml/entities'); +} diff --git a/components/mjs/input/mml/extensions/mml3/config.json b/components/mjs/input/mml/extensions/mml3/config.json new file mode 100644 index 000000000..4a0f06a9a --- /dev/null +++ b/components/mjs/input/mml/extensions/mml3/config.json @@ -0,0 +1,22 @@ +{ + "build": { + "id": "[mml]/mml3", + "component": "input/mml/extensions/mml3", + "targets": ["input/mathml/mml3"], + "excludeSubdirs": true + }, + "copy": { + "to": "../../../../../../bundle/input/mml/extensions", + "from": "../../../../../../ts/input/mathml/mml3", + "copy": [ + "mml3.sef.json" + ] + }, + "webpack": { + "name": "input/mml/extensions/mml3", + "libs": [ + "components/src/input/mml/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/mml/extensions/mml3/mml3.js b/components/mjs/input/mml/extensions/mml3/mml3.js similarity index 60% rename from components/src/input/mml/extensions/mml3/mml3.js rename to components/mjs/input/mml/extensions/mml3/mml3.js index 72ecdf12c..528d7f094 100644 --- a/components/src/input/mml/extensions/mml3/mml3.js +++ b/components/mjs/input/mml/extensions/mml3/mml3.js @@ -1,6 +1,6 @@ import './lib/mml3.js'; -import {Mml3Handler} from '../../../../../../js/input/mathml/mml3/mml3.js'; +import {Mml3Handler} from '#js/input/mathml/mml3/mml3.js'; if (MathJax.startup) { MathJax.startup.extendHandler(handler => Mml3Handler(handler)); diff --git a/components/src/input/mml/mml.js b/components/mjs/input/mml/init.js similarity index 68% rename from components/src/input/mml/mml.js rename to components/mjs/input/mml/init.js index 7e81b27f4..aa2291678 100644 --- a/components/src/input/mml/mml.js +++ b/components/mjs/input/mml/init.js @@ -1,11 +1,8 @@ import './lib/mml.js'; -import {MathML} from '../../../../js/input/mathml.js'; +import {MathML} from '#js/input/mathml.js'; +export {MathML}; -if (MathJax.startup) { - MathJax.startup.registerConstructor('mml', MathML); - MathJax.startup.useInput('mml'); -} if (MathJax.loader) { // // Install a path-filter to cause loading of an entity file to load all entities, diff --git a/components/mjs/input/mml/mml.js b/components/mjs/input/mml/mml.js new file mode 100644 index 000000000..98770e0d8 --- /dev/null +++ b/components/mjs/input/mml/mml.js @@ -0,0 +1,6 @@ +import {MathML} from './init.js'; + +if (MathJax.startup) { + MathJax.startup.registerConstructor('mml', MathML); + MathJax.startup.useInput('mml'); +} diff --git a/components/mjs/input/tex-base/config.json b/components/mjs/input/tex-base/config.json new file mode 100644 index 000000000..e0a52a01a --- /dev/null +++ b/components/mjs/input/tex-base/config.json @@ -0,0 +1,15 @@ +{ + "build": { + "component": "input/tex-base", + "targets": [ + "input/tex.ts", + "input/tex", + "input/tex/base" + ], + "excludeSubdirs": true + }, + "webpack": { + "name": "input/tex-base", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/src/input/tex-base/tex-base.js b/components/mjs/input/tex-base/tex-base.js similarity index 100% rename from components/src/input/tex-base/tex-base.js rename to components/mjs/input/tex-base/tex-base.js diff --git a/components/mjs/input/tex/config.json b/components/mjs/input/tex/config.json new file mode 100644 index 000000000..135d306c3 --- /dev/null +++ b/components/mjs/input/tex/config.json @@ -0,0 +1,25 @@ +{ + "build": { + "component": "input/tex", + "targets": [ + "input/tex.ts", + "input/tex", + "input/tex/base", + "input/tex/ams", + "input/tex/newcommand", + "input/tex/textmacros", + "input/tex/noundefined", + "input/tex/require", + "input/tex/autoload", + "input/tex/configmacros" + ], + "excludeSubdirs": true + }, + "webpack": { + "name": "input/tex", + "libs": [ + "components/src/startup/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extension.js b/components/mjs/input/tex/extension.js new file mode 100644 index 000000000..50e7f67a5 --- /dev/null +++ b/components/mjs/input/tex/extension.js @@ -0,0 +1,16 @@ +import {combineDefaults} from '#js/components/global.js'; +import {hasWindow} from '#js/util/context.js'; + +export function fontExtension(id, name, pkg = `@mathjax/${name}`) { + if (MathJax.loader) { + const FONTPATH = hasWindow ? `https://cdn.jsdelivr.net/npm/${pkg}` : pkg; + const path = name.replace(/-font-extension$/, '-extension'); + const jax = (MathJax.config?.startup?.output || 'chtml'); + combineDefaults(MathJax.config.loader, 'paths', {[path]: FONTPATH}); + combineDefaults(MathJax.config.loader, 'dependencies', {[`[${path}]/${jax}`]: [`output/${jax}`]}); + MathJax.loader.addPackageData(id, { + extraLoads: [`[${path}]/${jax}`], + rendererExtensions: [path] + }); + } +} diff --git a/components/src/input/tex/extensions/action/action.js b/components/mjs/input/tex/extensions/action/action.js similarity index 100% rename from components/src/input/tex/extensions/action/action.js rename to components/mjs/input/tex/extensions/action/action.js diff --git a/components/mjs/input/tex/extensions/action/config.json b/components/mjs/input/tex/extensions/action/config.json new file mode 100644 index 000000000..36d0c551a --- /dev/null +++ b/components/mjs/input/tex/extensions/action/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/action", + "component": "input/tex/extensions/action", + "targets": ["input/tex/action"] + }, + "webpack": { + "name": "input/tex/extensions/action", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/ams/ams.js b/components/mjs/input/tex/extensions/ams/ams.js similarity index 100% rename from components/src/input/tex/extensions/ams/ams.js rename to components/mjs/input/tex/extensions/ams/ams.js diff --git a/components/mjs/input/tex/extensions/ams/config.json b/components/mjs/input/tex/extensions/ams/config.json new file mode 100644 index 000000000..a236d0358 --- /dev/null +++ b/components/mjs/input/tex/extensions/ams/config.json @@ -0,0 +1,15 @@ +{ + "build": { + "id": "[tex]/ams", + "component": "input/tex/extensions/ams", + "targets": ["input/tex/ams"] + }, + "webpack": { + "name": "input/tex/extensions/ams", + "libs": [ + "components/src/input/tex/extensions/newcommand/lib", + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/amscd/amscd.js b/components/mjs/input/tex/extensions/amscd/amscd.js similarity index 100% rename from components/src/input/tex/extensions/amscd/amscd.js rename to components/mjs/input/tex/extensions/amscd/amscd.js diff --git a/components/mjs/input/tex/extensions/amscd/config.json b/components/mjs/input/tex/extensions/amscd/config.json new file mode 100644 index 000000000..9a28af216 --- /dev/null +++ b/components/mjs/input/tex/extensions/amscd/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/amscd", + "component": "input/tex/extensions/amscd", + "targets": ["input/tex/amscd"] + }, + "webpack": { + "name": "input/tex/extensions/amscd", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/autoload/autoload.js b/components/mjs/input/tex/extensions/autoload/autoload.js similarity index 100% rename from components/src/input/tex/extensions/autoload/autoload.js rename to components/mjs/input/tex/extensions/autoload/autoload.js diff --git a/components/mjs/input/tex/extensions/autoload/config.json b/components/mjs/input/tex/extensions/autoload/config.json new file mode 100644 index 000000000..db90045d9 --- /dev/null +++ b/components/mjs/input/tex/extensions/autoload/config.json @@ -0,0 +1,16 @@ +{ + "build": { + "id": "[tex]/autoload", + "component": "input/tex/extensions/autoload", + "targets": ["input/tex/autoload"] + }, + "webpack": { + "name": "input/tex/extensions/autoload", + "libs": [ + "components/src/input/tex/extensions/require/lib", + "components/src/input/tex-base/lib", + "components/src/startup/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extensions/bbm/bbm.js b/components/mjs/input/tex/extensions/bbm/bbm.js new file mode 100644 index 000000000..25dadc20d --- /dev/null +++ b/components/mjs/input/tex/extensions/bbm/bbm.js @@ -0,0 +1,4 @@ +import './lib/bbm.js'; +import {fontExtension} from '../../extension.js'; + +fontExtension('[tex]/bbm', 'mathjax-bbm-font-extension'); diff --git a/components/mjs/input/tex/extensions/bbm/config.json b/components/mjs/input/tex/extensions/bbm/config.json new file mode 100644 index 000000000..275c02251 --- /dev/null +++ b/components/mjs/input/tex/extensions/bbm/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/bbm", + "component": "input/tex/extensions/bbm", + "targets": ["input/tex/bbm"] + }, + "webpack": { + "name": "input/tex/extensions/bbm", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extensions/bboldx/bboldx.js b/components/mjs/input/tex/extensions/bboldx/bboldx.js new file mode 100644 index 000000000..cc32d683f --- /dev/null +++ b/components/mjs/input/tex/extensions/bboldx/bboldx.js @@ -0,0 +1,4 @@ +import './lib/bboldx.js'; +import {fontExtension} from '../../extension.js'; + +fontExtension('[tex]/bboldx', 'mathjax-bboldx-font-extension'); diff --git a/components/mjs/input/tex/extensions/bboldx/config.json b/components/mjs/input/tex/extensions/bboldx/config.json new file mode 100644 index 000000000..a2e3515b2 --- /dev/null +++ b/components/mjs/input/tex/extensions/bboldx/config.json @@ -0,0 +1,15 @@ +{ + "build": { + "id": "[tex]/bboldx", + "component": "input/tex/extensions/bboldx", + "targets": ["input/tex/bboldx"] + }, + "webpack": { + "name": "input/tex/extensions/bboldx", + "libs": [ + "components/src/input/tex/extensions/textmacros/lib", + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/bbox/bbox.js b/components/mjs/input/tex/extensions/bbox/bbox.js similarity index 100% rename from components/src/input/tex/extensions/bbox/bbox.js rename to components/mjs/input/tex/extensions/bbox/bbox.js diff --git a/components/mjs/input/tex/extensions/bbox/config.json b/components/mjs/input/tex/extensions/bbox/config.json new file mode 100644 index 000000000..3c233eb2b --- /dev/null +++ b/components/mjs/input/tex/extensions/bbox/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/bbox", + "component": "input/tex/extensions/bbox", + "targets": ["input/tex/bbox"] + }, + "webpack": { + "name": "input/tex/extensions/bbox", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extensions/begingroup/begingroup.js b/components/mjs/input/tex/extensions/begingroup/begingroup.js new file mode 100644 index 000000000..698d543f6 --- /dev/null +++ b/components/mjs/input/tex/extensions/begingroup/begingroup.js @@ -0,0 +1 @@ +import './lib/begingroup.js'; diff --git a/components/mjs/input/tex/extensions/begingroup/config.json b/components/mjs/input/tex/extensions/begingroup/config.json new file mode 100644 index 000000000..8452effd2 --- /dev/null +++ b/components/mjs/input/tex/extensions/begingroup/config.json @@ -0,0 +1,15 @@ +{ + "build": { + "id": "[tex]/begingroup", + "component": "input/tex/extensions/begingroup", + "targets": ["input/tex/begingroup"] + }, + "webpack": { + "name": "input/tex/extensions/begingroup", + "libs": [ + "components/src/input/tex/extensions/newcommand/lib", + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/boldsymbol/boldsymbol.js b/components/mjs/input/tex/extensions/boldsymbol/boldsymbol.js similarity index 100% rename from components/src/input/tex/extensions/boldsymbol/boldsymbol.js rename to components/mjs/input/tex/extensions/boldsymbol/boldsymbol.js diff --git a/components/mjs/input/tex/extensions/boldsymbol/config.json b/components/mjs/input/tex/extensions/boldsymbol/config.json new file mode 100644 index 000000000..ced5fa29e --- /dev/null +++ b/components/mjs/input/tex/extensions/boldsymbol/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/boldsymbol", + "component": "input/tex/extensions/boldsymbol", + "targets": ["input/tex/boldsymbol"] + }, + "webpack": { + "name": "input/tex/extensions/boldsymbol", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/braket/braket.js b/components/mjs/input/tex/extensions/braket/braket.js similarity index 100% rename from components/src/input/tex/extensions/braket/braket.js rename to components/mjs/input/tex/extensions/braket/braket.js diff --git a/components/mjs/input/tex/extensions/braket/config.json b/components/mjs/input/tex/extensions/braket/config.json new file mode 100644 index 000000000..12cf84f1f --- /dev/null +++ b/components/mjs/input/tex/extensions/braket/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/braket", + "component": "input/tex/extensions/braket", + "targets": ["input/tex/braket"] + }, + "webpack": { + "name": "input/tex/extensions/braket", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/bussproofs/bussproofs.js b/components/mjs/input/tex/extensions/bussproofs/bussproofs.js similarity index 100% rename from components/src/input/tex/extensions/bussproofs/bussproofs.js rename to components/mjs/input/tex/extensions/bussproofs/bussproofs.js diff --git a/components/mjs/input/tex/extensions/bussproofs/config.json b/components/mjs/input/tex/extensions/bussproofs/config.json new file mode 100644 index 000000000..dcfee11bf --- /dev/null +++ b/components/mjs/input/tex/extensions/bussproofs/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/bussproofs", + "component": "input/tex/extensions/bussproofs", + "targets": ["input/tex/bussproofs"] + }, + "webpack": { + "name": "input/tex/extensions/bussproofs", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/cancel/cancel.js b/components/mjs/input/tex/extensions/cancel/cancel.js similarity index 100% rename from components/src/input/tex/extensions/cancel/cancel.js rename to components/mjs/input/tex/extensions/cancel/cancel.js diff --git a/components/mjs/input/tex/extensions/cancel/config.json b/components/mjs/input/tex/extensions/cancel/config.json new file mode 100644 index 000000000..3ef0bc873 --- /dev/null +++ b/components/mjs/input/tex/extensions/cancel/config.json @@ -0,0 +1,15 @@ +{ + "build": { + "id": "[tex]/cancel", + "component": "input/tex/extensions/cancel", + "targets": ["input/tex/cancel"] + }, + "webpack": { + "name": "input/tex/extensions/cancel", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/input/tex/extensions/enclose/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/cases/cases.js b/components/mjs/input/tex/extensions/cases/cases.js similarity index 100% rename from components/src/input/tex/extensions/cases/cases.js rename to components/mjs/input/tex/extensions/cases/cases.js diff --git a/components/mjs/input/tex/extensions/cases/config.json b/components/mjs/input/tex/extensions/cases/config.json new file mode 100644 index 000000000..49d7c48e4 --- /dev/null +++ b/components/mjs/input/tex/extensions/cases/config.json @@ -0,0 +1,16 @@ +{ + "build": { + "id": "[tex]/cases", + "component": "input/tex/extensions/cases", + "targets": ["input/tex/cases"] + }, + "webpack": { + "name": "input/tex/extensions/cases", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/input/tex/extensions/ams/lib", + "components/src/input/tex/extensions/empheq/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/centernot/centernot.js b/components/mjs/input/tex/extensions/centernot/centernot.js similarity index 100% rename from components/src/input/tex/extensions/centernot/centernot.js rename to components/mjs/input/tex/extensions/centernot/centernot.js diff --git a/components/mjs/input/tex/extensions/centernot/config.json b/components/mjs/input/tex/extensions/centernot/config.json new file mode 100644 index 000000000..94b9d79bc --- /dev/null +++ b/components/mjs/input/tex/extensions/centernot/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/centernot", + "component": "input/tex/extensions/centernot", + "targets": ["input/tex/centernot"] + }, + "webpack": { + "name": "input/tex/extensions/centernot", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/color/color.js b/components/mjs/input/tex/extensions/color/color.js similarity index 100% rename from components/src/input/tex/extensions/color/color.js rename to components/mjs/input/tex/extensions/color/color.js diff --git a/components/mjs/input/tex/extensions/color/config.json b/components/mjs/input/tex/extensions/color/config.json new file mode 100644 index 000000000..84041ca4d --- /dev/null +++ b/components/mjs/input/tex/extensions/color/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/color", + "component": "input/tex/extensions/color", + "targets": ["input/tex/color"] + }, + "webpack": { + "name": "input/tex/extensions/color", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/colortbl/colortbl.js b/components/mjs/input/tex/extensions/colortbl/colortbl.js similarity index 100% rename from components/src/input/tex/extensions/colortbl/colortbl.js rename to components/mjs/input/tex/extensions/colortbl/colortbl.js diff --git a/components/mjs/input/tex/extensions/colortbl/config.json b/components/mjs/input/tex/extensions/colortbl/config.json new file mode 100644 index 000000000..13a313e50 --- /dev/null +++ b/components/mjs/input/tex/extensions/colortbl/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/colortbl", + "component": "input/tex/extensions/colortbl", + "targets": ["input/tex/colortbl"] + }, + "webpack": { + "name": "input/tex/extensions/colortbl", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/colorv2/colorv2.js b/components/mjs/input/tex/extensions/colorv2/colorv2.js similarity index 100% rename from components/src/input/tex/extensions/colorv2/colorv2.js rename to components/mjs/input/tex/extensions/colorv2/colorv2.js diff --git a/components/mjs/input/tex/extensions/colorv2/config.json b/components/mjs/input/tex/extensions/colorv2/config.json new file mode 100644 index 000000000..50f43caf6 --- /dev/null +++ b/components/mjs/input/tex/extensions/colorv2/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/colorv2", + "component": "input/tex/extensions/colorv2", + "targets": ["input/tex/colorv2"] + }, + "webpack": { + "name": "input/tex/extensions/colorv2", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extensions/configmacros/config.json b/components/mjs/input/tex/extensions/configmacros/config.json new file mode 100644 index 000000000..b28646a7a --- /dev/null +++ b/components/mjs/input/tex/extensions/configmacros/config.json @@ -0,0 +1,16 @@ +{ + "build": { + "id": "[tex]/configmacros", + "component": "input/tex/extensions/configmacros", + "targets": ["input/tex/configmacros"] + }, + "webpack": { + "name": "input/tex/extensions/configmacros", + "libs": [ + "components/src/input/tex/extensions/newcommand/lib", + "components/src/input/tex-base/lib", + "components/src/core/lib", + "components/src/startup/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/configmacros/configmacros.js b/components/mjs/input/tex/extensions/configmacros/configmacros.js similarity index 100% rename from components/src/input/tex/extensions/configmacros/configmacros.js rename to components/mjs/input/tex/extensions/configmacros/configmacros.js diff --git a/components/mjs/input/tex/extensions/dsfont/config.json b/components/mjs/input/tex/extensions/dsfont/config.json new file mode 100644 index 000000000..81f6d8c64 --- /dev/null +++ b/components/mjs/input/tex/extensions/dsfont/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/dsfont", + "component": "input/tex/extensions/dsfont", + "targets": ["input/tex/dsfont"] + }, + "webpack": { + "name": "input/tex/extensions/dsfont", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extensions/dsfont/dsfont.js b/components/mjs/input/tex/extensions/dsfont/dsfont.js new file mode 100644 index 000000000..fce2c5d9b --- /dev/null +++ b/components/mjs/input/tex/extensions/dsfont/dsfont.js @@ -0,0 +1,4 @@ +import './lib/dsfont.js'; +import {fontExtension} from '../../extension.js'; + +fontExtension('[tex]/dsfont', 'mathjax-dsfont-font-extension'); diff --git a/components/mjs/input/tex/extensions/empheq/config.json b/components/mjs/input/tex/extensions/empheq/config.json new file mode 100644 index 000000000..5231b5d62 --- /dev/null +++ b/components/mjs/input/tex/extensions/empheq/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/empheq", + "component": "input/tex/extensions/empheq", + "targets": ["input/tex/empheq"] + }, + "webpack": { + "name": "input/tex/extensions/empheq", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/empheq/empheq.js b/components/mjs/input/tex/extensions/empheq/empheq.js similarity index 100% rename from components/src/input/tex/extensions/empheq/empheq.js rename to components/mjs/input/tex/extensions/empheq/empheq.js diff --git a/components/mjs/input/tex/extensions/enclose/config.json b/components/mjs/input/tex/extensions/enclose/config.json new file mode 100644 index 000000000..e9d6603fb --- /dev/null +++ b/components/mjs/input/tex/extensions/enclose/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/enclose", + "component": "input/tex/extensions/enclose", + "targets": ["input/tex/enclose"] + }, + "webpack": { + "name": "input/tex/extensions/enclose", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/enclose/enclose.js b/components/mjs/input/tex/extensions/enclose/enclose.js similarity index 100% rename from components/src/input/tex/extensions/enclose/enclose.js rename to components/mjs/input/tex/extensions/enclose/enclose.js diff --git a/components/mjs/input/tex/extensions/extpfeil/config.json b/components/mjs/input/tex/extensions/extpfeil/config.json new file mode 100644 index 000000000..493771252 --- /dev/null +++ b/components/mjs/input/tex/extensions/extpfeil/config.json @@ -0,0 +1,16 @@ +{ + "build": { + "id": "[tex]/extpfeil", + "component": "input/tex/extensions/extpfeil", + "targets": ["input/tex/extpfeil"] + }, + "webpack": { + "name": "input/tex/extensions/extpfeil", + "libs": [ + "components/src/input/tex/extensions/ams/lib", + "components/src/input/tex/extensions/newcommand/lib", + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/extpfeil/extpfeil.js b/components/mjs/input/tex/extensions/extpfeil/extpfeil.js similarity index 100% rename from components/src/input/tex/extensions/extpfeil/extpfeil.js rename to components/mjs/input/tex/extensions/extpfeil/extpfeil.js diff --git a/components/mjs/input/tex/extensions/gensymb/config.json b/components/mjs/input/tex/extensions/gensymb/config.json new file mode 100644 index 000000000..5d8466579 --- /dev/null +++ b/components/mjs/input/tex/extensions/gensymb/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/gensymb", + "component": "input/tex/extensions/gensymb", + "targets": ["input/tex/gensymb"] + }, + "webpack": { + "name": "input/tex/extensions/gensymb", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/gensymb/gensymb.js b/components/mjs/input/tex/extensions/gensymb/gensymb.js similarity index 100% rename from components/src/input/tex/extensions/gensymb/gensymb.js rename to components/mjs/input/tex/extensions/gensymb/gensymb.js diff --git a/components/mjs/input/tex/extensions/html/config.json b/components/mjs/input/tex/extensions/html/config.json new file mode 100644 index 000000000..ee870d405 --- /dev/null +++ b/components/mjs/input/tex/extensions/html/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/html", + "component": "input/tex/extensions/html", + "targets": ["input/tex/html"] + }, + "webpack": { + "name": "input/tex/extensions/html", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/html/html.js b/components/mjs/input/tex/extensions/html/html.js similarity index 100% rename from components/src/input/tex/extensions/html/html.js rename to components/mjs/input/tex/extensions/html/html.js diff --git a/components/mjs/input/tex/extensions/mathtools/config.json b/components/mjs/input/tex/extensions/mathtools/config.json new file mode 100644 index 000000000..0c57ebc10 --- /dev/null +++ b/components/mjs/input/tex/extensions/mathtools/config.json @@ -0,0 +1,16 @@ +{ + "build": { + "id": "[tex]/mathtools", + "component": "input/tex/extensions/mathtools", + "targets": ["input/tex/mathtools"] + }, + "webpack": { + "name": "input/tex/extensions/mathtools", + "libs": [ + "components/src/input/tex/extensions/ams/lib", + "components/src/input/tex/extensions/newcommand/lib", + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/mathtools/mathtools.js b/components/mjs/input/tex/extensions/mathtools/mathtools.js similarity index 100% rename from components/src/input/tex/extensions/mathtools/mathtools.js rename to components/mjs/input/tex/extensions/mathtools/mathtools.js diff --git a/components/mjs/input/tex/extensions/mhchem/config.json b/components/mjs/input/tex/extensions/mhchem/config.json new file mode 100644 index 000000000..120c6b886 --- /dev/null +++ b/components/mjs/input/tex/extensions/mhchem/config.json @@ -0,0 +1,16 @@ +{ + "build": { + "id": "[tex]/mhchem", + "component": "input/tex/extensions/mhchem", + "targets": ["input/tex/mhchem"], + "excludeSubdirs": true + }, + "webpack": { + "name": "input/tex/extensions/mhchem", + "libs": [ + "components/src/input/tex/extensions/ams/lib", + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extensions/mhchem/mhchem.js b/components/mjs/input/tex/extensions/mhchem/mhchem.js new file mode 100644 index 000000000..a5d5490e5 --- /dev/null +++ b/components/mjs/input/tex/extensions/mhchem/mhchem.js @@ -0,0 +1,4 @@ +import './lib/mhchem.js'; +import {fontExtension} from '../../extension.js'; + +fontExtension('[tex]/mhchem', 'mathjax-mhchem-font-extension'); diff --git a/components/mjs/input/tex/extensions/newcommand/config.json b/components/mjs/input/tex/extensions/newcommand/config.json new file mode 100644 index 000000000..0ef05e0a3 --- /dev/null +++ b/components/mjs/input/tex/extensions/newcommand/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/newcommand", + "component": "input/tex/extensions/newcommand", + "targets": ["input/tex/newcommand"] + }, + "webpack": { + "name": "input/tex/extensions/newcommand", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/newcommand/newcommand.js b/components/mjs/input/tex/extensions/newcommand/newcommand.js similarity index 100% rename from components/src/input/tex/extensions/newcommand/newcommand.js rename to components/mjs/input/tex/extensions/newcommand/newcommand.js diff --git a/components/mjs/input/tex/extensions/noerrors/config.json b/components/mjs/input/tex/extensions/noerrors/config.json new file mode 100644 index 000000000..bc7f939fc --- /dev/null +++ b/components/mjs/input/tex/extensions/noerrors/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/noerrors", + "component": "input/tex/extensions/noerrors", + "targets": ["input/tex/noerrors"] + }, + "webpack": { + "name": "input/tex/extensions/noerrors", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/noerrors/noerrors.js b/components/mjs/input/tex/extensions/noerrors/noerrors.js similarity index 100% rename from components/src/input/tex/extensions/noerrors/noerrors.js rename to components/mjs/input/tex/extensions/noerrors/noerrors.js diff --git a/components/mjs/input/tex/extensions/noundefined/config.json b/components/mjs/input/tex/extensions/noundefined/config.json new file mode 100644 index 000000000..db521bf7f --- /dev/null +++ b/components/mjs/input/tex/extensions/noundefined/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/noundefined", + "component": "input/tex/extensions/noundefined", + "targets": ["input/tex/noundefined"] + }, + "webpack": { + "name": "input/tex/extensions/noundefined", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/noundefined/noundefined.js b/components/mjs/input/tex/extensions/noundefined/noundefined.js similarity index 100% rename from components/src/input/tex/extensions/noundefined/noundefined.js rename to components/mjs/input/tex/extensions/noundefined/noundefined.js diff --git a/components/mjs/input/tex/extensions/physics/config.json b/components/mjs/input/tex/extensions/physics/config.json new file mode 100644 index 000000000..c1e020b82 --- /dev/null +++ b/components/mjs/input/tex/extensions/physics/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/physics", + "component": "input/tex/extensions/physics", + "targets": ["input/tex/physics"] + }, + "webpack": { + "name": "input/tex/extensions/physics", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/physics/physics.js b/components/mjs/input/tex/extensions/physics/physics.js similarity index 100% rename from components/src/input/tex/extensions/physics/physics.js rename to components/mjs/input/tex/extensions/physics/physics.js diff --git a/components/mjs/input/tex/extensions/require/config.json b/components/mjs/input/tex/extensions/require/config.json new file mode 100644 index 000000000..6ba57a337 --- /dev/null +++ b/components/mjs/input/tex/extensions/require/config.json @@ -0,0 +1,15 @@ +{ + "build": { + "id": "[tex]/require", + "component": "input/tex/extensions/require", + "targets": ["input/tex/require"] + }, + "webpack": { + "name": "input/tex/extensions/require", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib", + "components/src/startup/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/require/require.js b/components/mjs/input/tex/extensions/require/require.js similarity index 100% rename from components/src/input/tex/extensions/require/require.js rename to components/mjs/input/tex/extensions/require/require.js diff --git a/components/mjs/input/tex/extensions/setoptions/config.json b/components/mjs/input/tex/extensions/setoptions/config.json new file mode 100644 index 000000000..f329b6f34 --- /dev/null +++ b/components/mjs/input/tex/extensions/setoptions/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/setoptions", + "component": "input/tex/extensions/setoptions", + "targets": ["input/tex/setoptions"] + }, + "webpack": { + "name": "input/tex/extensions/setoptions", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/setoptions/setoptions.js b/components/mjs/input/tex/extensions/setoptions/setoptions.js similarity index 100% rename from components/src/input/tex/extensions/setoptions/setoptions.js rename to components/mjs/input/tex/extensions/setoptions/setoptions.js diff --git a/components/mjs/input/tex/extensions/tagformat/config.json b/components/mjs/input/tex/extensions/tagformat/config.json new file mode 100644 index 000000000..7349b09ec --- /dev/null +++ b/components/mjs/input/tex/extensions/tagformat/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/tagformat", + "component": "input/tex/extensions/tagformat", + "targets": ["input/tex/tagformat"] + }, + "webpack": { + "name": "input/tex/extensions/tagformat", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/tagformat/tagformat.js b/components/mjs/input/tex/extensions/tagformat/tagformat.js similarity index 100% rename from components/src/input/tex/extensions/tagformat/tagformat.js rename to components/mjs/input/tex/extensions/tagformat/tagformat.js diff --git a/components/mjs/input/tex/extensions/texhtml/config.json b/components/mjs/input/tex/extensions/texhtml/config.json new file mode 100644 index 000000000..a47940bae --- /dev/null +++ b/components/mjs/input/tex/extensions/texhtml/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/texhtml", + "component": "input/tex/extensions/texhtml", + "targets": ["input/tex/texhtml"] + }, + "webpack": { + "name": "input/tex/extensions/texhtml", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extensions/texhtml/texhtml.js b/components/mjs/input/tex/extensions/texhtml/texhtml.js new file mode 100644 index 000000000..f49989fca --- /dev/null +++ b/components/mjs/input/tex/extensions/texhtml/texhtml.js @@ -0,0 +1 @@ +import './lib/texhtml.js'; diff --git a/components/mjs/input/tex/extensions/textcomp/config.json b/components/mjs/input/tex/extensions/textcomp/config.json new file mode 100644 index 000000000..4a2906280 --- /dev/null +++ b/components/mjs/input/tex/extensions/textcomp/config.json @@ -0,0 +1,15 @@ +{ + "build": { + "id": "[tex]/textcomp", + "component": "input/tex/extensions/textcomp", + "targets": ["input/tex/textcomp"] + }, + "webpack": { + "name": "input/tex/extensions/textcomp", + "libs": [ + "components/src/input/tex/extensions/textmacros/lib", + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/textcomp/textcomp.js b/components/mjs/input/tex/extensions/textcomp/textcomp.js similarity index 100% rename from components/src/input/tex/extensions/textcomp/textcomp.js rename to components/mjs/input/tex/extensions/textcomp/textcomp.js diff --git a/components/mjs/input/tex/extensions/textmacros/config.json b/components/mjs/input/tex/extensions/textmacros/config.json new file mode 100644 index 000000000..bd05f220d --- /dev/null +++ b/components/mjs/input/tex/extensions/textmacros/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/textmacros", + "component": "input/tex/extensions/textmacros", + "targets": ["input/tex/textmacros"] + }, + "webpack": { + "name": "input/tex/extensions/textmacros", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/textmacros/textmacros.js b/components/mjs/input/tex/extensions/textmacros/textmacros.js similarity index 100% rename from components/src/input/tex/extensions/textmacros/textmacros.js rename to components/mjs/input/tex/extensions/textmacros/textmacros.js diff --git a/components/mjs/input/tex/extensions/unicode/config.json b/components/mjs/input/tex/extensions/unicode/config.json new file mode 100644 index 000000000..4d228828e --- /dev/null +++ b/components/mjs/input/tex/extensions/unicode/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/unicode", + "component": "input/tex/extensions/unicode", + "targets": ["input/tex/unicode"] + }, + "webpack": { + "name": "input/tex/extensions/unicode", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/unicode/unicode.js b/components/mjs/input/tex/extensions/unicode/unicode.js similarity index 100% rename from components/src/input/tex/extensions/unicode/unicode.js rename to components/mjs/input/tex/extensions/unicode/unicode.js diff --git a/components/mjs/input/tex/extensions/units/config.json b/components/mjs/input/tex/extensions/units/config.json new file mode 100644 index 000000000..8657bb9c8 --- /dev/null +++ b/components/mjs/input/tex/extensions/units/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/units", + "component": "input/tex/extensions/units", + "targets": ["input/tex/units"] + }, + "webpack": { + "name": "input/tex/extensions/units", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/mjs/input/tex/extensions/units/units.js b/components/mjs/input/tex/extensions/units/units.js new file mode 100644 index 000000000..cdf2a4add --- /dev/null +++ b/components/mjs/input/tex/extensions/units/units.js @@ -0,0 +1 @@ +import './lib/units.js'; diff --git a/components/mjs/input/tex/extensions/upgreek/config.json b/components/mjs/input/tex/extensions/upgreek/config.json new file mode 100644 index 000000000..336080cf6 --- /dev/null +++ b/components/mjs/input/tex/extensions/upgreek/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/upgreek", + "component": "input/tex/extensions/upgreek", + "targets": ["input/tex/upgreek"] + }, + "webpack": { + "name": "input/tex/extensions/upgreek", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/upgreek/upgreek.js b/components/mjs/input/tex/extensions/upgreek/upgreek.js similarity index 100% rename from components/src/input/tex/extensions/upgreek/upgreek.js rename to components/mjs/input/tex/extensions/upgreek/upgreek.js diff --git a/components/mjs/input/tex/extensions/verb/config.json b/components/mjs/input/tex/extensions/verb/config.json new file mode 100644 index 000000000..4632c17a6 --- /dev/null +++ b/components/mjs/input/tex/extensions/verb/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "id": "[tex]/verb", + "component": "input/tex/extensions/verb", + "targets": ["input/tex/verb"] + }, + "webpack": { + "name": "input/tex/extensions/verb", + "libs": [ + "components/src/input/tex-base/lib", + "components/src/core/lib" + ] + } +} diff --git a/components/src/input/tex/extensions/verb/verb.js b/components/mjs/input/tex/extensions/verb/verb.js similarity index 100% rename from components/src/input/tex/extensions/verb/verb.js rename to components/mjs/input/tex/extensions/verb/verb.js diff --git a/components/src/input/tex/register.js b/components/mjs/input/tex/register.js similarity index 72% rename from components/src/input/tex/register.js rename to components/mjs/input/tex/register.js index 32a298277..dd32b0b41 100644 --- a/components/src/input/tex/register.js +++ b/components/mjs/input/tex/register.js @@ -1,4 +1,4 @@ -import {insert} from '../../../../js/util/Options.js'; +import {insert} from '#js/util/Options.js'; export function registerTeX(packageList = [], tex = true) { if (MathJax.startup) { @@ -12,6 +12,9 @@ export function registerTeX(packageList = [], tex = true) { let packages = MathJax.config.tex.packages; MathJax.config.tex.packages = packageList; if (packages) { + if (Array.isArray(packages)) { + packages = {'[+]': packages.filter((name) => !packageList.includes(name))}; + } insert(MathJax.config.tex, {packages}); } } diff --git a/components/src/input/tex/tex.js b/components/mjs/input/tex/tex.js similarity index 75% rename from components/src/input/tex/tex.js rename to components/mjs/input/tex/tex.js index d0ba3ba93..32766c2dc 100644 --- a/components/src/input/tex/tex.js +++ b/components/mjs/input/tex/tex.js @@ -1,12 +1,13 @@ import './lib/tex.js'; import {registerTeX} from './register.js'; -import {Loader} from '../../../../js/components/loader.js'; +import {Loader} from '#js/components/loader.js'; -Loader.preLoad( +Loader.preLoaded( 'input/tex-base', '[tex]/ams', '[tex]/newcommand', + '[tex]/textmacros', '[tex]/noundefined', '[tex]/require', '[tex]/autoload', @@ -17,6 +18,7 @@ registerTeX([ 'base', 'ams', 'newcommand', + 'textmacros', 'noundefined', 'require', 'autoload', diff --git a/components/mjs/loader/config.json b/components/mjs/loader/config.json new file mode 100644 index 000000000..035a48892 --- /dev/null +++ b/components/mjs/loader/config.json @@ -0,0 +1,13 @@ +{ + "build": { + "component": "loader", + "targets": [ + "components/loader.ts", + "components/package.ts" + ], + "excludeSubdirs": true + }, + "webpack": { + "name": "loader" + } +} diff --git a/components/src/loader/loader.js b/components/mjs/loader/loader.js similarity index 75% rename from components/src/loader/loader.js rename to components/mjs/loader/loader.js index 86db4704d..de1d47cd4 100644 --- a/components/src/loader/loader.js +++ b/components/mjs/loader/loader.js @@ -1,7 +1,7 @@ import './lib/loader.js'; -import {Loader, CONFIG} from '../../../js/components/loader.js'; -import {combineDefaults} from '../../../js/components/global.js'; +import {Loader, CONFIG} from '#js/components/loader.js'; +import {combineDefaults} from '#js/components/global.js'; import {dependencies, paths, provides} from '../dependencies.js'; combineDefaults(MathJax.config.loader, 'dependencies', dependencies); diff --git a/components/mjs/mml-chtml-nofont/config.json b/components/mjs/mml-chtml-nofont/config.json new file mode 100644 index 000000000..d89aa9fbc --- /dev/null +++ b/components/mjs/mml-chtml-nofont/config.json @@ -0,0 +1,6 @@ +{ + "webpack": { + "name": "mml-chtml-nofont", + "font": false + } +} diff --git a/components/mjs/mml-chtml-nofont/mml-chtml-nofont.js b/components/mjs/mml-chtml-nofont/mml-chtml-nofont.js new file mode 100644 index 000000000..b40505919 --- /dev/null +++ b/components/mjs/mml-chtml-nofont/mml-chtml-nofont.js @@ -0,0 +1,18 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/mml/mml.js'; +import {loadFont} from '../output/chtml/chtml.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/mml', + 'output/chtml', + 'ui/menu' +); +Loader.saveVersion('mml-chtml-nofont'); + +loadFont(startup); diff --git a/components/mjs/mml-chtml/config.json b/components/mjs/mml-chtml/config.json new file mode 100644 index 000000000..781ebdbe7 --- /dev/null +++ b/components/mjs/mml-chtml/config.json @@ -0,0 +1,5 @@ +{ + "webpack": { + "name": "mml-chtml" + } +} diff --git a/components/mjs/mml-chtml/mml-chtml.js b/components/mjs/mml-chtml/mml-chtml.js new file mode 100644 index 000000000..171c9a6ab --- /dev/null +++ b/components/mjs/mml-chtml/mml-chtml.js @@ -0,0 +1,18 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/mml/mml.js'; +import {loadFont} from '../output/chtml/chtml.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/mml', + 'output/chtml', + 'ui/menu' +); +Loader.saveVersion('mml-chtml'); + +loadFont(startup, true); diff --git a/components/mjs/mml-svg-nofont/config.json b/components/mjs/mml-svg-nofont/config.json new file mode 100644 index 000000000..606bb3344 --- /dev/null +++ b/components/mjs/mml-svg-nofont/config.json @@ -0,0 +1,6 @@ +{ + "webpack": { + "name": "mml-svg-nofont", + "font": false + } +} diff --git a/components/mjs/mml-svg-nofont/mml-svg-nofont.js b/components/mjs/mml-svg-nofont/mml-svg-nofont.js new file mode 100644 index 000000000..cc3004f57 --- /dev/null +++ b/components/mjs/mml-svg-nofont/mml-svg-nofont.js @@ -0,0 +1,18 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/mml/mml.js'; +import {loadFont} from '../output/svg/svg.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/mml', + 'output/svg', + 'ui/menu' +); +Loader.saveVersion('mml-svg-nofont'); + +loadFont(startup); diff --git a/components/mjs/mml-svg/config.json b/components/mjs/mml-svg/config.json new file mode 100644 index 000000000..ba8e4d51a --- /dev/null +++ b/components/mjs/mml-svg/config.json @@ -0,0 +1,5 @@ +{ + "webpack": { + "name": "mml-svg" + } +} diff --git a/components/mjs/mml-svg/mml-svg.js b/components/mjs/mml-svg/mml-svg.js new file mode 100644 index 000000000..fc19bdc55 --- /dev/null +++ b/components/mjs/mml-svg/mml-svg.js @@ -0,0 +1,18 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/mml/mml.js'; +import {loadFont} from '../output/svg/svg.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/mml', + 'output/svg', + 'ui/menu' +); +Loader.saveVersion('mml-svg'); + +loadFont(startup, true); diff --git a/components/mjs/node-main/config.json b/components/mjs/node-main/config.json new file mode 100644 index 000000000..28cd82bb6 --- /dev/null +++ b/components/mjs/node-main/config.json @@ -0,0 +1,14 @@ +{ + "copy": { + "to": "../../../bundle", + "from": ".", + "copy": [ + "node-main.mjs", + "node-main.cjs", + "node-main-setup.mjs" + ] + }, + "webpack": { + "name": "node-main" + } +} diff --git a/components/mjs/node-main/node-main-setup.mjs b/components/mjs/node-main/node-main-setup.mjs new file mode 100644 index 000000000..f143f4233 --- /dev/null +++ b/components/mjs/node-main/node-main-setup.mjs @@ -0,0 +1,7 @@ +import {createRequire} from 'module'; +global.require = createRequire(import.meta.url); + +const path = require("path"); + +if (!global.MathJax) global.MathJax = {}; +global.MathJax.__dirname = path.dirname(new URL(import.meta.url).pathname); diff --git a/components/mjs/node-main/node-main.cjs b/components/mjs/node-main/node-main.cjs new file mode 100644 index 000000000..a431849a0 --- /dev/null +++ b/components/mjs/node-main/node-main.cjs @@ -0,0 +1,5 @@ +if (!global.MathJax) global.MathJax = {}; + +global.MathJax.__dirname = __dirname; + +module.exports = require('./node-main.js').MathJax; diff --git a/components/mjs/node-main/node-main.js b/components/mjs/node-main/node-main.js new file mode 100644 index 000000000..13b635173 --- /dev/null +++ b/components/mjs/node-main/node-main.js @@ -0,0 +1,95 @@ +/************************************************************* + * + * Copyright (c) 2019-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * Load the needed MathJax components + */ + +import '../startup/init.js'; +import {Loader, CONFIG} from '#js/components/loader.js'; +import {Package} from '#js/components/package.js'; +import {combineDefaults, combineConfig} from '#js/components/global.js'; +import '../core/core.js'; +import '../adaptors/liteDOM/liteDOM.js'; +import {source} from '../source.js'; + +const MathJax = global.MathJax; + +const path = eval('require("path")'); // get path from node, not webpack +const dir = MathJax.config.__dirname; // set up by node-main.mjs or node-main.cjs + +/* + * Set up the initial configuration + */ +combineDefaults(MathJax.config, 'loader', { + paths: {'mathjax-newcm': '@mathjax/mathjax-newcm-font'}, + require: eval("(file) => import(file)"), // use dynamic imports + failed: (err) => {throw err} // pass on error message to init()'s catch function +}); +combineDefaults(MathJax.config, 'output', {font: 'mathjax-newcm'}); + +/* + * Mark the preloaded components + */ +Loader.preLoaded('loader', 'startup', 'core', 'adaptors/liteDOM'); + +if (path.basename(dir) === 'node-main') { + CONFIG.paths.esm = CONFIG.paths.mathjax; + CONFIG.paths.sre = '[esm]/sre'; + CONFIG.paths.mathjax = path.dirname(dir); + combineDefaults(CONFIG, 'source', source); +} else { + CONFIG.paths.mathjax = dir; +} +// +// Set the asynchronous loader to use the js directory, so we can load +// other files like entity definitions +// +const ROOT = path.resolve(dir, '..', '..', '..', path.basename(path.dirname(dir))); +const REQUIRE = MathJax.config.loader.require; +MathJax._.mathjax.mathjax.asyncLoad = function (name) { + return REQUIRE(name.charAt(0) === '.' ? path.resolve(ROOT, name) : + name.charAt(0) === '[' ? Package.resolvePath(name) : name); +}; + +/* + * The initialization function. Use as: + * + * require('mathjax').init({ ... }).then((MathJax) => { ... }); + * + * or + * + * import {init} from 'mathjax'; + * init({...}).then((MathJax) => {...}); + * + * where the argument to init() is a MathJax configuration (what would be set as MathJax = {...}). + * The init() function returns a promise that is resolved when MathJax is loaded and ready, and that + * is passed the MathJax global variable when it is called. + */ +const init = MathJax.init = (config = {}) => { + combineConfig(MathJax.config, config); + return Loader.load(...CONFIG.load) + .then(() => CONFIG.ready()) + .then(() => MathJax.startup.promise) // Wait for MathJax to finish starting up + .then(() => MathJax) // Pass MathJax global as argument to subsequent .then() calls + .catch(error => CONFIG.failed(error)); +} + +/* + * Export MathJax (with its init() function) + */ +export {MathJax}; diff --git a/components/mjs/node-main/node-main.mjs b/components/mjs/node-main/node-main.mjs new file mode 100644 index 000000000..a6eb7be34 --- /dev/null +++ b/components/mjs/node-main/node-main.mjs @@ -0,0 +1,4 @@ +import './node-main-setup.mjs'; +import {MathJax} from './node-main.js'; +export default MathJax; +export const init = MathJax.init; diff --git a/components/mjs/node-main/webpack.cjs b/components/mjs/node-main/webpack.cjs new file mode 100644 index 000000000..28f1a5951 --- /dev/null +++ b/components/mjs/node-main/webpack.cjs @@ -0,0 +1,8 @@ +module.exports = (pkg) => { + pkg.output.library = { + name: 'MathJax', + type: 'commonjs', + export: ['MathJax'], + } + return pkg; +} diff --git a/components/mjs/output/chtml/chtml.js b/components/mjs/output/chtml/chtml.js new file mode 100644 index 000000000..db898f017 --- /dev/null +++ b/components/mjs/output/chtml/chtml.js @@ -0,0 +1,12 @@ +import './lib/chtml.js'; + +import {CHTML} from '#js/output/chtml.js'; +import {DefaultFont, fontName} from '#js/output/chtml/DefaultFont.js'; +import {OutputUtil} from '../util.js'; + +OutputUtil.config('chtml', CHTML, fontName, DefaultFont); + +export function loadFont(startup, preload) { + return OutputUtil.loadFont(startup, 'chtml', fontName, preload); +} + diff --git a/components/mjs/output/chtml/config.json b/components/mjs/output/chtml/config.json new file mode 100644 index 000000000..2890a1977 --- /dev/null +++ b/components/mjs/output/chtml/config.json @@ -0,0 +1,19 @@ +{ + "build": { + "component": "output/chtml", + "targets": [ + "output/chtml.ts", + "output/chtml", + "output/common.ts", + "output/common" + ] + }, + "webpack": { + "name": "output/chtml", + "libs": [ + "components/src/core/lib", + "components/src/startup/lib" + ], + "font": false + } +} diff --git a/components/mjs/output/svg/config.json b/components/mjs/output/svg/config.json new file mode 100644 index 000000000..660839c96 --- /dev/null +++ b/components/mjs/output/svg/config.json @@ -0,0 +1,19 @@ +{ + "build": { + "component": "output/svg", + "targets": [ + "output/svg.ts", + "output/svg", + "output/common.ts", + "output/common" + ] + }, + "webpack": { + "name": "output/svg", + "libs": [ + "components/src/core/lib", + "components/src/startup/lib" + ], + "font": false + } +} diff --git a/components/mjs/output/svg/svg.js b/components/mjs/output/svg/svg.js new file mode 100644 index 000000000..3c07780ad --- /dev/null +++ b/components/mjs/output/svg/svg.js @@ -0,0 +1,12 @@ +import './lib/svg.js'; + +import {SVG} from '#js/output/svg.js'; +import {DefaultFont, fontName} from '#js/output/svg/DefaultFont.js'; +import {OutputUtil} from '../util.js'; + +OutputUtil.config('svg', SVG, fontName, DefaultFont); + +export function loadFont(startup, preload) { + return OutputUtil.loadFont(startup, 'svg', fontName, preload); +} + diff --git a/components/mjs/output/util.js b/components/mjs/output/util.js new file mode 100644 index 000000000..31d964747 --- /dev/null +++ b/components/mjs/output/util.js @@ -0,0 +1,90 @@ +import {combineDefaults, combineWithMathJax} from '#js/components/global.js'; +import {Package} from '#js/components/package.js'; +import {hasWindow} from '#js/util/context.js'; + +export const FONTPATH = hasWindow ? + 'https://cdn.jsdelivr.net/npm/@mathjax/%%FONT%%-font': + '@mathjax/%%FONT%%-font'; +export const OutputUtil = { + config(jax, jaxClass, defaultFont, fontClass) { + + if (MathJax.loader) { + + combineDefaults(MathJax.config, jax, MathJax.config.output || {}); + + let config = MathJax.config[jax]; + let font = config.font || config.fontData || defaultFont; + if (typeof(font) !== 'string') { + config.fontData = font; + config.font = font = font.NAME; + } + + if (font.charAt(0) !== '[') { + const path = (config.fontPath || FONTPATH); + const name = (font.match(/^[a-z]+:/) ? (font.match(/[^/:\\]*$/) || [jax])[0] : font); + combineDefaults(MathJax.config.loader, 'paths', { + [name]: (name === font ? path.replace(/%%FONT%%/g, font) : font) + }); + font = `[${name}]`; + } + const name = font.substring(1, font.length - 1); + + if (name !== defaultFont || !fontClass) { + + MathJax.loader.addPackageData(`output/${jax}`, {extraLoads: [`${font}/${jax}`]}); + + } else { + + const extraLoads = MathJax.config.loader[`${font}/${jax}`]?.extraLoads; + if (extraLoads) { + MathJax.loader.addPackageData(`output/${jax}`, {extraLoads}); + } + + combineWithMathJax({_: { + output: { + fonts: { + [name]: { + [jax + '_ts']: { + [fontClass.NAME + 'Font']: fontClass + } + } + } + } + }}); + + combineDefaults(MathJax, 'config', { + output: { + font: font, + }, + [jax]: { + fontData: fontClass, + dynamicPrefix: `${font}/${jax}/dynamic` + } + }); + if (jax === 'chtml') { + combineDefaults(MathJax.config, jax, { + fontURL: Package.resolvePath(`${font}/${jax}/woff2`, false), + }); + } + + } + } + + if (MathJax.startup) { + MathJax.startup.registerConstructor(jax, jaxClass); + MathJax.startup.useOutput(jax); + } + + }, + + loadFont(startup, jax, font, preloaded) { + if (!MathJax.loader) { + return startup; + } + if (preloaded) { + MathJax.loader.preLoaded(`[${font}]/${jax}`); + } + return Package.loadPromise(`output/${jax}`).then(startup); + } + +}; diff --git a/components/mjs/require/config.json b/components/mjs/require/config.json new file mode 100644 index 000000000..599ec23e9 --- /dev/null +++ b/components/mjs/require/config.json @@ -0,0 +1,9 @@ +{ + "copy": { + "to": "../../../bundle", + "from": "../..", + "copy": [ + "require.mjs" + ] + } +} diff --git a/ts/output/chtml/fonts/tex/script-bold.ts b/components/mjs/source-lab.js similarity index 83% rename from ts/output/chtml/fonts/tex/script-bold.ts rename to components/mjs/source-lab.js index 513e892c0..708290300 100644 --- a/ts/output/chtml/fonts/tex/script-bold.ts +++ b/components/mjs/source-lab.js @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2019-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,4 +14,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export {scriptBold} from '../../../common/fonts/tex/script-bold.js'; + +export const src = String(new URL('.', import.meta.url)).replace(/\/$/, ''); diff --git a/ts/output/svg/fonts/tex/script.ts b/components/mjs/source.cjs similarity index 85% rename from ts/output/svg/fonts/tex/script.ts rename to components/mjs/source.cjs index 86606f349..db7fddf94 100644 --- a/ts/output/svg/fonts/tex/script.ts +++ b/components/mjs/source.cjs @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2019-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,4 +14,5 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -export {script} from '../../../common/fonts/tex/script.js'; + +module.exports.src = __dirname; diff --git a/components/mjs/source.d.cts b/components/mjs/source.d.cts new file mode 100644 index 000000000..93e9f7a7c --- /dev/null +++ b/components/mjs/source.d.cts @@ -0,0 +1 @@ +export declare const src: string; diff --git a/components/src/source.js b/components/mjs/source.js similarity index 74% rename from components/src/source.js rename to components/mjs/source.js index 59d30bf1f..e632cbf88 100644 --- a/components/src/source.js +++ b/components/mjs/source.js @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2019-2021 The MathJax Consortium + * Copyright (c) 2019-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,30 +15,39 @@ * limitations under the License. */ -const src = __dirname; +import {src} from '#source/source.cjs'; export const source = { 'core': `${src}/core/core.js`, + 'adaptors/jsdom': `${src}/adaptors/jsdom/jsdom.js`, + 'adaptors/linkedom': `${src}/adaptors/linkedom/linkedom.js`, 'adaptors/liteDOM': `${src}/adaptors/liteDOM/liteDOM.js`, 'input/tex': `${src}/input/tex/tex.js`, 'input/tex-base': `${src}/input/tex-base/tex-base.js`, 'input/tex-full': `${src}/input/tex-full/tex-full.js`, '[tex]/action': `${src}/input/tex/extensions/action/action.js`, - '[tex]/all-packages': `${src}/input/tex/extensions/all-packages/all-packages.js`, - '[tex]/autoload': `${src}/input/tex/extensions/autoload/autoload.js`, '[tex]/ams': `${src}/input/tex/extensions/ams/ams.js`, '[tex]/amscd': `${src}/input/tex/extensions/amscd/amscd.js`, + '[tex]/autoload': `${src}/input/tex/extensions/autoload/autoload.js`, + '[tex]/bbm': `${src}/input/tex/extensions/bbm/bbm.js`, + '[tex]/bboldx': `${src}/input/tex/extensions/bboldx/bboldx.js`, '[tex]/bbox': `${src}/input/tex/extensions/bbox/bbox.js`, + '[tex]/begingroup': `${src}/input/tex/extensions/begingroup/begingroup.js`, '[tex]/boldsymbol': `${src}/input/tex/extensions/boldsymbol/boldsymbol.js`, '[tex]/braket': `${src}/input/tex/extensions/braket/braket.js`, '[tex]/bussproofs': `${src}/input/tex/extensions/bussproofs/bussproofs.js`, '[tex]/cancel': `${src}/input/tex/extensions/cancel/cancel.js`, + '[tex]/cases': `${src}/input/tex/extensions/cases/cases.js`, '[tex]/centernot': `${src}/input/tex/extensions/centernot/centernot.js`, '[tex]/color': `${src}/input/tex/extensions/color/color.js`, + '[tex]/colortbl': `${src}/input/tex/extensions/colortbl/colortbl.js`, '[tex]/colorv2': `${src}/input/tex/extensions/colorv2/colorv2.js`, '[tex]/configmacros': `${src}/input/tex/extensions/configmacros/configmacros.js`, + '[tex]/dsfont': `${src}/input/tex/extensions/dsfont/dsfont.js`, + '[tex]/empheq': `${src}/input/tex/extensions/empheq/empheq.js`, '[tex]/enclose': `${src}/input/tex/extensions/enclose/enclose.js`, '[tex]/extpfeil': `${src}/input/tex/extensions/extpfeil/extpfeil.js`, + '[tex]/gensymb': `${src}/input/tex/extensions/gensymb/gensymb.js`, '[tex]/html': `${src}/input/tex/extensions/html/html.js`, '[tex]/mathtools': `${src}/input/tex/extensions/mathtools/mathtools.js`, '[tex]/mhchem': `${src}/input/tex/extensions/mhchem/mhchem.js`, @@ -49,33 +58,41 @@ export const source = { '[tex]/require': `${src}/input/tex/extensions/require/require.js`, '[tex]/setoptions': `${src}/input/tex/extensions/setoptions/setoptions.js`, '[tex]/tagformat': `${src}/input/tex/extensions/tagformat/tagformat.js`, + '[tex]/texhtml': `${src}/input/tex/extensions/texhtml/texhtml.js`, + '[tex]/textcomp': `${src}/input/tex/extensions/textcomp/textcomp.js`, '[tex]/textmacros': `${src}/input/tex/extensions/textmacros/textmacros.js`, '[tex]/unicode': `${src}/input/tex/extensions/unicode/unicode.js`, + '[tex]/units': `${src}/input/tex/extensions/units/units.js`, + '[tex]/upgreek': `${src}/input/tex/extensions/upgreek/upgreek.js`, '[tex]/verb': `${src}/input/tex/extensions/verb/verb.js`, - '[tex]/cases': `${src}/input/tex/extensions/cases/cases.js`, - '[tex]/empheq': `${src}/input/tex/extensions/empheq/empheq.js`, 'input/mml': `${src}/input/mml/mml.js`, 'input/mml/entities': `${src}/input/mml/entities/entities.js`, '[mml]/mml3': `${src}/input/mml/extensions/mml3/mml3.js`, 'input/asciimath': `${src}/input/asciimath/asciimath.js`, 'output/chtml': `${src}/output/chtml/chtml.js`, - 'output/chtml/fonts/tex': `${src}/output/chtml/fonts/tex/tex.js`, 'output/svg': `${src}/output/svg/svg.js`, - 'output/svg/fonts/tex': `${src}/output/svg/fonts/tex/tex.js`, 'a11y/assistive-mml': `${src}/a11y/assistive-mml/assistive-mml.js`, 'a11y/semantic-enrich': `${src}/a11y/semantic-enrich/semantic-enrich.js`, + 'a11y/speech': `${src}/a11y/speech/speech.js`, 'a11y/complexity': `${src}/a11y/complexity/complexity.js`, 'a11y/explorer': `${src}/a11y/explorer/explorer.js`, 'a11y/sre': `${src}/a11y/sre/sre.js`, + '[mathmaps]': `${src}/../../bundle/sre/mathmaps`, 'ui/lazy': `${src}/ui/lazy/lazy.js`, 'ui/menu': `${src}/ui/menu/menu.js`, 'ui/safe': `${src}/ui/safe/safe.js`, 'mml-chtml': `${src}/mml-chtml/mml-chtml.js`, + 'mml-chtml-nofont': `${src}/mml-chtml-nofont/mml-chtml-nofont.js`, 'mml-svg': `${src}/mml-svg/mml-svg.js`, + 'mml-svg-nofont': `${src}/mml-svg-nofont/mml-svg-nofont.js`, 'tex-chtml': `${src}/tex-chtml/tex-chtml.js`, + 'tex-chtml-nofont': `${src}/tex-chtml-nofont/tex-chtml-nofont.js`, 'tex-svg': `${src}/tex-svg/tex-svg.js`, + 'tex-svg-nofont': `${src}/tex-svg-nofont/tex-svg-nofont.js`, 'tex-mml-chtml': `${src}/tex-mml-chtml/tex-mml-chtml.js`, + 'tex-mml-chtml-nofont': `${src}/tex-mml-chtml-nofont/tex-mml-chtml-nofont.js`, 'tex-mml-svg': `${src}/tex-mml-svg/tex-mml-svg.js`, + 'tex-mml-svg-nofont': `${src}/tex-mml-svg-nofont/tex-mml-svg-nofont.js`, 'loader': `${src}/loader/loader.js`, 'startup': `${src}/startup/startup.js` }; diff --git a/components/mjs/sre/config.json b/components/mjs/sre/config.json new file mode 100644 index 000000000..5cca64ca2 --- /dev/null +++ b/components/mjs/sre/config.json @@ -0,0 +1,9 @@ +{ + "copy": { + "to": "../../../bundle/sre", + "from": "[node]/speech-rule-engine/lib", + "copy": [ + "mathmaps" + ] + } +} diff --git a/components/mjs/startup/config.json b/components/mjs/startup/config.json new file mode 100644 index 000000000..c59df80f7 --- /dev/null +++ b/components/mjs/startup/config.json @@ -0,0 +1,14 @@ +{ + "build": { + "component": "startup", + "targets": [ + "components/loader.ts", + "components/package.ts", + "components/startup.ts" + ], + "excludeSubdirs": true + }, + "webpack": { + "name": "startup" + } +} diff --git a/components/mjs/startup/init.js b/components/mjs/startup/init.js new file mode 100644 index 000000000..f34d29799 --- /dev/null +++ b/components/mjs/startup/init.js @@ -0,0 +1,19 @@ +import './lib/startup.js'; + +import {combineDefaults} from '#js/components/global.js'; +import {dependencies, paths, provides, compatibility} from '../dependencies.js'; +import {Loader, CONFIG} from '#js/components/loader.js'; + +Loader.preLoaded('loader', 'startup'); + +combineDefaults(MathJax.config.loader, 'dependencies', dependencies); +combineDefaults(MathJax.config.loader, 'paths', paths); +combineDefaults(MathJax.config.loader, 'provides', provides); +combineDefaults(MathJax.config.loader, 'source', compatibility); + +export function startup(ready) { + return Loader.load(...CONFIG.load) + .then(() => (ready || function () {})()) + .then(() => CONFIG.ready()) + .catch(error => CONFIG.failed(error)); +} diff --git a/components/mjs/startup/startup.js b/components/mjs/startup/startup.js new file mode 100644 index 000000000..96a5862f0 --- /dev/null +++ b/components/mjs/startup/startup.js @@ -0,0 +1,3 @@ +import {startup} from './init.js'; + +startup(); diff --git a/components/mjs/tex-chtml-nofont/config.json b/components/mjs/tex-chtml-nofont/config.json new file mode 100644 index 000000000..349a7a204 --- /dev/null +++ b/components/mjs/tex-chtml-nofont/config.json @@ -0,0 +1,6 @@ +{ + "webpack": { + "name": "tex-chtml-nofont", + "font": false + } +} diff --git a/components/mjs/tex-chtml-nofont/tex-chtml-nofont.js b/components/mjs/tex-chtml-nofont/tex-chtml-nofont.js new file mode 100644 index 000000000..a76417c01 --- /dev/null +++ b/components/mjs/tex-chtml-nofont/tex-chtml-nofont.js @@ -0,0 +1,17 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/tex/tex.js'; +import {loadFont} from '../output/chtml/chtml.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'core', + 'input/tex', + 'output/chtml', + 'ui/menu' +); +Loader.saveVersion('tex-chtml-nofont'); + +loadFont(startup); diff --git a/components/mjs/tex-chtml/config.json b/components/mjs/tex-chtml/config.json new file mode 100644 index 000000000..9d1b2901a --- /dev/null +++ b/components/mjs/tex-chtml/config.json @@ -0,0 +1,5 @@ +{ + "webpack": { + "name": "tex-chtml" + } +} diff --git a/components/mjs/tex-chtml/tex-chtml.js b/components/mjs/tex-chtml/tex-chtml.js new file mode 100644 index 000000000..914858dcf --- /dev/null +++ b/components/mjs/tex-chtml/tex-chtml.js @@ -0,0 +1,18 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/tex/tex.js'; +import {loadFont} from '../output/chtml/chtml.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/tex', + 'output/chtml', + 'ui/menu' +); +Loader.saveVersion('tex-chtml'); + +loadFont(startup, true); diff --git a/components/mjs/tex-mml-chtml-nofont/config.json b/components/mjs/tex-mml-chtml-nofont/config.json new file mode 100644 index 000000000..bb511956e --- /dev/null +++ b/components/mjs/tex-mml-chtml-nofont/config.json @@ -0,0 +1,6 @@ +{ + "webpack": { + "name": "tex-mml-chtml-nofont", + "font": false + } +} diff --git a/components/mjs/tex-mml-chtml-nofont/tex-mml-chtml-nofont.js b/components/mjs/tex-mml-chtml-nofont/tex-mml-chtml-nofont.js new file mode 100644 index 000000000..ccb4ea1be --- /dev/null +++ b/components/mjs/tex-mml-chtml-nofont/tex-mml-chtml-nofont.js @@ -0,0 +1,19 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/tex/tex.js'; +import '../input/mml/mml.js'; +import {loadFont} from '../output/chtml/chtml.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/tex', 'input/mml', + 'output/chtml', + 'ui/menu' +); +Loader.saveVersion('tex-mml-chtml-nofont'); + +loadFont(startup); diff --git a/components/mjs/tex-mml-chtml/config.json b/components/mjs/tex-mml-chtml/config.json new file mode 100644 index 000000000..d68ac31d4 --- /dev/null +++ b/components/mjs/tex-mml-chtml/config.json @@ -0,0 +1,5 @@ +{ + "webpack": { + "name": "tex-mml-chtml" + } +} diff --git a/components/mjs/tex-mml-chtml/tex-mml-chtml.js b/components/mjs/tex-mml-chtml/tex-mml-chtml.js new file mode 100644 index 000000000..c9baf3e49 --- /dev/null +++ b/components/mjs/tex-mml-chtml/tex-mml-chtml.js @@ -0,0 +1,19 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/tex/tex.js'; +import '../input/mml/mml.js'; +import {loadFont} from '../output/chtml/chtml.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/tex', 'input/mml', + 'output/chtml', + 'ui/menu' +); +Loader.saveVersion('tex-mml-chtml'); + +loadFont(startup, true); diff --git a/components/mjs/tex-mml-svg-nofont/config.json b/components/mjs/tex-mml-svg-nofont/config.json new file mode 100644 index 000000000..fca0798cf --- /dev/null +++ b/components/mjs/tex-mml-svg-nofont/config.json @@ -0,0 +1,6 @@ +{ + "webpack": { + "name": "tex-mml-svg-nofont", + "font": false + } +} diff --git a/components/mjs/tex-mml-svg-nofont/tex-mml-svg-nofont.js b/components/mjs/tex-mml-svg-nofont/tex-mml-svg-nofont.js new file mode 100644 index 000000000..934f9880b --- /dev/null +++ b/components/mjs/tex-mml-svg-nofont/tex-mml-svg-nofont.js @@ -0,0 +1,19 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/tex/tex.js'; +import '../input/mml/mml.js'; +import {loadFont} from '../output/svg/svg.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/tex', 'input/mml', + 'output/svg', + 'ui/menu' +); +Loader.saveVersion('tex-mml-svg-nofont'); + +loadFont(startup); diff --git a/components/mjs/tex-mml-svg/config.json b/components/mjs/tex-mml-svg/config.json new file mode 100644 index 000000000..3cedbd0da --- /dev/null +++ b/components/mjs/tex-mml-svg/config.json @@ -0,0 +1,5 @@ +{ + "webpack": { + "name": "tex-mml-svg" + } +} diff --git a/components/mjs/tex-mml-svg/tex-mml-svg.js b/components/mjs/tex-mml-svg/tex-mml-svg.js new file mode 100644 index 000000000..d4c06ee5e --- /dev/null +++ b/components/mjs/tex-mml-svg/tex-mml-svg.js @@ -0,0 +1,19 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/tex/tex.js'; +import '../input/mml/mml.js'; +import {loadFont} from '../output/svg/svg.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/tex', 'input/mml', + 'output/svg', + 'ui/menu' +); +Loader.saveVersion('tex-mml-svg'); + +loadFont(startup, true); diff --git a/components/mjs/tex-svg-nofont/config.json b/components/mjs/tex-svg-nofont/config.json new file mode 100644 index 000000000..5659e7251 --- /dev/null +++ b/components/mjs/tex-svg-nofont/config.json @@ -0,0 +1,6 @@ +{ + "webpack": { + "name": "tex-svg-nofont", + "font": false + } +} diff --git a/components/mjs/tex-svg-nofont/tex-svg-nofont.js b/components/mjs/tex-svg-nofont/tex-svg-nofont.js new file mode 100644 index 000000000..308c355a8 --- /dev/null +++ b/components/mjs/tex-svg-nofont/tex-svg-nofont.js @@ -0,0 +1,17 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/tex/tex.js'; +import {loadFont} from '../output/svg/svg.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'core', + 'input/tex', + 'output/svg', + 'ui/menu' +); +Loader.saveVersion('tex-svg-nofont'); + +loadFont(startup); diff --git a/components/mjs/tex-svg/config.json b/components/mjs/tex-svg/config.json new file mode 100644 index 000000000..e3867c006 --- /dev/null +++ b/components/mjs/tex-svg/config.json @@ -0,0 +1,5 @@ +{ + "webpack": { + "name": "tex-svg" + } +} diff --git a/components/mjs/tex-svg/tex-svg.js b/components/mjs/tex-svg/tex-svg.js new file mode 100644 index 000000000..a3d23875c --- /dev/null +++ b/components/mjs/tex-svg/tex-svg.js @@ -0,0 +1,18 @@ +import {startup} from '../startup/init.js'; +import {Loader} from '#js/components/loader.js'; +import '../core/core.js'; +import '../input/tex/tex.js'; +import {loadFont} from '../output/svg/svg.js'; +import '../ui/menu/menu.js'; +import '../a11y/util.js'; + +Loader.preLoaded( + 'loader', 'startup', + 'core', + 'input/tex', + 'output/svg', + 'ui/menu' +); +Loader.saveVersion('tex-svg'); + +loadFont(startup, true); diff --git a/components/mjs/ui/lazy/config.json b/components/mjs/ui/lazy/config.json new file mode 100644 index 000000000..52a66b78e --- /dev/null +++ b/components/mjs/ui/lazy/config.json @@ -0,0 +1,10 @@ +{ + "build": { + "component": "ui/lazy", + "targets": ["ui/lazy"] + }, + "webpack": { + "name": "ui/lazy", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/src/ui/lazy/lazy.js b/components/mjs/ui/lazy/lazy.js similarity index 63% rename from components/src/ui/lazy/lazy.js rename to components/mjs/ui/lazy/lazy.js index b75c44bbe..e2724c5bf 100644 --- a/components/src/ui/lazy/lazy.js +++ b/components/mjs/ui/lazy/lazy.js @@ -1,6 +1,6 @@ import './lib/lazy.js'; -import {LazyHandler} from '../../../../js/ui/lazy/LazyHandler.js'; +import {LazyHandler} from '#js/ui/lazy/LazyHandler.js'; if (MathJax.startup) { MathJax.startup.extendHandler(handler => LazyHandler(handler)); diff --git a/components/mjs/ui/menu/config.json b/components/mjs/ui/menu/config.json new file mode 100644 index 000000000..4fffd9231 --- /dev/null +++ b/components/mjs/ui/menu/config.json @@ -0,0 +1,15 @@ +{ + "build": { + "component": "ui/menu", + "targets": ["ui/menu", "a11y/speech/SpeechMenu.ts"], + "excludeSubdirs": true + }, + "webpack": { + "name": "ui/menu", + "libs": [ + "components/src/core/lib", + "components/src/a11y/sre/lib", + "node_modules/mj-context-menu/js" + ] + } +} diff --git a/components/mjs/ui/menu/menu.js b/components/mjs/ui/menu/menu.js new file mode 100644 index 000000000..b4e50d092 --- /dev/null +++ b/components/mjs/ui/menu/menu.js @@ -0,0 +1,9 @@ +import './lib/menu.js'; + +import {combineDefaults} from '#js/components/global.js'; +import {MenuHandler} from '#js/ui/menu/MenuHandler.js'; +import {hasWindow} from '#js/util/context.js'; + +if (MathJax.startup && hasWindow) { + MathJax.startup.extendHandler(handler => MenuHandler(handler), 20); +} diff --git a/components/mjs/ui/safe/config.json b/components/mjs/ui/safe/config.json new file mode 100644 index 000000000..e836db2d2 --- /dev/null +++ b/components/mjs/ui/safe/config.json @@ -0,0 +1,10 @@ +{ + "build": { + "component": "ui/safe", + "targets": ["ui/safe"] + }, + "webpack": { + "name": "ui/safe", + "libs": ["components/src/core/lib"] + } +} diff --git a/components/mjs/ui/safe/safe.js b/components/mjs/ui/safe/safe.js new file mode 100644 index 000000000..d8b9aa1f8 --- /dev/null +++ b/components/mjs/ui/safe/safe.js @@ -0,0 +1,7 @@ +import './lib/safe.js'; + +import {SafeHandler} from '#js/ui/safe/SafeHandler.js'; + +if (MathJax.startup) { + MathJax.startup.extendHandler(handler => SafeHandler(handler)); +} diff --git a/components/require.d.mts b/components/require.d.mts new file mode 100644 index 000000000..dcc8de4d6 --- /dev/null +++ b/components/require.d.mts @@ -0,0 +1 @@ +export function require(file: string): any; diff --git a/components/require.mjs b/components/require.mjs new file mode 100644 index 000000000..a45271169 --- /dev/null +++ b/components/require.mjs @@ -0,0 +1,2 @@ +import {createRequire} from 'module'; +global.require = createRequire(import.meta.url); diff --git a/components/root-pack.js b/components/root-pack.js new file mode 100644 index 000000000..ee18e3eb9 --- /dev/null +++ b/components/root-pack.js @@ -0,0 +1,8 @@ +// +// Replacement for __dirname for root directory +// + +import {MathJax} from '#js/components/global.js'; + +const config = MathJax.config || {}; +export const mjxRoot = () => config?.loader?.paths?.mathjax || config?.__dirname || '/'; diff --git a/components/src/a11y/assistive-mml/assistive-mml.js b/components/src/a11y/assistive-mml/assistive-mml.js deleted file mode 100644 index 745e65aee..000000000 --- a/components/src/a11y/assistive-mml/assistive-mml.js +++ /dev/null @@ -1,7 +0,0 @@ -import './lib/assistive-mml.js'; - -import {AssistiveMmlHandler} from '../../../../js/a11y/assistive-mml.js'; - -if (MathJax.startup) { - MathJax.startup.extendHandler(handler => AssistiveMmlHandler(handler)); -} diff --git a/components/src/a11y/assistive-mml/build.json b/components/src/a11y/assistive-mml/build.json deleted file mode 100644 index c7ac2bd3e..000000000 --- a/components/src/a11y/assistive-mml/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component": "a11y/assistive-mml", - "targets": ["a11y/assistive-mml.ts"] -} - diff --git a/components/src/a11y/assistive-mml/webpack.config.js b/components/src/a11y/assistive-mml/webpack.config.js deleted file mode 100644 index b89b94d5b..000000000 --- a/components/src/a11y/assistive-mml/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'a11y/assistive-mml', // the package to build - '../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/mml/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/a11y/complexity/build.json b/components/src/a11y/complexity/build.json deleted file mode 100644 index c26a9b745..000000000 --- a/components/src/a11y/complexity/build.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "component": "a11y/complexity", - "targets": [ - "a11y/complexity.ts", - "a11y/complexity", - "a11y/semantic-enrich.ts" - ] -} diff --git a/components/src/a11y/complexity/webpack.config.js b/components/src/a11y/complexity/webpack.config.js deleted file mode 100644 index c049f6d89..000000000 --- a/components/src/a11y/complexity/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'a11y/complexity', // the package to build - '../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/a11y/semantic-enrich/lib', - 'components/src/input/mml/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/a11y/explorer/build.json b/components/src/a11y/explorer/build.json deleted file mode 100644 index 9ebcdc5a1..000000000 --- a/components/src/a11y/explorer/build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "component": "a11y/explorer", - "targets": ["a11y/explorer.ts", "a11y/explorer"] -} diff --git a/components/src/a11y/explorer/explorer.js b/components/src/a11y/explorer/explorer.js deleted file mode 100644 index 25a6f7b08..000000000 --- a/components/src/a11y/explorer/explorer.js +++ /dev/null @@ -1,8 +0,0 @@ -import './lib/explorer.js'; - -import {combineDefaults} from '../../../../js/components/global.js'; -import {ExplorerHandler} from '../../../../js/a11y/explorer.js'; - -if (MathJax.startup) { - MathJax.startup.extendHandler(handler => ExplorerHandler(handler)); -} diff --git a/components/src/a11y/explorer/webpack.config.js b/components/src/a11y/explorer/webpack.config.js deleted file mode 100644 index b44c45e70..000000000 --- a/components/src/a11y/explorer/webpack.config.js +++ /dev/null @@ -1,14 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'a11y/explorer', // the package to build - '../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/ui/menu/lib', - 'components/src/a11y/semantic-enrich/lib', - 'components/src/a11y/sre/lib', - 'components/src/input/mml/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/a11y/semantic-enrich/build.json b/components/src/a11y/semantic-enrich/build.json deleted file mode 100644 index c6f85eacb..000000000 --- a/components/src/a11y/semantic-enrich/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component": "a11y/semantic-enrich", - "targets": ["a11y/semantic-enrich.ts"] -} - diff --git a/components/src/a11y/semantic-enrich/semantic-enrich.js b/components/src/a11y/semantic-enrich/semantic-enrich.js deleted file mode 100644 index 2491174dc..000000000 --- a/components/src/a11y/semantic-enrich/semantic-enrich.js +++ /dev/null @@ -1,14 +0,0 @@ -import './lib/semantic-enrich.js'; - -import {combineDefaults} from '../../../../js/components/global.js'; -import Sre from '../../../../js/a11y/sre.js'; -import {EnrichHandler} from '../../../../js/a11y/semantic-enrich.js'; -import {MathML} from '../../../../js/input/mathml.js'; - -if (MathJax.loader) { - combineDefaults(MathJax.config.loader, 'a11y/semantic-enrich', {checkReady: () => Sre.sreReady()}); -} - -if (MathJax.startup) { - MathJax.startup.extendHandler(handler => EnrichHandler(handler, new MathML())); -} diff --git a/components/src/a11y/semantic-enrich/webpack.config.js b/components/src/a11y/semantic-enrich/webpack.config.js deleted file mode 100644 index 8de3e025f..000000000 --- a/components/src/a11y/semantic-enrich/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'a11y/semantic-enrich', // the package to build - '../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/mml/lib', - 'components/src/core/lib', - 'components/src/a11y/sre/lib' - ], - __dirname // our directory -); diff --git a/components/src/a11y/sre/build.json b/components/src/a11y/sre/build.json deleted file mode 100644 index fe6b7dd84..000000000 --- a/components/src/a11y/sre/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component": "a11y/sre", - "targets": ["a11y/sre.ts"] -} - diff --git a/components/src/a11y/sre/sre.js b/components/src/a11y/sre/sre.js deleted file mode 100644 index 0327644d9..000000000 --- a/components/src/a11y/sre/sre.js +++ /dev/null @@ -1,9 +0,0 @@ -import './lib/sre.js'; -import './sre_config.js'; -import Sre from '../../../../js/a11y/sre.js'; - -if (MathJax.startup) { - ((typeof window !== 'undefined') ? window : global). - SREfeature.custom = (loc) => Sre.preloadLocales(loc); -} - diff --git a/components/src/a11y/sre/sre_config.js b/components/src/a11y/sre/sre_config.js deleted file mode 100644 index 0dd3ae3e0..000000000 --- a/components/src/a11y/sre/sre_config.js +++ /dev/null @@ -1,19 +0,0 @@ -import {combineDefaults} from '../../../../js/components/global.js'; -import {Package} from '../../../../js/components/package.js'; - -// This sets up the correct link to the mathmaps files. -if (MathJax.startup) { - - let path = Package.resolvePath('[sre]', false); - - if (typeof window !== 'undefined') { - window.SREfeature = {json: path}; - } else { - // In Node get the absolute path to the mathmaps directory. - try { - path = MathJax.config.loader.require.resolve( - path + '/base.json').replace(/\/base\.json$/, ''); - } catch(_err) { } - global.SREfeature = {json: path}; - } -} diff --git a/components/src/a11y/sre/webpack.config.js b/components/src/a11y/sre/webpack.config.js deleted file mode 100644 index c89adb4b7..000000000 --- a/components/src/a11y/sre/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'a11y/sre', // the package to build - '../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/mml/lib', - 'components/src/core/lib', - 'components/src/startup/lib' - ], - __dirname // our directory -); diff --git a/components/src/adaptors/liteDOM/build.json b/components/src/adaptors/liteDOM/build.json deleted file mode 100644 index 334f3f091..000000000 --- a/components/src/adaptors/liteDOM/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component": "adaptors/liteDOM", - "targets": ["adaptors/liteAdaptor.ts", "adaptors/lite"] -} - diff --git a/components/src/adaptors/liteDOM/webpack.config.js b/components/src/adaptors/liteDOM/webpack.config.js deleted file mode 100644 index 6c29ad8c4..000000000 --- a/components/src/adaptors/liteDOM/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'adaptors/liteDOM', // the package to build - '../../../../js', // location of the MathJax js library - ['components/src/core/lib'], // packages to link to - __dirname // our directory -); diff --git a/components/src/core/build.json b/components/src/core/build.json deleted file mode 100644 index b9bbdb76b..000000000 --- a/components/src/core/build.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "component": "core", - - "targets": [ - "mathjax.ts", - "core", "util", "handlers", - "adaptors/HTMLAdaptor.ts", - "adaptors/browserAdaptor.ts", - "components/global.ts" - ], - - "exclude": [ - "core/MmlTree/JsonMmlVisitor.ts", - "core/MmlTree/LegacyMmlVisitor.ts", - "core/MmlTree/TestMmlVisitor.ts", - "util/asyncLoad", - "util/entities" - ] -} - diff --git a/components/src/core/core.js b/components/src/core/core.js deleted file mode 100644 index 059580e11..000000000 --- a/components/src/core/core.js +++ /dev/null @@ -1,14 +0,0 @@ -import './lib/core.js'; - -import {HTMLHandler} from '../../../js/handlers/html/HTMLHandler.js'; -import {browserAdaptor} from '../../../js/adaptors/browserAdaptor.js'; - -if (MathJax.startup) { - MathJax.startup.registerConstructor('HTMLHandler', HTMLHandler); - MathJax.startup.registerConstructor('browserAdaptor', browserAdaptor); - MathJax.startup.useHandler('HTMLHandler'); - MathJax.startup.useAdaptor('browserAdaptor'); -} -if (MathJax.loader) { - MathJax._.mathjax.mathjax.asyncLoad = (name => MathJax.loader.load(name)); -} diff --git a/components/src/core/webpack.config.js b/components/src/core/webpack.config.js deleted file mode 100644 index c52325252..000000000 --- a/components/src/core/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'core', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/input/asciimath/build.json b/components/src/input/asciimath/build.json deleted file mode 100644 index 4fca2b38f..000000000 --- a/components/src/input/asciimath/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component": "input/asciimath", - "targets": ["input/asciimath.ts", "input/asciimath"], - "excludeSubdirs": "true" -} diff --git a/components/src/input/asciimath/webpack.config.js b/components/src/input/asciimath/webpack.config.js deleted file mode 100644 index 7f9850852..000000000 --- a/components/src/input/asciimath/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/asciimath', // the package to build - '../../../../js', // location of the MathJax js library - ['components/src/core/lib'], // packages to link to - __dirname // our directory -); diff --git a/components/src/input/mml/build.json b/components/src/input/mml/build.json deleted file mode 100644 index d4864a0f5..000000000 --- a/components/src/input/mml/build.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "component": "input/mml", - "targets": [ - "input/mathml.ts", - "input/mathml" - ], - "excludeSubdirs": "true" -} diff --git a/components/src/input/mml/entities/entities.js b/components/src/input/mml/entities/entities.js deleted file mode 100644 index b02b6e50d..000000000 --- a/components/src/input/mml/entities/entities.js +++ /dev/null @@ -1,2 +0,0 @@ -import '../../../../../js/util/entities/all.js'; - diff --git a/components/src/input/mml/entities/webpack.config.js b/components/src/input/mml/entities/webpack.config.js deleted file mode 100644 index 2386e2bcc..000000000 --- a/components/src/input/mml/entities/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/mml/entities', // the package to build - '../../../../../js', // location of the MathJax js library - ['components/src/core/lib'], // packages to link to - __dirname // our directory -); diff --git a/components/src/input/mml/extensions/mml3/build.json b/components/src/input/mml/extensions/mml3/build.json deleted file mode 100644 index 6ae79ed71..000000000 --- a/components/src/input/mml/extensions/mml3/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[mml]/mml3", - "component": "input/mml/extensions/mml3", - "targets": ["input/mathml/mml3"] -} diff --git a/components/src/input/mml/extensions/mml3/copy.json b/components/src/input/mml/extensions/mml3/copy.json deleted file mode 100644 index aa791ea7a..000000000 --- a/components/src/input/mml/extensions/mml3/copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "to": "../../../../../../es5/input/mml/extensions", - "from": "../../../../../../ts/input/mathml/mml3", - "copy": [ - "mml3.sef.json" - ] -} diff --git a/components/src/input/mml/extensions/mml3/webpack.config.js b/components/src/input/mml/extensions/mml3/webpack.config.js deleted file mode 100644 index b09f30c9f..000000000 --- a/components/src/input/mml/extensions/mml3/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/mml/extensions/mml3', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/mml/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/mml/webpack.config.js b/components/src/input/mml/webpack.config.js deleted file mode 100644 index 301b5f845..000000000 --- a/components/src/input/mml/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/mml', // the package to build - '../../../../js', // location of the MathJax js library - ['components/src/core/lib'], // packages to link to - __dirname // our directory -); diff --git a/components/src/input/tex-base/build.json b/components/src/input/tex-base/build.json deleted file mode 100644 index 5e55e12cb..000000000 --- a/components/src/input/tex-base/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "component": "input/tex-base", - "targets": [ - "input/tex.ts", - "input/tex", - "input/tex/base" - ], - "exclude": ["input/tex/AllPackages.ts"], - "excludeSubdirs": "true" -} diff --git a/components/src/input/tex-base/webpack.config.js b/components/src/input/tex-base/webpack.config.js deleted file mode 100644 index df380e755..000000000 --- a/components/src/input/tex-base/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex-base', // the package to build - '../../../../js', // location of the MathJax js library - ['components/src/core/lib'], // packages to link to - __dirname // our directory -); diff --git a/components/src/input/tex-full/build.json b/components/src/input/tex-full/build.json deleted file mode 100644 index a245332b7..000000000 --- a/components/src/input/tex-full/build.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "component": "input/tex-full", - "targets": [ - "input/tex.ts", - "input/tex" - ] -} - diff --git a/components/src/input/tex-full/tex-full.js b/components/src/input/tex-full/tex-full.js deleted file mode 100644 index af10939e1..000000000 --- a/components/src/input/tex-full/tex-full.js +++ /dev/null @@ -1,12 +0,0 @@ -import './lib/tex-full.js'; -import '../tex/extensions/all-packages/all-packages.js'; -import {registerTeX} from '../tex/register.js'; - -if (MathJax.loader) { - MathJax.loader.preLoad( - 'input/tex-base', - '[tex]/all-packages' - ); -} - -registerTeX(); diff --git a/components/src/input/tex-full/webpack.config.js b/components/src/input/tex-full/webpack.config.js deleted file mode 100644 index 6c65c1a88..000000000 --- a/components/src/input/tex-full/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex-full', // the package to build - '../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/startup/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/build.json b/components/src/input/tex/build.json deleted file mode 100644 index 1c7005b61..000000000 --- a/components/src/input/tex/build.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "component": "input/tex", - "targets": [ - "input/tex.ts", - "input/tex", - "input/tex/base", - "input/tex/ams", - "input/tex/newcommand", - "input/tex/noundefined", - "input/tex/require", - "input/tex/autoload", - "input/tex/configmacros" - ], - "exclude": ["input/tex/AllPackages.ts"], - "excludeSubdirs": "true" -} diff --git a/components/src/input/tex/extensions/action/build.json b/components/src/input/tex/extensions/action/build.json deleted file mode 100644 index a0b6af601..000000000 --- a/components/src/input/tex/extensions/action/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/action", - "component": "input/tex/extensions/action", - "targets": ["input/tex/action"] -} diff --git a/components/src/input/tex/extensions/action/webpack.config.js b/components/src/input/tex/extensions/action/webpack.config.js deleted file mode 100644 index 4375ae570..000000000 --- a/components/src/input/tex/extensions/action/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/action', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/all-packages/all-packages.js b/components/src/input/tex/extensions/all-packages/all-packages.js deleted file mode 100644 index 982db5caf..000000000 --- a/components/src/input/tex/extensions/all-packages/all-packages.js +++ /dev/null @@ -1,12 +0,0 @@ -import './lib/all-packages.js'; - -import {AllPackages} from '../../../../../../js/input/tex/AllPackages.js'; -import '../../../../../../js/input/tex/autoload/AutoloadConfiguration.js'; -import '../../../../../../js/input/tex/require/RequireConfiguration.js'; -import {registerTeX} from '../../register.js'; - -if (MathJax.loader) { - MathJax.loader.preLoad('[tex]/autoload', '[tex]/require'); -} - -registerTeX(['require', ...AllPackages], false); diff --git a/components/src/input/tex/extensions/all-packages/build.json b/components/src/input/tex/extensions/all-packages/build.json deleted file mode 100644 index 216671f99..000000000 --- a/components/src/input/tex/extensions/all-packages/build.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "id": "[tex]/all-packages", - "component": "input/tex/extensions/all-packages", - "targets": [ - "input/tex/AllPackages.ts", - "input/tex/autoload", - "input/tex/require" - ] -} - diff --git a/components/src/input/tex/extensions/all-packages/webpack.config.js b/components/src/input/tex/extensions/all-packages/webpack.config.js deleted file mode 100644 index bdb842437..000000000 --- a/components/src/input/tex/extensions/all-packages/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/all-packages',// the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/startup/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/ams/build.json b/components/src/input/tex/extensions/ams/build.json deleted file mode 100644 index 865acc303..000000000 --- a/components/src/input/tex/extensions/ams/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/ams", - "component": "input/tex/extensions/ams", - "targets": ["input/tex/ams"] -} diff --git a/components/src/input/tex/extensions/ams/webpack.config.js b/components/src/input/tex/extensions/ams/webpack.config.js deleted file mode 100644 index 1bff208a7..000000000 --- a/components/src/input/tex/extensions/ams/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/ams', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/amscd/build.json b/components/src/input/tex/extensions/amscd/build.json deleted file mode 100644 index 6c3fc87ea..000000000 --- a/components/src/input/tex/extensions/amscd/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/amscd", - "component": "input/tex/extensions/amscd", - "targets": ["input/tex/amscd"] -} diff --git a/components/src/input/tex/extensions/amscd/webpack.config.js b/components/src/input/tex/extensions/amscd/webpack.config.js deleted file mode 100644 index c4fa76238..000000000 --- a/components/src/input/tex/extensions/amscd/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/amscd', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/autoload/build.json b/components/src/input/tex/extensions/autoload/build.json deleted file mode 100644 index d4f9b89e0..000000000 --- a/components/src/input/tex/extensions/autoload/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/autoload", - "component": "input/tex/extensions/autoload", - "targets": ["input/tex/autoload"] -} diff --git a/components/src/input/tex/extensions/autoload/webpack.config.js b/components/src/input/tex/extensions/autoload/webpack.config.js deleted file mode 100644 index 353163dd3..000000000 --- a/components/src/input/tex/extensions/autoload/webpack.config.js +++ /dev/null @@ -1,13 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/autoload', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex/extensions/require/lib', - 'components/src/input/tex-base/lib', - 'components/src/startup/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/bbox/build.json b/components/src/input/tex/extensions/bbox/build.json deleted file mode 100644 index c50918558..000000000 --- a/components/src/input/tex/extensions/bbox/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/bbox", - "component": "input/tex/extensions/bbox", - "targets": ["input/tex/bbox"] -} diff --git a/components/src/input/tex/extensions/bbox/webpack.config.js b/components/src/input/tex/extensions/bbox/webpack.config.js deleted file mode 100644 index 26cf2d1a7..000000000 --- a/components/src/input/tex/extensions/bbox/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/bbox', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/boldsymbol/build.json b/components/src/input/tex/extensions/boldsymbol/build.json deleted file mode 100644 index 3d59f0cb2..000000000 --- a/components/src/input/tex/extensions/boldsymbol/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/boldsymbol", - "component": "input/tex/extensions/boldsymbol", - "targets": ["input/tex/boldsymbol"] -} diff --git a/components/src/input/tex/extensions/boldsymbol/webpack.config.js b/components/src/input/tex/extensions/boldsymbol/webpack.config.js deleted file mode 100644 index a71489413..000000000 --- a/components/src/input/tex/extensions/boldsymbol/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/boldsymbol', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/braket/build.json b/components/src/input/tex/extensions/braket/build.json deleted file mode 100644 index c0631d751..000000000 --- a/components/src/input/tex/extensions/braket/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/braket", - "component": "input/tex/extensions/braket", - "targets": ["input/tex/braket"] -} diff --git a/components/src/input/tex/extensions/braket/webpack.config.js b/components/src/input/tex/extensions/braket/webpack.config.js deleted file mode 100644 index 04df1028d..000000000 --- a/components/src/input/tex/extensions/braket/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/braket', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/bussproofs/build.json b/components/src/input/tex/extensions/bussproofs/build.json deleted file mode 100644 index 242e91f16..000000000 --- a/components/src/input/tex/extensions/bussproofs/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/bussproofs", - "component": "input/tex/extensions/bussproofs", - "targets": ["input/tex/bussproofs"] -} diff --git a/components/src/input/tex/extensions/bussproofs/webpack.config.js b/components/src/input/tex/extensions/bussproofs/webpack.config.js deleted file mode 100644 index 2afad5e71..000000000 --- a/components/src/input/tex/extensions/bussproofs/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/bussproofs', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/cancel/build.json b/components/src/input/tex/extensions/cancel/build.json deleted file mode 100644 index 9577e4e95..000000000 --- a/components/src/input/tex/extensions/cancel/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/cancel", - "component": "input/tex/extensions/cancel", - "targets": ["input/tex/cancel"] -} diff --git a/components/src/input/tex/extensions/cancel/webpack.config.js b/components/src/input/tex/extensions/cancel/webpack.config.js deleted file mode 100644 index 0324cb7a1..000000000 --- a/components/src/input/tex/extensions/cancel/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/cancel', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/input/tex/extensions/enclose/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/cases/build.json b/components/src/input/tex/extensions/cases/build.json deleted file mode 100644 index b4be43cbc..000000000 --- a/components/src/input/tex/extensions/cases/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/cases", - "component": "input/tex/extensions/cases", - "targets": ["input/tex/cases"] -} diff --git a/components/src/input/tex/extensions/cases/webpack.config.js b/components/src/input/tex/extensions/cases/webpack.config.js deleted file mode 100644 index 057036b38..000000000 --- a/components/src/input/tex/extensions/cases/webpack.config.js +++ /dev/null @@ -1,14 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/cases', // the package to build - '../../../../../../js', // location of the compiled js files - [ // packages to link to (relative to Mathjax components) - 'components/src/input/tex-base/lib', - 'components/src/input/tex/extensions/ams/lib', - 'components/src/input/tex/extensions/empheq/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); - diff --git a/components/src/input/tex/extensions/centernot/build.json b/components/src/input/tex/extensions/centernot/build.json deleted file mode 100644 index 1ebcd76b6..000000000 --- a/components/src/input/tex/extensions/centernot/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/centernot", - "component": "input/tex/extensions/centernot", - "targets": ["input/tex/centernot"] -} diff --git a/components/src/input/tex/extensions/centernot/webpack.config.js b/components/src/input/tex/extensions/centernot/webpack.config.js deleted file mode 100644 index 28d313fdf..000000000 --- a/components/src/input/tex/extensions/centernot/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/centernot', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/color/build.json b/components/src/input/tex/extensions/color/build.json deleted file mode 100644 index 3e8614c11..000000000 --- a/components/src/input/tex/extensions/color/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/color", - "component": "input/tex/extensions/color", - "targets": ["input/tex/color"] -} diff --git a/components/src/input/tex/extensions/color/webpack.config.js b/components/src/input/tex/extensions/color/webpack.config.js deleted file mode 100644 index 3a656402f..000000000 --- a/components/src/input/tex/extensions/color/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/color', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/colortbl/build.json b/components/src/input/tex/extensions/colortbl/build.json deleted file mode 100644 index cf70b9a7d..000000000 --- a/components/src/input/tex/extensions/colortbl/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/colortbl", - "component": "input/tex/extensions/colortbl", - "targets": ["input/tex/colortbl"] -} diff --git a/components/src/input/tex/extensions/colortbl/webpack.config.js b/components/src/input/tex/extensions/colortbl/webpack.config.js deleted file mode 100644 index 74b52a8d3..000000000 --- a/components/src/input/tex/extensions/colortbl/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/colortbl', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/colorv2/build.json b/components/src/input/tex/extensions/colorv2/build.json deleted file mode 100644 index 0710e56e4..000000000 --- a/components/src/input/tex/extensions/colorv2/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/colorv2", - "component": "input/tex/extensions/colorv2", - "targets": ["input/tex/colorv2"] -} diff --git a/components/src/input/tex/extensions/colorv2/webpack.config.js b/components/src/input/tex/extensions/colorv2/webpack.config.js deleted file mode 100644 index cb7959bc3..000000000 --- a/components/src/input/tex/extensions/colorv2/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/colorv2', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/configmacros/build.json b/components/src/input/tex/extensions/configmacros/build.json deleted file mode 100644 index 809b5d94c..000000000 --- a/components/src/input/tex/extensions/configmacros/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/configmacros", - "component": "input/tex/extensions/configmacros", - "targets": ["input/tex/configmacros"] -} diff --git a/components/src/input/tex/extensions/configmacros/webpack.config.js b/components/src/input/tex/extensions/configmacros/webpack.config.js deleted file mode 100644 index a7b83b2e7..000000000 --- a/components/src/input/tex/extensions/configmacros/webpack.config.js +++ /dev/null @@ -1,13 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/configmacros',// the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex/extensions/newcommand/lib', - 'components/src/input/tex-base/lib', - 'components/src/core/lib', - 'components/src/startup/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/empheq/build.json b/components/src/input/tex/extensions/empheq/build.json deleted file mode 100644 index f0563a9b2..000000000 --- a/components/src/input/tex/extensions/empheq/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/empheq", - "component": "input/tex/extensions/empheq", - "targets": ["input/tex/empheq"] -} diff --git a/components/src/input/tex/extensions/empheq/webpack.config.js b/components/src/input/tex/extensions/empheq/webpack.config.js deleted file mode 100644 index 735dd6d90..000000000 --- a/components/src/input/tex/extensions/empheq/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/empheq', // the package to build - '../../../../../../js', // location of the compiled js files - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); - diff --git a/components/src/input/tex/extensions/enclose/build.json b/components/src/input/tex/extensions/enclose/build.json deleted file mode 100644 index ebf489c82..000000000 --- a/components/src/input/tex/extensions/enclose/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/enclose", - "component": "input/tex/extensions/enclose", - "targets": ["input/tex/enclose"] -} diff --git a/components/src/input/tex/extensions/enclose/webpack.config.js b/components/src/input/tex/extensions/enclose/webpack.config.js deleted file mode 100644 index a1bf56ae0..000000000 --- a/components/src/input/tex/extensions/enclose/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/enclose', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/extpfeil/build.json b/components/src/input/tex/extensions/extpfeil/build.json deleted file mode 100644 index 37378a525..000000000 --- a/components/src/input/tex/extensions/extpfeil/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/extpfeil", - "component": "input/tex/extensions/extpfeil", - "targets": ["input/tex/extpfeil"] -} diff --git a/components/src/input/tex/extensions/extpfeil/webpack.config.js b/components/src/input/tex/extensions/extpfeil/webpack.config.js deleted file mode 100644 index 018ceff34..000000000 --- a/components/src/input/tex/extensions/extpfeil/webpack.config.js +++ /dev/null @@ -1,13 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/extpfeil', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex/extensions/ams/lib', - 'components/src/input/tex/extensions/newcommand/lib', - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/gensymb/build.json b/components/src/input/tex/extensions/gensymb/build.json deleted file mode 100644 index 220fe879d..000000000 --- a/components/src/input/tex/extensions/gensymb/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/gensymb", - "component": "input/tex/extensions/gensymb", - "targets": ["input/tex/gensymb"] -} diff --git a/components/src/input/tex/extensions/gensymb/webpack.config.js b/components/src/input/tex/extensions/gensymb/webpack.config.js deleted file mode 100644 index 808daa560..000000000 --- a/components/src/input/tex/extensions/gensymb/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/gensymb', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/html/build.json b/components/src/input/tex/extensions/html/build.json deleted file mode 100644 index 7ee5d20ac..000000000 --- a/components/src/input/tex/extensions/html/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/html", - "component": "input/tex/extensions/html", - "targets": ["input/tex/html"] -} diff --git a/components/src/input/tex/extensions/html/webpack.config.js b/components/src/input/tex/extensions/html/webpack.config.js deleted file mode 100644 index 4fae2f816..000000000 --- a/components/src/input/tex/extensions/html/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/html', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/mathtools/build.json b/components/src/input/tex/extensions/mathtools/build.json deleted file mode 100644 index b00ef3147..000000000 --- a/components/src/input/tex/extensions/mathtools/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/mathtools", - "component": "input/tex/extensions/mathtools", - "targets": ["input/tex/mathtools"] -} diff --git a/components/src/input/tex/extensions/mathtools/webpack.config.js b/components/src/input/tex/extensions/mathtools/webpack.config.js deleted file mode 100644 index 1b882c5ae..000000000 --- a/components/src/input/tex/extensions/mathtools/webpack.config.js +++ /dev/null @@ -1,13 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/mathtools', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex/extensions/ams/lib', - 'components/src/input/tex/extensions/newcommand/lib', - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/mhchem/build.json b/components/src/input/tex/extensions/mhchem/build.json deleted file mode 100644 index e7728bdad..000000000 --- a/components/src/input/tex/extensions/mhchem/build.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "id": "[tex]/mhchem", - "component": "input/tex/extensions/mhchem", - "targets": ["input/tex/mhchem"], - "exclude": ["input/tex/mhchem/mhchem_parser.d.ts"] -} diff --git a/components/src/input/tex/extensions/mhchem/mhchem.js b/components/src/input/tex/extensions/mhchem/mhchem.js deleted file mode 100644 index cac9cc9c6..000000000 --- a/components/src/input/tex/extensions/mhchem/mhchem.js +++ /dev/null @@ -1 +0,0 @@ -import './lib/mhchem.js'; diff --git a/components/src/input/tex/extensions/mhchem/webpack.config.js b/components/src/input/tex/extensions/mhchem/webpack.config.js deleted file mode 100644 index c50bd476b..000000000 --- a/components/src/input/tex/extensions/mhchem/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/mhchem', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex/extensions/ams/lib', - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/newcommand/build.json b/components/src/input/tex/extensions/newcommand/build.json deleted file mode 100644 index 119063b2f..000000000 --- a/components/src/input/tex/extensions/newcommand/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/newcommand", - "component": "input/tex/extensions/newcommand", - "targets": ["input/tex/newcommand"] -} diff --git a/components/src/input/tex/extensions/newcommand/webpack.config.js b/components/src/input/tex/extensions/newcommand/webpack.config.js deleted file mode 100644 index 1deed0d0f..000000000 --- a/components/src/input/tex/extensions/newcommand/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/newcommand', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/noerrors/build.json b/components/src/input/tex/extensions/noerrors/build.json deleted file mode 100644 index dae2b51e0..000000000 --- a/components/src/input/tex/extensions/noerrors/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/noerrors", - "component": "input/tex/extensions/noerrors", - "targets": ["input/tex/noerrors"] -} diff --git a/components/src/input/tex/extensions/noerrors/webpack.config.js b/components/src/input/tex/extensions/noerrors/webpack.config.js deleted file mode 100644 index 6e9290157..000000000 --- a/components/src/input/tex/extensions/noerrors/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/noerrors', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/noundefined/build.json b/components/src/input/tex/extensions/noundefined/build.json deleted file mode 100644 index 3ea2d344c..000000000 --- a/components/src/input/tex/extensions/noundefined/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/noundefined", - "component": "input/tex/extensions/noundefined", - "targets": ["input/tex/noundefined"] -} diff --git a/components/src/input/tex/extensions/noundefined/webpack.config.js b/components/src/input/tex/extensions/noundefined/webpack.config.js deleted file mode 100644 index 177ff29d1..000000000 --- a/components/src/input/tex/extensions/noundefined/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/noundefined', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/physics/build.json b/components/src/input/tex/extensions/physics/build.json deleted file mode 100644 index b0ba5aaec..000000000 --- a/components/src/input/tex/extensions/physics/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/physics", - "component": "input/tex/extensions/physics", - "targets": ["input/tex/physics"] -} diff --git a/components/src/input/tex/extensions/physics/webpack.config.js b/components/src/input/tex/extensions/physics/webpack.config.js deleted file mode 100644 index fbfa9a71c..000000000 --- a/components/src/input/tex/extensions/physics/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/physics', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/require/build.json b/components/src/input/tex/extensions/require/build.json deleted file mode 100644 index 594088cfc..000000000 --- a/components/src/input/tex/extensions/require/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/require", - "component": "input/tex/extensions/require", - "targets": ["input/tex/require"] -} diff --git a/components/src/input/tex/extensions/require/webpack.config.js b/components/src/input/tex/extensions/require/webpack.config.js deleted file mode 100644 index 63ff19488..000000000 --- a/components/src/input/tex/extensions/require/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/require', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib', - 'components/src/startup/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/setoptions/build.json b/components/src/input/tex/extensions/setoptions/build.json deleted file mode 100644 index f7171fd64..000000000 --- a/components/src/input/tex/extensions/setoptions/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/setoptions", - "component": "input/tex/extensions/setoptions", - "targets": ["input/tex/setoptions"] -} diff --git a/components/src/input/tex/extensions/setoptions/webpack.config.js b/components/src/input/tex/extensions/setoptions/webpack.config.js deleted file mode 100644 index 1260438d7..000000000 --- a/components/src/input/tex/extensions/setoptions/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/setoptions', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/tagformat/build.json b/components/src/input/tex/extensions/tagformat/build.json deleted file mode 100644 index e56479448..000000000 --- a/components/src/input/tex/extensions/tagformat/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/tagformat", - "component": "input/tex/extensions/tagformat", - "targets": ["input/tex/tagformat"] -} diff --git a/components/src/input/tex/extensions/tagformat/webpack.config.js b/components/src/input/tex/extensions/tagformat/webpack.config.js deleted file mode 100644 index 35bb113e1..000000000 --- a/components/src/input/tex/extensions/tagformat/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/tagformat', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/textcomp/build.json b/components/src/input/tex/extensions/textcomp/build.json deleted file mode 100644 index dc88ae71c..000000000 --- a/components/src/input/tex/extensions/textcomp/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/textcomp", - "component": "input/tex/extensions/textcomp", - "targets": ["input/tex/textcomp"] -} diff --git a/components/src/input/tex/extensions/textcomp/webpack.config.js b/components/src/input/tex/extensions/textcomp/webpack.config.js deleted file mode 100644 index 364a539ef..000000000 --- a/components/src/input/tex/extensions/textcomp/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/textcomp', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex/extensions/textmacros/lib', - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/textmacros/build.json b/components/src/input/tex/extensions/textmacros/build.json deleted file mode 100644 index 80b0e02d9..000000000 --- a/components/src/input/tex/extensions/textmacros/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/textmacros", - "component": "input/tex/extensions/textmacros", - "targets": ["input/tex/textmacros"] -} diff --git a/components/src/input/tex/extensions/textmacros/webpack.config.js b/components/src/input/tex/extensions/textmacros/webpack.config.js deleted file mode 100644 index 8a6488382..000000000 --- a/components/src/input/tex/extensions/textmacros/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/textmacros', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/unicode/build.json b/components/src/input/tex/extensions/unicode/build.json deleted file mode 100644 index 2e7604802..000000000 --- a/components/src/input/tex/extensions/unicode/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/unicode", - "component": "input/tex/extensions/unicode", - "targets": ["input/tex/unicode"] -} diff --git a/components/src/input/tex/extensions/unicode/webpack.config.js b/components/src/input/tex/extensions/unicode/webpack.config.js deleted file mode 100644 index 8054276b3..000000000 --- a/components/src/input/tex/extensions/unicode/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/unicode', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/upgreek/build.json b/components/src/input/tex/extensions/upgreek/build.json deleted file mode 100644 index 70c9812ea..000000000 --- a/components/src/input/tex/extensions/upgreek/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/upgreek", - "component": "input/tex/extensions/upgreek", - "targets": ["input/tex/upgreek"] -} diff --git a/components/src/input/tex/extensions/upgreek/webpack.config.js b/components/src/input/tex/extensions/upgreek/webpack.config.js deleted file mode 100644 index d47c688b0..000000000 --- a/components/src/input/tex/extensions/upgreek/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/upgreek', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/extensions/verb/build.json b/components/src/input/tex/extensions/verb/build.json deleted file mode 100644 index 53f726931..000000000 --- a/components/src/input/tex/extensions/verb/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "id": "[tex]/verb", - "component": "input/tex/extensions/verb", - "targets": ["input/tex/verb"] -} diff --git a/components/src/input/tex/extensions/verb/webpack.config.js b/components/src/input/tex/extensions/verb/webpack.config.js deleted file mode 100644 index 48bb2b8f4..000000000 --- a/components/src/input/tex/extensions/verb/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex/extensions/verb', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/input/tex-base/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/input/tex/webpack.config.js b/components/src/input/tex/webpack.config.js deleted file mode 100644 index dd3dc693e..000000000 --- a/components/src/input/tex/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'input/tex', // the package to build - '../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/startup/lib', - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/latest/latest.js b/components/src/latest/latest.js deleted file mode 100644 index 95ab5953f..000000000 --- a/components/src/latest/latest.js +++ /dev/null @@ -1,3 +0,0 @@ -import {loadLatest} from '../../../js/components/latest.js'; - -loadLatest(); diff --git a/components/src/latest/webpack.config.js b/components/src/latest/webpack.config.js deleted file mode 100644 index ff1fb8529..000000000 --- a/components/src/latest/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'latest', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/loader/build.json b/components/src/loader/build.json deleted file mode 100644 index ca2c4a878..000000000 --- a/components/src/loader/build.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "component": "loader", - "targets": [ - "components/loader.ts", - "components/package.ts" - ] -} diff --git a/components/src/loader/webpack.config.js b/components/src/loader/webpack.config.js deleted file mode 100644 index f23953bb7..000000000 --- a/components/src/loader/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'loader', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/mml-chtml/mml-chtml.js b/components/src/mml-chtml/mml-chtml.js deleted file mode 100644 index dbaaf98f0..000000000 --- a/components/src/mml-chtml/mml-chtml.js +++ /dev/null @@ -1,9 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/mml/mml.js'; -import '../output/chtml/chtml.js'; -import '../output/chtml/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../startup/startup.js'; diff --git a/components/src/mml-chtml/preload.js b/components/src/mml-chtml/preload.js deleted file mode 100644 index e3f202f7a..000000000 --- a/components/src/mml-chtml/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/mml', - 'output/chtml', 'output/chtml/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml' -); diff --git a/components/src/mml-chtml/webpack.config.js b/components/src/mml-chtml/webpack.config.js deleted file mode 100644 index c488da142..000000000 --- a/components/src/mml-chtml/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'mml-chtml', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/mml-svg/mml-svg.js b/components/src/mml-svg/mml-svg.js deleted file mode 100644 index 34cef63b2..000000000 --- a/components/src/mml-svg/mml-svg.js +++ /dev/null @@ -1,9 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/mml/mml.js'; -import '../output/svg/svg.js'; -import '../output/svg/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../startup/startup.js'; diff --git a/components/src/mml-svg/preload.js b/components/src/mml-svg/preload.js deleted file mode 100644 index 3cb47d42e..000000000 --- a/components/src/mml-svg/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/mml', - 'output/svg', 'output/svg/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml' -); diff --git a/components/src/mml-svg/webpack.config.js b/components/src/mml-svg/webpack.config.js deleted file mode 100644 index 0d2fe5c4b..000000000 --- a/components/src/mml-svg/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'mml-svg', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/node-main/node-main.js b/components/src/node-main/node-main.js deleted file mode 100644 index 13679e369..000000000 --- a/components/src/node-main/node-main.js +++ /dev/null @@ -1,83 +0,0 @@ -/************************************************************* - * - * Copyright (c) 2019-2021 The MathJax Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -const path = eval("require('path')"); // use actual node version, not webpack's version - -/* - * Load the needed MathJax components - */ -require('../startup/init.js'); -const {Loader, CONFIG} = require('../../../js/components/loader.js'); -const {combineDefaults, combineConfig} = require('../../../js/components/global.js'); - -/* - * Set up the initial configuration - */ -combineDefaults(MathJax.config, 'loader', { - require: eval('require'), // use node's require() to load files - failed: (err) => {throw err} // pass on error message to init()'s catch function -}); - -/* - * Preload core and liteDOM adaptor (needed for node) - */ -Loader.preLoad('loader', 'startup', 'core', 'adaptors/liteDOM'); -require('../core/core.js'); -require('../adaptors/liteDOM/liteDOM.js'); - -/* - * Set the mathjax root path to the location where node-main.js was loaded from, - * using the actual node __dirname, not the webpack one, and removing - * the directory if we are loaded from components/src/node-main. - */ -const dir = CONFIG.paths.mathjax = eval('__dirname'); -if (path.basename(dir) === 'node-main') { - CONFIG.paths.mathjax = path.dirname(dir); - combineDefaults(CONFIG, 'source', require('../source.js').source); - // - // Set the asynchronous loader to use the js directory, so we can load - // other files like entity definitions - // - const ROOT = path.resolve(dir, '../../../js'); - const REQUIRE = MathJax.config.loader.require; - MathJax._.mathjax.mathjax.asyncLoad = function (name) { - return REQUIRE(name.charAt(0) === '.' ? path.resolve(ROOT, name) : name); - }; -} - - -/* - * The initialization function. Use as: - * - * require('mathjax').init({ ... }).then((MathJax) => { ... }); - * - * where the argument to init() is a MathJax configuration (what would be set as MathJax = {...}). - * The init() function returns a promise that is resolved when MathJax is loaded and ready, and that - * is passed the MathJax global variable when it is called. - */ -const init = (config = {}) => { - combineConfig(MathJax.config, config); - return Loader.load(...CONFIG.load) - .then(() => CONFIG.ready()) - .then(() => MathJax) // Pass MathJax global as argument to subsequent .then() calls - .catch(error => CONFIG.failed(error)); -} - -/* - * Export the init() function - */ -export {init}; diff --git a/components/src/node-main/webpack.config.js b/components/src/node-main/webpack.config.js deleted file mode 100644 index ea41c8c12..000000000 --- a/components/src/node-main/webpack.config.js +++ /dev/null @@ -1,17 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -const package = PACKAGE( - 'node-main', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); - -// make node-main.js exports available to caller -package.output.library = { - name: 'init', - type: 'commonjs', - export: 'init' -}; - -module.exports = package; diff --git a/components/src/output/chtml/build.json b/components/src/output/chtml/build.json deleted file mode 100644 index 36eb3e25f..000000000 --- a/components/src/output/chtml/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component": "output/chtml", - "targets": ["output/chtml.ts", "output/chtml", "output/common"], - "exclude": ["output/chtml/fonts", "output/common/fonts"] -} diff --git a/components/src/output/chtml/chtml.js b/components/src/output/chtml/chtml.js deleted file mode 100644 index 37f38ba6e..000000000 --- a/components/src/output/chtml/chtml.js +++ /dev/null @@ -1,17 +0,0 @@ -import './lib/chtml.js'; - -import {combineDefaults} from '../../../../js/components/global.js'; -import {CHTML} from '../../../../js/output/chtml.js'; - -if (MathJax.loader) { - combineDefaults(MathJax.config.loader, 'output/chtml', { - checkReady() { - return MathJax.loader.load("output/chtml/fonts/tex"); - } - }); -} - -if (MathJax.startup) { - MathJax.startup.registerConstructor('chtml', CHTML); - MathJax.startup.useOutput('chtml'); -} diff --git a/components/src/output/chtml/fonts/tex/build.json b/components/src/output/chtml/fonts/tex/build.json deleted file mode 100644 index 6967166c5..000000000 --- a/components/src/output/chtml/fonts/tex/build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "component": "output/chtml/fonts/tex", - "targets": ["output/chtml/fonts/tex.ts", "output/chtml/fonts/tex", "output/common/fonts/tex"] -} diff --git a/components/src/output/chtml/fonts/tex/copy.json b/components/src/output/chtml/fonts/tex/copy.json deleted file mode 100644 index f8dce11b8..000000000 --- a/components/src/output/chtml/fonts/tex/copy.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "to": "../../../../../../es5/output/chtml/fonts/woff-v2", - "from": "../../../../../../ts/output/chtml/fonts/tex-woff-v2", - "copy": [ - "MathJax_AMS-Regular.woff", - "MathJax_Calligraphic-Bold.woff", - "MathJax_Calligraphic-Regular.woff", - "MathJax_Fraktur-Bold.woff", - "MathJax_Fraktur-Regular.woff", - "MathJax_Main-Bold.woff", - "MathJax_Main-Italic.woff", - "MathJax_Main-Regular.woff", - "MathJax_Math-BoldItalic.woff", - "MathJax_Math-Italic.woff", - "MathJax_Math-Regular.woff", - "MathJax_SansSerif-Bold.woff", - "MathJax_SansSerif-Italic.woff", - "MathJax_SansSerif-Regular.woff", - "MathJax_Script-Regular.woff", - "MathJax_Size1-Regular.woff", - "MathJax_Size2-Regular.woff", - "MathJax_Size3-Regular.woff", - "MathJax_Size4-Regular.woff", - "MathJax_Typewriter-Regular.woff", - "MathJax_Vector-Bold.woff", - "MathJax_Vector-Regular.woff", - "MathJax_Zero.woff" - ] -} diff --git a/components/src/output/chtml/fonts/tex/tex.js b/components/src/output/chtml/fonts/tex/tex.js deleted file mode 100644 index 6f208760e..000000000 --- a/components/src/output/chtml/fonts/tex/tex.js +++ /dev/null @@ -1,14 +0,0 @@ -import './lib/tex.js'; - -import {combineDefaults} from '../../../../../../js/components/global.js'; -import {Package} from '../../../../../../js/components/package.js'; -import {selectOptionsFromKeys} from '../../../../../../js/util/Options.js'; -import {TeXFont} from '../../../../../../js/output/chtml/fonts/tex.js'; - -if (MathJax.startup) { - combineDefaults(MathJax.config, 'chtml', { - fontURL: Package.resolvePath('output/chtml/fonts/woff-v2', false) - }); - const options = selectOptionsFromKeys(MathJax.config.chtml || {}, TeXFont.OPTIONS); - combineDefaults(MathJax.config, 'chtml', {font: new TeXFont(options)}); -} diff --git a/components/src/output/chtml/fonts/tex/webpack.config.js b/components/src/output/chtml/fonts/tex/webpack.config.js deleted file mode 100644 index c1bd29f81..000000000 --- a/components/src/output/chtml/fonts/tex/webpack.config.js +++ /dev/null @@ -1,12 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'output/chtml/fonts/tex', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/core/lib', - 'components/src/output/chtml/lib', - 'components/src/startup/lib' - ], - __dirname // our directory -); diff --git a/components/src/output/chtml/nofont.js b/components/src/output/chtml/nofont.js deleted file mode 100644 index b4da7605d..000000000 --- a/components/src/output/chtml/nofont.js +++ /dev/null @@ -1,5 +0,0 @@ -import {FontData} from '../../../../js/output/chtml/FontData.js'; - -export class TeXFont extends FontData {}; - -TeXFont.OPTIONS = {fontURL: '.'}; diff --git a/components/src/output/chtml/webpack.config.js b/components/src/output/chtml/webpack.config.js deleted file mode 100644 index 3900985d5..000000000 --- a/components/src/output/chtml/webpack.config.js +++ /dev/null @@ -1,18 +0,0 @@ -const webpack = require("webpack"); -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'output/chtml', // the package to build - '../../../../js', // location of the MathJax js library - ['components/src/core/lib'], // packages to link to - __dirname // our directory -); - -module.exports.plugins.push( - new webpack.NormalModuleReplacementPlugin( - /\/fonts\/tex\.js$/, - function (resource) { - resource.request = '../../components/src/output/chtml/nofont.js'; - } - ) -); diff --git a/components/src/output/svg/build.json b/components/src/output/svg/build.json deleted file mode 100644 index 0339d5154..000000000 --- a/components/src/output/svg/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component": "output/svg", - "targets": ["output/svg.ts", "output/svg", "output/common"], - "exclude": ["output/svg/fonts", "output/common/fonts"] -} diff --git a/components/src/output/svg/fonts/tex/build.json b/components/src/output/svg/fonts/tex/build.json deleted file mode 100644 index b417f9330..000000000 --- a/components/src/output/svg/fonts/tex/build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "component": "output/svg/fonts/tex", - "targets": ["output/svg/fonts/tex.ts", "output/svg/fonts/tex", "output/common/fonts/tex"] -} diff --git a/components/src/output/svg/fonts/tex/tex.js b/components/src/output/svg/fonts/tex/tex.js deleted file mode 100644 index ec1018d12..000000000 --- a/components/src/output/svg/fonts/tex/tex.js +++ /dev/null @@ -1,10 +0,0 @@ -import './lib/tex.js'; - -import {TeXFont} from '../../../../../../js/output/svg/fonts/tex.js'; -import {combineDefaults} from '../../../../../../js/components/global.js'; -import {selectOptionsFromKeys} from '../../../../../../js/util/Options.js'; - -if (MathJax.startup) { - const options = selectOptionsFromKeys(MathJax.config.svg || {}, TeXFont.OPTIONS); - combineDefaults(MathJax.config, 'svg', {font: new TeXFont(options)}); -} diff --git a/components/src/output/svg/fonts/tex/webpack.config.js b/components/src/output/svg/fonts/tex/webpack.config.js deleted file mode 100644 index 4c425fef5..000000000 --- a/components/src/output/svg/fonts/tex/webpack.config.js +++ /dev/null @@ -1,11 +0,0 @@ -const PACKAGE = require('../../../../../webpack.common.js'); - -module.exports = PACKAGE( - 'output/svg/fonts/tex', // the package to build - '../../../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/core/lib', - 'components/src/output/svg/lib' - ], - __dirname // our directory -); diff --git a/components/src/output/svg/nofont.js b/components/src/output/svg/nofont.js deleted file mode 100644 index 1db6be21a..000000000 --- a/components/src/output/svg/nofont.js +++ /dev/null @@ -1,5 +0,0 @@ -import {FontData} from '../../../../js/output/svg/FontData.js'; - -export class TeXFont extends FontData {}; - -TeXFont.OPTIONS = {fontURL: '.'}; diff --git a/components/src/output/svg/svg.js b/components/src/output/svg/svg.js deleted file mode 100644 index d79520ac2..000000000 --- a/components/src/output/svg/svg.js +++ /dev/null @@ -1,17 +0,0 @@ -import './lib/svg.js'; - -import {combineDefaults} from '../../../../js/components/global.js'; -import {SVG} from '../../../../js/output/svg.js'; - -if (MathJax.loader) { - combineDefaults(MathJax.config.loader, 'output/svg', { - checkReady() { - return MathJax.loader.load("output/svg/fonts/tex"); - } - }); -} - -if (MathJax.startup) { - MathJax.startup.registerConstructor('svg', SVG); - MathJax.startup.useOutput('svg'); -} diff --git a/components/src/output/svg/webpack.config.js b/components/src/output/svg/webpack.config.js deleted file mode 100644 index b062ec2fd..000000000 --- a/components/src/output/svg/webpack.config.js +++ /dev/null @@ -1,18 +0,0 @@ -const webpack = require("webpack"); -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'output/svg', // the package to build - '../../../../js', // location of the MathJax js library - ['components/src/core/lib'], // packages to link to - __dirname // our directory -); - -module.exports.plugins.push( - new webpack.NormalModuleReplacementPlugin( - /\/fonts\/tex\.js$/, - function (resource) { - resource.request = '../../components/src/output/svg/nofont.js'; - } - ) -); diff --git a/components/src/sre/copy.json b/components/src/sre/copy.json deleted file mode 100644 index 4d105112b..000000000 --- a/components/src/sre/copy.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "to": "../../../es5/sre", - "from": "[node]/speech-rule-engine/lib", - "copy": [ - "mathmaps" - ] -} diff --git a/components/src/startup/build.json b/components/src/startup/build.json deleted file mode 100644 index 3498ffced..000000000 --- a/components/src/startup/build.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "component": "startup", - "targets": [ - "components/loader.ts", - "components/package.ts", - "components/startup.ts" - ] -} diff --git a/components/src/startup/init.js b/components/src/startup/init.js deleted file mode 100644 index ccbe1b412..000000000 --- a/components/src/startup/init.js +++ /dev/null @@ -1,9 +0,0 @@ -import './lib/startup.js'; - -import {combineDefaults} from '../../../js/components/global.js'; -import {dependencies, paths, provides, compatibility} from '../dependencies.js'; - -combineDefaults(MathJax.config.loader, 'dependencies', dependencies); -combineDefaults(MathJax.config.loader, 'paths', paths); -combineDefaults(MathJax.config.loader, 'provides', provides); -combineDefaults(MathJax.config.loader, 'source', compatibility); diff --git a/components/src/startup/startup.js b/components/src/startup/startup.js deleted file mode 100644 index 2a6dad2ad..000000000 --- a/components/src/startup/startup.js +++ /dev/null @@ -1,8 +0,0 @@ -import './init.js'; -import {Loader, CONFIG} from '../../../js/components/loader.js'; - -Loader.preLoad('loader'); - -Loader.load(...CONFIG.load) - .then(() => CONFIG.ready()) - .catch(error => CONFIG.failed(error)); diff --git a/components/src/startup/webpack.config.js b/components/src/startup/webpack.config.js deleted file mode 100644 index 46f7f97e1..000000000 --- a/components/src/startup/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'startup', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/tex-chtml-full-speech/preload.js b/components/src/tex-chtml-full-speech/preload.js deleted file mode 100644 index 8957d1b09..000000000 --- a/components/src/tex-chtml-full-speech/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/tex-full', - 'output/chtml', 'output/chtml/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml', 'a11y/sre' -); diff --git a/components/src/tex-chtml-full-speech/tex-chtml-full-speech.js b/components/src/tex-chtml-full-speech/tex-chtml-full-speech.js deleted file mode 100644 index 1af76d25f..000000000 --- a/components/src/tex-chtml-full-speech/tex-chtml-full-speech.js +++ /dev/null @@ -1,19 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/tex-full/tex-full.js'; -import '../output/chtml/chtml.js'; -import '../output/chtml/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../a11y/sre/sre.js'; -import MathMaps from '../../../js/a11y/mathmaps.js'; -import base from 'speech-rule-engine/lib/mathmaps/base.json'; -import en from 'speech-rule-engine/lib/mathmaps/en.json'; -import nemeth from 'speech-rule-engine/lib/mathmaps/nemeth.json'; - -MathMaps.set('base', base); -MathMaps.set('en', en); -MathMaps.set('nemeth', nemeth); - -import '../startup/startup.js'; diff --git a/components/src/tex-chtml-full-speech/webpack.config.js b/components/src/tex-chtml-full-speech/webpack.config.js deleted file mode 100644 index 1c12fdedd..000000000 --- a/components/src/tex-chtml-full-speech/webpack.config.js +++ /dev/null @@ -1,9 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'tex-chtml-full-speech', // the package to build - '../../../js', // location of the MathJax js library - [ // packages to link to - ], - __dirname // our directory -); diff --git a/components/src/tex-chtml-full/preload.js b/components/src/tex-chtml-full/preload.js deleted file mode 100644 index 76c81c92f..000000000 --- a/components/src/tex-chtml-full/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/tex-full', - 'output/chtml', 'output/chtml/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml' -); diff --git a/components/src/tex-chtml-full/tex-chtml-full.js b/components/src/tex-chtml-full/tex-chtml-full.js deleted file mode 100644 index 79cd25af1..000000000 --- a/components/src/tex-chtml-full/tex-chtml-full.js +++ /dev/null @@ -1,9 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/tex-full/tex-full.js'; -import '../output/chtml/chtml.js'; -import '../output/chtml/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../startup/startup.js'; diff --git a/components/src/tex-chtml-full/webpack.config.js b/components/src/tex-chtml-full/webpack.config.js deleted file mode 100644 index 56dda0e12..000000000 --- a/components/src/tex-chtml-full/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'tex-chtml-full', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/tex-chtml/preload.js b/components/src/tex-chtml/preload.js deleted file mode 100644 index 89f110c51..000000000 --- a/components/src/tex-chtml/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/tex', - 'output/chtml', 'output/chtml/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml' -); diff --git a/components/src/tex-chtml/tex-chtml.js b/components/src/tex-chtml/tex-chtml.js deleted file mode 100644 index 0bea55b57..000000000 --- a/components/src/tex-chtml/tex-chtml.js +++ /dev/null @@ -1,9 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/tex/tex.js'; -import '../output/chtml/chtml.js'; -import '../output/chtml/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../startup/startup.js'; diff --git a/components/src/tex-chtml/webpack.config.js b/components/src/tex-chtml/webpack.config.js deleted file mode 100644 index 2d5c67f1b..000000000 --- a/components/src/tex-chtml/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'tex-chtml', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/tex-mml-chtml/preload.js b/components/src/tex-mml-chtml/preload.js deleted file mode 100644 index 7adb6a3be..000000000 --- a/components/src/tex-mml-chtml/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/tex', 'input/mml', - 'output/chtml', 'output/chtml/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml' -); diff --git a/components/src/tex-mml-chtml/tex-mml-chtml.js b/components/src/tex-mml-chtml/tex-mml-chtml.js deleted file mode 100644 index 9a1d1ecb1..000000000 --- a/components/src/tex-mml-chtml/tex-mml-chtml.js +++ /dev/null @@ -1,10 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/tex/tex.js'; -import '../input/mml/mml.js'; -import '../output/chtml/chtml.js'; -import '../output/chtml/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../startup/startup.js'; diff --git a/components/src/tex-mml-chtml/webpack.config.js b/components/src/tex-mml-chtml/webpack.config.js deleted file mode 100644 index 2d1195b86..000000000 --- a/components/src/tex-mml-chtml/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'tex-mml-chtml', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/tex-mml-svg/preload.js b/components/src/tex-mml-svg/preload.js deleted file mode 100644 index 69d6a2c55..000000000 --- a/components/src/tex-mml-svg/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/tex', 'input/mml', - 'output/svg', 'output/svg/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml' -); diff --git a/components/src/tex-mml-svg/tex-mml-svg.js b/components/src/tex-mml-svg/tex-mml-svg.js deleted file mode 100644 index 631bf8c8e..000000000 --- a/components/src/tex-mml-svg/tex-mml-svg.js +++ /dev/null @@ -1,10 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/tex/tex.js'; -import '../input/mml/mml.js'; -import '../output/svg/svg.js'; -import '../output/svg/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../startup/startup.js'; diff --git a/components/src/tex-mml-svg/webpack.config.js b/components/src/tex-mml-svg/webpack.config.js deleted file mode 100644 index 1323d6731..000000000 --- a/components/src/tex-mml-svg/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'tex-mml-svg', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/tex-svg-full/preload.js b/components/src/tex-svg-full/preload.js deleted file mode 100644 index d4165cf8c..000000000 --- a/components/src/tex-svg-full/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/tex-full', - 'output/svg', 'output/svg/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml' -); diff --git a/components/src/tex-svg-full/tex-svg-full.js b/components/src/tex-svg-full/tex-svg-full.js deleted file mode 100644 index 188f52620..000000000 --- a/components/src/tex-svg-full/tex-svg-full.js +++ /dev/null @@ -1,9 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/tex-full/tex-full.js'; -import '../output/svg/svg.js'; -import '../output/svg/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../startup/startup.js'; diff --git a/components/src/tex-svg-full/webpack.config.js b/components/src/tex-svg-full/webpack.config.js deleted file mode 100644 index 391234bad..000000000 --- a/components/src/tex-svg-full/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'tex-svg-full', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/tex-svg/preload.js b/components/src/tex-svg/preload.js deleted file mode 100644 index 284ce317f..000000000 --- a/components/src/tex-svg/preload.js +++ /dev/null @@ -1,9 +0,0 @@ -import {Loader} from '../../../js/components/loader.js'; - -Loader.preLoad( - 'loader', 'startup', - 'core', - 'input/tex', - 'output/svg', 'output/svg/fonts/tex.js', - 'ui/menu', 'a11y/assistive-mml' -); diff --git a/components/src/tex-svg/tex-svg.js b/components/src/tex-svg/tex-svg.js deleted file mode 100644 index 8225eb1fd..000000000 --- a/components/src/tex-svg/tex-svg.js +++ /dev/null @@ -1,9 +0,0 @@ -import '../startup/init.js'; -import './preload.js'; -import '../core/core.js'; -import '../input/tex/tex.js'; -import '../output/svg/svg.js'; -import '../output/svg/fonts/tex/tex.js'; -import '../ui/menu/menu.js'; -import '../a11y/assistive-mml/assistive-mml.js'; -import '../startup/startup.js'; diff --git a/components/src/tex-svg/webpack.config.js b/components/src/tex-svg/webpack.config.js deleted file mode 100644 index 3a0b36889..000000000 --- a/components/src/tex-svg/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../webpack.common.js'); - -module.exports = PACKAGE( - 'tex-svg', // the package to build - '../../../js', // location of the MathJax js library - [], // packages to link to - __dirname // our directory -); diff --git a/components/src/ui/lazy/build.json b/components/src/ui/lazy/build.json deleted file mode 100644 index 118dae50f..000000000 --- a/components/src/ui/lazy/build.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "component": "ui/lazy", - "targets": ["ui/lazy"] -} - diff --git a/components/src/ui/lazy/webpack.config.js b/components/src/ui/lazy/webpack.config.js deleted file mode 100644 index ce8209ecc..000000000 --- a/components/src/ui/lazy/webpack.config.js +++ /dev/null @@ -1,10 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'ui/lazy', // the package to build - '../../../../js', // location of the MathJax js library - [ // packages to link to - 'components/src/core/lib' - ], - __dirname // our directory -); diff --git a/components/src/ui/menu/build.json b/components/src/ui/menu/build.json deleted file mode 100644 index 7e29548dd..000000000 --- a/components/src/ui/menu/build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "component": "ui/menu", - "targets": ["ui/menu"] -} diff --git a/components/src/ui/menu/menu.js b/components/src/ui/menu/menu.js deleted file mode 100644 index 701943bac..000000000 --- a/components/src/ui/menu/menu.js +++ /dev/null @@ -1,7 +0,0 @@ -import './lib/menu.js'; - -import {MenuHandler} from '../../../../js/ui/menu/MenuHandler.js'; - -if (MathJax.startup && typeof window !== 'undefined') { - MathJax.startup.extendHandler(handler => MenuHandler(handler), 20); -} diff --git a/components/src/ui/menu/webpack.config.js b/components/src/ui/menu/webpack.config.js deleted file mode 100644 index 8788bae4c..000000000 --- a/components/src/ui/menu/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'ui/menu', // the package to build - '../../../../js', // location of the MathJax js library - ['components/src/core/lib', 'node_modules/mj-context-menu/js'], // packages to link to - __dirname // our directory -); diff --git a/components/src/ui/safe/build.json b/components/src/ui/safe/build.json deleted file mode 100644 index c3ee2c58d..000000000 --- a/components/src/ui/safe/build.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "component": "ui/safe", - "targets": ["ui/safe"] -} diff --git a/components/src/ui/safe/safe.js b/components/src/ui/safe/safe.js deleted file mode 100644 index 8eab2fabe..000000000 --- a/components/src/ui/safe/safe.js +++ /dev/null @@ -1,7 +0,0 @@ -import './lib/safe.js'; - -import {SafeHandler} from '../../../../js/ui/safe/SafeHandler.js'; - -if (MathJax.startup && typeof window !== 'undefined') { - MathJax.startup.extendHandler(handler => SafeHandler(handler)); -} diff --git a/components/src/ui/safe/webpack.config.js b/components/src/ui/safe/webpack.config.js deleted file mode 100644 index a95788a0c..000000000 --- a/components/src/ui/safe/webpack.config.js +++ /dev/null @@ -1,8 +0,0 @@ -const PACKAGE = require('../../../webpack.common.js'); - -module.exports = PACKAGE( - 'ui/safe', // the package to build - '../../../../js', // location of the MathJax js library - ['components/src/core/lib'], // packages to link to - __dirname // our directory -); diff --git a/components/sre-pack.js b/components/sre-pack.js new file mode 100644 index 000000000..fd75e9f89 --- /dev/null +++ b/components/sre-pack.js @@ -0,0 +1,7 @@ +// +// Replacement for __dirname for sre-root directory +// + +import { mjxRoot } from '@mathjax/src/components/root-pack.js'; + +export const sreRoot = () => mjxRoot() + '/sre'; diff --git a/components/webpack.common.cjs b/components/webpack.common.cjs new file mode 100644 index 000000000..805a4ab3b --- /dev/null +++ b/components/webpack.common.cjs @@ -0,0 +1,259 @@ +/************************************************************* + * + * Copyright (c) 2018-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview Creates configurations for webpacking of MathJax components + * + * @author dpvc@mathjax.org (Davide Cervone) + */ + +/****************************************************************/ + +const fs = require('fs'); +const path = require('path'); +const webpack = require('webpack'); +const TerserPlugin = require('terser-webpack-plugin'); + +const DIRNAME = __dirname; + +/** + * @param {string} string The string whose special characters are to be escaped + * @return {string} The string with regex special characters escaped + */ +function quoteRE(string) { + return string.replace(/([\\.{}[\]()?*+^$])/g, '\\$1'); +} + +/****************************************************************/ + +/** + * Creates the plugin needed for including jsdir in the output + * + * @param {string} js The location of the compiled js files + * @param {string} dir The directory of the component being built + * @param {string} target The module target (cjs or mjs) + * @param {boolean} font False to replace font with the no-font file + * @param {string} jax The name of jax for a font-based default redirection + * @param {string} name The component name + * @return {any[]} The plugin array (empty or with the conversion plugin) + */ +const PLUGINS = function (js, dir, target, font, jax, name) { + // + // Replace components/mjs/root with the webpack version + // and map mathjax-full/js to mathjax-full/${target} + // similarly for @mathjax/src/js. + // + const plugins = [ + new webpack.NormalModuleReplacementPlugin( + /mjs\/components\/mjs\/root\.js/, + '../../../components/root-pack.js' + ), + new webpack.NormalModuleReplacementPlugin( + /mjs\/components\/mjs\/sre-root\.js/, + '../../../components/sre-pack.js' + ), + new webpack.NormalModuleReplacementPlugin( + /mathjax-full\/js\//, + function (resource) { + resource.request = resource.request.replace(/mathjax-full\/js\//, `mathjax-full/${target}/`); + } + ), + new webpack.NormalModuleReplacementPlugin( + /@mathjax\/src\/js\//, + function (resource) { + resource.request = resource.request.replace(/@mathjax\/src\/js\//, `@mathjax/src/${target}/`); + } + ) + ]; + + // + // Replace default font with the no-font file + // + if (!font) { + plugins.push( + new webpack.NormalModuleReplacementPlugin( + /-font\/.*?\/default\.js/, + function (resource) { + resource.request = resource.request.replace(/\/.*?\/default\.js/, '/nofont.js'); + } + ) + ); + } + + // + // Replace font-based default font + // + if (jax) { + plugins.push( + new webpack.NormalModuleReplacementPlugin( + new RegExp(`#default-font\\/${jax}\\/default\\.js$`), + function (resource) { + resource.request = path.resolve(dir, `../../${target}/${jax}/default.js`); + } + ) + ); + } + + return plugins; +}; + +/****************************************************************/ + +/** + * Creates the plugin needed for converting mathjax references to component/lib references + * + * @param {string} js The location of the compiled js files + * @param {string} dir The directory of the component being built + * @param {string} es The es version (5 or '') + * @param {string[]} libs The component library directories to be linked against + * @return {Object} The plugin object: {plugins: [...]} + */ +const RESOLVE = function (js, dir, target, libs) { + // + // Get directories and regular expressions for them + // + const sep = quoteRE(path.sep); + const root = path.dirname(DIRNAME); + const mjdir = path.resolve(root, target); + const jsdir = path.resolve(dir, js); + const jsRE = new RegExp(quoteRE(jsdir) + sep); + const mjRE = new RegExp(quoteRE(mjdir) + sep); + + // + // Add directory names to libraries + // + const libREs = libs + .map(lib => lib.replace(/components\/(?:src|js)\//, 'components/' + target + '/')) + .map(lib => (lib.charAt(0) === '.' ? + [jsRE, path.join(dir, lib) + path.sep] : + [mjRE, path.join(root, lib) + path.sep])); + + // + // Function to get full paths using the proper package.json file get the + // pseudo-package includes to be correct. + // + const {fullPath} = require(`./${target}/fullpath.cjs`); + + // + // Function to replace imported files by ones in the specified component lib directories. + // + const replaceLibs = (resource) => { + const request = fullPath(resource); + // + // Loop through the libraries and see if the imported file is there, + // and return it if so. + // + for (const [re, lib] of libREs) { + const match = request.match(re); + if (match) { + const file = lib + request.substring(match[0].length); + if (fs.existsSync(file)) { + return file; + } + } + } + } + + // + // A plugin that looks for files and modules to see if they need replacing with library versions. + // + class ResolveReplacementPlugin { + apply(resolver) { + const target = resolver.ensureHook("resolved"); + resolver + .getHook('normalResolve') + .tapAsync(ResolveReplacementPlugin.name, (request, resolveContext, callback) => { + const file = replaceLibs(request); + if (!file) return callback(); + resolver.doResolve( + target, + {...request, path: file, request: undefined}, + 'library redirect', + resolveContext, + callback + ); + }); + } + } + + // + // The resolve object to use + // + return { + plugins: [new ResolveReplacementPlugin()] + }; +} + +/****************************************************************/ + +/** + * Create a webpack configuration for a distribution file + * + * @param {{ + * name: string, // The name of the component to create + * js: string, // The path to the compiled .js files (default is mathjax js directory) + * target: string, // 'mjs' or 'cjs' (defaults to 'mjs') + * bundle: string, // name of sub-directory where packed files go (defaults to 'bundle') + * libs: string[], // Array of paths to component lib directories to link against + * dir: string, // The directory of the component being built + * dist: string, // The path to the directory where the component .js file will be placed + * (defaults to the bundle directory in the same directory as the js directory) + * font: boolean, // false to replace default font with no font + * jax: string, // the jax whose default font should be redirected + * }} options + * @return {object} The webpack configuration object + */ +const PACKAGE = function (options) { + let {name, js, target = 'mjs', bundle = 'bundle', libs = [], dir, dist = '', font = true, jax = ''} = options; + dir = dir.replace(/\/$/, ''); + if (!js) { + js = path.relative(process.cwd(), path.resolve(DIRNAME, '..', target)); + } + const distDir = dist ? path.resolve(dir, dist) : + path.resolve(js, '..', bundle, path.dirname(name)); + const basename = path.basename(name); + return { + name: basename, + entry: path.join(dir, basename + '.js'), + output: { + path: distDir, + filename: basename + (dist === '.' ? '.min.js' : '.js') + }, + target: ['web', 'es' + (target === 'mjs' ? '6' : '5')], // needed for IE11 and old browsers + plugins: PLUGINS(js, dir, target, font, jax, name), + resolve: RESOLVE(js, dir, target, libs), + performance: { + hints: false + }, + optimization: { + minimize: true, + minimizer: [new TerserPlugin({ + extractComments: false, + parallel: true, + terserOptions: { + output: { + ascii_only: true + } + } + })] + }, +// devtool: 'source-map', + mode: 'production' + }; +} + +module.exports.PACKAGE = PACKAGE; diff --git a/components/webpack.common.js b/components/webpack.common.js deleted file mode 100644 index 997a8b0a9..000000000 --- a/components/webpack.common.js +++ /dev/null @@ -1,190 +0,0 @@ -/************************************************************* - * - * Copyright (c) 2018 The MathJax Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Creates configurations for webpacking of MathJax components - * - * @author dpvc@mathjax.org (Davide Cervone) - */ - -const fs = require('fs'); -const path = require('path'); -const webpack = require('webpack'); -const TerserPlugin = require('terser-webpack-plugin'); - -/**************************************************************/ - -/** - * @param {string} string The string whose special characters are to be escaped - * @return {string} The string with regex special characters escaped - */ -function quoteRE(string) { - return string.replace(/([\\.{}[\]()?*^$])/g, '\\$1') -} - -/** - * Creates the plugin needed for including jsdir in the output - * - * @param {string} js The location of the compiled js files - * @param {string} dir The directory of the component being built - * @return {any[]} The plugin array (empty or with the conversion plugin) - */ -const PLUGINS = function (js, dir) { - const mjdir = path.resolve(__dirname, '..', 'js'); - const jsdir = path.resolve(dir, js); - - // - // Record the js directory for the pack command - // - return [new webpack.DefinePlugin({ - __JSDIR__: jsdir - })]; -}; - -/** - * Creates the plugin needed for converting mathjax references to component/lib references - * - * @param {string} js The location of the compiled js files - * @param {string[]} lib The component library directories to be linked against - * @param {string} dir The directory of the component being built - * @return {any[]} The plugin array (empty or with the conversion plugin) - */ -const RESOLVE = function (js, libs, dir) { - const mjdir = path.resolve(__dirname, '..', 'js'); - const jsdir = path.resolve(dir, js); - const mjRE = new RegExp('^(?:' + quoteRE(jsdir) + '|' + quoteRE(mjdir) + ')' + quoteRE(path.sep)); - const root = path.dirname(mjdir); - - // - // Add directory names to libraries - // - libs = libs.map(lib => path.join(lib.charAt(0) === '.' ? dir : root, lib) + path.sep); - - // - // Function replace imported files by ones in the specified component lib directories. - // - const replaceLibs = (resource) => { - // - // The full file name to check. - // - const request = require.resolve( - resource.request ? - resource.request.charAt(0) === '.' ? path.resolve(resource.path, resource.request) : resource.request : - resource.path - ); - // - // Only check files in the MathJax js directory. - // - if (!request.match(mjRE)) return; - // - // Loop through the libraries and see if the imported file is there. - // If so, replace the request with the library version and return. - // - for (const lib of libs) { - const file = request.replace(mjRE, lib); - if (fs.existsSync(file)) { - resource.path = file; - resource.request = undefined; - return; - } - } - } - - // - // A plugin that looks for files and modules to see if they need replacing with library versions. - // - class ResolveReplacementPlugin { - apply(compiler) { - compiler.hooks.file.tap(ResolveReplacementPlugin.name, replaceLibs); - compiler.hooks.module.tap(ResolveReplacementPlugin.name, replaceLibs); - } - } - - return {plugins: [new ResolveReplacementPlugin()]}; -} - -/** - * Add babel-loader to appropriate directories - * - * @param {string} dir The directory for the component being built - * @return {any} The modules specification for the webpack configuration - */ -const MODULE = function (dir) { - // - // Only need to transpile our directory and components directory - // - const dirRE = (dir.substr(0, __dirname.length) === __dirname ? quoteRE(__dirname) : - '(?:' + quoteRE(__dirname) + '|' + quoteRE(dir) + ')'); - return { - // NOTE: for babel transpilation - rules: [{ - test: new RegExp(dirRE + quoteRE(path.sep) + '.*\\.js$'), - exclude: new RegExp(quoteRE(path.join(path.dirname(__dirname), 'es5') + path.sep)), - use: { - loader: 'babel-loader', - options: { - presets: ['@babel/env'] - } - } - }] - } -}; - -/** - * Create a webpack configuration for a distribution file - * - * @param {string} name The name of the component to create - * @param {string} js The path to the compiled .js files - * @param {string[]} libs Array of paths to component lib directories to link against - * @param {string} dir The directory of the component buing built - * @param {string} dist The path to the directory where the component .js file will be placed - * (defaults to es5 in the same directory as the js directory) - */ -const PACKAGE = function (name, js, libs, dir, dist) { - const distDir = dist ? path.resolve(dir, dist) : - path.resolve(path.dirname(js), 'es5', path.dirname(name)); - name = path.basename(name); - return { - name: name, - entry: path.join(dir, name + '.js'), - output: { - path: distDir, - filename: name + (dist === '.' ? '.min.js' : '.js') - }, - target: ['web', 'es5'], // needed for IE11 and old browsers - plugins: PLUGINS(js, dir), - resolve: RESOLVE(js, libs, dir), - module: MODULE(dir), - performance: { - hints: false - }, - optimization: { - minimize: true, - minimizer: [new TerserPlugin({ - extractComments: false, - terserOptions: { - output: { - ascii_only: true - } - } - })] - }, - mode: 'production' - }; -} - -module.exports = PACKAGE; diff --git a/components/webpack.config.cjs b/components/webpack.config.cjs new file mode 100644 index 000000000..9bf31bd76 --- /dev/null +++ b/components/webpack.config.cjs @@ -0,0 +1,39 @@ +/************************************************************* + * + * Copyright (c) 2023-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview The webpack configuration file for use with CommonJS files + * + * @author dpvc@mathjax.org (Davide Cervone) + */ + +const fs = require('fs'); +const path = require('path'); +const {PACKAGE} = require('./webpack.common.cjs'); + +const dir = path.join(process.cwd(), process.argv[3].split(/=/)[1]); +const bundle = (process.argv[4] === '--env' ? process.argv[5].split(/=/)[1] : 'bundle'); +const json = require(path.join(dir, 'config.json')).webpack; + +let pkg = PACKAGE({...json, target: 'cjs', bundle, dir}); + +const modify = path.join(dir, 'webpack.cjs'); +if (fs.existsSync(modify)) { + pkg = require(modify)(pkg); +} + +module.exports = pkg; diff --git a/components/webpack.config.mjs b/components/webpack.config.mjs new file mode 100644 index 000000000..f13c9d940 --- /dev/null +++ b/components/webpack.config.mjs @@ -0,0 +1,42 @@ +/************************************************************* + * + * Copyright (c) 2023-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview The webpack configuration file for use with ES-modules + * + * @author dpvc@mathjax.org (Davide Cervone) + */ + +import fs from 'fs'; +import path from 'path'; +import {createRequire} from 'module'; +const require = createRequire(import.meta.url); + +const {PACKAGE} = require('./webpack.common.cjs'); + +const dir = path.join(process.cwd(), process.argv[3].split(/=/)[1]); +const bundle = (process.argv[4] === '--env' ? process.argv[5].split(/=/)[1] : 'bundle'); +const json = require(path.join(dir, 'config.json')).webpack; + +let pkg = PACKAGE({...json, target: 'mjs', bundle, dir}); + +const modify = path.join(dir, 'webpack.cjs'); +if (fs.existsSync(modify)) { + pkg = require(modify)(pkg); +} + +export default pkg; diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 000000000..9f3f93010 --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,34 @@ +import eslint from "@eslint/js"; +import jsdoc from 'eslint-plugin-jsdoc'; +import tseslint from "typescript-eslint"; + +// For documentation see +// https://typescript-eslint.io/packages/typescript-eslint#config + +export default tseslint.config({ + extends: [ + eslint.configs.recommended, + jsdoc.configs['flat/recommended'], + ...tseslint.configs.recommended + ], + languageOptions: { + parserOptions: { + project: true, + } + }, + files: ['ts/**/*.ts'], + ignores: ["**/*.d.ts", "**/*.js", "**/cjs/*"], + "rules": { + "@typescript-eslint/prefer-includes": "error", + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/no-unused-vars": ["error", + { "varsIgnorePattern": "^_", "argsIgnorePattern": "^_", + "caughtErrorsIgnorePattern": "^_" } + ], + "@typescript-eslint/no-empty-object-type": ["error", {"allowInterfaces": "with-single-extends"}], + "@typescript-eslint/no-unused-expressions": ["error", { "allowTernary": true }], + "prefer-const": ["error", {"destructuring": "all"}], + "jsdoc/tag-lines": ["warn", "always", {"count": 0, "startLines": 1}] + } +}); + diff --git a/lab/build/config.json b/lab/build/config.json new file mode 100644 index 000000000..c0e0366ff --- /dev/null +++ b/lab/build/config.json @@ -0,0 +1,6 @@ +{ + "webpack": { + "name": "sre", + "dist": ".." + } +} diff --git a/lab/build/sre.js b/lab/build/sre.js new file mode 100644 index 000000000..2e50078fe --- /dev/null +++ b/lab/build/sre.js @@ -0,0 +1 @@ +export * from '#js/a11y/sre/sre.js'; diff --git a/lab/build/webpack.cjs b/lab/build/webpack.cjs new file mode 100644 index 000000000..39fe85f87 --- /dev/null +++ b/lab/build/webpack.cjs @@ -0,0 +1,7 @@ +const webpack = require('webpack'); + +module.exports = (pkg) => { + pkg.experiments = {outputModule: true}; + pkg.output.library = {type: 'module'}; + return pkg; +} diff --git a/lab/sre.d.ts b/lab/sre.d.ts new file mode 100644 index 000000000..490d0f740 --- /dev/null +++ b/lab/sre.d.ts @@ -0,0 +1 @@ +export const SRE: any; diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index aa6ba740d..000000000 --- a/package-lock.json +++ /dev/null @@ -1,8782 +0,0 @@ -{ - "name": "mathjax-full", - "version": "3.2.2", - "lockfileVersion": 2, - "requires": true, - "packages": { - "": { - "name": "mathjax-full", - "version": "3.2.2", - "license": "Apache-2.0", - "dependencies": { - "esm": "^3.2.25", - "mhchemparser": "^4.1.0", - "mj-context-menu": "^0.6.1", - "speech-rule-engine": "^4.0.6" - }, - "devDependencies": { - "@babel/core": "^7.17.12", - "@babel/preset-env": "^7.17.12", - "babel-loader": "^8.2.5", - "copyfiles": "^2.4.1", - "diff": "^5.0.0", - "rimraf": "^3.0.2", - "tape": "^5.5.3", - "terser-webpack-plugin": "^5.3.1", - "tslint": "^6.1.3", - "tslint-jsdoc-rules": "^0.2.0", - "tslint-unix-formatter": "^0.2.0", - "typescript": "^4.6.4", - "typescript-tools": "^0.3.1", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2" - } - }, - "node_modules/@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/compat-data": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", - "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/core": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz", - "integrity": "sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==", - "dev": true, - "dependencies": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.12", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helpers": "^7.17.9", - "@babel/parser": "^7.17.12", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.12", - "@babel/types": "^7.17.12", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/generator": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.12.tgz", - "integrity": "sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.12", - "@jridgewell/gen-mapping": "^0.3.0", - "jsesc": "^2.5.1" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dev": true, - "dependencies": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", - "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-class-features-plugin": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.12.tgz", - "integrity": "sha512-sZoOeUTkFJMyhqCei2+Z+wtH/BehW8NVKQt7IRUQlRiOARuXymJYfN/FCcI8CvVbR0XVyDM6eLFOlR7YtiXnew==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-member-expression-to-functions": "^7.17.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-create-regexp-features-plugin": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz", - "integrity": "sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - }, - "peerDependencies": { - "@babel/core": "^7.4.0-0" - } - }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-function-name": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", - "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-member-expression-to-functions": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", - "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz", - "integrity": "sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.12", - "@babel/types": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-plugin-utils": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", - "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "dev": true, - "dependencies": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-simple-access": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", - "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", - "dev": true, - "dependencies": { - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "dependencies": { - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dev": true, - "dependencies": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/helpers": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", - "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", - "dev": true, - "dependencies": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.9", - "@babel/types": "^7.17.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/highlight": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", - "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/parser": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.12.tgz", - "integrity": "sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA==", - "dev": true, - "bin": { - "parser": "bin/babel-parser.js" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz", - "integrity": "sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz", - "integrity": "sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.13.0" - } - }, - "node_modules/@babel/plugin-proposal-async-generator-functions": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz", - "integrity": "sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-properties": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz", - "integrity": "sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-class-static-block": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.12.tgz", - "integrity": "sha512-8ILyDG6eL14F8iub97dVc8q35Md0PJYAnA5Kz9NACFOkt6ffCcr0FISyUPKHsvuAy36fkpIitxZ9bVYPFMGQHA==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.12.0" - } - }, - "node_modules/@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-export-namespace-from": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz", - "integrity": "sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-json-strings": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz", - "integrity": "sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-json-strings": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz", - "integrity": "sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz", - "integrity": "sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.12.tgz", - "integrity": "sha512-6l9cO3YXXRh4yPCPRA776ZyJ3RobG4ZKJZhp7NDRbKIOeV3dBPG8FXCF7ZtiO2RTCIOkQOph1xDDcc01iWVNjQ==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-optional-chaining": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz", - "integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-methods": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz", - "integrity": "sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==", - "dev": true, - "dependencies": { - "@babel/helper-create-class-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-private-property-in-object": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz", - "integrity": "sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-proposal-unicode-property-regex": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz", - "integrity": "sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.12.13" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.3" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.10.4" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.8.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.14.5" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-arrow-functions": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz", - "integrity": "sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-async-to-generator": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz", - "integrity": "sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==", - "dev": true, - "dependencies": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-remap-async-to-generator": "^7.16.8" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-block-scoping": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz", - "integrity": "sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-classes": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz", - "integrity": "sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw==", - "dev": true, - "dependencies": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-computed-properties": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz", - "integrity": "sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.12.tgz", - "integrity": "sha512-P8pt0YiKtX5UMUL5Xzsc9Oyij+pJE6JuC+F1k0/brq/OOGs5jDa1If3OY0LRWGvJsJhI+8tsiecL3nJLc0WTlg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-duplicate-keys": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz", - "integrity": "sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dev": true, - "dependencies": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-for-of": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.17.12.tgz", - "integrity": "sha512-76lTwYaCxw8ldT7tNmye4LLwSoKDbRCBzu6n/DcK/P3FOR29+38CIIaVIZfwol9By8W/QHORYEnYSLuvcQKrsg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dev": true, - "dependencies": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-literals": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz", - "integrity": "sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-amd": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.17.12.tgz", - "integrity": "sha512-p5rt9tB5Ndcc2Za7CeNxVf7YAjRcUMR6yi8o8tKjb9KhRkEvXwa+C0hj6DA5bVDkKRxB0NYhMUGbVKoFu4+zEA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-commonjs": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.12.tgz", - "integrity": "sha512-tVPs6MImAJz+DiX8Y1xXEMdTk5Lwxu9jiPjlS+nv5M2A59R7+/d1+9A8C/sbuY0b3QjIxqClkj6KAplEtRvzaA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-simple-access": "^7.17.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-systemjs": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.12.tgz", - "integrity": "sha512-NVhDb0q00hqZcuLduUf/kMzbOQHiocmPbIxIvk23HLiEqaTKC/l4eRxeC7lO63M72BmACoiKOcb9AkOAJRerpw==", - "dev": true, - "dependencies": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-modules-umd": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.17.12.tgz", - "integrity": "sha512-BnsPkrUHsjzZGpnrmJeDFkOMMljWFHPjDc9xDcz71/C+ybF3lfC3V4m3dwXPLZrE5b3bgd4V+3/Pj+3620d7IA==", - "dev": true, - "dependencies": { - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz", - "integrity": "sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0" - } - }, - "node_modules/@babel/plugin-transform-new-target": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz", - "integrity": "sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-parameters": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz", - "integrity": "sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-regenerator": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz", - "integrity": "sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==", - "dev": true, - "dependencies": { - "regenerator-transform": "^0.15.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-reserved-words": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz", - "integrity": "sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-spread": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz", - "integrity": "sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-template-literals": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.17.12.tgz", - "integrity": "sha512-kAKJ7DX1dSRa2s7WN1xUAuaQmkTpN+uig4wCKWivVXIObqGbVTUlSavHyfI2iZvz89GFAMGm9p2DBJ4Y1Tp0hw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-typeof-symbol": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz", - "integrity": "sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.17.12" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dev": true, - "dependencies": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-env": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.17.12.tgz", - "integrity": "sha512-Kke30Rj3Lmcx97bVs71LO0s8M6FmJ7tUAQI9fNId62rf0cYG1UAWwdNO9/sE0/pLEahAw1MqMorymoD12bj5Fg==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.17.12", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.17.12", - "@babel/plugin-proposal-async-generator-functions": "^7.17.12", - "@babel/plugin-proposal-class-properties": "^7.17.12", - "@babel/plugin-proposal-class-static-block": "^7.17.12", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.17.12", - "@babel/plugin-proposal-json-strings": "^7.17.12", - "@babel/plugin-proposal-logical-assignment-operators": "^7.17.12", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.17.12", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.17.12", - "@babel/plugin-proposal-private-methods": "^7.17.12", - "@babel/plugin-proposal-private-property-in-object": "^7.17.12", - "@babel/plugin-proposal-unicode-property-regex": "^7.17.12", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.17.12", - "@babel/plugin-transform-async-to-generator": "^7.17.12", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.17.12", - "@babel/plugin-transform-classes": "^7.17.12", - "@babel/plugin-transform-computed-properties": "^7.17.12", - "@babel/plugin-transform-destructuring": "^7.17.12", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.17.12", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.17.12", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.17.12", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.17.12", - "@babel/plugin-transform-modules-commonjs": "^7.17.12", - "@babel/plugin-transform-modules-systemjs": "^7.17.12", - "@babel/plugin-transform-modules-umd": "^7.17.12", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12", - "@babel/plugin-transform-new-target": "^7.17.12", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.17.12", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.17.9", - "@babel/plugin-transform-reserved-words": "^7.17.12", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.17.12", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.17.12", - "@babel/plugin-transform-typeof-symbol": "^7.17.12", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.17.12", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.22.1", - "semver": "^6.3.0" - }, - "engines": { - "node": ">=6.9.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "dependencies": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/traverse": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.12.tgz", - "integrity": "sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.12", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.12", - "@babel/types": "^7.17.12", - "debug": "^4.1.0", - "globals": "^11.1.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@babel/types": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.12.tgz", - "integrity": "sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - }, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", - "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", - "dev": true, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", - "dev": true, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "node_modules/@jridgewell/source-map/node_modules/@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "dependencies": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", - "dev": true - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", - "dev": true, - "dependencies": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "node_modules/@types/eslint": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz", - "integrity": "sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==", - "dev": true, - "dependencies": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "node_modules/@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "dependencies": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "node_modules/@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "node_modules/@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "node_modules/@types/node": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.9.tgz", - "integrity": "sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ==", - "dev": true - }, - "node_modules/@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "dependencies": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "node_modules/@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "dependencies": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "node_modules/@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "node_modules/@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "dependencies": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "node_modules/@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "dependencies": { - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "node_modules/@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "node_modules/@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "dependencies": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "node_modules/@webpack-cli/configtest": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", - "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", - "dev": true, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x", - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/info": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", - "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", - "dev": true, - "dependencies": { - "envinfo": "^7.7.3" - }, - "peerDependencies": { - "webpack-cli": "4.x.x" - } - }, - "node_modules/@webpack-cli/serve": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", - "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", - "dev": true, - "peerDependencies": { - "webpack-cli": "4.x.x" - }, - "peerDependenciesMeta": { - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "node_modules/@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "node_modules/acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true, - "bin": { - "acorn": "bin/acorn" - }, - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "peerDependencies": { - "acorn": "^8" - } - }, - "node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/array.prototype.every": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz", - "integrity": "sha512-vWnriJI//SOMOWtXbU/VXhJ/InfnNHPF6BLKn5WfY8xXy+NWql0fUy20GO3sdqBhCAO+qw8S/E5nJiZX+QFdCA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/babel-loader": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", - "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", - "dev": true, - "dependencies": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - }, - "engines": { - "node": ">= 8.9" - }, - "peerDependencies": { - "@babel/core": "^7.0.0", - "webpack": ">=2" - } - }, - "node_modules/babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "dependencies": { - "object.assign": "^4.1.0" - } - }, - "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", - "dev": true, - "dependencies": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.1.tgz", - "integrity": "sha512-TihqEe4sQcb/QcPJvxe94/9RZuLQuF1+To4WqQcRvc+3J3gLCPIPgDKzGLG6zmQLfH3nn25heRuDNkS2KR4I8A==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.20.0" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - }, - "peerDependencies": { - "@babel/core": "^7.0.0-0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "node_modules/big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true, - "engines": { - "node": "*" - } - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" - } - ], - "dependencies": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" - }, - "bin": { - "browserslist": "cli.js" - }, - "engines": { - "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" - } - }, - "node_modules/buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "node_modules/builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/caniuse-lite": { - "version": "1.0.30001341", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", - "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - } - ] - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true, - "engines": { - "node": ">=6.0" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "dependencies": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "node_modules/commander": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", - "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==", - "engines": { - "node": "^12.20.0 || >=14" - } - }, - "node_modules/commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.1" - } - }, - "node_modules/copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "dependencies": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "bin": { - "copyfiles": "copyfiles", - "copyup": "copyfiles" - } - }, - "node_modules/copyfiles/node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/copyfiles/node_modules/yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/core-js-compat": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.5.tgz", - "integrity": "sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg==", - "dev": true, - "dependencies": { - "browserslist": "^4.20.3", - "semver": "7.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/core-js" - } - }, - "node_modules/core-js-compat/node_modules/semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "dependencies": { - "ms": "2.1.2" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/deep-equal": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", - "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "es-get-iterator": "^1.1.1", - "get-intrinsic": "^1.0.1", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.1.1", - "isarray": "^2.0.5", - "object-is": "^1.1.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3", - "which-boxed-primitive": "^1.0.1", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/deep-equal/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "node_modules/diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/dotignore": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", - "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", - "dev": true, - "dependencies": { - "minimatch": "^3.0.4" - }, - "bin": { - "ignored": "bin/ignored" - } - }, - "node_modules/electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "node_modules/emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, - "node_modules/enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", - "dev": true, - "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true, - "bin": { - "envinfo": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-get-iterator/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - }, - "node_modules/es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true, - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==", - "engines": { - "node": ">=6" - } - }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "dependencies": { - "estraverse": "^5.2.0" - }, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esrecurse/node_modules/estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "engines": { - "node": ">=4.0" - } - }, - "node_modules/esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true, - "engines": { - "node": ">=0.8.x" - } - }, - "node_modules/execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "node_modules/find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "dependencies": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/avajs/find-cache-dir?sponsor=1" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.3" - } - }, - "node_modules/foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true, - "engines": { - "node": ">=6.9.0" - } - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - }, - "engines": { - "node": ">= 0.4.0" - } - }, - "node_modules/has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-dynamic-import": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-dynamic-import/-/has-dynamic-import-2.0.1.tgz", - "integrity": "sha512-X3fbtsZmwb6W7fJGR9o7x65fZoodygCrZ3TVycvghP62yYQfS0t4RS0Qcz+j5tQYUKeSWS09tHkWW6WhFV3XhQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true, - "engines": { - "node": ">=10.17.0" - } - }, - "node_modules/import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "dependencies": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - }, - "bin": { - "import-local-fixture": "fixtures/cli.js" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "node_modules/internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "dependencies": { - "has-bigints": "^1.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "dependencies": { - "isobject": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "dependencies": { - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/jest-worker": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz", - "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==", - "dev": true, - "dependencies": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "engines": { - "node": ">= 10.13.0" - } - }, - "node_modules/jest-worker/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/jest-worker/node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true, - "bin": { - "json5": "lib/cli.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true, - "engines": { - "node": ">=6.11.5" - } - }, - "node_modules/loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", - "dev": true, - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, - "engines": { - "node": ">=8.9.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/mhchemparser": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz", - "integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==" - }, - "node_modules/mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dev": true, - "dependencies": { - "mime-db": "1.51.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "node_modules/mj-context-menu": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", - "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "node_modules/neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node_modules/node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", - "dev": true - }, - "node_modules/noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", - "dev": true, - "dependencies": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "node_modules/punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "dependencies": { - "safe-buffer": "^5.1.0" - } - }, - "node_modules/readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "node_modules/rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "dependencies": { - "resolve": "^1.9.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", - "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "dev": true, - "dependencies": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", - "dev": true - }, - "node_modules/regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" - } - }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true, - "bin": { - "jsesc": "bin/jsesc" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", - "dev": true, - "dependencies": { - "is-core-module": "^2.8.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "dependencies": { - "resolve-from": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/resumer": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", - "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", - "dev": true, - "dependencies": { - "through": "~2.3.4" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "node_modules/schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 8.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "dependencies": { - "randombytes": "^2.1.0" - } - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "dependencies": { - "kind-of": "^6.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", - "dev": true - }, - "node_modules/source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/speech-rule-engine": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.6.tgz", - "integrity": "sha512-Hqa4ywf7d3lX2YsnnE8BeEdqFyaTwPSyyVhVGWZlQw4XVh0NCijyVsMZD3I9HsG5JBuDXyRaMVVNZcGJlKbZxA==", - "dependencies": { - "commander": "9.2.0", - "wicked-good-xpath": "1.3.0", - "xmldom-sre": "0.1.31" - }, - "bin": { - "sre": "bin/sre" - } - }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "node_modules/string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.5.tgz", - "integrity": "sha512-Lnh17webJVsD6ECeovpVN17RlAKjmz4rF9S+8Y45CkMc/ufVpTkU3vZIyIC7sllQ1FCvObZnnCdNs/HXTUOTlg==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/tape": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/tape/-/tape-5.5.3.tgz", - "integrity": "sha512-hPBJZBL9S7bH9vECg/KSM24slGYV589jJr4dmtiJrLD71AL66+8o4b9HdZazXZyvnilqA7eE8z5/flKiy0KsBg==", - "dev": true, - "dependencies": { - "array.prototype.every": "^1.1.3", - "call-bind": "^1.0.2", - "deep-equal": "^2.0.5", - "defined": "^1.0.0", - "dotignore": "^0.1.2", - "for-each": "^0.3.3", - "get-package-type": "^0.1.0", - "glob": "^7.2.0", - "has": "^1.0.3", - "has-dynamic-import": "^2.0.1", - "inherits": "^2.0.4", - "is-regex": "^1.1.4", - "minimist": "^1.2.6", - "object-inspect": "^1.12.0", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "resolve": "^2.0.0-next.3", - "resumer": "^0.0.0", - "string.prototype.trim": "^1.2.5", - "through": "^2.3.8" - }, - "bin": { - "tape": "bin/tape" - } - }, - "node_modules/tape/node_modules/resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", - "dev": true, - "dependencies": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", - "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", - "dev": true, - "dependencies": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } - } - }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/terser-webpack-plugin/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "dependencies": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - } - }, - "node_modules/through2/node_modules/isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "node_modules/through2/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/through2/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev || >= 4.0.0-dev" - } - }, - "node_modules/tslint-jsdoc-rules": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/tslint-jsdoc-rules/-/tslint-jsdoc-rules-0.2.0.tgz", - "integrity": "sha512-7r6OP+cuGSsW+FHVKlg1gJrZ0RAfaHQjLJD3Grw9gAvemjAxBkkswiAlgAYy+DIG/SLUQ0EOh6LTzJNP7bk0eQ==", - "dev": true, - "dependencies": { - "tslint": "^5.*" - } - }, - "node_modules/tslint-jsdoc-rules/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/tslint-jsdoc-rules/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tslint-jsdoc-rules/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/tslint-jsdoc-rules/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tslint-jsdoc-rules/node_modules/tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" - } - }, - "node_modules/tslint-unix-formatter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/tslint-unix-formatter/-/tslint-unix-formatter-0.2.0.tgz", - "integrity": "sha512-EDEzVIPm4DWXOvmgYs5T53p3uIE1GFPO9Z+4lAam2qNkgKCXdW6jx2ieaX6g5OvA/vorH7CbbmRHVA8NQgZQQA==", - "dev": true, - "dependencies": { - "tslint": "^5.*" - } - }, - "node_modules/tslint-unix-formatter/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/tslint-unix-formatter/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tslint-unix-formatter/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/tslint-unix-formatter/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tslint-unix-formatter/node_modules/tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - }, - "bin": { - "tslint": "bin/tslint" - }, - "engines": { - "node": ">=4.8.0" - }, - "peerDependencies": { - "typescript": ">=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev" - } - }, - "node_modules/tslint/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "node_modules/tslint/node_modules/diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true, - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/tslint/node_modules/mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "dependencies": { - "minimist": "^1.2.5" - }, - "bin": { - "mkdirp": "bin/cmd.js" - } - }, - "node_modules/tslint/node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "dependencies": { - "tslib": "^1.8.1" - }, - "peerDependencies": { - "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || >=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || >=2.9.0-dev || >= 3.0.0-dev || >= 3.1.0-dev" - } - }, - "node_modules/typescript": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/typescript-tools": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/typescript-tools/-/typescript-tools-0.3.1.tgz", - "integrity": "sha1-MlhSu+lFwwIQpjbOdjMHcHpTxEk=", - "dev": true, - "bin": { - "tss": "bin/tss" - } - }, - "node_modules/unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "node_modules/watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", - "dev": true, - "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack": { - "version": "5.72.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", - "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", - "dev": true, - "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", - "webpack-sources": "^3.2.3" - }, - "bin": { - "webpack": "bin/webpack.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } - } - }, - "node_modules/webpack-cli": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", - "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", - "dev": true, - "dependencies": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.1", - "@webpack-cli/info": "^1.4.1", - "@webpack-cli/serve": "^1.6.1", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "execa": "^5.0.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" - }, - "bin": { - "webpack-cli": "bin/cli.js" - }, - "engines": { - "node": ">=10.13.0" - }, - "peerDependencies": { - "webpack": "4.x.x || 5.x.x" - }, - "peerDependenciesMeta": { - "@webpack-cli/generators": { - "optional": true - }, - "@webpack-cli/migrate": { - "optional": true - }, - "webpack-bundle-analyzer": { - "optional": true - }, - "webpack-dev-server": { - "optional": true - } - } - }, - "node_modules/webpack-cli/node_modules/commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "dependencies": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - }, - "engines": { - "node": ">=10.0.0" - } - }, - "node_modules/webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "dependencies": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", - "dev": true, - "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/wicked-good-xpath": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", - "integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w=" - }, - "node_modules/wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/xmldom-sre": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", - "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==", - "engines": { - "node": ">=0.1" - } - }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true, - "engines": { - "node": ">=0.4" - } - }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, - "engines": { - "node": ">=10" - } - } - }, - "dependencies": { - "@ampproject/remapping": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", - "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.1.0", - "@jridgewell/trace-mapping": "^0.3.9" - } - }, - "@babel/code-frame": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", - "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", - "dev": true, - "requires": { - "@babel/highlight": "^7.16.7" - } - }, - "@babel/compat-data": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.17.10.tgz", - "integrity": "sha512-GZt/TCsG70Ms19gfZO1tM4CVnXsPgEPBCpJu+Qz3L0LUDsY5nZqFZglIoPC1kIYOtNBZlrnFT+klg12vFGZXrw==", - "dev": true - }, - "@babel/core": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.17.12.tgz", - "integrity": "sha512-44ODe6O1IVz9s2oJE3rZ4trNNKTX9O7KpQpfAP4t8QII/zwrVRHL7i2pxhqtcY7tqMLrrKfMlBKnm1QlrRFs5w==", - "dev": true, - "requires": { - "@ampproject/remapping": "^2.1.0", - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.12", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helpers": "^7.17.9", - "@babel/parser": "^7.17.12", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.12", - "@babel/types": "^7.17.12", - "convert-source-map": "^1.7.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.1", - "semver": "^6.3.0" - } - }, - "@babel/generator": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.17.12.tgz", - "integrity": "sha512-V49KtZiiiLjH/CnIW6OjJdrenrGoyh6AmKQ3k2AZFKozC1h846Q4NYlZ5nqAigPDUXfGzC88+LOUuG8yKd2kCw==", - "dev": true, - "requires": { - "@babel/types": "^7.17.12", - "@jridgewell/gen-mapping": "^0.3.0", - "jsesc": "^2.5.1" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.1.tgz", - "integrity": "sha512-GcHwniMlA2z+WFPWuY8lp3fsza0I8xPFMWL5+n8LYyP6PSvPrXf4+n8stDHZY2DM0zy9sVkRDy1jDI4XGzYVqg==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@babel/helper-annotate-as-pure": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.16.7.tgz", - "integrity": "sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-builder-binary-assignment-operator-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.16.7.tgz", - "integrity": "sha512-C6FdbRaxYjwVu/geKW4ZeQ0Q31AftgRcdSnZ5/jsH6BzCJbtvXvhpfkbkThYSuutZA7nCXpPR6AD9zd1dprMkA==", - "dev": true, - "requires": { - "@babel/helper-explode-assignable-expression": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-compilation-targets": { - "version": "7.17.10", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.17.10.tgz", - "integrity": "sha512-gh3RxjWbauw/dFiU/7whjd0qN9K6nPJMqe6+Er7rOavFh0CQUSwhAE3IcTho2rywPJFxej6TUUHDkWcYI6gGqQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-validator-option": "^7.16.7", - "browserslist": "^4.20.2", - "semver": "^6.3.0" - } - }, - "@babel/helper-create-class-features-plugin": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.17.12.tgz", - "integrity": "sha512-sZoOeUTkFJMyhqCei2+Z+wtH/BehW8NVKQt7IRUQlRiOARuXymJYfN/FCcI8CvVbR0XVyDM6eLFOlR7YtiXnew==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-member-expression-to-functions": "^7.17.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7" - } - }, - "@babel/helper-create-regexp-features-plugin": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.17.12.tgz", - "integrity": "sha512-b2aZrV4zvutr9AIa6/gA3wsZKRwTKYoDxYiFKcESS3Ug2GTXzwBEvMuuFLhCQpEnRXs1zng4ISAXSUxxKBIcxw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "regexpu-core": "^5.0.1" - } - }, - "@babel/helper-define-polyfill-provider": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.3.1.tgz", - "integrity": "sha512-J9hGMpJQmtWmj46B3kBHmL38UhJGhYX7eqkcq+2gsstyYt341HmPeWspihX43yVRA0mS+8GGk2Gckc7bY/HCmA==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.13.0", - "@babel/helper-module-imports": "^7.12.13", - "@babel/helper-plugin-utils": "^7.13.0", - "@babel/traverse": "^7.13.0", - "debug": "^4.1.1", - "lodash.debounce": "^4.0.8", - "resolve": "^1.14.2", - "semver": "^6.1.2" - } - }, - "@babel/helper-environment-visitor": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", - "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-explode-assignable-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.16.7.tgz", - "integrity": "sha512-KyUenhWMC8VrxzkGP0Jizjo4/Zx+1nNZhgocs+gLzyZyB8SHidhoq9KK/8Ato4anhwsivfkBLftky7gvzbZMtQ==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-function-name": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.17.9.tgz", - "integrity": "sha512-7cRisGlVtiVqZ0MW0/yFB4atgpGLWEHUVYnb448hZK4x+vih0YO5UoS11XIYtZYqHd0dIPMdUSv8q5K4LdMnIg==", - "dev": true, - "requires": { - "@babel/template": "^7.16.7", - "@babel/types": "^7.17.0" - } - }, - "@babel/helper-hoist-variables": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", - "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-member-expression-to-functions": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.17.7.tgz", - "integrity": "sha512-thxXgnQ8qQ11W2wVUObIqDL4p148VMxkt5T/qpN5k2fboRyzFGFmKsTGViquyM5QHKUy48OZoca8kw4ajaDPyw==", - "dev": true, - "requires": { - "@babel/types": "^7.17.0" - } - }, - "@babel/helper-module-imports": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", - "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-module-transforms": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.17.12.tgz", - "integrity": "sha512-t5s2BeSWIghhFRPh9XMn6EIGmvn8Lmw5RVASJzkIx1mSemubQQBNIZiQD7WzaFmaHIrjAec4x8z9Yx8SjJ1/LA==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-simple-access": "^7.17.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/helper-validator-identifier": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.12", - "@babel/types": "^7.17.12" - } - }, - "@babel/helper-optimise-call-expression": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.16.7.tgz", - "integrity": "sha512-EtgBhg7rd/JcnpZFXpBy0ze1YRfdm7BnBX4uKMBd3ixa3RGAE002JZB66FJyNH7g0F38U05pXmA5P8cBh7z+1w==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.17.12.tgz", - "integrity": "sha512-JDkf04mqtN3y4iAbO1hv9U2ARpPyPL1zqyWs/2WG1pgSq9llHFjStX5jdxb84himgJm+8Ng+x0oiWF/nw/XQKA==", - "dev": true - }, - "@babel/helper-remap-async-to-generator": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.16.8.tgz", - "integrity": "sha512-fm0gH7Flb8H51LqJHy3HJ3wnE1+qtYR2A99K06ahwrawLdOFsCEWjZOrYricXJHoPSudNKxrMBUPEIPxiIIvBw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-wrap-function": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helper-replace-supers": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.16.7.tgz", - "integrity": "sha512-y9vsWilTNaVnVh6xiJfABzsNpgDPKev9HnAgz6Gb1p6UUwf9NepdlsV7VXGCftJM+jqD5f7JIEubcpLjZj5dBw==", - "dev": true, - "requires": { - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-member-expression-to-functions": "^7.16.7", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/traverse": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-simple-access": { - "version": "7.17.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.17.7.tgz", - "integrity": "sha512-txyMCGroZ96i+Pxr3Je3lzEJjqwaRC9buMUgtomcrLe5Nd0+fk1h0LLA+ixUF5OW7AhHuQ7Es1WcQJZmZsz2XA==", - "dev": true, - "requires": { - "@babel/types": "^7.17.0" - } - }, - "@babel/helper-skip-transparent-expression-wrappers": { - "version": "7.16.0", - "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.16.0.tgz", - "integrity": "sha512-+il1gTy0oHwUsBQZyJvukbB4vPMdcYBrFHa0Uc4AizLxbq6BOYC51Rv4tWocX9BLBDLZ4kc6qUFpQ6HRgL+3zw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.0" - } - }, - "@babel/helper-split-export-declaration": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", - "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", - "dev": true, - "requires": { - "@babel/types": "^7.16.7" - } - }, - "@babel/helper-validator-identifier": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", - "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", - "dev": true - }, - "@babel/helper-validator-option": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", - "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", - "dev": true - }, - "@babel/helper-wrap-function": { - "version": "7.16.8", - "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.16.8.tgz", - "integrity": "sha512-8RpyRVIAW1RcDDGTA+GpPAwV22wXCfKOoM9bet6TLkGIFTkRQSkH1nMQ5Yet4MpoXe1ZwHPVtNasc2w0uZMqnw==", - "dev": true, - "requires": { - "@babel/helper-function-name": "^7.16.7", - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.16.8", - "@babel/types": "^7.16.8" - } - }, - "@babel/helpers": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.17.9.tgz", - "integrity": "sha512-cPCt915ShDWUEzEp3+UNRktO2n6v49l5RSnG9M5pS24hA+2FAc5si+Pn1i4VVbQQ+jh+bIZhPFQOJOzbrOYY1Q==", - "dev": true, - "requires": { - "@babel/template": "^7.16.7", - "@babel/traverse": "^7.17.9", - "@babel/types": "^7.17.0" - } - }, - "@babel/highlight": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", - "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.17.12.tgz", - "integrity": "sha512-FLzHmN9V3AJIrWfOpvRlZCeVg/WLdicSnTMsLur6uDj9TT8ymUlG9XxURdW/XvuygK+2CW0poOJABdA4m/YKxA==", - "dev": true - }, - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.17.12.tgz", - "integrity": "sha512-xCJQXl4EeQ3J9C4yOmpTrtVGmzpm2iSzyxbkZHw7UCnZBftHpF/hpII80uWVyVrc40ytIClHjgWGTG1g/yB+aw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.17.12.tgz", - "integrity": "sha512-/vt0hpIw0x4b6BLKUkwlvEoiGZYYLNZ96CzyHYPbtG2jZGz6LBe7/V+drYrc/d+ovrF9NBi0pmtvmNb/FsWtRQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-proposal-optional-chaining": "^7.17.12" - } - }, - "@babel/plugin-proposal-async-generator-functions": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.17.12.tgz", - "integrity": "sha512-RWVvqD1ooLKP6IqWTA5GyFVX2isGEgC5iFxKzfYOIy/QEFdxYyCybBDtIGjipHpb9bDWHzcqGqFakf+mVmBTdQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-remap-async-to-generator": "^7.16.8", - "@babel/plugin-syntax-async-generators": "^7.8.4" - } - }, - "@babel/plugin-proposal-class-properties": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-properties/-/plugin-proposal-class-properties-7.17.12.tgz", - "integrity": "sha512-U0mI9q8pW5Q9EaTHFPwSVusPMV/DV9Mm8p7csqROFLtIE9rBF5piLqyrBGigftALrBcsBGu4m38JneAe7ZDLXw==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-proposal-class-static-block": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-class-static-block/-/plugin-proposal-class-static-block-7.17.12.tgz", - "integrity": "sha512-8ILyDG6eL14F8iub97dVc8q35Md0PJYAnA5Kz9NACFOkt6ffCcr0FISyUPKHsvuAy36fkpIitxZ9bVYPFMGQHA==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-class-static-block": "^7.14.5" - } - }, - "@babel/plugin-proposal-dynamic-import": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.16.7.tgz", - "integrity": "sha512-I8SW9Ho3/8DRSdmDdH3gORdyUuYnk1m4cMxUAdu5oy4n3OfN8flDEH+d60iG7dUfi0KkYwSvoalHzzdRzpWHTg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-dynamic-import": "^7.8.3" - } - }, - "@babel/plugin-proposal-export-namespace-from": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-export-namespace-from/-/plugin-proposal-export-namespace-from-7.17.12.tgz", - "integrity": "sha512-j7Ye5EWdwoXOpRmo5QmRyHPsDIe6+u70ZYZrd7uz+ebPYFKfRcLcNu3Ro0vOlJ5zuv8rU7xa+GttNiRzX56snQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3" - } - }, - "@babel/plugin-proposal-json-strings": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.17.12.tgz", - "integrity": "sha512-rKJ+rKBoXwLnIn7n6o6fulViHMrOThz99ybH+hKHcOZbnN14VuMnH9fo2eHE69C8pO4uX1Q7t2HYYIDmv8VYkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-json-strings": "^7.8.3" - } - }, - "@babel/plugin-proposal-logical-assignment-operators": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-logical-assignment-operators/-/plugin-proposal-logical-assignment-operators-7.17.12.tgz", - "integrity": "sha512-EqFo2s1Z5yy+JeJu7SFfbIUtToJTVlC61/C7WLKDntSw4Sz6JNAIfL7zQ74VvirxpjB5kz/kIx0gCcb+5OEo2Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" - } - }, - "@babel/plugin-proposal-nullish-coalescing-operator": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-nullish-coalescing-operator/-/plugin-proposal-nullish-coalescing-operator-7.17.12.tgz", - "integrity": "sha512-ws/g3FSGVzv+VH86+QvgtuJL/kR67xaEIF2x0iPqdDfYW6ra6JF3lKVBkWynRLcNtIC1oCTfDRVxmm2mKzy+ag==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" - } - }, - "@babel/plugin-proposal-numeric-separator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-numeric-separator/-/plugin-proposal-numeric-separator-7.16.7.tgz", - "integrity": "sha512-vQgPMknOIgiuVqbokToyXbkY/OmmjAzr/0lhSIbG/KmnzXPGwW/AdhdKpi+O4X/VkWiWjnkKOBiqJrTaC98VKw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-numeric-separator": "^7.10.4" - } - }, - "@babel/plugin-proposal-object-rest-spread": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.17.12.tgz", - "integrity": "sha512-6l9cO3YXXRh4yPCPRA776ZyJ3RobG4ZKJZhp7NDRbKIOeV3dBPG8FXCF7ZtiO2RTCIOkQOph1xDDcc01iWVNjQ==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-transform-parameters": "^7.17.12" - } - }, - "@babel/plugin-proposal-optional-catch-binding": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.16.7.tgz", - "integrity": "sha512-eMOH/L4OvWSZAE1VkHbr1vckLG1WUcHGJSLqqQwl2GaUqG6QjddvrOaTUMNYiv77H5IKPMZ9U9P7EaHwvAShfA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" - } - }, - "@babel/plugin-proposal-optional-chaining": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-optional-chaining/-/plugin-proposal-optional-chaining-7.17.12.tgz", - "integrity": "sha512-7wigcOs/Z4YWlK7xxjkvaIw84vGhDv/P1dFGQap0nHkc8gFKY/r+hXc8Qzf5k1gY7CvGIcHqAnOagVKJJ1wVOQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0", - "@babel/plugin-syntax-optional-chaining": "^7.8.3" - } - }, - "@babel/plugin-proposal-private-methods": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-methods/-/plugin-proposal-private-methods-7.17.12.tgz", - "integrity": "sha512-SllXoxo19HmxhDWm3luPz+cPhtoTSKLJE9PXshsfrOzBqs60QP0r8OaJItrPhAj0d7mZMnNF0Y1UUggCDgMz1A==", - "dev": true, - "requires": { - "@babel/helper-create-class-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-proposal-private-property-in-object": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.17.12.tgz", - "integrity": "sha512-/6BtVi57CJfrtDNKfK5b66ydK2J5pXUKBKSPD2G1whamMuEnZWgoOIfO8Vf9F/DoD4izBLD/Au4NMQfruzzykg==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-create-class-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5" - } - }, - "@babel/plugin-proposal-unicode-property-regex": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.17.12.tgz", - "integrity": "sha512-Wb9qLjXf3ZazqXA7IvI7ozqRIXIGPtSo+L5coFmEkhTQK18ao4UDDD0zdTGAarmbLj2urpRwrc6893cu5Bfh0A==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-syntax-async-generators": { - "version": "7.8.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", - "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-class-properties": { - "version": "7.12.13", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", - "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.12.13" - } - }, - "@babel/plugin-syntax-class-static-block": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", - "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-dynamic-import": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", - "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-export-namespace-from": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", - "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.3" - } - }, - "@babel/plugin-syntax-json-strings": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", - "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-logical-assignment-operators": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", - "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-nullish-coalescing-operator": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", - "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-numeric-separator": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", - "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.10.4" - } - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", - "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-catch-binding": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", - "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-optional-chaining": { - "version": "7.8.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", - "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.8.0" - } - }, - "@babel/plugin-syntax-private-property-in-object": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", - "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-syntax-top-level-await": { - "version": "7.14.5", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", - "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.14.5" - } - }, - "@babel/plugin-transform-arrow-functions": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.17.12.tgz", - "integrity": "sha512-PHln3CNi/49V+mza4xMwrg+WGYevSF1oaiXaC2EQfdp4HWlSjRsrDXWJiQBKpP7749u6vQ9mcry2uuFOv5CXvA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-async-to-generator": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.17.12.tgz", - "integrity": "sha512-J8dbrWIOO3orDzir57NRsjg4uxucvhby0L/KZuGsWDj0g7twWK3g7JhJhOrXtuXiw8MeiSdJ3E0OW9H8LYEzLQ==", - "dev": true, - "requires": { - "@babel/helper-module-imports": "^7.16.7", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-remap-async-to-generator": "^7.16.8" - } - }, - "@babel/plugin-transform-block-scoped-functions": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.16.7.tgz", - "integrity": "sha512-JUuzlzmF40Z9cXyytcbZEZKckgrQzChbQJw/5PuEHYeqzCsvebDx0K0jWnIIVcmmDOAVctCgnYs0pMcrYj2zJg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-block-scoping": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.17.12.tgz", - "integrity": "sha512-jw8XW/B1i7Lqwqj2CbrViPcZijSxfguBWZP2aN59NHgxUyO/OcO1mfdCxH13QhN5LbWhPkX+f+brKGhZTiqtZQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-classes": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.17.12.tgz", - "integrity": "sha512-cvO7lc7pZat6BsvH6l/EGaI8zpl8paICaoGk+7x7guvtfak/TbIf66nYmJOH13EuG0H+Xx3M+9LQDtSvZFKXKw==", - "dev": true, - "requires": { - "@babel/helper-annotate-as-pure": "^7.16.7", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-optimise-call-expression": "^7.16.7", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-replace-supers": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "globals": "^11.1.0" - } - }, - "@babel/plugin-transform-computed-properties": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.17.12.tgz", - "integrity": "sha512-a7XINeplB5cQUWMg1E/GI1tFz3LfK021IjV1rj1ypE+R7jHm+pIHmHl25VNkZxtx9uuYp7ThGk8fur1HHG7PgQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-destructuring": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.17.12.tgz", - "integrity": "sha512-P8pt0YiKtX5UMUL5Xzsc9Oyij+pJE6JuC+F1k0/brq/OOGs5jDa1If3OY0LRWGvJsJhI+8tsiecL3nJLc0WTlg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-dotall-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.16.7.tgz", - "integrity": "sha512-Lyttaao2SjZF6Pf4vk1dVKv8YypMpomAbygW+mU5cYP3S5cWTfCJjG8xV6CFdzGFlfWK81IjL9viiTvpb6G7gQ==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-duplicate-keys": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.17.12.tgz", - "integrity": "sha512-EA5eYFUG6xeerdabina/xIoB95jJ17mAkR8ivx6ZSu9frKShBjpOGZPn511MTDTkiCO+zXnzNczvUM69YSf3Zw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-exponentiation-operator": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.16.7.tgz", - "integrity": "sha512-8UYLSlyLgRixQvlYH3J2ekXFHDFLQutdy7FfFAMm3CPZ6q9wHCwnUyiXpQCe3gVVnQlHc5nsuiEVziteRNTXEA==", - "dev": true, - "requires": { - "@babel/helper-builder-binary-assignment-operator-visitor": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-for-of": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.17.12.tgz", - "integrity": "sha512-76lTwYaCxw8ldT7tNmye4LLwSoKDbRCBzu6n/DcK/P3FOR29+38CIIaVIZfwol9By8W/QHORYEnYSLuvcQKrsg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-function-name": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.16.7.tgz", - "integrity": "sha512-SU/C68YVwTRxqWj5kgsbKINakGag0KTgq9f2iZEXdStoAbOzLHEBRYzImmA6yFo8YZhJVflvXmIHUO7GWHmxxA==", - "dev": true, - "requires": { - "@babel/helper-compilation-targets": "^7.16.7", - "@babel/helper-function-name": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-literals": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.17.12.tgz", - "integrity": "sha512-8iRkvaTjJciWycPIZ9k9duu663FT7VrBdNqNgxnVXEFwOIp55JWcZd23VBRySYbnS3PwQ3rGiabJBBBGj5APmQ==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-member-expression-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.16.7.tgz", - "integrity": "sha512-mBruRMbktKQwbxaJof32LT9KLy2f3gH+27a5XSuXo6h7R3vqltl0PgZ80C8ZMKw98Bf8bqt6BEVi3svOh2PzMw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-modules-amd": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.17.12.tgz", - "integrity": "sha512-p5rt9tB5Ndcc2Za7CeNxVf7YAjRcUMR6yi8o8tKjb9KhRkEvXwa+C0hj6DA5bVDkKRxB0NYhMUGbVKoFu4+zEA==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-commonjs": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.17.12.tgz", - "integrity": "sha512-tVPs6MImAJz+DiX8Y1xXEMdTk5Lwxu9jiPjlS+nv5M2A59R7+/d1+9A8C/sbuY0b3QjIxqClkj6KAplEtRvzaA==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-simple-access": "^7.17.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-systemjs": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.17.12.tgz", - "integrity": "sha512-NVhDb0q00hqZcuLduUf/kMzbOQHiocmPbIxIvk23HLiEqaTKC/l4eRxeC7lO63M72BmACoiKOcb9AkOAJRerpw==", - "dev": true, - "requires": { - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-validator-identifier": "^7.16.7", - "babel-plugin-dynamic-import-node": "^2.3.3" - } - }, - "@babel/plugin-transform-modules-umd": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.17.12.tgz", - "integrity": "sha512-BnsPkrUHsjzZGpnrmJeDFkOMMljWFHPjDc9xDcz71/C+ybF3lfC3V4m3dwXPLZrE5b3bgd4V+3/Pj+3620d7IA==", - "dev": true, - "requires": { - "@babel/helper-module-transforms": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-named-capturing-groups-regex": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.17.12.tgz", - "integrity": "sha512-vWoWFM5CKaTeHrdUJ/3SIOTRV+MBVGybOC9mhJkaprGNt5demMymDW24yC74avb915/mIRe3TgNb/d8idvnCRA==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.17.12", - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-new-target": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.17.12.tgz", - "integrity": "sha512-CaOtzk2fDYisbjAD4Sd1MTKGVIpRtx9bWLyj24Y/k6p4s4gQ3CqDGJauFJxt8M/LEx003d0i3klVqnN73qvK3w==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-object-super": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.16.7.tgz", - "integrity": "sha512-14J1feiQVWaGvRxj2WjyMuXS2jsBkgB3MdSN5HuC2G5nRspa5RK9COcs82Pwy5BuGcjb+fYaUj94mYcOj7rCvw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7", - "@babel/helper-replace-supers": "^7.16.7" - } - }, - "@babel/plugin-transform-parameters": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.17.12.tgz", - "integrity": "sha512-6qW4rWo1cyCdq1FkYri7AHpauchbGLXpdwnYsfxFb+KtddHENfsY5JZb35xUwkK5opOLcJ3BNd2l7PhRYGlwIA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-property-literals": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.16.7.tgz", - "integrity": "sha512-z4FGr9NMGdoIl1RqavCqGG+ZuYjfZ/hkCIeuH6Do7tXmSm0ls11nYVSJqFEUOSJbDab5wC6lRE/w6YjVcr6Hqw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-regenerator": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.17.9.tgz", - "integrity": "sha512-Lc2TfbxR1HOyn/c6b4Y/b6NHoTb67n/IoWLxTu4kC7h4KQnWlhCq2S8Tx0t2SVvv5Uu87Hs+6JEJ5kt2tYGylQ==", - "dev": true, - "requires": { - "regenerator-transform": "^0.15.0" - } - }, - "@babel/plugin-transform-reserved-words": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.17.12.tgz", - "integrity": "sha512-1KYqwbJV3Co03NIi14uEHW8P50Md6KqFgt0FfpHdK6oyAHQVTosgPuPSiWud1HX0oYJ1hGRRlk0fP87jFpqXZA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-shorthand-properties": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.16.7.tgz", - "integrity": "sha512-hah2+FEnoRoATdIb05IOXf+4GzXYTq75TVhIn1PewihbpyrNWUt2JbudKQOETWw6QpLe+AIUpJ5MVLYTQbeeUg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-spread": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.17.12.tgz", - "integrity": "sha512-9pgmuQAtFi3lpNUstvG9nGfk9DkrdmWNp9KeKPFmuZCpEnxRzYlS8JgwPjYj+1AWDOSvoGN0H30p1cBOmT/Svg==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-skip-transparent-expression-wrappers": "^7.16.0" - } - }, - "@babel/plugin-transform-sticky-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.16.7.tgz", - "integrity": "sha512-NJa0Bd/87QV5NZZzTuZG5BPJjLYadeSZ9fO6oOUoL4iQx+9EEuw/eEM92SrsT19Yc2jgB1u1hsjqDtH02c3Drw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-template-literals": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.17.12.tgz", - "integrity": "sha512-kAKJ7DX1dSRa2s7WN1xUAuaQmkTpN+uig4wCKWivVXIObqGbVTUlSavHyfI2iZvz89GFAMGm9p2DBJ4Y1Tp0hw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-typeof-symbol": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.17.12.tgz", - "integrity": "sha512-Q8y+Jp7ZdtSPXCThB6zjQ74N3lj0f6TDh1Hnf5B+sYlzQ8i5Pjp8gW0My79iekSpT4WnI06blqP6DT0OmaXXmw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.17.12" - } - }, - "@babel/plugin-transform-unicode-escapes": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.16.7.tgz", - "integrity": "sha512-TAV5IGahIz3yZ9/Hfv35TV2xEm+kaBDaZQCn2S/hG9/CZ0DktxJv9eKfPc7yYCvOYR4JGx1h8C+jcSOvgaaI/Q==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/plugin-transform-unicode-regex": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.16.7.tgz", - "integrity": "sha512-oC5tYYKw56HO75KZVLQ+R/Nl3Hro9kf8iG0hXoaHP7tjAyCpvqBiSNe6vGrZni1Z6MggmUOC6A7VP7AVmw225Q==", - "dev": true, - "requires": { - "@babel/helper-create-regexp-features-plugin": "^7.16.7", - "@babel/helper-plugin-utils": "^7.16.7" - } - }, - "@babel/preset-env": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.17.12.tgz", - "integrity": "sha512-Kke30Rj3Lmcx97bVs71LO0s8M6FmJ7tUAQI9fNId62rf0cYG1UAWwdNO9/sE0/pLEahAw1MqMorymoD12bj5Fg==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.17.10", - "@babel/helper-compilation-targets": "^7.17.10", - "@babel/helper-plugin-utils": "^7.17.12", - "@babel/helper-validator-option": "^7.16.7", - "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.17.12", - "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.17.12", - "@babel/plugin-proposal-async-generator-functions": "^7.17.12", - "@babel/plugin-proposal-class-properties": "^7.17.12", - "@babel/plugin-proposal-class-static-block": "^7.17.12", - "@babel/plugin-proposal-dynamic-import": "^7.16.7", - "@babel/plugin-proposal-export-namespace-from": "^7.17.12", - "@babel/plugin-proposal-json-strings": "^7.17.12", - "@babel/plugin-proposal-logical-assignment-operators": "^7.17.12", - "@babel/plugin-proposal-nullish-coalescing-operator": "^7.17.12", - "@babel/plugin-proposal-numeric-separator": "^7.16.7", - "@babel/plugin-proposal-object-rest-spread": "^7.17.12", - "@babel/plugin-proposal-optional-catch-binding": "^7.16.7", - "@babel/plugin-proposal-optional-chaining": "^7.17.12", - "@babel/plugin-proposal-private-methods": "^7.17.12", - "@babel/plugin-proposal-private-property-in-object": "^7.17.12", - "@babel/plugin-proposal-unicode-property-regex": "^7.17.12", - "@babel/plugin-syntax-async-generators": "^7.8.4", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-syntax-class-static-block": "^7.14.5", - "@babel/plugin-syntax-dynamic-import": "^7.8.3", - "@babel/plugin-syntax-export-namespace-from": "^7.8.3", - "@babel/plugin-syntax-json-strings": "^7.8.3", - "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", - "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", - "@babel/plugin-syntax-numeric-separator": "^7.10.4", - "@babel/plugin-syntax-object-rest-spread": "^7.8.3", - "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", - "@babel/plugin-syntax-optional-chaining": "^7.8.3", - "@babel/plugin-syntax-private-property-in-object": "^7.14.5", - "@babel/plugin-syntax-top-level-await": "^7.14.5", - "@babel/plugin-transform-arrow-functions": "^7.17.12", - "@babel/plugin-transform-async-to-generator": "^7.17.12", - "@babel/plugin-transform-block-scoped-functions": "^7.16.7", - "@babel/plugin-transform-block-scoping": "^7.17.12", - "@babel/plugin-transform-classes": "^7.17.12", - "@babel/plugin-transform-computed-properties": "^7.17.12", - "@babel/plugin-transform-destructuring": "^7.17.12", - "@babel/plugin-transform-dotall-regex": "^7.16.7", - "@babel/plugin-transform-duplicate-keys": "^7.17.12", - "@babel/plugin-transform-exponentiation-operator": "^7.16.7", - "@babel/plugin-transform-for-of": "^7.17.12", - "@babel/plugin-transform-function-name": "^7.16.7", - "@babel/plugin-transform-literals": "^7.17.12", - "@babel/plugin-transform-member-expression-literals": "^7.16.7", - "@babel/plugin-transform-modules-amd": "^7.17.12", - "@babel/plugin-transform-modules-commonjs": "^7.17.12", - "@babel/plugin-transform-modules-systemjs": "^7.17.12", - "@babel/plugin-transform-modules-umd": "^7.17.12", - "@babel/plugin-transform-named-capturing-groups-regex": "^7.17.12", - "@babel/plugin-transform-new-target": "^7.17.12", - "@babel/plugin-transform-object-super": "^7.16.7", - "@babel/plugin-transform-parameters": "^7.17.12", - "@babel/plugin-transform-property-literals": "^7.16.7", - "@babel/plugin-transform-regenerator": "^7.17.9", - "@babel/plugin-transform-reserved-words": "^7.17.12", - "@babel/plugin-transform-shorthand-properties": "^7.16.7", - "@babel/plugin-transform-spread": "^7.17.12", - "@babel/plugin-transform-sticky-regex": "^7.16.7", - "@babel/plugin-transform-template-literals": "^7.17.12", - "@babel/plugin-transform-typeof-symbol": "^7.17.12", - "@babel/plugin-transform-unicode-escapes": "^7.16.7", - "@babel/plugin-transform-unicode-regex": "^7.16.7", - "@babel/preset-modules": "^0.1.5", - "@babel/types": "^7.17.12", - "babel-plugin-polyfill-corejs2": "^0.3.0", - "babel-plugin-polyfill-corejs3": "^0.5.0", - "babel-plugin-polyfill-regenerator": "^0.3.0", - "core-js-compat": "^3.22.1", - "semver": "^6.3.0" - } - }, - "@babel/preset-modules": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.5.tgz", - "integrity": "sha512-A57th6YRG7oR3cq/yt/Y84MvGgE0eJG2F1JLhKuyG+jFxEgrd/HAMJatiFtmOiZurz+0DkrvbheCLaV5f2JfjA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "@babel/plugin-proposal-unicode-property-regex": "^7.4.4", - "@babel/plugin-transform-dotall-regex": "^7.4.4", - "@babel/types": "^7.4.4", - "esutils": "^2.0.2" - } - }, - "@babel/runtime": { - "version": "7.17.9", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", - "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", - "dev": true, - "requires": { - "regenerator-runtime": "^0.13.4" - } - }, - "@babel/template": { - "version": "7.16.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", - "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/parser": "^7.16.7", - "@babel/types": "^7.16.7" - } - }, - "@babel/traverse": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.17.12.tgz", - "integrity": "sha512-zULPs+TbCvOkIFd4FrG53xrpxvCBwLIgo6tO0tJorY7YV2IWFxUfS/lXDJbGgfyYt9ery/Gxj2niwttNnB0gIw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.16.7", - "@babel/generator": "^7.17.12", - "@babel/helper-environment-visitor": "^7.16.7", - "@babel/helper-function-name": "^7.17.9", - "@babel/helper-hoist-variables": "^7.16.7", - "@babel/helper-split-export-declaration": "^7.16.7", - "@babel/parser": "^7.17.12", - "@babel/types": "^7.17.12", - "debug": "^4.1.0", - "globals": "^11.1.0" - } - }, - "@babel/types": { - "version": "7.17.12", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.17.12.tgz", - "integrity": "sha512-rH8i29wcZ6x9xjzI5ILHL/yZkbQnCERdHlogKuIb4PUr7do4iT8DPekrTbBLWTnRQm6U0GYABbTMSzijmEqlAg==", - "dev": true, - "requires": { - "@babel/helper-validator-identifier": "^7.16.7", - "to-fast-properties": "^2.0.0" - } - }, - "@discoveryjs/json-ext": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", - "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==", - "dev": true - }, - "@jridgewell/gen-mapping": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", - "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.0", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@jridgewell/resolve-uri": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.7.tgz", - "integrity": "sha512-8cXDaBBHOr2pQ7j77Y6Vp5VDT2sIqWyWQ56TjEq4ih/a4iST3dItRe8Q9fp0rrIl9DoKhWQtUQz/YpOxLkXbNA==", - "dev": true - }, - "@jridgewell/set-array": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.1.tgz", - "integrity": "sha512-Ct5MqZkLGEXTVmQYbGtx9SVqD2fqwvdubdps5D3djjAkgkKwT918VNOz65pEHFaYTeWcukmJmH5SwsA9Tn2ObQ==", - "dev": true - }, - "@jridgewell/source-map": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.2.tgz", - "integrity": "sha512-m7O9o2uR8k2ObDysZYzdfhb08VuEml5oWGiosa1VdaPZ/A6QyPkAJuwN0Q1lhULOf6B7MtQmHENS743hWtCrgw==", - "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" - }, - "dependencies": { - "@jridgewell/gen-mapping": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", - "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", - "dev": true, - "requires": { - "@jridgewell/set-array": "^1.0.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.9" - } - } - } - }, - "@jridgewell/sourcemap-codec": { - "version": "1.4.13", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.13.tgz", - "integrity": "sha512-GryiOJmNcWbovBxTfZSF71V/mXbgcV3MewDe3kIMCLyIh5e7SKAeUZs+rMnJ8jkMolZ/4/VsdBmMrw3l+VdZ3w==", - "dev": true - }, - "@jridgewell/trace-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.13.tgz", - "integrity": "sha512-o1xbKhp9qnIAoHJSWd6KlCZfqslL4valSF81H8ImioOAxluWYWOpWkpyktY2vnt4tbrX9XYaxovq6cgowaJp2w==", - "dev": true, - "requires": { - "@jridgewell/resolve-uri": "^3.0.3", - "@jridgewell/sourcemap-codec": "^1.4.10" - } - }, - "@types/eslint": { - "version": "8.2.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.2.2.tgz", - "integrity": "sha512-nQxgB8/Sg+QKhnV8e0WzPpxjIGT3tuJDDzybkDi8ItE/IgTlHo07U0shaIjzhcvQxlq9SDRE42lsJ23uvEgJ2A==", - "dev": true, - "requires": { - "@types/estree": "*", - "@types/json-schema": "*" - } - }, - "@types/eslint-scope": { - "version": "3.7.3", - "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", - "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", - "dev": true, - "requires": { - "@types/eslint": "*", - "@types/estree": "*" - } - }, - "@types/estree": { - "version": "0.0.51", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.51.tgz", - "integrity": "sha512-CuPgU6f3eT/XgKKPqKd/gLZV1Xmvf1a2R5POBOGQa6uv82xpls89HU5zKeVoyR8XzHd1RGNOlQlvUe3CFkjWNQ==", - "dev": true - }, - "@types/json-schema": { - "version": "7.0.9", - "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", - "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==", - "dev": true - }, - "@types/node": { - "version": "17.0.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.9.tgz", - "integrity": "sha512-5dNBXu/FOER+EXnyah7rn8xlNrfMOQb/qXnw4NQgLkCygKBKhdmF/CA5oXVOKZLBEahw8s2WP9LxIcN/oDDRgQ==", - "dev": true - }, - "@webassemblyjs/ast": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.1.tgz", - "integrity": "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==", - "dev": true, - "requires": { - "@webassemblyjs/helper-numbers": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1" - } - }, - "@webassemblyjs/floating-point-hex-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.1.tgz", - "integrity": "sha512-iGRfyc5Bq+NnNuX8b5hwBrRjzf0ocrJPI6GWFodBFzmFnyvrQ83SHKhmilCU/8Jv67i4GJZBMhEzltxzcNagtQ==", - "dev": true - }, - "@webassemblyjs/helper-api-error": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.1.tgz", - "integrity": "sha512-RlhS8CBCXfRUR/cwo2ho9bkheSXG0+NwooXcc3PAILALf2QLdFyj7KGsKRbVc95hZnhnERon4kW/D3SZpp6Tcg==", - "dev": true - }, - "@webassemblyjs/helper-buffer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.1.tgz", - "integrity": "sha512-gwikF65aDNeeXa8JxXa2BAk+REjSyhrNC9ZwdT0f8jc4dQQeDQ7G4m0f2QCLPJiMTTO6wfDmRmj/pW0PsUvIcA==", - "dev": true - }, - "@webassemblyjs/helper-numbers": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.1.tgz", - "integrity": "sha512-vDkbxiB8zfnPdNK9Rajcey5C0w+QJugEglN0of+kmO8l7lDb77AnlKYQF7aarZuCrv+l0UvqL+68gSDr3k9LPQ==", - "dev": true, - "requires": { - "@webassemblyjs/floating-point-hex-parser": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/helper-wasm-bytecode": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.1.tgz", - "integrity": "sha512-PvpoOGiJwXeTrSf/qfudJhwlvDQxFgelbMqtq52WWiXC6Xgg1IREdngmPN3bs4RoO83PnL/nFrxucXj1+BX62Q==", - "dev": true - }, - "@webassemblyjs/helper-wasm-section": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.1.tgz", - "integrity": "sha512-10P9No29rYX1j7F3EVPX3JvGPQPae+AomuSTPiF9eBQeChHI6iqjMIwR9JmOJXwpnn/oVGDk7I5IlskuMwU/pg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1" - } - }, - "@webassemblyjs/ieee754": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.1.tgz", - "integrity": "sha512-hJ87QIPtAMKbFq6CGTkZYJivEwZDbQUgYd3qKSadTNOhVY7p+gfP6Sr0lLRVTaG1JjFj+r3YchoqRYxNH3M0GQ==", - "dev": true, - "requires": { - "@xtuc/ieee754": "^1.2.0" - } - }, - "@webassemblyjs/leb128": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.1.tgz", - "integrity": "sha512-BJ2P0hNZ0u+Th1YZXJpzW6miwqQUGcIHT1G/sf72gLVD9DZ5AdYTqPNbHZh6K1M5VmKvFXwGSWZADz+qBWxeRw==", - "dev": true, - "requires": { - "@xtuc/long": "4.2.2" - } - }, - "@webassemblyjs/utf8": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.1.tgz", - "integrity": "sha512-9kqcxAEdMhiwQkHpkNiorZzqpGrodQQ2IGrHHxCy+Ozng0ofyMA0lTqiLkVs1uzTRejX+/O0EOT7KxqVPuXosQ==", - "dev": true - }, - "@webassemblyjs/wasm-edit": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.1.tgz", - "integrity": "sha512-g+RsupUC1aTHfR8CDgnsVRVZFJqdkFHpsHMfJuWQzWU3tvnLC07UqHICfP+4XyL2tnr1amvl1Sdp06TnYCmVkA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/helper-wasm-section": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-opt": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "@webassemblyjs/wast-printer": "1.11.1" - } - }, - "@webassemblyjs/wasm-gen": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.1.tgz", - "integrity": "sha512-F7QqKXwwNlMmsulj6+O7r4mmtAlCWfO/0HdgOxSklZfQcDu0TpLiD1mRt/zF25Bk59FIjEuGAIyn5ei4yMfLhA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wasm-opt": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.1.tgz", - "integrity": "sha512-VqnkNqnZlU5EB64pp1l7hdm3hmQw7Vgqa0KF/KCNO9sIpI6Fk6brDEiX+iCOYrvMuBWDws0NkTOxYEb85XQHHw==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-buffer": "1.11.1", - "@webassemblyjs/wasm-gen": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1" - } - }, - "@webassemblyjs/wasm-parser": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.1.tgz", - "integrity": "sha512-rrBujw+dJu32gYB7/Lup6UhdkPx9S9SnobZzRVL7VcBH9Bt9bCBLEuX/YXOOtBsOZ4NQrRykKhffRWHvigQvOA==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/helper-api-error": "1.11.1", - "@webassemblyjs/helper-wasm-bytecode": "1.11.1", - "@webassemblyjs/ieee754": "1.11.1", - "@webassemblyjs/leb128": "1.11.1", - "@webassemblyjs/utf8": "1.11.1" - } - }, - "@webassemblyjs/wast-printer": { - "version": "1.11.1", - "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.1.tgz", - "integrity": "sha512-IQboUWM4eKzWW+N/jij2sRatKMh99QEelo3Eb2q0qXkvPRISAj8Qxtmw5itwqK+TTkBuUIE45AxYPToqPtL5gg==", - "dev": true, - "requires": { - "@webassemblyjs/ast": "1.11.1", - "@xtuc/long": "4.2.2" - } - }, - "@webpack-cli/configtest": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.1.1.tgz", - "integrity": "sha512-1FBc1f9G4P/AxMqIgfZgeOTuRnwZMten8E7zap5zgpPInnCrP8D4Q81+4CWIch8i/Nf7nXjP0v6CjjbHOrXhKg==", - "dev": true, - "requires": {} - }, - "@webpack-cli/info": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.4.1.tgz", - "integrity": "sha512-PKVGmazEq3oAo46Q63tpMr4HipI3OPfP7LiNOEJg963RMgT0rqheag28NCML0o3GIzA3DmxP1ZIAv9oTX1CUIA==", - "dev": true, - "requires": { - "envinfo": "^7.7.3" - } - }, - "@webpack-cli/serve": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.6.1.tgz", - "integrity": "sha512-gNGTiTrjEVQ0OcVnzsRSqTxaBSr+dmTfm+qJsCDluky8uhdLWep7Gcr62QsAKHTMxjCS/8nEITsmFAhfIx+QSw==", - "dev": true, - "requires": {} - }, - "@xtuc/ieee754": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", - "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", - "dev": true - }, - "@xtuc/long": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", - "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", - "dev": true - }, - "acorn": { - "version": "8.7.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", - "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", - "dev": true - }, - "acorn-import-assertions": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", - "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==", - "dev": true, - "requires": {} - }, - "ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, - "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} - }, - "ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "requires": { - "sprintf-js": "~1.0.2" - } - }, - "array.prototype.every": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/array.prototype.every/-/array.prototype.every-1.1.3.tgz", - "integrity": "sha512-vWnriJI//SOMOWtXbU/VXhJ/InfnNHPF6BLKn5WfY8xXy+NWql0fUy20GO3sdqBhCAO+qw8S/E5nJiZX+QFdCA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.0", - "is-string": "^1.0.7" - } - }, - "available-typed-arrays": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.5.tgz", - "integrity": "sha512-DMD0KiN46eipeziST1LPP/STfDU0sufISXmjSgvVsoU2tqxctQeASejWcfNtxYKqETM1UxQ8sp2OrSBWpHY6sw==", - "dev": true - }, - "babel-loader": { - "version": "8.2.5", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.5.tgz", - "integrity": "sha512-OSiFfH89LrEMiWd4pLNqGz4CwJDtbs2ZVc+iGu2HrkRfPxId9F2anQj38IxWpmRfsUY0aBZYi1EFcd3mhtRMLQ==", - "dev": true, - "requires": { - "find-cache-dir": "^3.3.1", - "loader-utils": "^2.0.0", - "make-dir": "^3.1.0", - "schema-utils": "^2.6.5" - } - }, - "babel-plugin-dynamic-import-node": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.3.tgz", - "integrity": "sha512-jZVI+s9Zg3IqA/kdi0i6UDCybUI3aSBLnglhYbSSjKlV7yF1F/5LWv8MakQmvYpnbJDS6fcBL2KzHSxNCMtWSQ==", - "dev": true, - "requires": { - "object.assign": "^4.1.0" - } - }, - "babel-plugin-polyfill-corejs2": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.3.1.tgz", - "integrity": "sha512-v7/T6EQcNfVLfcN2X8Lulb7DjprieyLWJK/zOWH5DUYcAgex9sP3h25Q+DLsX9TloXe3y1O8l2q2Jv9q8UVB9w==", - "dev": true, - "requires": { - "@babel/compat-data": "^7.13.11", - "@babel/helper-define-polyfill-provider": "^0.3.1", - "semver": "^6.1.1" - } - }, - "babel-plugin-polyfill-corejs3": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.5.1.tgz", - "integrity": "sha512-TihqEe4sQcb/QcPJvxe94/9RZuLQuF1+To4WqQcRvc+3J3gLCPIPgDKzGLG6zmQLfH3nn25heRuDNkS2KR4I8A==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1", - "core-js-compat": "^3.20.0" - } - }, - "babel-plugin-polyfill-regenerator": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.3.1.tgz", - "integrity": "sha512-Y2B06tvgHYt1x0yz17jGkGeeMr5FeKUu+ASJ+N6nB5lQ8Dapfg42i0OVrf8PNGJ3zKL4A23snMi1IRwrqqND7A==", - "dev": true, - "requires": { - "@babel/helper-define-polyfill-provider": "^0.3.1" - } - }, - "balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true - }, - "big.js": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", - "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", - "dev": true - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "browserslist": { - "version": "4.20.3", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.20.3.tgz", - "integrity": "sha512-NBhymBQl1zM0Y5dQT/O+xiLP9/rzOIQdKM/eMJBAq7yBgaB6krIYLGejrwVYnSHZdqjscB1SPuAjHwxjvN6Wdg==", - "dev": true, - "requires": { - "caniuse-lite": "^1.0.30001332", - "electron-to-chromium": "^1.4.118", - "escalade": "^3.1.1", - "node-releases": "^2.0.3", - "picocolors": "^1.0.0" - } - }, - "buffer-from": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", - "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", - "dev": true - }, - "builtin-modules": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", - "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", - "dev": true - }, - "call-bind": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz", - "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "get-intrinsic": "^1.0.2" - } - }, - "caniuse-lite": { - "version": "1.0.30001341", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001341.tgz", - "integrity": "sha512-2SodVrFFtvGENGCv0ChVJIDQ0KPaS1cg7/qtfMaICgeMolDdo/Z2OD32F0Aq9yl6F4YFwGPBS5AaPqNYiW4PoA==", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "chrome-trace-event": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", - "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", - "dev": true - }, - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "clone-deep": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", - "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4", - "kind-of": "^6.0.2", - "shallow-clone": "^3.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "colorette": { - "version": "2.0.16", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.16.tgz", - "integrity": "sha512-hUewv7oMjCp+wkBv5Rm0v87eJhq4woh5rSR+42YSQJKecCqgIqNkZ6lAlQms/BwHPJA5NKMRlpxPRv0n8HQW6g==", - "dev": true - }, - "commander": { - "version": "9.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-9.2.0.tgz", - "integrity": "sha512-e2i4wANQiSXgnrBlIatyHtP1odfUp0BbV5Y5nEGbxtIrStkEOAAzCUirvLBNXHLr7kwLvJl6V+4V3XV9x7Wd9w==" - }, - "commondir": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", - "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "convert-source-map": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", - "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "copyfiles": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", - "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", - "dev": true, - "requires": { - "glob": "^7.0.5", - "minimatch": "^3.0.3", - "mkdirp": "^1.0.4", - "noms": "0.0.0", - "through2": "^2.0.1", - "untildify": "^4.0.0", - "yargs": "^16.1.0" - }, - "dependencies": { - "yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - }, - "yargs-parser": { - "version": "20.2.9", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", - "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", - "dev": true - } - } - }, - "core-js-compat": { - "version": "3.22.5", - "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.22.5.tgz", - "integrity": "sha512-rEF75n3QtInrYICvJjrAgV03HwKiYvtKHdPtaba1KucG+cNZ4NJnH9isqt979e67KZlhpbCOTwnsvnIr+CVeOg==", - "dev": true, - "requires": { - "browserslist": "^4.20.3", - "semver": "7.0.0" - }, - "dependencies": { - "semver": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.0.0.tgz", - "integrity": "sha512-+GB6zVA9LWh6zovYQLALHwv5rb2PHGlJi3lfiqIHxR0uuwCgefcOJc59v9fv1w8GbStwxuuqqAjI9NMAOOgq1A==", - "dev": true - } - } - }, - "core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true - }, - "cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "requires": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - } - }, - "debug": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", - "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "deep-equal": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.0.5.tgz", - "integrity": "sha512-nPiRgmbAtm1a3JsnLCf6/SLfXcjyN5v8L1TXzdCmHrXJ4hx+gW/w1YCcn7z8gJtSiDArZCgYtbao3QqLm/N1Sw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "es-get-iterator": "^1.1.1", - "get-intrinsic": "^1.0.1", - "is-arguments": "^1.0.4", - "is-date-object": "^1.0.2", - "is-regex": "^1.1.1", - "isarray": "^2.0.5", - "object-is": "^1.1.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "regexp.prototype.flags": "^1.3.0", - "side-channel": "^1.0.3", - "which-boxed-primitive": "^1.0.1", - "which-collection": "^1.0.1", - "which-typed-array": "^1.1.2" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - } - } - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "defined": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", - "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=", - "dev": true - }, - "diff": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", - "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", - "dev": true - }, - "dotignore": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/dotignore/-/dotignore-0.1.2.tgz", - "integrity": "sha512-UGGGWfSauusaVJC+8fgV+NVvBXkCTmVv7sk6nojDZZvuOUNGUy0Zk4UpHQD6EDjS0jpBwcACvH4eofvyzBcRDw==", - "dev": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "electron-to-chromium": { - "version": "1.4.137", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.137.tgz", - "integrity": "sha512-0Rcpald12O11BUogJagX3HsCN3FE83DSqWjgXoHo5a72KUKMSfI39XBgJpgNNxS9fuGzytaFjE06kZkiVFy2qA==", - "dev": true - }, - "emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true - }, - "emojis-list": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", - "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", - "dev": true - }, - "enhanced-resolve": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.9.3.tgz", - "integrity": "sha512-Bq9VSor+kjvW3f9/MiiR4eE3XYgOl7/rS8lnSxbRbF3kS0B2r+Y9w5krBWxZgDxASVZbdYrn5wT4j/Wb0J9qow==", - "dev": true, - "requires": { - "graceful-fs": "^4.2.4", - "tapable": "^2.2.0" - } - }, - "envinfo": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", - "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==", - "dev": true - }, - "es-abstract": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", - "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "get-intrinsic": "^1.1.1", - "get-symbol-description": "^1.0.0", - "has": "^1.0.3", - "has-symbols": "^1.0.2", - "internal-slot": "^1.0.3", - "is-callable": "^1.2.4", - "is-negative-zero": "^2.0.1", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.1", - "is-string": "^1.0.7", - "is-weakref": "^1.0.1", - "object-inspect": "^1.11.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "string.prototype.trimend": "^1.0.4", - "string.prototype.trimstart": "^1.0.4", - "unbox-primitive": "^1.0.1" - } - }, - "es-get-iterator": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.2.tgz", - "integrity": "sha512-+DTO8GYwbMCwbywjimwZMHp8AuYXOS2JZFWoi2AlPOS3ebnII9w/NLpNZtA7A0YLaVDw+O7KFCeoIV7OPvM7hQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.0", - "has-symbols": "^1.0.1", - "is-arguments": "^1.1.0", - "is-map": "^2.0.2", - "is-set": "^2.0.2", - "is-string": "^1.0.5", - "isarray": "^2.0.5" - }, - "dependencies": { - "isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true - } - } - }, - "es-module-lexer": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", - "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==", - "dev": true - }, - "es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "requires": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - } - }, - "esm": { - "version": "3.2.25", - "resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz", - "integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==" - }, - "esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true - }, - "esrecurse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", - "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, - "requires": { - "estraverse": "^5.2.0" - }, - "dependencies": { - "estraverse": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", - "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true - } - } - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "events": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", - "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", - "dev": true - }, - "execa": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", - "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", - "dev": true, - "requires": { - "cross-spawn": "^7.0.3", - "get-stream": "^6.0.0", - "human-signals": "^2.1.0", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.1", - "onetime": "^5.1.2", - "signal-exit": "^3.0.3", - "strip-final-newline": "^2.0.0" - } - }, - "fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "fastest-levenshtein": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", - "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==", - "dev": true - }, - "find-cache-dir": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", - "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", - "dev": true, - "requires": { - "commondir": "^1.0.1", - "make-dir": "^3.0.2", - "pkg-dir": "^4.1.0" - } - }, - "find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - } - }, - "for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", - "dev": true, - "requires": { - "is-callable": "^1.1.3" - } - }, - "foreach": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", - "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=", - "dev": true - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", - "dev": true - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "gensync": { - "version": "1.0.0-beta.2", - "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-intrinsic": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz", - "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1" - } - }, - "get-package-type": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", - "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", - "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", - "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "glob": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", - "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "glob-to-regexp": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", - "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", - "dev": true - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.9", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", - "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==", - "dev": true - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-bigints": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", - "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", - "dev": true - }, - "has-dynamic-import": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-dynamic-import/-/has-dynamic-import-2.0.1.tgz", - "integrity": "sha512-X3fbtsZmwb6W7fJGR9o7x65fZoodygCrZ3TVycvghP62yYQfS0t4RS0Qcz+j5tQYUKeSWS09tHkWW6WhFV3XhQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", - "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==", - "dev": true - }, - "has-tostringtag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", - "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "human-signals": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", - "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", - "dev": true - }, - "import-local": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", - "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", - "dev": true, - "requires": { - "pkg-dir": "^4.2.0", - "resolve-cwd": "^3.0.0" - } - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true - }, - "internal-slot": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", - "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" - } - }, - "interpret": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", - "integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==", - "dev": true - }, - "is-arguments": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", - "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } - }, - "is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-callable": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", - "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", - "dev": true - }, - "is-core-module": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.1.tgz", - "integrity": "sha512-SdNCUs284hr40hFTFP6l0IfZ/RSrMXF3qgoRHd3/79unUTvrFO/JoXwkGm+5J/Oe3E/b5GsnG330uUNgRpu1PA==", - "dev": true, - "requires": { - "has": "^1.0.3" - } - }, - "is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true - }, - "is-map": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.2.tgz", - "integrity": "sha512-cOZFQQozTha1f4MxLFzlgKYPTyj26picdZTx82hbc/Xf4K/tZOOXSCkMvU4pKioRXGDLJRn0GM7Upe7kR721yg==", - "dev": true - }, - "is-negative-zero": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", - "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", - "dev": true - }, - "is-number-object": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", - "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } - }, - "is-set": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.2.tgz", - "integrity": "sha512-+2cnTEZeY5z/iXGbLhPrOAaK/Mau5k5eXq9j14CpRTftq0pAJu2MwVRSZhyZWBzx3o6X795Lz6Bpb6R0GKf37g==", - "dev": true - }, - "is-shared-array-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", - "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", - "dev": true - }, - "is-stream": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", - "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", - "dev": true - }, - "is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", - "dev": true, - "requires": { - "has-symbols": "^1.0.2" - } - }, - "is-typed-array": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.8.tgz", - "integrity": "sha512-HqH41TNZq2fgtGT8WHVFVJhBVGuY3AnP3Q36K8JKXUxSxRgk/d+7NjmwG2vo2mYmXK8UYZKu0qH8bVP5gEisjA==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0" - } - }, - "is-weakmap": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.1.tgz", - "integrity": "sha512-NSBR4kH5oVj1Uwvv970ruUkCV7O1mzgVFO4/rev2cLRda9Tm9HrL70ZPut4rOHgY0FNrUu9BCbXA2sdQ+x0chA==", - "dev": true - }, - "is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2" - } - }, - "is-weakset": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.2.tgz", - "integrity": "sha512-t2yVvttHkQktwnNNmBQ98AhENLdPUTDTE21uPqAQ0ARwQfGeQKRVS0NNurH7bTf7RrvcVn1OOge45CnBeHCSmg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" - } - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", - "dev": true - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "jest-worker": { - "version": "27.4.6", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.4.6.tgz", - "integrity": "sha512-gHWJF/6Xi5CTG5QCvROr6GcmpIqNYpDJyc8A1h/DyXqH1tD6SnRCM0d3U5msV31D2LB/U+E0M+W4oyvKV44oNw==", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true - }, - "supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", - "dev": true, - "requires": { - "has-flag": "^4.0.0" - } - } - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json5": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", - "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==", - "dev": true - }, - "kind-of": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true - }, - "loader-runner": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", - "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", - "dev": true - }, - "loader-utils": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.2.tgz", - "integrity": "sha512-TM57VeHptv569d/GKh6TAYdzKblwDNiumOdkFnejjD0XwTH87K90w3O7AiJRqdQoXygvi1VQTJTLGhJl7WqA7A==", - "dev": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, - "locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "requires": { - "p-locate": "^4.1.0" - } - }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", - "dev": true - }, - "make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dev": true, - "requires": { - "semver": "^6.0.0" - } - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "mhchemparser": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/mhchemparser/-/mhchemparser-4.1.1.tgz", - "integrity": "sha512-R75CUN6O6e1t8bgailrF1qPq+HhVeFTM3XQ0uzI+mXTybmphy3b6h4NbLOYhemViQ3lUs+6CKRkC3Ws1TlYREA==" - }, - "mime-db": { - "version": "1.51.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.51.0.tgz", - "integrity": "sha512-5y8A56jg7XVQx2mbv1lu49NR4dokRnhZYTtL+KGfaa27uq4pSTXkwQkFJl4pkRMyNFz/EtYDSkiiEHx3F7UN6g==", - "dev": true - }, - "mime-types": { - "version": "2.1.34", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.34.tgz", - "integrity": "sha512-6cP692WwGIs9XXdOO4++N+7qjqv0rqxxVvJ3VHPh/Sc9mVZcQP+ZGhkKiTvWMQRr2tbHkJP/Yn7Y0npb3ZBs4A==", - "dev": true, - "requires": { - "mime-db": "1.51.0" - } - }, - "mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", - "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", - "dev": true - }, - "mj-context-menu": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", - "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" - }, - "mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "dev": true - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "neo-async": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", - "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", - "dev": true - }, - "node-releases": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.4.tgz", - "integrity": "sha512-gbMzqQtTtDz/00jQzZ21PQzdI9PyLYqUSvD0p3naOhX4odFji0ZxYdnVwPTxmSwkmxhcFImpozceidSG+AgoPQ==", - "dev": true - }, - "noms": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", - "integrity": "sha1-2o69nzr51nYJGbJ9nNyAkqczKFk=", - "dev": true, - "requires": { - "inherits": "^2.0.1", - "readable-stream": "~1.0.31" - } - }, - "npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "requires": { - "path-key": "^3.0.0" - } - }, - "object-inspect": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", - "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", - "dev": true - }, - "object-is": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.5.tgz", - "integrity": "sha512-3cyDsyHgtmi7I7DfSSI2LDp6SK2lwvtbg0p0R1e0RvTqF5ceGx+K2dfSjm1bKDMVCFEDAQvy+o8c6a7VujOddw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object.assign": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", - "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "define-properties": "^1.1.3", - "has-symbols": "^1.0.1", - "object-keys": "^1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "requires": { - "wrappy": "1" - } - }, - "onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "requires": { - "mimic-fn": "^2.1.0" - } - }, - "p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "requires": { - "p-limit": "^2.2.0" - } - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", - "dev": true - }, - "path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true - }, - "path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true - }, - "picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true - }, - "pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "requires": { - "find-up": "^4.0.0" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "randombytes": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", - "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", - "dev": true, - "requires": { - "safe-buffer": "^5.1.0" - } - }, - "readable-stream": { - "version": "1.0.34", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", - "integrity": "sha1-Elgg40vIQtLyqq+v5MKRbuMsFXw=", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" - } - }, - "rechoir": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", - "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", - "dev": true, - "requires": { - "resolve": "^1.9.0" - } - }, - "regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "regenerate-unicode-properties": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.0.1.tgz", - "integrity": "sha512-vn5DU6yg6h8hP/2OkQo3K7uVILvY4iu0oI4t3HFa81UPkhGJwkRwM10JEc3upjdhHjs/k8GJY1sRBhk5sr69Bw==", - "dev": true, - "requires": { - "regenerate": "^1.4.2" - } - }, - "regenerator-runtime": { - "version": "0.13.9", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", - "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==", - "dev": true - }, - "regenerator-transform": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.0.tgz", - "integrity": "sha512-LsrGtPmbYg19bcPHwdtmXwbW+TqNvtY4riE3P83foeHRroMbH6/2ddFBfab3t7kbzc7v7p4wbkIecHImqt0QNg==", - "dev": true, - "requires": { - "@babel/runtime": "^7.8.4" - } - }, - "regexp.prototype.flags": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.4.1.tgz", - "integrity": "sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "regexpu-core": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.0.1.tgz", - "integrity": "sha512-CriEZlrKK9VJw/xQGJpQM5rY88BtuL8DM+AEwvcThHilbxiTAy8vq4iJnd2tqq8wLmjbGZzP7ZcKFjbGkmEFrw==", - "dev": true, - "requires": { - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.0.1", - "regjsgen": "^0.6.0", - "regjsparser": "^0.8.2", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.0.0" - } - }, - "regjsgen": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.6.0.tgz", - "integrity": "sha512-ozE883Uigtqj3bx7OhL1KNbCzGyW2NQZPl6Hs09WTvCuZD5sTI4JY58bkbQWa/Y9hxIsvJ3M8Nbf7j54IqeZbA==", - "dev": true - }, - "regjsparser": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.8.4.tgz", - "integrity": "sha512-J3LABycON/VNEu3abOviqGHuB/LOtOQj8SKmfP9anY5GfAVw/SPjwzSjxGjbZXIxbGfqTHtJw58C2Li/WkStmA==", - "dev": true, - "requires": { - "jsesc": "~0.5.0" - }, - "dependencies": { - "jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=", - "dev": true - } - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "resolve": { - "version": "1.21.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.21.0.tgz", - "integrity": "sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==", - "dev": true, - "requires": { - "is-core-module": "^2.8.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - } - }, - "resolve-cwd": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", - "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", - "dev": true, - "requires": { - "resolve-from": "^5.0.0" - } - }, - "resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true - }, - "resumer": { - "version": "0.0.0", - "resolved": "https://registry.npmjs.org/resumer/-/resumer-0.0.0.tgz", - "integrity": "sha1-8ej0YeQGS6Oegq883CqMiT0HZ1k=", - "dev": true, - "requires": { - "through": "~2.3.4" - } - }, - "rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, - "schema-utils": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.1.tgz", - "integrity": "sha512-SHiNtMOUGWBQJwzISiVYKu82GiV4QYGePp3odlY1tuKO7gPtphAT5R/py0fA6xtbgLL/RvtJZnU9b8s0F1q0Xg==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.5", - "ajv": "^6.12.4", - "ajv-keywords": "^3.5.2" - } - }, - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - }, - "serialize-javascript": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", - "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", - "dev": true, - "requires": { - "randombytes": "^2.1.0" - } - }, - "shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "requires": { - "shebang-regex": "^3.0.0" - } - }, - "shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true - }, - "side-channel": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", - "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", - "dev": true, - "requires": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" - } - }, - "signal-exit": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", - "integrity": "sha512-sDl4qMFpijcGw22U5w63KmD3cZJfBuFlVNbVMKje2keoKML7X2UzWbc4XrmEbDwg0NXJc3yv4/ox7b+JWb57kQ==", - "dev": true - }, - "source-map-support": { - "version": "0.5.21", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", - "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - }, - "dependencies": { - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "speech-rule-engine": { - "version": "4.0.6", - "resolved": "https://registry.npmjs.org/speech-rule-engine/-/speech-rule-engine-4.0.6.tgz", - "integrity": "sha512-Hqa4ywf7d3lX2YsnnE8BeEdqFyaTwPSyyVhVGWZlQw4XVh0NCijyVsMZD3I9HsG5JBuDXyRaMVVNZcGJlKbZxA==", - "requires": { - "commander": "9.2.0", - "wicked-good-xpath": "1.3.0", - "xmldom-sre": "0.1.31" - } - }, - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, - "string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "requires": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - } - }, - "string.prototype.trim": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.5.tgz", - "integrity": "sha512-Lnh17webJVsD6ECeovpVN17RlAKjmz4rF9S+8Y45CkMc/ufVpTkU3vZIyIC7sllQ1FCvObZnnCdNs/HXTUOTlg==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3", - "es-abstract": "^1.19.1" - } - }, - "string.prototype.trimend": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", - "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "string.prototype.trimstart": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", - "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.3" - } - }, - "strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "requires": { - "ansi-regex": "^5.0.1" - } - }, - "strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true - }, - "tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", - "dev": true - }, - "tape": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/tape/-/tape-5.5.3.tgz", - "integrity": "sha512-hPBJZBL9S7bH9vECg/KSM24slGYV589jJr4dmtiJrLD71AL66+8o4b9HdZazXZyvnilqA7eE8z5/flKiy0KsBg==", - "dev": true, - "requires": { - "array.prototype.every": "^1.1.3", - "call-bind": "^1.0.2", - "deep-equal": "^2.0.5", - "defined": "^1.0.0", - "dotignore": "^0.1.2", - "for-each": "^0.3.3", - "get-package-type": "^0.1.0", - "glob": "^7.2.0", - "has": "^1.0.3", - "has-dynamic-import": "^2.0.1", - "inherits": "^2.0.4", - "is-regex": "^1.1.4", - "minimist": "^1.2.6", - "object-inspect": "^1.12.0", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "object.assign": "^4.1.2", - "resolve": "^2.0.0-next.3", - "resumer": "^0.0.0", - "string.prototype.trim": "^1.2.5", - "through": "^2.3.8" - }, - "dependencies": { - "resolve": { - "version": "2.0.0-next.3", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.3.tgz", - "integrity": "sha512-W8LucSynKUIDu9ylraa7ueVZ7hc0uAgJBxVsQSKOXOyle8a93qXhcz+XAXZ8bIq2d6i4Ehddn6Evt+0/UwKk6Q==", - "dev": true, - "requires": { - "is-core-module": "^2.2.0", - "path-parse": "^1.0.6" - } - } - } - }, - "terser": { - "version": "5.14.2", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.14.2.tgz", - "integrity": "sha512-oL0rGeM/WFQCUd0y2QrWxYnq7tfSuKBiqTjRPWrRgB46WD/kiwHwF8T23z78H6Q6kGCuuHcPB+KULHRdxvVGQA==", - "dev": true, - "requires": { - "@jridgewell/source-map": "^0.3.2", - "acorn": "^8.5.0", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - } - } - }, - "terser-webpack-plugin": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.1.tgz", - "integrity": "sha512-GvlZdT6wPQKbDNW/GDQzZFg/j4vKU96yl2q6mcUkzKOgW4gwf1Z8cZToUCrz31XHlPWH8MVb1r2tFtdDtTGJ7g==", - "dev": true, - "requires": { - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.0", - "source-map": "^0.6.1", - "terser": "^5.7.2" - }, - "dependencies": { - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - } - } - }, - "through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "through2": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", - "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", - "dev": true, - "requires": { - "readable-stream": "~2.3.6", - "xtend": "~4.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - } - } - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "tslint": { - "version": "6.1.3", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz", - "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.3", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.13.0", - "tsutils": "^2.29.0" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - } - } - }, - "tslint-jsdoc-rules": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/tslint-jsdoc-rules/-/tslint-jsdoc-rules-0.2.0.tgz", - "integrity": "sha512-7r6OP+cuGSsW+FHVKlg1gJrZ0RAfaHQjLJD3Grw9gAvemjAxBkkswiAlgAYy+DIG/SLUQ0EOh6LTzJNP7bk0eQ==", - "dev": true, - "requires": { - "tslint": "^5.*" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - } - } - } - }, - "tslint-unix-formatter": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/tslint-unix-formatter/-/tslint-unix-formatter-0.2.0.tgz", - "integrity": "sha512-EDEzVIPm4DWXOvmgYs5T53p3uIE1GFPO9Z+4lAam2qNkgKCXdW6jx2ieaX6g5OvA/vorH7CbbmRHVA8NQgZQQA==", - "dev": true, - "requires": { - "tslint": "^5.*" - }, - "dependencies": { - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true - }, - "diff": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", - "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", - "dev": true - }, - "mkdirp": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", - "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", - "dev": true, - "requires": { - "minimist": "^1.2.5" - } - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "tslint": { - "version": "5.20.1", - "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz", - "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "builtin-modules": "^1.1.1", - "chalk": "^2.3.0", - "commander": "^2.12.1", - "diff": "^4.0.1", - "glob": "^7.1.1", - "js-yaml": "^3.13.1", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.1", - "resolve": "^1.3.2", - "semver": "^5.3.0", - "tslib": "^1.8.0", - "tsutils": "^2.29.0" - } - } - } - }, - "tsutils": { - "version": "2.29.0", - "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", - "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", - "dev": true, - "requires": { - "tslib": "^1.8.1" - } - }, - "typescript": { - "version": "4.6.4", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.6.4.tgz", - "integrity": "sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==", - "dev": true - }, - "typescript-tools": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/typescript-tools/-/typescript-tools-0.3.1.tgz", - "integrity": "sha1-MlhSu+lFwwIQpjbOdjMHcHpTxEk=", - "dev": true - }, - "unbox-primitive": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", - "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1", - "has-bigints": "^1.0.1", - "has-symbols": "^1.0.2", - "which-boxed-primitive": "^1.0.2" - } - }, - "unicode-canonical-property-names-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", - "dev": true - }, - "unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", - "dev": true, - "requires": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" - } - }, - "unicode-match-property-value-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.0.0.tgz", - "integrity": "sha512-7Yhkc0Ye+t4PNYzOGKedDhXbYIBe1XEQYQxOPyhcXNMJ0WCABqqj6ckydd6pWRZTHV4GuCPKdBAUiMc60tsKVw==", - "dev": true - }, - "unicode-property-aliases-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.0.0.tgz", - "integrity": "sha512-5Zfuy9q/DFr4tfO7ZPeVXb1aPoeQSdeFMLpYuFebehDAhbuevLs5yxSZmIFN1tP5F9Wl4IpJrYojg85/zgyZHQ==", - "dev": true - }, - "untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", - "dev": true - }, - "uri-js": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", - "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "watchpack": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.3.1.tgz", - "integrity": "sha512-x0t0JuydIo8qCNctdDrn1OzH/qDzk2+rdCOC3YzumZ42fiMqmQ7T3xQurykYMhYfHaPHTp4ZxAx2NfUo1K6QaA==", - "dev": true, - "requires": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" - } - }, - "webpack": { - "version": "5.72.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.72.1.tgz", - "integrity": "sha512-dXG5zXCLspQR4krZVR6QgajnZOjW2K/djHvdcRaDQvsjV9z9vaW6+ja5dZOYbqBBjF6kGXka/2ZyxNdc+8Jung==", - "dev": true, - "requires": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^0.0.51", - "@webassemblyjs/ast": "1.11.1", - "@webassemblyjs/wasm-edit": "1.11.1", - "@webassemblyjs/wasm-parser": "1.11.1", - "acorn": "^8.4.1", - "acorn-import-assertions": "^1.7.6", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.9.3", - "es-module-lexer": "^0.9.0", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.1.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.1.3", - "watchpack": "^2.3.1", - "webpack-sources": "^3.2.3" - }, - "dependencies": { - "schema-utils": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz", - "integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==", - "dev": true, - "requires": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - } - } - } - }, - "webpack-cli": { - "version": "4.9.2", - "resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.9.2.tgz", - "integrity": "sha512-m3/AACnBBzK/kMTcxWHcZFPrw/eQuY4Df1TxvIWfWM2x7mRqBQCqKEd96oCUa9jkapLBaFfRce33eGDb4Pr7YQ==", - "dev": true, - "requires": { - "@discoveryjs/json-ext": "^0.5.0", - "@webpack-cli/configtest": "^1.1.1", - "@webpack-cli/info": "^1.4.1", - "@webpack-cli/serve": "^1.6.1", - "colorette": "^2.0.14", - "commander": "^7.0.0", - "execa": "^5.0.0", - "fastest-levenshtein": "^1.0.12", - "import-local": "^3.0.2", - "interpret": "^2.2.0", - "rechoir": "^0.7.0", - "webpack-merge": "^5.7.3" - }, - "dependencies": { - "commander": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", - "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", - "dev": true - } - } - }, - "webpack-merge": { - "version": "5.8.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.8.0.tgz", - "integrity": "sha512-/SaI7xY0831XwP6kzuwhKWVKDP9t1QY1h65lAFLbZqMPIuYcD9QAW4u9STIbU9kaJbPBB/geU/gLr1wDjOhQ+Q==", - "dev": true, - "requires": { - "clone-deep": "^4.0.1", - "wildcard": "^2.0.0" - } - }, - "webpack-sources": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", - "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", - "dev": true - }, - "which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-boxed-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", - "dev": true, - "requires": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - } - }, - "which-collection": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.1.tgz", - "integrity": "sha512-W8xeTUwaln8i3K/cY1nGXzdnVZlidBcagyNFtBdD5kxnb4TvGKR7FfSIS3mYpwWS1QUCutfKz8IY8RjftB0+1A==", - "dev": true, - "requires": { - "is-map": "^2.0.1", - "is-set": "^2.0.1", - "is-weakmap": "^2.0.1", - "is-weakset": "^2.0.1" - } - }, - "which-typed-array": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.7.tgz", - "integrity": "sha512-vjxaB4nfDqwKI0ws7wZpxIlde1XrLX5uB0ZjpfshgmapJMD7jJWhZI+yToJTqaFByF0eNBcYxbjmCzoRP7CfEw==", - "dev": true, - "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "es-abstract": "^1.18.5", - "foreach": "^2.0.5", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.7" - } - }, - "wicked-good-xpath": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/wicked-good-xpath/-/wicked-good-xpath-1.3.0.tgz", - "integrity": "sha1-gbDpXoZQ5JyUsiKY//hoa1VTz2w=" - }, - "wildcard": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", - "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==", - "dev": true - }, - "wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dev": true, - "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "requires": { - "color-convert": "^2.0.1" - } - }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "requires": { - "color-name": "~1.1.4" - } - }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - } - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xmldom-sre": { - "version": "0.1.31", - "resolved": "https://registry.npmjs.org/xmldom-sre/-/xmldom-sre-0.1.31.tgz", - "integrity": "sha512-f9s+fUkX04BxQf+7mMWAp5zk61pciie+fFLC9hX9UVvCeJQfNHRHXpeo5MPcR0EUf57PYLdt+ZO4f3Ipk2oZUw==" - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "dev": true - }, - "y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true - } - } -} diff --git a/package.json b/package.json index c3c244ebc..ef2dece39 100644 --- a/package.json +++ b/package.json @@ -1,24 +1,7 @@ { - "name": "mathjax-full", - "version": "3.2.2", + "name": "@mathjax/src", + "version": "4.0.0", "description": "Beautiful and accessible math in all browsers. MathJax is an open-source JavaScript display engine for LaTeX, MathML, and AsciiMath notation that works in all browsers and in server-side node applications. This package includes the source code as well as the packaged components.", - "license": "Apache-2.0", - "main": "components/src/node-main/node-main.js", - "files": [ - "/es5", - "/js", - "/ts", - "/components", - "LICENSE", - "README.md", - "CONTRIBUTING.md", - "tsconfig.json", - "tslint.json" - ], - "repository": { - "type": "git", - "url": "https://github.com/mathjax/Mathjax-src/" - }, "keywords": [ "MathJax", "math", @@ -28,43 +11,166 @@ "TeX", "AsciiMath" ], + "license": "Apache-2.0", + "maintainers": [ + "MathJax Consortium (http://www.mathjax.org)" + ], + "bugs": { + "url": "http://github.com/mathjax/MathJax/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/mathjax/Mathjax-src/" + }, + "type": "module", + "main": "components/mjs/node-main/node-main.js", + "exports": { + ".": { + "import": "./bundle/node-main.mjs", + "require": "./bundle/node-main.cjs" + }, + "./source": { + "import": "./components/mjs/node-main/node-main.mjs", + "require": "./components/cjs/node-main/node-main.cjs" + }, + "./js/*": { + "import": "./mjs/*", + "require": "./cjs/*" + }, + "./components/src/*": { + "import": "./components/mjs/*", + "require": "./components/cjs/*" + }, + "./components/js/*": { + "import": "./components/mjs/*", + "require": "./components/cjs/*" + }, + "./require.mjs": "./bundle/require.mjs", + "./es5/*": "./bundle/*", + "./*": "./*" + }, + "imports": { + "#js/*": "@mathjax/src/mjs/*", + "#source/*": "@mathjax/src/components/mjs/*", + "#root/*": "@mathjax/src/mjs/components/mjs/*", + "#menu/*": "mj-context-menu/js/*", + "#sre/*": "speech-rule-engine/js/*", + "#mhchem/*": "mhchemparser/esm/*", + "#default-font/*": "@mathjax/mathjax-newcm-font/mjs/*" + }, + "files": [ + "/bundle", + "/cjs", + "/mjs", + "/ts", + "/components", + "LICENSE", + "README.md", + "CONTRIBUTING.md", + "tsconfig*" + ], "scripts": { - "clean:js": "npx rimraf js", - "clean:es5": "npx rimraf es5", - "clean:lib": "npx rimraf 'components/src/**/lib'", - "clean": "npm run --silent clean:js && npm run --silent clean:es5 && npm run --silent clean:lib", - "copy:mj2": "npx copyfiles -u 1 'ts/input/asciimath/mathjax2/**/*' js", - "copy:mml3": "npx copyfiles -u 1 'ts/input/mathml/mml3/mml3.sef.json' js", - "precompile": "npm run --silent clean:js", - "compile": "npx tsc", - "postcompile": "npm run --silent copy:mj2 && npm run --silent copy:mml3", - "premake-components": "npm run --silent clean:es5 && npm run --silent clean:lib", - "make-components": "cd components && node bin/makeAll src | grep --line-buffered 'Building\\|Webpacking\\|Copying\\|npx'", - "premake-mml3-xslt": "cd ts/input/mathml/mml3 && grep '^\\s*\\(<\\|or\\|xmlns\\|excl\\|\">\\)' mml3.ts > mml3.xsl", - "make-mml3-xslt": "cd ts/input/mathml/mml3 && npx xslt3 -t -xsl:mml3.xsl -export:mml3.sef.json -nogo", - "postmake-mml3-xslt": "npx rimraf ts/input/mathml/mml3/mml3.xsl" + "=============================================================================== code hygene": "", + "lint": "check() { eslint ${1:-ts/}; }; check", + "lint:fix": "fix() { eslint --fix ${1:-ts/}; }; fix", + "format": "check() { prettier --check ${1:-\"ts/**/*.{ts,tsx}\"}; }; check", + "format:fix": "fix() { prettier --write ${1:-\"ts/**/*.{ts,tsx}\"}; }; fix", + "=============================================================================== clean": "", + "clean:dir": "clean() { pnpm -s log:single \"Cleaning $1 directory\"; pnpm rimraf $1; }; clean", + "clean:lib": "clean() { pnpm -s log:single \"Cleaning $1 component libs\"; pnpm rimraf -g components/$1'/**/lib'; }; clean", + "clean:mod": "clean() { pnpm -s log:comp \"Cleaning $1 module\"; pnpm -s clean:dir $1 && pnpm -s clean:lib $1; }; clean", + "=============================================================================== copy": "", + "copy:assets": "pnpm -s log:comp 'Copying assets'; copy() { pnpm -s copy:mj2 $1 && pnpm -s copy:mml3 $1 && pnpm -s copy:html $1; }; copy", + "copy:html": "copy() { pnpm -s log:single 'Copying sre auxiliary files'; pnpm copyfiles -u 1 'ts/a11y/sre/*.html' 'ts/a11y/sre/require.*' $1; }; copy", + "copy:mj2": "copy() { pnpm -s log:single 'Copying legacy code AsciiMath'; pnpm copyfiles -u 1 'ts/input/asciimath/legacy/**/*' $1; }; copy", + "copy:mml3": "copy() { pnpm -s log:single 'Copying legacy code MathML3'; pnpm copyfiles -u 1 ts/input/mathml/mml3/mml3.sef.json $1; }; copy", + "copy:pkg": "copy() { pnpm -s log:single \"Copying package.json to $1\"; pnpm copyfiles -u 2 components/bin/package.json $1; }; copy", + "=============================================================================== log": "", + "log:comp": "log() { echo \\\\033[32m$1\\\\033[0m; }; log", + "log:header": "log() { echo '============='; echo $1; echo '============='; }; log", + "log:single": "log() { echo \\\\033[34m--$1\\\\033[0m; }; log", + "=============================================================================== cjs": "", + "cjs:build": "pnpm -s log:header 'Building cjs'; pnpm -s cjs:src:build && pnpm -s cjs:components:build", + "cjs:bundle:clean": "pnpm clean:dir bundle-cjs", + "cjs:bundle:finalize": "pnpm -s log:single 'Finalize cjs bundle'; echo '{\n \"type\": \"commonjs\"\n}' > bundle-cjs/package.json;", + "cjs:compile": "pnpm -s cjs:copy:components && pnpm -s cjs:copy:ts && pnpm -s cjs:compile:tsc", + "cjs:compile:tsc": "pnpm -s log:single 'Compiling cjs typescript files' && pnpm tsc --project tsconfig/worker-cjs.json && pnpm tsc --project tsconfig/cjs.json", + "cjs:components:build": "pnpm -s log:comp 'Building cjs components'; pnpm -s cjs:components:src:build && pnpm clean:dir bundle-cjs && pnpm -s cjs:components:make --build", + "cjs:components:clean": "pnpm -s log:single \"Cleaning cjs components\"; pnpm rimraf components/cjs", + "cjs:components:compile": "pnpm -s log:single 'Compiling component files'; pnpm tsc --project tsconfig/components.json", + "cjs:components:copy": "pnpm copyfiles -u 2 -e 'components/mjs/**/*.js' 'components/mjs/**/*' components/cjs", + "cjs:components:finalize": "pnpm -s log:comp 'Finalize cjs components'; pnpm -s cjs:components:copy && pnpm -s copy:pkg components/cjs && pnpm -s clean:lib cjs", + "cjs:components:make": "make() { pnpm -s log:single 'Making cjs components'; components/bin/makeAll --cjs --terse --bundle-cjs $1 components/cjs; }; make", + "cjs:components:src:build": "pnpm -s log:comp 'Building cjs components sources'; pnpm cjs:components:clean && pnpm cjs:components:compile && pnpm cjs:components:finalize", + "cjs:src:build": "pnpm -s log:comp 'Building cjs sources'; pnpm -s link:src && pnpm clean:dir cjs && pnpm -s cjs:compile && pnpm -s copy:assets cjs && pnpm -s copy:pkg cjs", + "cjs:copy:components": "pnpm -s log:single 'Moving cjs files from components' && pnpm copyfiles -u 2 'components/mjs/**/*.cjs' 'components/mjs/**/*.d.cts' components/cjs", + "cjs:copy:ts": "pnpm -s log:single 'Moving cjs files from ts' && pnpm copyfiles -u 1 'ts/**/*.cjs' cjs", + "=============================================================================== mjs": "", + "mjs:build": "pnpm -s log:header 'Building mjs'; pnpm -s mjs:src:build && pnpm -s mjs:components:build", + "mjs:bundle:finalize": "pnpm -s log:single 'Finalize mjs bundle'; echo '{\n \"type\": \"commonjs\"\n}' > bundle/package.json;", + "mjs:compile": "pnpm -s log:single 'Compiling mjs typescript files'; pnpm tsc --project tsconfig/mjs.json && pnpm tsc --project tsconfig/worker.json", + "mjs:components:build": "pnpm -s log:comp 'Compiling mjs component files'; pnpm clean:lib mjs && pnpm clean:dir bundle && pnpm mjs:components:make && pnpm mjs:bundle:finalize", + "mjs:components:make": "pnpm -s log:single 'Making mjs components'; components/bin/makeAll --mjs --terse components/mjs", + "mjs:src:build": "pnpm -s log:comp 'Building mjs sources'; pnpm -s link:src && pnpm -s clean:dir mjs && pnpm -s mjs:compile && pnpm -s copy:assets mjs", + "=============================================================================== mml3": "", + "mml3:make:xslt": "pnpm xslt3 -t -xsl:/tmp/mml3.xsl -export:ts/input/mathml/mml3/mml3.sef.json -nogo", + "mml3:post:xslt": "pnpm rimraf /tmp/mml3.xsl", + "mml3:pre:xslt": "grep '^\\s*\\(<\\|or\\|xmlns\\|excl\\|\">\\)' ts/input/mathml/mml3/mml3.ts > /tmp/mml3.xsl", + "mml3-xslt": "pnpm -s mml3:pre:xslt && pnpm -s mml3:make:xslt && pnpm -s mml3:post:xslt", + "=============================================================================== misc": "", + "lab:sre": "pnpm -s log:single 'Making lab/sre'; node components/bin/makeAll --terse lab/build", + "link:src": "pnpm -s log:single 'Setting symbolic link'; node components/bin/link-full", + "use-cjs": "echo '{\n \"extends\": \"./tsconfig/cjs.json\"\n}' > tsconfig.json", + "use-mjs": "echo '{\n \"extends\": \"./tsconfig/mjs.json\"\n}' > tsconfig.json", + "=============================================================================== aliases": "", + "test": "cd testsuite && pnpm -s test --verbose", + "test:gh": "cd testsuite && pnpm -s test --silent", + "clean": "pnpm -s clean:mod cjs && pnpm -s cjs:bundle:clean && pnpm -s clean:mod mjs && pnpm -s clean:dir bundle", + "compile-cjs": "pnpm -s cjs:compile", + "compile-mjs": "pnpm -s mjs:compile", + "build-cjs": "pnpm -s cjs:build", + "build-mjs": "pnpm -s mjs:build", + "make-cjs-components": "pnpm -s cjs:components:make && pnpm -s cjs:bundle:finalize", + "make-mjs-components": "pnpm -s mjs:components:make", + "make-one": "make() { components/bin/makeAll --no-subdirs $3 $4 --${2:-mjs} components/${2-:mjs}/$1; }; make", + "make-components": "pnpm -s make-mjs-components", + "compile": "pnpm -s compile-mjs", + "build": "pnpm -s build-mjs", + "build-all": "pnpm -s build-mjs ; echo ; pnpm -s build-cjs" }, "devDependencies": { - "@babel/core": "^7.17.12", - "@babel/preset-env": "^7.17.12", - "babel-loader": "^8.2.5", + "@eslint/js": "^9.28.0", + "@xmldom/xmldom": "^0.8.10", "copyfiles": "^2.4.1", - "diff": "^5.0.0", - "rimraf": "^3.0.2", - "tape": "^5.5.3", - "terser-webpack-plugin": "^5.3.1", - "tslint": "^6.1.3", - "tslint-jsdoc-rules": "^0.2.0", - "tslint-unix-formatter": "^0.2.0", - "typescript": "^4.6.4", + "diff": "^5.2.0", + "eslint": "^9.28.0", + "eslint-formatter-unix": "^8.40.0", + "eslint-plugin-jsdoc": "^48.11.0", + "eslint-plugin-prettier": "^5.4.1", + "husky": "^9.1.7", + "lint-staged": "^15.5.2", + "prettier": "^3.5.3", + "rimraf": "^5.0.10", + "terser-webpack-plugin": "^5.3.14", + "typedoc": "^0.28.5", + "typescript": "^5.8.3", + "typescript-eslint": "^8.33.1", "typescript-tools": "^0.3.1", - "webpack": "^5.72.1", - "webpack-cli": "^4.9.2" + "webpack": "^5.99.9", + "webpack-cli": "^5.1.4", + "wicked-good-xpath": "^1.3.0", + "xslt3": "^2.7.0" + }, + "lint-staged": { + "ts/**/*.ts": [ + "pnpm format:fix", + "pnpm lint:fix" + ] }, "dependencies": { - "esm": "^3.2.25", - "mhchemparser": "^4.1.0", - "mj-context-menu": "^0.6.1", - "speech-rule-engine": "^4.0.6" + "@mathjax/mathjax-newcm-font": "4.0.0", + "mhchemparser": "^4.2.1", + "mj-context-menu": "^0.9.1", + "speech-rule-engine": "5.0.0-beta.1" } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 000000000..7dfbced8e --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,3145 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@mathjax/mathjax-newcm-font': + specifier: 4.0.0 + version: 4.0.0 + mhchemparser: + specifier: ^4.2.1 + version: 4.2.1 + mj-context-menu: + specifier: ^0.9.1 + version: 0.9.1 + speech-rule-engine: + specifier: 5.0.0-beta.1 + version: 5.0.0-beta.1 + devDependencies: + '@eslint/js': + specifier: ^9.28.0 + version: 9.28.0 + '@xmldom/xmldom': + specifier: ^0.8.10 + version: 0.8.10 + copyfiles: + specifier: ^2.4.1 + version: 2.4.1 + diff: + specifier: ^5.2.0 + version: 5.2.0 + eslint: + specifier: ^9.28.0 + version: 9.28.0 + eslint-formatter-unix: + specifier: ^8.40.0 + version: 8.40.0 + eslint-plugin-jsdoc: + specifier: ^48.11.0 + version: 48.11.0(eslint@9.28.0) + eslint-plugin-prettier: + specifier: ^5.4.1 + version: 5.4.1(@types/eslint@9.6.1)(eslint@9.28.0)(prettier@3.5.3) + husky: + specifier: ^9.1.7 + version: 9.1.7 + lint-staged: + specifier: ^15.5.2 + version: 15.5.2 + prettier: + specifier: ^3.5.3 + version: 3.5.3 + rimraf: + specifier: ^5.0.10 + version: 5.0.10 + terser-webpack-plugin: + specifier: ^5.3.14 + version: 5.3.14(webpack@5.99.9) + typedoc: + specifier: ^0.28.5 + version: 0.28.5(typescript@5.8.3) + typescript: + specifier: ^5.8.3 + version: 5.8.3 + typescript-eslint: + specifier: ^8.33.1 + version: 8.33.1(eslint@9.28.0)(typescript@5.8.3) + typescript-tools: + specifier: ^0.3.1 + version: 0.3.1 + webpack: + specifier: ^5.99.9 + version: 5.99.9(webpack-cli@5.1.4) + webpack-cli: + specifier: ^5.1.4 + version: 5.1.4(webpack@5.99.9) + wicked-good-xpath: + specifier: ^1.3.0 + version: 1.3.0 + xslt3: + specifier: ^2.7.0 + version: 2.7.0 + +packages: + + '@discoveryjs/json-ext@0.5.7': + resolution: {integrity: sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==} + engines: {node: '>=10.0.0'} + + '@es-joy/jsdoccomment@0.46.0': + resolution: {integrity: sha512-C3Axuq1xd/9VqFZpW4YAzOx5O9q/LP46uIQy/iNDpHG3fmPa6TBtvfglMCs3RBiBxAIi0Go97r8+jvTt55XMyQ==} + engines: {node: '>=16'} + + '@eslint-community/eslint-utils@4.7.0': + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.20.0': + resolution: {integrity: sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.2.2': + resolution: {integrity: sha512-+GPzk8PlG0sPpzdU5ZvIRMPidzAnZDl/s9L+y13iodqvb8leL53bTannOrQ/Im7UkpsmFU5Ily5U60LWixnmLg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.14.0': + resolution: {integrity: sha512-qIbV0/JZr7iSDjqAc60IqbLdsj9GDt16xQtWD+B78d/HAlvysGdZZ6rpJHGAc2T0FQx1X6thsSPdnoiGKdNtdg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.28.0': + resolution: {integrity: sha512-fnqSjGWd/CoIp4EXIxWVK/sHA6DOHN4+8Ix2cX5ycOY7LG0UY8nHCU5pIp2eaE1Mc7Qd8kHspYNzYXT2ojPLzg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.3.1': + resolution: {integrity: sha512-0J+zgWxHN+xXONWIyPWKFMgVuJoZuGiIFu8yxk7RJjxkzpGmyja5wRFqZIVtjDVOQpV+Rw0iOAjYPE2eQyjr0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@gerrit0/mini-shiki@3.7.0': + resolution: {integrity: sha512-7iY9wg4FWXmeoFJpUL2u+tsmh0d0jcEJHAIzVxl3TG4KL493JNnisdLAILZ77zcD+z3J0keEXZ+lFzUgzQzPDg==} + + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@mathjax/mathjax-newcm-font@4.0.0': + resolution: {integrity: sha512-kpsJgIF4FpWiwIkFgOPmWwy5GXfL25spmJJNg27HQxPddmEL8Blx0jn2BuU/nlwjM/9SnYpEfDrWiAMgLPlB8Q==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.1.2': + resolution: {integrity: sha512-fdDH1LSGfZdTH2sxdpVMw31BanV28K/Gry0cVFxaNP77neJSkd82mM8ErPNYs9e+0O7SdHBLTDzDgwUuy18RnQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@pkgr/core@0.2.7': + resolution: {integrity: sha512-YLT9Zo3oNPJoBjBc4q8G2mjU4tqIbf5CEOORbUUr48dCD9q3umJ3IPlVqOqDakPfd2HuwccBaqlGhN4Gmr5OWg==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + + '@shikijs/engine-oniguruma@3.7.0': + resolution: {integrity: sha512-5BxcD6LjVWsGu4xyaBC5bu8LdNgPCVBnAkWTtOCs/CZxcB22L8rcoWfv7Hh/3WooVjBZmFtyxhgvkQFedPGnFw==} + + '@shikijs/langs@3.7.0': + resolution: {integrity: sha512-1zYtdfXLr9xDKLTGy5kb7O0zDQsxXiIsw1iIBcNOO8Yi5/Y1qDbJ+0VsFoqTlzdmneO8Ij35g7QKF8kcLyznCQ==} + + '@shikijs/themes@3.7.0': + resolution: {integrity: sha512-VJx8497iZPy5zLiiCTSIaOChIcKQwR0FebwE9S3rcN0+J/GTWwQ1v/bqhTbpbY3zybPKeO8wdammqkpXc4NVjQ==} + + '@shikijs/types@3.7.0': + resolution: {integrity: sha512-MGaLeaRlSWpnP0XSAum3kP3a8vtcTsITqoEPYdt3lQG3YCdQH4DnEhodkYcNMcU0uW0RffhoD1O3e0vG5eSBBg==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@types/eslint-scope@3.7.7': + resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/node@22.15.30': + resolution: {integrity: sha512-6Q7lr06bEHdlfplU6YRbgG1SFBdlsfNC4/lX+SkhiTs0cpJkOElmWls8PxDFv4yY/xKb8Y6SO0OmSX4wgqTZbA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@typescript-eslint/eslint-plugin@8.33.1': + resolution: {integrity: sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.33.1 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/parser@8.33.1': + resolution: {integrity: sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/project-service@8.33.1': + resolution: {integrity: sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/scope-manager@8.33.1': + resolution: {integrity: sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.33.1': + resolution: {integrity: sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/type-utils@8.33.1': + resolution: {integrity: sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/types@8.33.1': + resolution: {integrity: sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@8.33.1': + resolution: {integrity: sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/utils@8.33.1': + resolution: {integrity: sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + '@typescript-eslint/visitor-keys@8.33.1': + resolution: {integrity: sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@webassemblyjs/ast@1.14.1': + resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} + + '@webassemblyjs/floating-point-hex-parser@1.13.2': + resolution: {integrity: sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==} + + '@webassemblyjs/helper-api-error@1.13.2': + resolution: {integrity: sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==} + + '@webassemblyjs/helper-buffer@1.14.1': + resolution: {integrity: sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==} + + '@webassemblyjs/helper-numbers@1.13.2': + resolution: {integrity: sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==} + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': + resolution: {integrity: sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==} + + '@webassemblyjs/helper-wasm-section@1.14.1': + resolution: {integrity: sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==} + + '@webassemblyjs/ieee754@1.13.2': + resolution: {integrity: sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==} + + '@webassemblyjs/leb128@1.13.2': + resolution: {integrity: sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==} + + '@webassemblyjs/utf8@1.13.2': + resolution: {integrity: sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==} + + '@webassemblyjs/wasm-edit@1.14.1': + resolution: {integrity: sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==} + + '@webassemblyjs/wasm-gen@1.14.1': + resolution: {integrity: sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==} + + '@webassemblyjs/wasm-opt@1.14.1': + resolution: {integrity: sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==} + + '@webassemblyjs/wasm-parser@1.14.1': + resolution: {integrity: sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==} + + '@webassemblyjs/wast-printer@1.14.1': + resolution: {integrity: sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==} + + '@webpack-cli/configtest@2.1.1': + resolution: {integrity: sha512-wy0mglZpDSiSS0XHrVR+BAdId2+yxPSoJW8fsna3ZpYSlufjvxnP4YbKTCBZnNIcGN4r6ZPXV55X4mYExOfLmw==} + engines: {node: '>=14.15.0'} + peerDependencies: + webpack: 5.x.x + webpack-cli: 5.x.x + + '@webpack-cli/info@2.0.2': + resolution: {integrity: sha512-zLHQdI/Qs1UyT5UBdWNqsARasIA+AaF8t+4u2aS2nEpBQh2mWIVb8qAklq0eUENnC5mOItrIB4LiS9xMtph18A==} + engines: {node: '>=14.15.0'} + peerDependencies: + webpack: 5.x.x + webpack-cli: 5.x.x + + '@webpack-cli/serve@2.0.5': + resolution: {integrity: sha512-lqaoKnRYBdo1UgDX8uF24AfGMifWK19TxPmM5FHc2vAGxrJ/qtyUyFBWoY1tISZdelsQ5fBcOusifo5o5wSJxQ==} + engines: {node: '>=14.15.0'} + peerDependencies: + webpack: 5.x.x + webpack-cli: 5.x.x + webpack-dev-server: '*' + peerDependenciesMeta: + webpack-dev-server: + optional: true + + '@xmldom/xmldom@0.8.10': + resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} + engines: {node: '>=10.0.0'} + + '@xmldom/xmldom@0.9.8': + resolution: {integrity: sha512-p96FSY54r+WJ50FIOsCOjyj/wavs8921hG5+kVMmZgKcvIKxMXHTrjNJvRgWa/zuX3B6t2lijLNFaOyuxUH+2A==} + engines: {node: '>=14.6'} + + '@xtuc/ieee754@1.2.0': + resolution: {integrity: sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==} + + '@xtuc/long@4.2.2': + resolution: {integrity: sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-keywords@5.1.0: + resolution: {integrity: sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==} + peerDependencies: + ajv: ^8.8.2 + + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + + ansi-escapes@7.0.0: + resolution: {integrity: sha512-GdYO7a61mR0fOlAsvC9/rIHf7L96sBc6dEWzeOu+KAea5bZyQRPIpojrVoI4AXGJS/ycu/fBTdLrUkA4ODrvjw==} + engines: {node: '>=18'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.1.0: + resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} + + are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + + axios@1.9.0: + resolution: {integrity: sha512-re4CqKTJaURpzbLHtIi6XpDv20/CnpXOtjRY5/CU32L8gU8ek9UIivcfvSWvmKEngmVbrUtPpdDwWDWL7DNHvg==} + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.25.0: + resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + caniuse-lite@1.0.30001721: + resolution: {integrity: sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.4.1: + resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + chrome-trace-event@1.0.4: + resolution: {integrity: sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==} + engines: {node: '>=6.0'} + + cli-cursor@5.0.0: + resolution: {integrity: sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==} + engines: {node: '>=18'} + + cli-truncate@4.0.0: + resolution: {integrity: sha512-nPdaFdQ0h/GEigbPClz11D0v/ZJEwxmeVZGeMo3Z5StPtUTkA9o1lD6QwoirYiSDzbcwn2XcjwmCp68W1IS4TA==} + engines: {node: '>=18'} + + cliui@7.0.4: + resolution: {integrity: sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==} + + clone-deep@4.0.1: + resolution: {integrity: sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==} + engines: {node: '>=6'} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + + commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + commander@14.0.0: + resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} + engines: {node: '>=20'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + engines: {node: '>= 12.0.0'} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + copyfiles@2.4.1: + resolution: {integrity: sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==} + hasBin: true + + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + + diff@5.2.0: + resolution: {integrity: sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A==} + engines: {node: '>=0.3.1'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.5.165: + resolution: {integrity: sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==} + + emoji-regex@10.4.0: + resolution: {integrity: sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw==} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.18.1: + resolution: {integrity: sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==} + engines: {node: '>=10.13.0'} + + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + + envinfo@7.14.0: + resolution: {integrity: sha512-CO40UI41xDQzhLB1hWyqUKgFhs250pNcGbyGKe1l/e4FSaI/+YE4IMG76GDt0In67WLPACIITC+sOi08x4wIvg==} + engines: {node: '>=4'} + hasBin: true + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-formatter-unix@8.40.0: + resolution: {integrity: sha512-gfsmFZ/cb1MobrMfYl2IPFLZEz2tWQVO/tnmziNQdhWJMN85GfZD64dcPsEgaEoeVKgAtK6W9LWLlOxhJWZvDw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-plugin-jsdoc@48.11.0: + resolution: {integrity: sha512-d12JHJDPNo7IFwTOAItCeJY1hcqoIxE0lHA8infQByLilQ9xkqrRa6laWCnsuCrf+8rUnvxXY1XuTbibRBNylA==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 + + eslint-plugin-prettier@5.4.1: + resolution: {integrity: sha512-9dF+KuU/Ilkq27A8idRP7N2DH8iUR6qXcjF3FR2wETY21PZdBrIjwCau8oboyGj9b7etWmTGEeM8e7oOed6ZWg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@8.3.0: + resolution: {integrity: sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.0: + resolution: {integrity: sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint@9.28.0: + resolution: {integrity: sha512-ocgh41VhRlf9+fVpe7QKzwLj9c92fDiqOj8Y3Sd4/ZmVA4Btx4PlUYPq4pp9JDyupkf1upbEXecxL2mwNV7jPQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.3.0: + resolution: {integrity: sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} + + execa@8.0.1: + resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} + engines: {node: '>=16.17'} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + + fastest-levenshtein@1.0.16: + resolution: {integrity: sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==} + engines: {node: '>= 4.9.1'} + + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flat@5.0.2: + resolution: {integrity: sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==} + hasBin: true + + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + + follow-redirects@1.15.9: + resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.3: + resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==} + engines: {node: '>= 6'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-east-asian-width@1.3.0: + resolution: {integrity: sha512-vpeMIQKxczTD/0s2CdEWHcb0eeJe6TFjxb+J5xgX7hScxqrGuyjmv4c1D4A/gelKfyox0gJJwIHF+fLjeaM8kQ==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@8.0.1: + resolution: {integrity: sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==} + engines: {node: '>=16'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + human-signals@5.0.0: + resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} + engines: {node: '>=16.17.0'} + + husky@9.1.7: + resolution: {integrity: sha512-5gs5ytaNjBrh5Ow3zrvdUUY+0VxIuWVL4i9irt6friV+BqdCfmV11CQTWMiBYWHbXhco+J1kHfTOUkePhCDvMA==} + engines: {node: '>=18'} + hasBin: true + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + interpret@3.1.1: + resolution: {integrity: sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==} + engines: {node: '>=10.13.0'} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-fullwidth-code-point@4.0.0: + resolution: {integrity: sha512-O4L094N2/dZ7xqVdrXhh9r1KODPJpFms8B5sGdJLPy664AgvXsreZUyCQQNItZRDlYug4xStLjNp/sz3HvBowQ==} + engines: {node: '>=12'} + + is-fullwidth-code-point@5.0.0: + resolution: {integrity: sha512-OVa3u9kkBbw7b8Xw5F9P+D/T9X+Z4+JruYVNapTjPYZYUznQ5YfWeFkOj606XYYW8yugTfC8Pj0hYqvi4ryAhA==} + engines: {node: '>=18'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-plain-object@2.0.4: + resolution: {integrity: sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==} + engines: {node: '>=0.10.0'} + + is-stream@3.0.0: + resolution: {integrity: sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + isarray@0.0.1: + resolution: {integrity: sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==} + + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + isobject@3.0.1: + resolution: {integrity: sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==} + engines: {node: '>=0.10.0'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jest-worker@27.5.1: + resolution: {integrity: sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==} + engines: {node: '>= 10.13.0'} + + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true + + jsdoc-type-pratt-parser@4.0.0: + resolution: {integrity: sha512-YtOli5Cmzy3q4dP26GraSOeAhqecewG04hoO8DY56CH4KJ9Fvv5qKWUCCo3HZob7esJQHCv6/+bnTy72xZZaVQ==} + engines: {node: '>=12.0.0'} + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kind-of@6.0.3: + resolution: {integrity: sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==} + engines: {node: '>=0.10.0'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + linkify-it@5.0.0: + resolution: {integrity: sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==} + + lint-staged@15.5.2: + resolution: {integrity: sha512-YUSOLq9VeRNAo/CTaVmhGDKG+LBtA8KF1X4K5+ykMSwWST1vDxJRB2kv2COgLb1fvpCo+A/y9A0G0znNVmdx4w==} + engines: {node: '>=18.12.0'} + hasBin: true + + listr2@8.3.3: + resolution: {integrity: sha512-LWzX2KsqcB1wqQ4AHgYb4RsDXauQiqhjLk+6hjbaeHG4zpjjVAB6wC/gz6X0l+Du1cN3pUB5ZlrvTbhGSNnUQQ==} + engines: {node: '>=18.0.0'} + + loader-runner@4.3.0: + resolution: {integrity: sha512-3R/1M+yS3j5ou80Me59j7F9IMs4PXs3VqRrm0TU3AbKPxlmpoY1TNscJV/oGJXo8qCatFGTfDbY6W6ipGOYXfg==} + engines: {node: '>=6.11.5'} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + log-update@6.1.0: + resolution: {integrity: sha512-9ie8ItPR6tjY5uYJh8K/Zrv/RMZ5VOlOWvtZdEHYSTFKZfIBPQa9tOAEeAWhd+AnIneLJ22w5fjOYtoutpWq5w==} + engines: {node: '>=18'} + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lunr@2.3.9: + resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} + + markdown-it@14.1.0: + resolution: {integrity: sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==} + hasBin: true + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdurl@2.0.0: + resolution: {integrity: sha512-Lf+9+2r+Tdp5wXDXC4PcIBjTDtq4UKjCPMQhKIuzpJNW0b96kVqSwW0bT7FhRSfmAiFYgP+SCRvdrDozfh0U5w==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + mhchemparser@4.2.1: + resolution: {integrity: sha512-kYmyrCirqJf3zZ9t/0wGgRZ4/ZJw//VwaRVGA75C4nhE60vtnIzhl9J9ndkX/h6hxSN7pjg/cE0VxbnNM+bnDQ==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + mimic-fn@4.0.0: + resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} + engines: {node: '>=12'} + + mimic-function@5.0.1: + resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} + engines: {node: '>=18'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + + mj-context-menu@0.9.1: + resolution: {integrity: sha512-ECPcVXZFRfeYOxb1MWGzctAtnQcZ6nRucE3orfkKX7t/KE2mlXO2K/bq4BcCGOuhdz3Wg2BZDy2S8ECK73/iIw==} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + neo-async@2.6.2: + resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + noms@0.0.0: + resolution: {integrity: sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==} + + npm-run-path@5.3.0: + resolution: {integrity: sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@6.0.0: + resolution: {integrity: sha512-1FlR+gjXK7X+AsAHso35MnyN5KqGwJRi/31ft6x0M194ht7S+rWAvd7PHss9xSKMzE0asv1pyIHaJYq+BbacAQ==} + engines: {node: '>=12'} + + onetime@7.0.0: + resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} + engines: {node: '>=18'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-imports@2.2.1: + resolution: {integrity: sha512-OL/zLggRp8mFhKL0rNORUTR4yBYujK/uU+xZL+/0Rgm2QE4nLO9v8PzEweSJEbMGKmDRjJE4R3IMJlL2di4JeQ==} + engines: {node: '>= 18'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-key@4.0.0: + resolution: {integrity: sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==} + engines: {node: '>=12'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pidtree@0.6.0: + resolution: {integrity: sha512-eG2dWTVw5bzqGRztnHExczNxt5VGsE6OwTeCG3fdUf9KBsZzO3R5OIIIzWR+iZA0NtZ+RDVdaoE2dK1cn6jH4g==} + engines: {node: '>=0.10'} + hasBin: true + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier-linter-helpers@1.0.0: + resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} + engines: {node: '>=6.0.0'} + + prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + engines: {node: '>=14'} + hasBin: true + + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode.js@2.3.1: + resolution: {integrity: sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==} + engines: {node: '>=6'} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + + readable-stream@1.0.34: + resolution: {integrity: sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==} + + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + rechoir@0.8.0: + resolution: {integrity: sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==} + engines: {node: '>= 10.13.0'} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + restore-cursor@5.1.0: + resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} + engines: {node: '>=18'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + + rimraf@5.0.10: + resolution: {integrity: sha512-l0OE8wL34P4nJH/H2ffoaniAokM2qSmrtXHmlpvYr5AVVX8msAyW0l8NVJFDxlSK4u3Uh/f41cQheDVdnYijwQ==} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + saxon-js@2.7.0: + resolution: {integrity: sha512-uGAv7H85EuWtAyyXVezXBg3/j2UvhEfT3N9+sqkGwCJVW33KlkadllDCdES/asCDklUo0UlM6178tZ0n3GPZjQ==} + + schema-utils@4.3.2: + resolution: {integrity: sha512-Gn/JaSk/Mt9gYubxTtSn/QCV4em9mpAPiR1rqy/Ocu19u/G9J5WWdNoUT4SiV6mFC3y6cxyFcFwdzPM3FgxGAQ==} + engines: {node: '>= 10.13.0'} + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + serialize-javascript@6.0.2: + resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + + shallow-clone@3.0.1: + resolution: {integrity: sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==} + engines: {node: '>=8'} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + slashes@3.0.12: + resolution: {integrity: sha512-Q9VME8WyGkc7pJf6QEkj3wE+2CnvZMI+XJhwdTPR8Z/kWQRXi7boAWLDibRPyHRTUTPx5FaU7MsyrjI3yLB4HA==} + + slice-ansi@5.0.0: + resolution: {integrity: sha512-FC+lgizVPfie0kkhqUScwRu1O/lF6NOgJmlCgK+/LYxDCTk8sGelYaHDhFcDN+Sn3Cv+3VSa4Byeo+IMCzpMgQ==} + engines: {node: '>=12'} + + slice-ansi@7.1.0: + resolution: {integrity: sha512-bSiSngZ/jWeX93BqeIAbImyTbEihizcwNjFoRUIY/T1wWQsfsm2Vw1agPKylXvQTU7iASGdHhyqRlqQzfz+Htg==} + engines: {node: '>=18'} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + + spdx-license-ids@3.0.21: + resolution: {integrity: sha512-Bvg/8F5XephndSK3JffaRqdT+gyhfqIPwDHpX80tJrF8QQRYMo8sNMeaZ2Dp5+jhwKnUmIOyFFQfHRkjJm5nXg==} + + speech-rule-engine@5.0.0-beta.1: + resolution: {integrity: sha512-arqcJpXEYRG9mQMxRCNd2xFERGvIvwvuhcnoXDw/SyeYNyJ5I9SUU5ft+BPw0M1rPpwl3Q+6ZeeYAcwGXTa6oQ==} + hasBin: true + + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string-width@7.2.0: + resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} + engines: {node: '>=18'} + + string_decoder@0.10.31: + resolution: {integrity: sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==} + + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} + + strip-final-newline@3.0.0: + resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + synckit@0.11.8: + resolution: {integrity: sha512-+XZ+r1XGIJGeQk3VvXhT6xx/VpbHsRzsTkGgF6E5RX9TTXD0118l87puaEBZ566FhqblC6U0d4XnubznJDm30A==} + engines: {node: ^14.18.0 || >=16.0.0} + + synckit@0.9.3: + resolution: {integrity: sha512-JJoOEKTfL1urb1mDoEblhD9NhEbWmq9jHEMEnxoC4ujUaZ4itA8vKgwkFAyNClgxplLi9tsUKX+EduK0p/l7sg==} + engines: {node: ^14.18.0 || >=16.0.0} + + tapable@2.2.2: + resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} + engines: {node: '>=6'} + + terser-webpack-plugin@5.3.14: + resolution: {integrity: sha512-vkZjpUjb6OMS7dhV+tILUW6BhpDR7P2L/aQSAv+Uwk+m8KATX9EccViHTJR2qDtACKPIYndLGCyl3FMo+r2LMw==} + engines: {node: '>= 10.13.0'} + peerDependencies: + '@swc/core': '*' + esbuild: '*' + uglify-js: '*' + webpack: ^5.1.0 + peerDependenciesMeta: + '@swc/core': + optional: true + esbuild: + optional: true + uglify-js: + optional: true + + terser@5.41.0: + resolution: {integrity: sha512-H406eLPXpZbAX14+B8psIuvIr8+3c+2hkuYzpMkoE0ij+NdsVATbA78vb8neA/eqrj7rywa2pIkdmWRsXW6wmw==} + engines: {node: '>=10'} + hasBin: true + + through2@2.0.5: + resolution: {integrity: sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + typedoc@0.28.5: + resolution: {integrity: sha512-5PzUddaA9FbaarUzIsEc4wNXCiO4Ot3bJNeMF2qKpYlTmM9TTaSHQ7162w756ERCkXER/+o2purRG6YOAv6EMA==} + engines: {node: '>= 18', pnpm: '>= 10'} + hasBin: true + peerDependencies: + typescript: 5.0.x || 5.1.x || 5.2.x || 5.3.x || 5.4.x || 5.5.x || 5.6.x || 5.7.x || 5.8.x + + typescript-eslint@8.33.1: + resolution: {integrity: sha512-AgRnV4sKkWOiZ0Kjbnf5ytTJXMUZQ0qhSVdQtDNYLPLnjsATEYhaO94GlRQwi4t4gO8FfjM6NnikHeKjUm8D7A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <5.9.0' + + typescript-tools@0.3.1: + resolution: {integrity: sha512-rFRO0bQ5fOu0r6oESjJkgtLE1yCSi7uBz4X2EvawjM9EwH127gBR2h0EM2DK/EcN3FQEJAn14GLBnoyi9nXNig==} + hasBin: true + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + uc.micro@2.1.0: + resolution: {integrity: sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + untildify@4.0.0: + resolution: {integrity: sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==} + engines: {node: '>=8'} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + + watchpack@2.4.4: + resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} + engines: {node: '>=10.13.0'} + + webpack-cli@5.1.4: + resolution: {integrity: sha512-pIDJHIEI9LR0yxHXQ+Qh95k2EvXpWzZ5l+d+jIo+RdSm9MiHfzazIxwwni/p7+x4eJZuvG1AJwgC4TNQ7NRgsg==} + engines: {node: '>=14.15.0'} + hasBin: true + peerDependencies: + '@webpack-cli/generators': '*' + webpack: 5.x.x + webpack-bundle-analyzer: '*' + webpack-dev-server: '*' + peerDependenciesMeta: + '@webpack-cli/generators': + optional: true + webpack-bundle-analyzer: + optional: true + webpack-dev-server: + optional: true + + webpack-merge@5.10.0: + resolution: {integrity: sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==} + engines: {node: '>=10.0.0'} + + webpack-sources@3.3.2: + resolution: {integrity: sha512-ykKKus8lqlgXX/1WjudpIEjqsafjOTcOJqxnAbMLAu/KCsDCJ6GBtvscewvTkrn24HsnvFwrSCbenFrhtcCsAA==} + engines: {node: '>=10.13.0'} + + webpack@5.99.9: + resolution: {integrity: sha512-brOPwM3JnmOa+7kd3NsmOUOwbDAj8FT9xDsG3IW0MgbN9yZV7Oi/s/+MNQ/EcSMqw7qfoRyXPoeEWT8zLVdVGg==} + engines: {node: '>=10.13.0'} + hasBin: true + peerDependencies: + webpack-cli: '*' + peerDependenciesMeta: + webpack-cli: + optional: true + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wicked-good-xpath@1.3.0: + resolution: {integrity: sha512-Gd9+TUn5nXdwj/hFsPVx5cuHHiF5Bwuc30jZ4+ronF1qHK5O7HD0sgmXWSEgwKquT3ClLoKPVbO6qGwVwLzvAw==} + + wildcard@2.0.1: + resolution: {integrity: sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==} + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrap-ansi@9.0.0: + resolution: {integrity: sha512-G8ura3S+3Z2G+mkgNRq8dqaFZAuxfsxpBB8OCTGRTCtp+l/v9nbFNmCUP1BZMts3G1142MsZfn6eeUKrr4PD1Q==} + engines: {node: '>=18'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + xslt3@2.7.0: + resolution: {integrity: sha512-Vt32LhCt4CQULtGPWlGW++PhS+o3LA6z3PDvig9lDfbo2cIHcaEnyrRYDTilw4N0EbAyxCaw5E0B+DICZEYktQ==} + hasBin: true + + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yaml@2.8.0: + resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@20.2.9: + resolution: {integrity: sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==} + engines: {node: '>=10'} + + yargs@16.2.0: + resolution: {integrity: sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==} + engines: {node: '>=10'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@discoveryjs/json-ext@0.5.7': {} + + '@es-joy/jsdoccomment@0.46.0': + dependencies: + comment-parser: 1.4.1 + esquery: 1.6.0 + jsdoc-type-pratt-parser: 4.0.0 + + '@eslint-community/eslint-utils@4.7.0(eslint@9.28.0)': + dependencies: + eslint: 9.28.0 + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.1': {} + + '@eslint/config-array@0.20.0': + dependencies: + '@eslint/object-schema': 2.1.6 + debug: 4.4.1 + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.2.2': {} + + '@eslint/core@0.14.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.1 + espree: 10.3.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.0 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.28.0': {} + + '@eslint/object-schema@2.1.6': {} + + '@eslint/plugin-kit@0.3.1': + dependencies: + '@eslint/core': 0.14.0 + levn: 0.4.1 + + '@gerrit0/mini-shiki@3.7.0': + dependencies: + '@shikijs/engine-oniguruma': 3.7.0 + '@shikijs/langs': 3.7.0 + '@shikijs/themes': 3.7.0 + '@shikijs/types': 3.7.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.6': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.3.1 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.3.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@mathjax/mathjax-newcm-font@4.0.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.1.2': {} + + '@pkgr/core@0.2.7': {} + + '@shikijs/engine-oniguruma@3.7.0': + dependencies: + '@shikijs/types': 3.7.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.7.0': + dependencies: + '@shikijs/types': 3.7.0 + + '@shikijs/themes@3.7.0': + dependencies: + '@shikijs/types': 3.7.0 + + '@shikijs/types@3.7.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@types/eslint-scope@3.7.7': + dependencies: + '@types/eslint': 9.6.1 + '@types/estree': 1.0.8 + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + + '@types/estree@1.0.8': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/node@22.15.30': + dependencies: + undici-types: 6.21.0 + + '@types/unist@3.0.3': {} + + '@typescript-eslint/eslint-plugin@8.33.1(@typescript-eslint/parser@8.33.1(eslint@9.28.0)(typescript@5.8.3))(eslint@9.28.0)(typescript@5.8.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.33.1(eslint@9.28.0)(typescript@5.8.3) + '@typescript-eslint/scope-manager': 8.33.1 + '@typescript-eslint/type-utils': 8.33.1(eslint@9.28.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.33.1(eslint@9.28.0)(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.33.1 + eslint: 9.28.0 + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.33.1(eslint@9.28.0)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.33.1 + '@typescript-eslint/types': 8.33.1 + '@typescript-eslint/typescript-estree': 8.33.1(typescript@5.8.3) + '@typescript-eslint/visitor-keys': 8.33.1 + debug: 4.4.1 + eslint: 9.28.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.33.1(typescript@5.8.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.33.1(typescript@5.8.3) + '@typescript-eslint/types': 8.33.1 + debug: 4.4.1 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.33.1': + dependencies: + '@typescript-eslint/types': 8.33.1 + '@typescript-eslint/visitor-keys': 8.33.1 + + '@typescript-eslint/tsconfig-utils@8.33.1(typescript@5.8.3)': + dependencies: + typescript: 5.8.3 + + '@typescript-eslint/type-utils@8.33.1(eslint@9.28.0)(typescript@5.8.3)': + dependencies: + '@typescript-eslint/typescript-estree': 8.33.1(typescript@5.8.3) + '@typescript-eslint/utils': 8.33.1(eslint@9.28.0)(typescript@5.8.3) + debug: 4.4.1 + eslint: 9.28.0 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.33.1': {} + + '@typescript-eslint/typescript-estree@8.33.1(typescript@5.8.3)': + dependencies: + '@typescript-eslint/project-service': 8.33.1(typescript@5.8.3) + '@typescript-eslint/tsconfig-utils': 8.33.1(typescript@5.8.3) + '@typescript-eslint/types': 8.33.1 + '@typescript-eslint/visitor-keys': 8.33.1 + debug: 4.4.1 + fast-glob: 3.3.3 + is-glob: 4.0.3 + minimatch: 9.0.5 + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@5.8.3) + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.33.1(eslint@9.28.0)(typescript@5.8.3)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.28.0) + '@typescript-eslint/scope-manager': 8.33.1 + '@typescript-eslint/types': 8.33.1 + '@typescript-eslint/typescript-estree': 8.33.1(typescript@5.8.3) + eslint: 9.28.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.33.1': + dependencies: + '@typescript-eslint/types': 8.33.1 + eslint-visitor-keys: 4.2.0 + + '@webassemblyjs/ast@1.14.1': + dependencies: + '@webassemblyjs/helper-numbers': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + + '@webassemblyjs/floating-point-hex-parser@1.13.2': {} + + '@webassemblyjs/helper-api-error@1.13.2': {} + + '@webassemblyjs/helper-buffer@1.14.1': {} + + '@webassemblyjs/helper-numbers@1.13.2': + dependencies: + '@webassemblyjs/floating-point-hex-parser': 1.13.2 + '@webassemblyjs/helper-api-error': 1.13.2 + '@xtuc/long': 4.2.2 + + '@webassemblyjs/helper-wasm-bytecode@1.13.2': {} + + '@webassemblyjs/helper-wasm-section@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/wasm-gen': 1.14.1 + + '@webassemblyjs/ieee754@1.13.2': + dependencies: + '@xtuc/ieee754': 1.2.0 + + '@webassemblyjs/leb128@1.13.2': + dependencies: + '@xtuc/long': 4.2.2 + + '@webassemblyjs/utf8@1.13.2': {} + + '@webassemblyjs/wasm-edit@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/helper-wasm-section': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-opt': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + '@webassemblyjs/wast-printer': 1.14.1 + + '@webassemblyjs/wasm-gen@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wasm-opt@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-buffer': 1.14.1 + '@webassemblyjs/wasm-gen': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + + '@webassemblyjs/wasm-parser@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/helper-api-error': 1.13.2 + '@webassemblyjs/helper-wasm-bytecode': 1.13.2 + '@webassemblyjs/ieee754': 1.13.2 + '@webassemblyjs/leb128': 1.13.2 + '@webassemblyjs/utf8': 1.13.2 + + '@webassemblyjs/wast-printer@1.14.1': + dependencies: + '@webassemblyjs/ast': 1.14.1 + '@xtuc/long': 4.2.2 + + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.99.9)': + dependencies: + webpack: 5.99.9(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.99.9) + + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.99.9)': + dependencies: + webpack: 5.99.9(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.99.9) + + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.99.9)': + dependencies: + webpack: 5.99.9(webpack-cli@5.1.4) + webpack-cli: 5.1.4(webpack@5.99.9) + + '@xmldom/xmldom@0.8.10': {} + + '@xmldom/xmldom@0.9.8': {} + + '@xtuc/ieee754@1.2.0': {} + + '@xtuc/long@4.2.2': {} + + acorn-jsx@5.3.2(acorn@8.14.1): + dependencies: + acorn: 8.14.1 + + acorn@8.14.1: {} + + ajv-formats@2.1.1(ajv@8.17.1): + optionalDependencies: + ajv: 8.17.1 + + ajv-keywords@5.1.0(ajv@8.17.1): + dependencies: + ajv: 8.17.1 + fast-deep-equal: 3.1.3 + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ajv@8.17.1: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.0.6 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-escapes@7.0.0: + dependencies: + environment: 1.1.0 + + ansi-regex@5.0.1: {} + + ansi-regex@6.1.0: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.1: {} + + are-docs-informative@0.0.2: {} + + argparse@2.0.1: {} + + asynckit@0.4.0: {} + + axios@1.9.0: + dependencies: + follow-redirects: 1.15.9 + form-data: 4.0.3 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.25.0: + dependencies: + caniuse-lite: 1.0.30001721 + electron-to-chromium: 1.5.165 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.0) + + buffer-from@1.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001721: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.4.1: {} + + chrome-trace-event@1.0.4: {} + + cli-cursor@5.0.0: + dependencies: + restore-cursor: 5.1.0 + + cli-truncate@4.0.0: + dependencies: + slice-ansi: 5.0.0 + string-width: 7.2.0 + + cliui@7.0.4: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clone-deep@4.0.1: + dependencies: + is-plain-object: 2.0.4 + kind-of: 6.0.3 + shallow-clone: 3.0.1 + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@2.0.20: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + commander@10.0.1: {} + + commander@13.1.0: {} + + commander@14.0.0: {} + + commander@2.20.3: {} + + comment-parser@1.4.1: {} + + concat-map@0.0.1: {} + + copyfiles@2.4.1: + dependencies: + glob: 7.2.3 + minimatch: 3.1.2 + mkdirp: 1.0.4 + noms: 0.0.0 + through2: 2.0.5 + untildify: 4.0.0 + yargs: 16.2.0 + + core-util-is@1.0.3: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + deep-is@0.1.4: {} + + delayed-stream@1.0.0: {} + + diff@5.2.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.165: {} + + emoji-regex@10.4.0: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.18.1: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.2.2 + + entities@4.5.0: {} + + envinfo@7.14.0: {} + + environment@1.1.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-formatter-unix@8.40.0: {} + + eslint-plugin-jsdoc@48.11.0(eslint@9.28.0): + dependencies: + '@es-joy/jsdoccomment': 0.46.0 + are-docs-informative: 0.0.2 + comment-parser: 1.4.1 + debug: 4.4.1 + escape-string-regexp: 4.0.0 + eslint: 9.28.0 + espree: 10.3.0 + esquery: 1.6.0 + parse-imports: 2.2.1 + semver: 7.7.2 + spdx-expression-parse: 4.0.0 + synckit: 0.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-prettier@5.4.1(@types/eslint@9.6.1)(eslint@9.28.0)(prettier@3.5.3): + dependencies: + eslint: 9.28.0 + prettier: 3.5.3 + prettier-linter-helpers: 1.0.0 + synckit: 0.11.8 + optionalDependencies: + '@types/eslint': 9.6.1 + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@8.3.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.0: {} + + eslint@9.28.0: + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.28.0) + '@eslint-community/regexpp': 4.12.1 + '@eslint/config-array': 0.20.0 + '@eslint/config-helpers': 0.2.2 + '@eslint/core': 0.14.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.28.0 + '@eslint/plugin-kit': 0.3.1 + '@humanfs/node': 0.16.6 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.1 + escape-string-regexp: 4.0.0 + eslint-scope: 8.3.0 + eslint-visitor-keys: 4.2.0 + espree: 10.3.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + transitivePeerDependencies: + - supports-color + + espree@10.3.0: + dependencies: + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) + eslint-visitor-keys: 4.2.0 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + eventemitter3@5.0.1: {} + + events@3.3.0: {} + + execa@8.0.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 8.0.1 + human-signals: 5.0.0 + is-stream: 3.0.0 + merge-stream: 2.0.0 + npm-run-path: 5.3.0 + onetime: 6.0.0 + signal-exit: 4.1.0 + strip-final-newline: 3.0.0 + + fast-deep-equal@3.1.3: {} + + fast-diff@1.3.0: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.0.6: {} + + fastest-levenshtein@1.0.16: {} + + fastq@1.19.1: + dependencies: + reusify: 1.1.0 + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flat@5.0.2: {} + + flatted@3.3.3: {} + + follow-redirects@1.15.9: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.3: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fs.realpath@1.0.0: {} + + function-bind@1.1.2: {} + + get-caller-file@2.0.5: {} + + get-east-asian-width@1.3.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + get-stream@8.0.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob-to-regexp@0.4.1: {} + + glob@10.4.5: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@14.0.0: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + human-signals@5.0.0: {} + + husky@9.1.7: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + interpret@3.1.1: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-fullwidth-code-point@4.0.0: {} + + is-fullwidth-code-point@5.0.0: + dependencies: + get-east-asian-width: 1.3.0 + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-plain-object@2.0.4: + dependencies: + isobject: 3.0.1 + + is-stream@3.0.0: {} + + isarray@0.0.1: {} + + isarray@1.0.0: {} + + isexe@2.0.0: {} + + isobject@3.0.1: {} + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jest-worker@27.5.1: + dependencies: + '@types/node': 22.15.30 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + js-yaml@4.1.0: + dependencies: + argparse: 2.0.1 + + jsdoc-type-pratt-parser@4.0.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kind-of@6.0.3: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lilconfig@3.1.3: {} + + linkify-it@5.0.0: + dependencies: + uc.micro: 2.1.0 + + lint-staged@15.5.2: + dependencies: + chalk: 5.4.1 + commander: 13.1.0 + debug: 4.4.1 + execa: 8.0.1 + lilconfig: 3.1.3 + listr2: 8.3.3 + micromatch: 4.0.8 + pidtree: 0.6.0 + string-argv: 0.3.2 + yaml: 2.8.0 + transitivePeerDependencies: + - supports-color + + listr2@8.3.3: + dependencies: + cli-truncate: 4.0.0 + colorette: 2.0.20 + eventemitter3: 5.0.1 + log-update: 6.1.0 + rfdc: 1.4.1 + wrap-ansi: 9.0.0 + + loader-runner@4.3.0: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + log-update@6.1.0: + dependencies: + ansi-escapes: 7.0.0 + cli-cursor: 5.0.0 + slice-ansi: 7.1.0 + strip-ansi: 7.1.0 + wrap-ansi: 9.0.0 + + lru-cache@10.4.3: {} + + lunr@2.3.9: {} + + markdown-it@14.1.0: + dependencies: + argparse: 2.0.1 + entities: 4.5.0 + linkify-it: 5.0.0 + mdurl: 2.0.0 + punycode.js: 2.3.1 + uc.micro: 2.1.0 + + math-intrinsics@1.1.0: {} + + mdurl@2.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + mhchemparser@4.2.1: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + + mimic-fn@4.0.0: {} + + mimic-function@5.0.1: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.1 + + minipass@7.1.2: {} + + mj-context-menu@0.9.1: {} + + mkdirp@1.0.4: {} + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + neo-async@2.6.2: {} + + node-releases@2.0.19: {} + + noms@0.0.0: + dependencies: + inherits: 2.0.4 + readable-stream: 1.0.34 + + npm-run-path@5.3.0: + dependencies: + path-key: 4.0.0 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@6.0.0: + dependencies: + mimic-fn: 4.0.0 + + onetime@7.0.0: + dependencies: + mimic-function: 5.0.1 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-imports@2.2.1: + dependencies: + es-module-lexer: 1.7.0 + slashes: 3.0.12 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-key@4.0.0: {} + + path-parse@1.0.7: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pidtree@0.6.0: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + prelude-ls@1.2.1: {} + + prettier-linter-helpers@1.0.0: + dependencies: + fast-diff: 1.3.0 + + prettier@3.5.3: {} + + process-nextick-args@2.0.1: {} + + proxy-from-env@1.1.0: {} + + punycode.js@2.3.1: {} + + punycode@2.3.1: {} + + queue-microtask@1.2.3: {} + + randombytes@2.1.0: + dependencies: + safe-buffer: 5.2.1 + + readable-stream@1.0.34: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 0.0.1 + string_decoder: 0.10.31 + + readable-stream@2.3.8: + dependencies: + core-util-is: 1.0.3 + inherits: 2.0.4 + isarray: 1.0.0 + process-nextick-args: 2.0.1 + safe-buffer: 5.1.2 + string_decoder: 1.1.1 + util-deprecate: 1.0.2 + + rechoir@0.8.0: + dependencies: + resolve: 1.22.10 + + require-directory@2.1.1: {} + + require-from-string@2.0.2: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + restore-cursor@5.1.0: + dependencies: + onetime: 7.0.0 + signal-exit: 4.1.0 + + reusify@1.1.0: {} + + rfdc@1.4.1: {} + + rimraf@5.0.10: + dependencies: + glob: 10.4.5 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + safe-buffer@5.1.2: {} + + safe-buffer@5.2.1: {} + + saxon-js@2.7.0: + dependencies: + axios: 1.9.0 + transitivePeerDependencies: + - debug + + schema-utils@4.3.2: + dependencies: + '@types/json-schema': 7.0.15 + ajv: 8.17.1 + ajv-formats: 2.1.1(ajv@8.17.1) + ajv-keywords: 5.1.0(ajv@8.17.1) + + semver@7.7.2: {} + + serialize-javascript@6.0.2: + dependencies: + randombytes: 2.1.0 + + shallow-clone@3.0.1: + dependencies: + kind-of: 6.0.3 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@4.1.0: {} + + slashes@3.0.12: {} + + slice-ansi@5.0.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 4.0.0 + + slice-ansi@7.1.0: + dependencies: + ansi-styles: 6.2.1 + is-fullwidth-code-point: 5.0.0 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + spdx-exceptions@2.5.0: {} + + spdx-expression-parse@4.0.0: + dependencies: + spdx-exceptions: 2.5.0 + spdx-license-ids: 3.0.21 + + spdx-license-ids@3.0.21: {} + + speech-rule-engine@5.0.0-beta.1: + dependencies: + '@xmldom/xmldom': 0.9.8 + commander: 14.0.0 + wicked-good-xpath: 1.3.0 + + string-argv@0.3.2: {} + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + + string-width@7.2.0: + dependencies: + emoji-regex: 10.4.0 + get-east-asian-width: 1.3.0 + strip-ansi: 7.1.0 + + string_decoder@0.10.31: {} + + string_decoder@1.1.1: + dependencies: + safe-buffer: 5.1.2 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.1.0: + dependencies: + ansi-regex: 6.1.0 + + strip-final-newline@3.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + synckit@0.11.8: + dependencies: + '@pkgr/core': 0.2.7 + + synckit@0.9.3: + dependencies: + '@pkgr/core': 0.1.2 + tslib: 2.8.1 + + tapable@2.2.2: {} + + terser-webpack-plugin@5.3.14(webpack@5.99.9): + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + jest-worker: 27.5.1 + schema-utils: 4.3.2 + serialize-javascript: 6.0.2 + terser: 5.41.0 + webpack: 5.99.9(webpack-cli@5.1.4) + + terser@5.41.0: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.14.1 + commander: 2.20.3 + source-map-support: 0.5.21 + + through2@2.0.5: + dependencies: + readable-stream: 2.3.8 + xtend: 4.0.2 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-api-utils@2.1.0(typescript@5.8.3): + dependencies: + typescript: 5.8.3 + + tslib@2.8.1: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + typedoc@0.28.5(typescript@5.8.3): + dependencies: + '@gerrit0/mini-shiki': 3.7.0 + lunr: 2.3.9 + markdown-it: 14.1.0 + minimatch: 9.0.5 + typescript: 5.8.3 + yaml: 2.8.0 + + typescript-eslint@8.33.1(eslint@9.28.0)(typescript@5.8.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.33.1(@typescript-eslint/parser@8.33.1(eslint@9.28.0)(typescript@5.8.3))(eslint@9.28.0)(typescript@5.8.3) + '@typescript-eslint/parser': 8.33.1(eslint@9.28.0)(typescript@5.8.3) + '@typescript-eslint/utils': 8.33.1(eslint@9.28.0)(typescript@5.8.3) + eslint: 9.28.0 + typescript: 5.8.3 + transitivePeerDependencies: + - supports-color + + typescript-tools@0.3.1: {} + + typescript@5.8.3: {} + + uc.micro@2.1.0: {} + + undici-types@6.21.0: {} + + untildify@4.0.0: {} + + update-browserslist-db@1.1.3(browserslist@4.25.0): + dependencies: + browserslist: 4.25.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + util-deprecate@1.0.2: {} + + watchpack@2.4.4: + dependencies: + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + + webpack-cli@5.1.4(webpack@5.99.9): + dependencies: + '@discoveryjs/json-ext': 0.5.7 + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.99.9) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.99.9) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.99.9) + colorette: 2.0.20 + commander: 10.0.1 + cross-spawn: 7.0.6 + envinfo: 7.14.0 + fastest-levenshtein: 1.0.16 + import-local: 3.2.0 + interpret: 3.1.1 + rechoir: 0.8.0 + webpack: 5.99.9(webpack-cli@5.1.4) + webpack-merge: 5.10.0 + + webpack-merge@5.10.0: + dependencies: + clone-deep: 4.0.1 + flat: 5.0.2 + wildcard: 2.0.1 + + webpack-sources@3.3.2: {} + + webpack@5.99.9(webpack-cli@5.1.4): + dependencies: + '@types/eslint-scope': 3.7.7 + '@types/estree': 1.0.8 + '@types/json-schema': 7.0.15 + '@webassemblyjs/ast': 1.14.1 + '@webassemblyjs/wasm-edit': 1.14.1 + '@webassemblyjs/wasm-parser': 1.14.1 + acorn: 8.14.1 + browserslist: 4.25.0 + chrome-trace-event: 1.0.4 + enhanced-resolve: 5.18.1 + es-module-lexer: 1.7.0 + eslint-scope: 5.1.1 + events: 3.3.0 + glob-to-regexp: 0.4.1 + graceful-fs: 4.2.11 + json-parse-even-better-errors: 2.3.1 + loader-runner: 4.3.0 + mime-types: 2.1.35 + neo-async: 2.6.2 + schema-utils: 4.3.2 + tapable: 2.2.2 + terser-webpack-plugin: 5.3.14(webpack@5.99.9) + watchpack: 2.4.4 + webpack-sources: 3.3.2 + optionalDependencies: + webpack-cli: 5.1.4(webpack@5.99.9) + transitivePeerDependencies: + - '@swc/core' + - esbuild + - uglify-js + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wicked-good-xpath@1.3.0: {} + + wildcard@2.0.1: {} + + word-wrap@1.2.5: {} + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + + wrap-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.1 + string-width: 7.2.0 + strip-ansi: 7.1.0 + + wrappy@1.0.2: {} + + xslt3@2.7.0: + dependencies: + axios: 1.9.0 + saxon-js: 2.7.0 + transitivePeerDependencies: + - debug + + xtend@4.0.2: {} + + y18n@5.0.8: {} + + yaml@2.8.0: {} + + yargs-parser@20.2.9: {} + + yargs@16.2.0: + dependencies: + cliui: 7.0.4 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 20.2.9 + + yocto-queue@0.1.0: {} diff --git a/testsuite/jest.config.mjs b/testsuite/jest.config.mjs new file mode 100644 index 000000000..71e4fb11b --- /dev/null +++ b/testsuite/jest.config.mjs @@ -0,0 +1,32 @@ +/** + * For a detailed explanation regarding each configuration property, visit: + * https://jestjs.io/docs/configuration + */ + +import * as path from 'path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const tsjest = path.resolve(__dirname, 'node_modules', 'ts-jest'); + +const config = { + rootDir: '..', + clearMocks: true, + collectCoverage: true, + coverageDirectory: 'coverage', + coverageProvider: 'v8', + coveragePathIgnorePatterns: ['node_modules', 'testsuite', 'mjs/util/entities'], + testEnvironment: 'node', + preset: tsjest, + testMatch: [ + '**/tests/**/*.test.ts' + ], + extensionsToTreatAsEsm: ['.ts'], + transform: { + '^.+\\.tsx?$': [ tsjest, { useESM: true, tsconfig: './tsconfig.json' } ], + }, + reporters: ['default', [path.resolve(__dirname, 'src/texReporter.js'), {}]] +}; + +export default config; diff --git a/testsuite/lib/AsyncLoad.child.cjs b/testsuite/lib/AsyncLoad.child.cjs new file mode 100644 index 000000000..c67f38605 --- /dev/null +++ b/testsuite/lib/AsyncLoad.child.cjs @@ -0,0 +1,3 @@ +module.exports = { + loaded: true +}; diff --git a/testsuite/lib/AsyncLoad.child.mjs b/testsuite/lib/AsyncLoad.child.mjs new file mode 100644 index 000000000..e67d2a017 --- /dev/null +++ b/testsuite/lib/AsyncLoad.child.mjs @@ -0,0 +1 @@ +export const loaded = true; diff --git a/testsuite/lib/error.js b/testsuite/lib/error.js new file mode 100644 index 000000000..7f06b4d2c --- /dev/null +++ b/testsuite/lib/error.js @@ -0,0 +1,10 @@ +import {Configuration} from '#js/input/tex/Configuration.js'; +import {ConfigurationType} from '#js/input/tex/HandlerTypes.js'; + +import {VERSION} from '#js/components/version.js'; + +MathJax.loader.checkVersion('[tex]/error', VERSION, 'tex-extension'); + +Configuration.create('error', { + [ConfigurationType.CONFIG]: () => {throw new Error('Error in Dependency')} +}); diff --git a/testsuite/package.json b/testsuite/package.json new file mode 100644 index 000000000..ef7e0abda --- /dev/null +++ b/testsuite/package.json @@ -0,0 +1,24 @@ +{ + "name": "MathJax jest", + "version": "1.0.0", + "description": "MathJax jest tests for v4", + "type": "module", + "scripts": { + "test": "NODE_OPTIONS='--experimental-vm-modules --no-warnings' pnpm jest" + }, + "imports": { + "#js/*": "../mjs/*", + "#source/*": "../components/mjs/*", + "#src/*": "./src/*", + "#helpers": "./js/src/index.js" + }, + "dependencies": { + "@jest/globals": "^29.7.0", + "@mathjax/mathjax-bbm-font-extension": "0.4.2-beta.8", + "@types/jest": "^29.5.14", + "jest": "^29.7.0", + "ts-jest": "^29.3.4", + "ts-node": "^10.9.2", + "xml-js": "^1.6.11" + } +} diff --git a/testsuite/pnpm-lock.yaml b/testsuite/pnpm-lock.yaml new file mode 100644 index 000000000..9a5d25485 --- /dev/null +++ b/testsuite/pnpm-lock.yaml @@ -0,0 +1,2725 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@jest/globals': + specifier: ^29.7.0 + version: 29.7.0 + '@mathjax/mathjax-bbm-font-extension': + specifier: 0.4.2-beta.8 + version: 0.4.2-beta.8 + '@types/jest': + specifier: ^29.5.14 + version: 29.5.14 + jest: + specifier: ^29.7.0 + version: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + ts-jest: + specifier: ^29.3.4 + version: 29.3.4(@babel/core@7.27.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.4))(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)))(typescript@5.4.5) + ts-node: + specifier: ^10.9.2 + version: 10.9.2(@types/node@22.15.29)(typescript@5.4.5) + xml-js: + specifier: ^1.6.11 + version: 1.6.11 + +packages: + + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.27.5': + resolution: {integrity: sha512-KiRAp/VoJaWkkte84TvUd9qjdbZAdiqyvMxrGl1N6vzFogKmaLgoM3L1kgtLicp2HP5fBJS8JrZKLVIZGVJAVg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.27.4': + resolution: {integrity: sha512-bXYxrXFubeYdvB0NhD/NBB3Qi6aZeV20GOWVI47t2dkecCEoneR4NPVcb7abpXDEvejgrUfFtG6vG/zxAKmg+g==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.27.5': + resolution: {integrity: sha512-ZGhA37l0e/g2s1Cnzdix0O3aLYm66eF8aufiVteOgnwxgnRP8GoyMj7VWsgWnQbVKXyge7hqrFh2K2TQM6t1Hw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.27.3': + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.27.1': + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.27.6': + resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.27.5': + resolution: {integrity: sha512-OsQd175SxWkGlzbny8J3K8TnnDD0N3lrIUtB92xwyRpzaenGZhxDvxN/JgU00U3CDZNj9tPuDJ5H0WS4Nt3vKg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.27.1': + resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.27.1': + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.27.1': + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.27.4': + resolution: {integrity: sha512-oNcu2QbHqts9BtOWJosOVJapWjBDSxGCpFvikNR5TGDYDQf3JwpIoMzIKrvfoti93cLfPJEG4tH9SPVeyCGgdA==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.27.6': + resolution: {integrity: sha512-ETyHEk2VHHvl9b9jZP5IHPavHYk57EhanlRRuae9XCpb/j5bDCbPPMOBfCWhnl/7EDJz0jEMCi/RhccCE8r1+Q==} + engines: {node: '>=6.9.0'} + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jest/console@29.7.0': + resolution: {integrity: sha512-5Ni4CU7XHQi32IJ398EEP4RrB8eV09sXP2ROqD4bksHrnTree52PsxvX8tpL8LvTZ3pFzXyPbNQReSN41CAhOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/core@29.7.0': + resolution: {integrity: sha512-n7aeXWKMnGtDA48y8TLWJPJmLmmZ642Ceo78cYWEpiD7FzDgmNDV/GCVRorPABdXLJZ/9wzzgZAlHjXjxDHGsg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/environment@29.7.0': + resolution: {integrity: sha512-aQIfHDq33ExsN4jP1NWGXhxgQ/wixs60gDiKO+XVMd8Mn0NWPWgc34ZQDTb2jKaUWQ7MuwoitXAsN2XVXNMpAw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect-utils@29.7.0': + resolution: {integrity: sha512-GlsNBWiFQFCVi9QVSx7f5AgMeLxe9YCCs5PuP2O2LdjDAA8Jh9eX7lA1Jq/xdXw3Wb3hyvlFNfZIfcRetSzYcA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/expect@29.7.0': + resolution: {integrity: sha512-8uMeAMycttpva3P1lBHB8VciS9V0XAr3GymPpipdyQXbBcuhkLQOSe8E/p92RyAdToS6ZD1tFkX+CkhoECE0dQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/fake-timers@29.7.0': + resolution: {integrity: sha512-q4DH1Ha4TTFPdxLsqDXK1d3+ioSL7yL5oCMJZgDYm6i+6CygW5E5xVr/D1HdsGxjt1ZWSfUAs9OxSB/BNelWrQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/globals@29.7.0': + resolution: {integrity: sha512-mpiz3dutLbkW2MNFubUGUEVLkTGiqW6yLVTA+JbP6fI6J5iL9Y0Nlg8k95pcF8ctKwCS7WVxteBs29hhfAotzQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/reporters@29.7.0': + resolution: {integrity: sha512-DApq0KJbJOEzAFYjHADNNxAE3KbhxQB1y5Kplb5Waqw6zVbuWatSnMjE5gs8FUgEPmNsnZA3NCWl9NG0ia04Pg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/source-map@29.6.3': + resolution: {integrity: sha512-MHjT95QuipcPrpLM+8JMSzFx6eHp5Bm+4XeFDJlwsvVBjmKNiIAvasGK2fxz2WbGRlnvqehFbh07MMa7n3YJnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-result@29.7.0': + resolution: {integrity: sha512-Fdx+tv6x1zlkJPcWXmMDAG2HBnaR9XPSd5aDWQVsfrZmLVT3lU1cwyxLgRmXR9yrq4NBoEm9BMsfgFzTQAbJYA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/test-sequencer@29.7.0': + resolution: {integrity: sha512-GQwJ5WZVrKnOJuiYiAF52UNUJXgTZx1NHjFSEB0qEMmSZKAkdMoIzw/Cj6x6NF4AvV23AUqDpFzQkN/eYCYTxw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/transform@29.7.0': + resolution: {integrity: sha512-ok/BTPFzFKVMwO5eOHRrvnBVHdRy9IrsrW1GpMaQ9MCnilNLXQKmAX8s1YXDFaai9xJpac2ySzV0YeRRECr2Vw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jridgewell/gen-mapping@0.3.8': + resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} + engines: {node: '>=6.0.0'} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/set-array@1.2.1': + resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@jridgewell/trace-mapping@0.3.25': + resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + + '@mathjax/mathjax-bbm-font-extension@0.4.2-beta.8': + resolution: {integrity: sha512-FU/M4IJ6dRCRxxfnxRSAwWgEEvcpgqqzupiSe3JW8TCl2zR0co3zaYtO1oaHGrmmlqAkARPRJnpxViIWhfPr6A==} + + '@sinclair/typebox@0.27.8': + resolution: {integrity: sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@10.3.0': + resolution: {integrity: sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==} + + '@tsconfig/node10@1.0.11': + resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==} + + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} + + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} + + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.20.7': + resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} + + '@types/graceful-fs@4.1.9': + resolution: {integrity: sha512-olP3sd1qOEe5dXTSaFvQG+02VdRXcdytWLAZsAq1PecU8uqQAhkrnbli7DagjtXKW/Bl7YJbUsa8MPcuc8LHEQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/jest@29.5.14': + resolution: {integrity: sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==} + + '@types/node@22.15.29': + resolution: {integrity: sha512-LNdjOkUDlU1RZb8e1kOIUpN1qQUlzGkEtbVNo53vbrwDg5om6oduhm4SiUaPW5ASTXhAiP0jInWG8Qx9fVlOeQ==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.33': + resolution: {integrity: sha512-WpxBCKWPLr4xSsHgz511rFJAM+wS28w2zEO1QDNY5zM/S8ok70NNfztH0xwhqKyaK0OHCbN98LDAZuy1ctxDkA==} + + acorn-walk@8.3.4: + resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} + engines: {node: '>=0.4.0'} + + acorn@8.14.1: + resolution: {integrity: sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==} + engines: {node: '>=0.4.0'} + hasBin: true + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + async@3.2.6: + resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + + babel-jest@29.7.0: + resolution: {integrity: sha512-BrvGY3xZSwEcCzKvKsCi2GgHqDqsYkOP4/by5xCgIwGXQxIEh+8ew3gmrE1y7XRR6LHZIj6yLYnUi/mm2KXKBg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.8.0 + + babel-plugin-istanbul@6.1.1: + resolution: {integrity: sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==} + engines: {node: '>=8'} + + babel-plugin-jest-hoist@29.6.3: + resolution: {integrity: sha512-ESAc/RJvGTFEzRwOTT4+lNDk/GNHMkKbNzsvT0qKRfDyyYTskxB5rnU2njIDYVxXCBHHEI1c0YwHob3WaYujOg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + babel-preset-current-node-syntax@1.1.0: + resolution: {integrity: sha512-ldYss8SbBlWva1bs28q78Ju5Zq1F+8BrqBZZ0VFhLBvhh6lCpC2o3gDJi/5DRLs9FgYZCnmPYIVFU4lRXCkyUw==} + peerDependencies: + '@babel/core': ^7.0.0 + + babel-preset-jest@29.6.3: + resolution: {integrity: sha512-0B3bhxR6snWXJZtR/RliHTDPRgn1sNHOR0yVtq/IiQFyuOVjFS+wuio/R4gSNkyYmKmJB4wGZv2NZanmKmTnNA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@babel/core': ^7.0.0 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + brace-expansion@2.0.1: + resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.25.0: + resolution: {integrity: sha512-PJ8gYKeS5e/whHBh8xrwYK+dAvEj7JXtz6uTucnMRB8OiGTsKccFekoRrjajPBHV8oOY+2tI4uxeceSimKwMFA==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs-logger@0.2.6: + resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} + engines: {node: '>= 6'} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001721: + resolution: {integrity: sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + cjs-module-lexer@1.4.3: + resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + collect-v8-coverage@1.0.2: + resolution: {integrity: sha512-lHl4d5/ONEbLlJvaJNtsF/Lz+WvB07u2ycqTYbdrq7UypDXailES4valYb2eWiJFxZlVmpGekfqoxQhzyFdT4Q==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + create-jest@29.7.0: + resolution: {integrity: sha512-Adz2bdH0Vq3F53KEMJOoftQFutWCukm6J24wbPWRO4k1kMY7gS7ds/uoJkNuV8wDCtWWnuwGcJwpWcih+zEW1Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + dedent@1.6.0: + resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + diff-sequences@29.6.3: + resolution: {integrity: sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + diff@4.0.2: + resolution: {integrity: sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==} + engines: {node: '>=0.3.1'} + + ejs@3.1.10: + resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} + engines: {node: '>=0.10.0'} + hasBin: true + + electron-to-chromium@1.5.165: + resolution: {integrity: sha512-naiMx1Z6Nb2TxPU6fiFrUrDTjyPMLdTtaOd2oLmG8zVSg2hCWGkhPyxwk+qRmZ1ytwVqUv0u7ZcDA5+ALhaUtw==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + error-ex@1.3.2: + resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit@0.1.2: + resolution: {integrity: sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==} + engines: {node: '>= 0.8.0'} + + expect@29.7.0: + resolution: {integrity: sha512-2Zks0hf1VLFYI1kbh0I5jP3KHHyCHpkfyHBzsSXRFgl/Bg9mWYfMW8oD+PdMPlEwy5HNsR9JutYy6pMeOh61nw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + filelist@1.0.4: + resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Glob versions prior to v9 are no longer supported + + globals@11.12.0: + resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} + engines: {node: '>=4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@5.2.1: + resolution: {integrity: sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@4.0.1: + resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} + engines: {node: '>=10'} + + istanbul-reports@3.1.7: + resolution: {integrity: sha512-BewmUXImeuRk2YY0PVbxgKAysvhRPUQE0h5QRM++nVWyubKGV0l8qQ5op8+B2DOmwSe63Jivj0BjkPQVf8fP5g==} + engines: {node: '>=8'} + + jake@10.9.2: + resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} + engines: {node: '>=10'} + hasBin: true + + jest-changed-files@29.7.0: + resolution: {integrity: sha512-fEArFiwf1BpQ+4bXSprcDc3/x4HSzL4al2tozwVpDFpsxALjLYdyiIK4e5Vz66GQJIbXJ82+35PtysofptNX2w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-circus@29.7.0: + resolution: {integrity: sha512-3E1nCMgipcTkCocFwM90XXQab9bS+GMsjdpmPrlelaxwD93Ad8iVEjX/vvHPdLPnFf+L40u+5+iutRdA1N9myw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-cli@29.7.0: + resolution: {integrity: sha512-OVVobw2IubN/GSYsxETi+gOe7Ka59EFMR/twOU3Jb2GnKKeMGJB5SGUUrEz3SFVmJASUdZUzy83sLNNQ2gZslg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@29.7.0: + resolution: {integrity: sha512-uXbpfeQ7R6TZBqI3/TxCU4q4ttk3u0PJeC+E0zbfSoSjq6bJ7buBPxzQPL0ifrkY4DNu4JUdk0ImlBUYi840eQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + peerDependencies: + '@types/node': '*' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + ts-node: + optional: true + + jest-diff@29.7.0: + resolution: {integrity: sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-docblock@29.7.0: + resolution: {integrity: sha512-q617Auw3A612guyaFgsbFeYpNP5t2aoUNLwBUbc/0kD1R4t9ixDbyFTHd1nok4epoVFpr7PmeWHrhvuV3XaJ4g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-each@29.7.0: + resolution: {integrity: sha512-gns+Er14+ZrEoC5fhOfYCY1LOHHr0TI+rQUHZS8Ttw2l7gl+80eHc/gFf2Ktkw0+SIACDTeWvpFcv3B04VembQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-environment-node@29.7.0: + resolution: {integrity: sha512-DOSwCRqXirTOyheM+4d5YZOrWcdu0LNZ87ewUoywbcb2XR4wKgqiG8vNeYwhjFMbEkfju7wx2GYH0P2gevGvFw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@29.7.0: + resolution: {integrity: sha512-fP8u2pyfqx0K1rGn1R9pyE0/KTn+G7PxktWidOBTqFPLYX0b9ksaMFkhK5vrS3DVun09pckLdlx90QthlW7AmA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-leak-detector@29.7.0: + resolution: {integrity: sha512-kYA8IJcSYtST2BY9I+SMC32nDpBT3J2NvWJx8+JCuCdl/CR1I4EKUJROiP8XtCcxqgTTBGJNdbB1A8XRKbTetw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-matcher-utils@29.7.0: + resolution: {integrity: sha512-sBkD+Xi9DtcChsI3L3u0+N0opgPYnCRPtGcQYrgXmR+hmt/fYfWAL0xRXYU8eWOdfuLgBe0YCW3AFtnRLagq/g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-message-util@29.7.0: + resolution: {integrity: sha512-GBEV4GRADeP+qtB2+6u61stea8mGcOT4mCtrYISZwfu9/ISHFJ/5zOMXYbpBE9RsS5+Gb63DW4FgmnKJ79Kf6w==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-mock@29.7.0: + resolution: {integrity: sha512-ITOMZn+UkYS4ZFh83xYAOzWStloNzJFO2s8DWrE4lhtGD+AorgnbkiKERe4wQVBydIGPx059g6riW5Btp6Llnw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@29.6.3: + resolution: {integrity: sha512-KJJBsRCyyLNWCNBOvZyRDnAIfUiRJ8v+hOBQYGn8gDyF3UegwiP4gwRR3/SDa42g1YbVycTidUF3rKjyLFDWbg==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve-dependencies@29.7.0: + resolution: {integrity: sha512-un0zD/6qxJ+S0et7WxeI3H5XSe9lTBBR7bOHCHXkKR6luG5mwDDlIzVQ0V5cZCuoTgEdcdwzTghYkTWfubi+nA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-resolve@29.7.0: + resolution: {integrity: sha512-IOVhZSrg+UvVAshDSDtHyFCCBUl/Q3AAJv8iZ6ZjnZ74xzvwuzLXid9IIIPgTnY62SJjfuupMKZsZQRsCvxEgA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runner@29.7.0: + resolution: {integrity: sha512-fsc4N6cPCAahybGBfTRcq5wFR6fpLznMg47sY5aDpsoejOcVYFb07AHuSnR0liMcPTgBsA3ZJL6kFOjPdoNipQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-runtime@29.7.0: + resolution: {integrity: sha512-gUnLjgwdGqW7B4LvOIkbKs9WGbn+QLqRQQ9juC6HndeDiezIwhDP+mhMwHWCEcfQ5RUXa6OPnFF8BJh5xegwwQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-snapshot@29.7.0: + resolution: {integrity: sha512-Rm0BMWtxBcioHr1/OX5YCP8Uov4riHvKPknOGs804Zg9JGZgmIBkbtlxJC/7Z4msKYVbIJtfU+tKb8xlYNfdkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-watcher@29.7.0: + resolution: {integrity: sha512-49Fg7WXkU3Vl2h6LbLtMQ/HyB6rXSIX7SqvBLQmssRBGN9I0PNvPmAmCWSOY6SOvrjhI/F7/bGAv9RtnsPA03g==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest@29.7.0: + resolution: {integrity: sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.1: + resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==} + hasBin: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + resolve.exports@2.0.3: + resolution: {integrity: sha512-OcXjMsGdhL4XnbShKpAcSqPMzQoYkYyhbEaeSko47MjRP9NfEQMhZkXL1DoFlt9LWQn4YttrdnV6X2OiyzBi+A==} + engines: {node: '>=10'} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + sax@1.4.1: + resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + ts-jest@29.3.4: + resolution: {integrity: sha512-Iqbrm8IXOmV+ggWHOTEbjwyCf2xZlUMv5npExksXohL+tk8va4Fjhb+X2+Rt9NBmgO7bJ8WpnMLOwih/DnMlFA==} + engines: {node: ^14.15.0 || ^16.10.0 || ^18.0.0 || >=20.0.0} + hasBin: true + peerDependencies: + '@babel/core': '>=7.0.0-beta.0 <8' + '@jest/transform': ^29.0.0 + '@jest/types': ^29.0.0 + babel-jest: ^29.0.0 + esbuild: '*' + jest: ^29.0.0 + typescript: '>=4.3 <6' + peerDependenciesMeta: + '@babel/core': + optional: true + '@jest/transform': + optional: true + '@jest/types': + optional: true + babel-jest: + optional: true + esbuild: + optional: true + + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true + peerDependencies: + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' + peerDependenciesMeta: + '@swc/core': + optional: true + '@swc/wasm': + optional: true + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@4.0.2: + resolution: {integrity: sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==} + engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + + xml-js@1.6.11: + resolution: {integrity: sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g==} + hasBin: true + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.27.5': {} + + '@babel/core@7.27.4': + dependencies: + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.27.4) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.27.5': + dependencies: + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.27.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.27.4 + '@babel/types': 7.27.6 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.27.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.27.4 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.27.1': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.27.6': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 + + '@babel/parser@7.27.5': + dependencies: + '@babel/types': 7.27.6 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.27.4)': + dependencies: + '@babel/core': 7.27.4 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 + + '@babel/traverse@7.27.4': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.27.5 + '@babel/parser': 7.27.5 + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 + debug: 4.4.1 + globals: 11.12.0 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.27.6': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + + '@bcoe/v8-coverage@0.2.3': {} + + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.1 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jest/console@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + chalk: 4.1.2 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + + '@jest/core@29.7.0(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5))': + dependencies: + '@jest/console': 29.7.0 + '@jest/reporters': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 3.9.0 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-changed-files: 29.7.0 + jest-config: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-resolve-dependencies: 29.7.0 + jest-runner: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + jest-watcher: 29.7.0 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-ansi: 6.0.1 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + - ts-node + + '@jest/environment@29.7.0': + dependencies: + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + jest-mock: 29.7.0 + + '@jest/expect-utils@29.7.0': + dependencies: + jest-get-type: 29.6.3 + + '@jest/expect@29.7.0': + dependencies: + expect: 29.7.0 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@29.7.0': + dependencies: + '@jest/types': 29.6.3 + '@sinonjs/fake-timers': 10.3.0 + '@types/node': 22.15.29 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + '@jest/globals@29.7.0': + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/types': 29.6.3 + jest-mock: 29.7.0 + transitivePeerDependencies: + - supports-color + + '@jest/reporters@29.7.0': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + '@types/node': 22.15.29 + chalk: 4.1.2 + collect-v8-coverage: 1.0.2 + exit: 0.1.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 4.0.1 + istanbul-reports: 3.1.7 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + jest-worker: 29.7.0 + slash: 3.0.0 + string-length: 4.0.2 + strip-ansi: 6.0.1 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.8 + + '@jest/source-map@29.6.3': + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@29.7.0': + dependencies: + '@jest/console': 29.7.0 + '@jest/types': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.2 + + '@jest/test-sequencer@29.7.0': + dependencies: + '@jest/test-result': 29.7.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + slash: 3.0.0 + + '@jest/transform@29.7.0': + dependencies: + '@babel/core': 7.27.4 + '@jest/types': 29.6.3 + '@jridgewell/trace-mapping': 0.3.25 + babel-plugin-istanbul: 6.1.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + micromatch: 4.0.8 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 4.0.2 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.15.29 + '@types/yargs': 17.0.33 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.8': + dependencies: + '@jridgewell/set-array': 1.2.1 + '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/trace-mapping': 0.3.25 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/set-array@1.2.1': {} + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@jridgewell/trace-mapping@0.3.25': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@jridgewell/trace-mapping@0.3.9': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.0 + + '@mathjax/mathjax-bbm-font-extension@0.4.2-beta.8': {} + + '@sinclair/typebox@0.27.8': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@10.3.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@tsconfig/node10@1.0.11': {} + + '@tsconfig/node12@1.0.11': {} + + '@tsconfig/node14@1.0.3': {} + + '@tsconfig/node16@1.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.20.7 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.27.6 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.27.5 + '@babel/types': 7.27.6 + + '@types/babel__traverse@7.20.7': + dependencies: + '@babel/types': 7.27.6 + + '@types/graceful-fs@4.1.9': + dependencies: + '@types/node': 22.15.29 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/jest@29.5.14': + dependencies: + expect: 29.7.0 + pretty-format: 29.7.0 + + '@types/node@22.15.29': + dependencies: + undici-types: 6.21.0 + + '@types/stack-utils@2.0.3': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.33': + dependencies: + '@types/yargs-parser': 21.0.3 + + acorn-walk@8.3.4: + dependencies: + acorn: 8.14.1 + + acorn@8.14.1: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + + arg@4.1.3: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + async@3.2.6: {} + + babel-jest@29.7.0(@babel/core@7.27.4): + dependencies: + '@babel/core': 7.27.4 + '@jest/transform': 29.7.0 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 6.1.1 + babel-preset-jest: 29.6.3(@babel/core@7.27.4) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@6.1.1: + dependencies: + '@babel/helper-plugin-utils': 7.27.1 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-instrument: 5.2.1 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@29.6.3: + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.27.6 + '@types/babel__core': 7.20.5 + '@types/babel__traverse': 7.20.7 + + babel-preset-current-node-syntax@1.1.0(@babel/core@7.27.4): + dependencies: + '@babel/core': 7.27.4 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.27.4) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.27.4) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.27.4) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.27.4) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.27.4) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.27.4) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.27.4) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.27.4) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.27.4) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.27.4) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.27.4) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.27.4) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.27.4) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.27.4) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.27.4) + + babel-preset-jest@29.6.3(@babel/core@7.27.4): + dependencies: + '@babel/core': 7.27.4 + babel-plugin-jest-hoist: 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.4) + + balanced-match@1.0.2: {} + + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.25.0: + dependencies: + caniuse-lite: 1.0.30001721 + electron-to-chromium: 1.5.165 + node-releases: 2.0.19 + update-browserslist-db: 1.1.3(browserslist@4.25.0) + + bs-logger@0.2.6: + dependencies: + fast-json-stable-stringify: 2.1.0 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + caniuse-lite@1.0.30001721: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + char-regex@1.0.2: {} + + ci-info@3.9.0: {} + + cjs-module-lexer@1.4.3: {} + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + co@4.6.0: {} + + collect-v8-coverage@1.0.2: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + concat-map@0.0.1: {} + + convert-source-map@2.0.0: {} + + create-jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)): + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + exit: 0.1.2 + graceful-fs: 4.2.11 + jest-config: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + jest-util: 29.7.0 + prompts: 2.4.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + create-require@1.1.1: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.1: + dependencies: + ms: 2.1.3 + + dedent@1.6.0: {} + + deepmerge@4.3.1: {} + + detect-newline@3.1.0: {} + + diff-sequences@29.6.3: {} + + diff@4.0.2: {} + + ejs@3.1.10: + dependencies: + jake: 10.9.2 + + electron-to-chromium@1.5.165: {} + + emittery@0.13.1: {} + + emoji-regex@8.0.0: {} + + error-ex@1.3.2: + dependencies: + is-arrayish: 0.2.1 + + escalade@3.2.0: {} + + escape-string-regexp@2.0.0: {} + + esprima@4.0.1: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit@0.1.2: {} + + expect@29.7.0: + dependencies: + '@jest/expect-utils': 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + + fast-json-stable-stringify@2.1.0: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + filelist@1.0.4: + dependencies: + minimatch: 5.1.6 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + fs.realpath@1.0.0: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-package-type@0.1.0: {} + + get-stream@6.0.1: {} + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 3.1.2 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@11.12.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + html-escaper@2.0.2: {} + + human-signals@2.1.0: {} + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + is-arrayish@0.2.1: {} + + is-core-module@2.16.1: + dependencies: + hasown: 2.0.2 + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-number@7.0.0: {} + + is-stream@2.0.1: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@5.2.1: + dependencies: + '@babel/core': 7.27.4 + '@babel/parser': 7.27.5 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.27.4 + '@babel/parser': 7.27.5 + '@istanbuljs/schema': 0.1.3 + istanbul-lib-coverage: 3.2.2 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@4.0.1: + dependencies: + debug: 4.4.1 + istanbul-lib-coverage: 3.2.2 + source-map: 0.6.1 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.1.7: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jake@10.9.2: + dependencies: + async: 3.2.6 + chalk: 4.1.2 + filelist: 1.0.4 + minimatch: 3.1.2 + + jest-changed-files@29.7.0: + dependencies: + execa: 5.1.1 + jest-util: 29.7.0 + p-limit: 3.1.0 + + jest-circus@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/expect': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.6.0 + is-generator-fn: 2.1.0 + jest-each: 29.7.0 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-runtime: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + p-limit: 3.1.0 + pretty-format: 29.7.0 + pure-rand: 6.1.0 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + chalk: 4.1.2 + create-jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + exit: 0.1.2 + import-local: 3.2.0 + jest-config: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + jest-util: 29.7.0 + jest-validate: 29.7.0 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + jest-config@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)): + dependencies: + '@babel/core': 7.27.4 + '@jest/test-sequencer': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.27.4) + chalk: 4.1.2 + ci-info: 3.9.0 + deepmerge: 4.3.1 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-circus: 29.7.0 + jest-environment-node: 29.7.0 + jest-get-type: 29.6.3 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-runner: 29.7.0 + jest-util: 29.7.0 + jest-validate: 29.7.0 + micromatch: 4.0.8 + parse-json: 5.2.0 + pretty-format: 29.7.0 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 22.15.29 + ts-node: 10.9.2(@types/node@22.15.29)(typescript@5.4.5) + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@29.7.0: + dependencies: + chalk: 4.1.2 + diff-sequences: 29.6.3 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-docblock@29.7.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@29.7.0: + dependencies: + '@jest/types': 29.6.3 + chalk: 4.1.2 + jest-get-type: 29.6.3 + jest-util: 29.7.0 + pretty-format: 29.7.0 + + jest-environment-node@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + jest-mock: 29.7.0 + jest-util: 29.7.0 + + jest-get-type@29.6.3: {} + + jest-haste-map@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/graceful-fs': 4.1.9 + '@types/node': 22.15.29 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 29.6.3 + jest-util: 29.7.0 + jest-worker: 29.7.0 + micromatch: 4.0.8 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@29.7.0: + dependencies: + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-matcher-utils@29.7.0: + dependencies: + chalk: 4.1.2 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + pretty-format: 29.7.0 + + jest-message-util@29.7.0: + dependencies: + '@babel/code-frame': 7.27.1 + '@jest/types': 29.6.3 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + micromatch: 4.0.8 + pretty-format: 29.7.0 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + jest-util: 29.7.0 + + jest-pnp-resolver@1.2.3(jest-resolve@29.7.0): + optionalDependencies: + jest-resolve: 29.7.0 + + jest-regex-util@29.6.3: {} + + jest-resolve-dependencies@29.7.0: + dependencies: + jest-regex-util: 29.6.3 + jest-snapshot: 29.7.0 + transitivePeerDependencies: + - supports-color + + jest-resolve@29.7.0: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-pnp-resolver: 1.2.3(jest-resolve@29.7.0) + jest-util: 29.7.0 + jest-validate: 29.7.0 + resolve: 1.22.10 + resolve.exports: 2.0.3 + slash: 3.0.0 + + jest-runner@29.7.0: + dependencies: + '@jest/console': 29.7.0 + '@jest/environment': 29.7.0 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + chalk: 4.1.2 + emittery: 0.13.1 + graceful-fs: 4.2.11 + jest-docblock: 29.7.0 + jest-environment-node: 29.7.0 + jest-haste-map: 29.7.0 + jest-leak-detector: 29.7.0 + jest-message-util: 29.7.0 + jest-resolve: 29.7.0 + jest-runtime: 29.7.0 + jest-util: 29.7.0 + jest-watcher: 29.7.0 + jest-worker: 29.7.0 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@29.7.0: + dependencies: + '@jest/environment': 29.7.0 + '@jest/fake-timers': 29.7.0 + '@jest/globals': 29.7.0 + '@jest/source-map': 29.6.3 + '@jest/test-result': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + chalk: 4.1.2 + cjs-module-lexer: 1.4.3 + collect-v8-coverage: 1.0.2 + glob: 7.2.3 + graceful-fs: 4.2.11 + jest-haste-map: 29.7.0 + jest-message-util: 29.7.0 + jest-mock: 29.7.0 + jest-regex-util: 29.6.3 + jest-resolve: 29.7.0 + jest-snapshot: 29.7.0 + jest-util: 29.7.0 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@29.7.0: + dependencies: + '@babel/core': 7.27.4 + '@babel/generator': 7.27.5 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.27.4) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.27.4) + '@babel/types': 7.27.6 + '@jest/expect-utils': 29.7.0 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-preset-current-node-syntax: 1.1.0(@babel/core@7.27.4) + chalk: 4.1.2 + expect: 29.7.0 + graceful-fs: 4.2.11 + jest-diff: 29.7.0 + jest-get-type: 29.6.3 + jest-matcher-utils: 29.7.0 + jest-message-util: 29.7.0 + jest-util: 29.7.0 + natural-compare: 1.4.0 + pretty-format: 29.7.0 + semver: 7.7.2 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-watcher@29.7.0: + dependencies: + '@jest/test-result': 29.7.0 + '@jest/types': 29.6.3 + '@types/node': 22.15.29 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 29.7.0 + string-length: 4.0.2 + + jest-worker@29.7.0: + dependencies: + '@types/node': 22.15.29 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)): + dependencies: + '@jest/core': 29.7.0(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + '@jest/types': 29.6.3 + import-local: 3.2.0 + jest-cli: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - supports-color + - ts-node + + js-tokens@4.0.0: {} + + js-yaml@3.14.1: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + jsesc@3.1.0: {} + + json-parse-even-better-errors@2.3.1: {} + + json5@2.2.3: {} + + kleur@3.0.3: {} + + leven@3.1.0: {} + + lines-and-columns@1.2.4: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + lodash.memoize@4.1.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.2 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + merge-stream@2.0.0: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 2.3.1 + + mimic-fn@2.1.0: {} + + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + + minimatch@5.1.6: + dependencies: + brace-expansion: 2.0.1 + + ms@2.1.3: {} + + natural-compare@1.4.0: {} + + node-int64@0.4.0: {} + + node-releases@2.0.19: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-try@2.2.0: {} + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.27.1 + error-ex: 1.3.2 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + path-exists@4.0.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-parse@1.0.7: {} + + picocolors@1.1.1: {} + + picomatch@2.3.1: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + pure-rand@6.1.0: {} + + react-is@18.3.1: {} + + require-directory@2.1.1: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@5.0.0: {} + + resolve.exports@2.0.3: {} + + resolve@1.22.10: + dependencies: + is-core-module: 2.16.1 + path-parse: 1.0.7 + supports-preserve-symlinks-flag: 1.0.0 + + sax@1.4.1: {} + + semver@6.3.1: {} + + semver@7.7.2: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + signal-exit@3.0.7: {} + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.6.1: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + supports-preserve-symlinks-flag@1.0.0: {} + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 7.2.3 + minimatch: 3.1.2 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + ts-jest@29.3.4(@babel/core@7.27.4)(@jest/transform@29.7.0)(@jest/types@29.6.3)(babel-jest@29.7.0(@babel/core@7.27.4))(jest@29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)))(typescript@5.4.5): + dependencies: + bs-logger: 0.2.6 + ejs: 3.1.10 + fast-json-stable-stringify: 2.1.0 + jest: 29.7.0(@types/node@22.15.29)(ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5)) + jest-util: 29.7.0 + json5: 2.2.3 + lodash.memoize: 4.1.2 + make-error: 1.3.6 + semver: 7.7.2 + type-fest: 4.41.0 + typescript: 5.4.5 + yargs-parser: 21.1.1 + optionalDependencies: + '@babel/core': 7.27.4 + '@jest/transform': 29.7.0 + '@jest/types': 29.6.3 + babel-jest: 29.7.0(@babel/core@7.27.4) + + ts-node@10.9.2(@types/node@22.15.29)(typescript@5.4.5): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.11 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.15.29 + acorn: 8.14.1 + acorn-walk: 8.3.4 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.2 + make-error: 1.3.6 + typescript: 5.4.5 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@4.41.0: {} + + typescript@5.4.5: {} + + undici-types@6.21.0: {} + + update-browserslist-db@1.1.3(browserslist@4.25.0): + dependencies: + browserslist: 4.25.0 + escalade: 3.2.0 + picocolors: 1.1.1 + + v8-compile-cache-lib@3.0.1: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.25 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrappy@1.0.2: {} + + write-file-atomic@4.0.2: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 3.0.7 + + xml-js@1.6.11: + dependencies: + sax: 1.4.1 + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yargs-parser@21.1.1: {} + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yn@3.1.1: {} + + yocto-queue@0.1.0: {} diff --git a/testsuite/scripts/test-diff.el b/testsuite/scripts/test-diff.el new file mode 100644 index 000000000..bf0c7d8be --- /dev/null +++ b/testsuite/scripts/test-diff.el @@ -0,0 +1,113 @@ +;;; +;;; Tools for working with Jest tests in Emacs. +;;; +;;; +;;; Copyright (c) 2024 The MathJax Consortium + +(require 'ediff) + +;;; Jest Tests +;;; ========== +;;; +;;; Run by piping stdout and stderr into a file. Then use the output file form +;;; the stderr pipe to replace expected for actual +;;; +;;; If piping stderr only the output file will contain noise for tty +;;; colorization. +;;; + +(defun jest-find-expected () + (block find-fail-block + (let ((expected (condition-case nil + (search-forward "Expected value") + (error nil)))) + (if (null expected) + (let ((expected (condition-case nil + (search-forward "Expected:") + (error nil)))) + expected) + expected)))) + +(defun jest-find-fail () + ;; Returns start end for actual and expected and position of fail o/w nil. + (interactive) + (block find-fail-block + (let ((pos (condition-case nil + (search-forward "●" nil t) + (error nil)))) + (when (null pos) + (return-from find-fail-block nil)) + (let ((expected (jest-find-expected)) + (actual (condition-case nil + (search-forward "Received:") + (error nil))) + ) + (when (or (null actual) (null expected)) + (return-from find-fail-block nil)) + (let* ((beg1 (progn + (goto-char actual) + (search-forward "\"") + (backward-char) + (point))) + (dummy1 (forward-sexp)) + (end1 (1- (point))) + (fail1 (buffer-substring beg1 end1)) + (beg2 (progn + (goto-char expected) + (search-forward "\"") + (backward-char) + (point))) + (dummy2 (forward-sexp)) + (end2 (1- (point))) + (fail2 (buffer-substring beg2 end2))) + (list (cons beg1 end1) (cons beg2 end2) pos (cons fail1 fail2)) + ))))) + + +;; Automatic region ediff for failed test. +(defun jest-diff-fail () + (interactive) + ;; (do* ((fail (find-fail))) + ;; ((null fail)) + (let ((fail (jest-find-fail))) + (when (null fail) nil) + (ediff-regions-internal + (get-buffer (buffer-name)) (caar fail) (cdar fail) + (get-buffer (buffer-name)) (caadr fail) (cdadr fail) + nil 'ediff-regions-wordwise 'word-mode nil))) + +(global-set-key [?\C-c ?\C-d] 'jest-diff-fail) + +;; Separates expected and received values for all failed tests +;; into two separate buffers/files for ease of comparison. +;; Then simply run an ediff-buffers. +(defun jest-separate-fails (bufferA bufferB) + (interactive + (list (read-buffer "Buffer for Expected: ") + (read-buffer "Buffer for Received: "))) + (condition-case nil + (search-forward "Summary of all failing tests") + (error (beginning-of-buffer))) + (do ((fail (jest-find-fail) (jest-find-fail))) + ((null fail) nil) + (print fail) + (append-to-buffer bufferA (caadr fail) (cdadr fail)) + (with-current-buffer bufferA (insert "\n\n")) + (append-to-buffer bufferB (caar fail) (cdar fail)) + (with-current-buffer bufferB (insert "\n\n")) + )) + +;;; Replace expected for actual +;;; Make sure that the test output is in the other window. +;;; Go to position where you want the next test inserted. +(defun jest-replace-expected-for-actual () + (interactive) + (block expected-block + (other-window 1) + (let* ((fail (jest-find-fail)) + (actual (car (fourth fail))) + (str (subseq actual 1)) + ) + (other-window 1) + (insert str) + ))) diff --git a/testsuite/src/constants.d.ts b/testsuite/src/constants.d.ts new file mode 100644 index 000000000..e47557ed1 --- /dev/null +++ b/testsuite/src/constants.d.ts @@ -0,0 +1 @@ +export const tmpJsonFile: string; diff --git a/testsuite/src/constants.js b/testsuite/src/constants.js new file mode 100644 index 000000000..ed7778d84 --- /dev/null +++ b/testsuite/src/constants.js @@ -0,0 +1 @@ +export const tmpJsonFile = '/tmp/test.json'; diff --git a/testsuite/src/dirname.ts b/testsuite/src/dirname.ts new file mode 100644 index 000000000..40b2d0905 --- /dev/null +++ b/testsuite/src/dirname.ts @@ -0,0 +1,6 @@ +declare var __dirname: string; + +export function setDirname(name: string) { + __dirname = name; +} + diff --git a/testsuite/src/index.ts b/testsuite/src/index.ts new file mode 100644 index 000000000..7cbcd1662 --- /dev/null +++ b/testsuite/src/index.ts @@ -0,0 +1,2 @@ +export * from './setupTex.js'; +export * from './xmlMatch.js'; diff --git a/testsuite/src/setupTex.ts b/testsuite/src/setupTex.ts new file mode 100644 index 000000000..8f8b31252 --- /dev/null +++ b/testsuite/src/setupTex.ts @@ -0,0 +1,446 @@ +import {TeX} from '#js/input/tex.js'; +import {AbstractParseMap, RegExpMap, CommandMap} from '#js/input/tex/TokenMap.js'; +import {ConfigurationHandler} from '#js/input/tex/Configuration.js'; +import {HandlerType, ConfigurationType} from '#js/input/tex/HandlerTypes.js'; +import {MapHandler} from '#js/input/tex/MapHandler.js'; +import {HTMLDocument} from '#js/handlers/html/HTMLDocument.js'; +import {RegisterHTMLHandler} from '#js/handlers/html.js'; +import {liteAdaptor} from '#js/adaptors/liteAdaptor.js'; +import {MathItem, STATE} from '#js/core/MathItem.js'; +import {SerializedMmlVisitor} from '#js/core/MmlTree/SerializedMmlVisitor.js'; +import {MmlNode} from '#js/core/MmlTree/MmlNode.js'; +import {mathjax} from '#js/mathjax.js'; +import {OptionList} from '#js/util/Options.js'; +import {tmpJsonFile} from '#src/constants.js'; +import * as fs from 'fs'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import {init} from '#source/node-main/node-main.mjs'; +import {expect} from '@jest/globals'; +// eslint-disable-next-line @typescript-eslint/ban-ts-comment +// @ts-ignore +import {source} from '#source/source.js'; + +declare const MathJax: any; +type MATHITEM = MathItem; +type PackageList = (string | [string, number])[]; + +/** + * The various conversion functions (set up in setupTex... function below). + */ +let convert: (tex: string, display: boolean) => string; +let render: (text: string, display: boolean) => string; +let typeset: (text: string, display: boolean) => Promise; +let page: (text: string) => Promise; + +/** + * A promise that resolves when the components are loaded and set up. + */ +let componentPromise: Promise; + +/** + * Get the adaptor, and register HTML documents. + */ +const adaptor = liteAdaptor(); +const handler = RegisterHTMLHandler(adaptor); + +/** + * A vistor to convert MmlNodes to serialized MathML. + */ +const visitor = new SerializedMmlVisitor(); +export const toMathML = ((node: MmlNode) => visitor.visitTree(node)); + +/*********************************************************************/ + +/** + * Trap output produced while running code. + * @param method The console method to trap. + * @param code The code to run. + * @return The output sent to the given method. + */ +export function trapOutput(method: string, code: () => void) { + const saved = (console as any)[method]; + let message = ''; + (console as any)[method] = (...msg: any[]) => {message += (message ? '\n' : '') + msg.join(' ')}; + code(); + (console as any)[method] = saved; + return message; +} + +/** + * Trap errors produced while running code. + * @param code The code to run. + * @return The error message produced. + */ +export function trapErrors(code: () => void) { + let message = '(no error)'; + reportErrors = true; + try {code()} catch (e) {message = e.message} + reportErrors = false; + return message; +} + +/** + * Trap errors produced while running code. + * @param code The code to run. + * @return The error message produced. + */ +export async function trapAsyncErrors(code: () => Promise) { + let message = '(no error)'; + reportErrors = true; + await code().catch((e) => {message = e.message}); + reportErrors = false; + return message; +} + +/** + * When true, errors will throw rather than produce merror elements. + */ +let reportErrors = false; + +/** + * Configuration that causes TeX errors to throw rather than + * generate merror elements, so we can trap them with trapErrors(). + */ +export const throwTexErrors = { + formatError(jax: any, err: Error) { + if (reportErrors) throw err; + return jax.formatError(err); + } +} + +/** + * Configuration that causes compile errors to throw rather than + * generate merror elements, so we can trap them with trapErrors(). + */ +export const throwCompileErrors = { + options: { + compileError(jax: any, math: any, err: Error) { + if (reportErrors) throw err; + return jax.compileError(math, err); + } + } +} + +/** + * Trap TeX processing errors and return an expect() result + * @param string The TeX string to process + * @param display True for display style, false for in-line + * @param typeset The function used to typeset the TeX (tex2mml, typeset2mml, etc) + */ +export function expectTexError( + tex: string, + display: boolean = true, + fn: (((tex: string, display?: boolean) => any) | ((tex: string) => any)) = tex2mml, +): any { + return expect(trapErrors(() => fn(tex, display))); +} + +/** + * Trap TeX processing errors and return an expect() result + * @param string The TeX string to process + * @param display True for display style, false for in-line + * @param typeset The function used to typeset the TeX (tex2mml, typeset2mml, etc) + */ +export function expectTypesetError( + tex: string, + display: boolean = true, + fn: (((tex: string, display?: boolean) => Promise) | ((tex: string) => Promise)) = typeset2mml, +): any { + return expect(trapAsyncErrors(() => fn(tex, display))).resolves; +} + +/*********************************************************************/ + +/** + * Set up TeX input packages and options for tex2mml(), and create the convert() function, + * which uses MathDocument.convert() to compile the TeX. + * + * @param {string[]} packages The TeX packages to configure + * @param {OptionList} options The TeX options to include + */ +export function setupTex(packages: PackageList = ['base'], options: OptionList = {}) { + const parserOptions = Object.assign({}, {packages}, throwTexErrors, options); + const tex = new TeX(parserOptions); + const html = new HTMLDocument('', adaptor, {InputJax: tex}); + convert = (expr: string, display: boolean) => + toMathML(html.convert(expr, {display: display, end: STATE.CONVERT})); +} + +/** + * Set up TeX input packages and options for render2mml(), and create the render() function, + * which uses MathDocument.findMath().compile() to compile the TeX from within a document. + * + * @param {string[]} packages The TeX packages to configure + * @param {OptionList} options The TeX options to include + */ +export function setupTexRender(packages: PackageList = ['base'], options: OptionList = {}) { + const parserOptions = Object.assign( + {}, + {packages: packages, inlineMath: {'[+]': [['$', '$']]}}, + throwTexErrors, + options + ); + const tex = new TeX(parserOptions); + render = (text: string, display: boolean) => { + const delim = display ? '$$' : '$'; + const document = `${delim}${text}${delim}`; + const html = mathjax.document(document, {InputJax: tex}); + html.findMath().compile(); + return toMathML((Array.from(html.math)[0] as MATHITEM).root); + } +} + +/** + * Set up TeX input packages and options for typeset2mml(), and create the typeset() function, + * which uses MathDocument.findMath().compile() wrapped in handleRetriesFor() to + * compile the TeX from within a document asynchronously. + * + * @param {string[]} packages The TeX packages to configure + * @param {OptionList} options The TeX options to include + */ +export function setupTexTypeset(packages: PackageList = ['base'], options: OptionList = {}) { + MathJax.config.tex = Object.assign( + {}, + {packages: packages, inlineMath: {'[+]': [['$', '$']]}}, + throwTexErrors, + options + ); + typeset = async (text: string, display: boolean) => { + await componentPromise; + const delim = display ? '$$' : '$'; + MathJax.config.startup.document = + `${delim}${text}${delim}`; + MathJax.startup.getComponents(); + const mathdoc = MathJax.startup.document; + await mathjax.handleRetriesFor(() => mathdoc.findMath().compile()); + return toMathML((Array.from(mathdoc.math) as MATHITEM[])[0].root); + } +} + +/** + * Set up TeX input packages and options for page2mml(), and create the page() function, + * which uses MathDocument.findMath().compile() wrapped in handleRetriesFor() to + * compile a pagefrom within a document asynchronously, and test an array of results, + * one for each expression in the page. + * + * @param {string[]} packages The TeX packages to configure + * @param {OptionList} options The TeX options to include + */ +export function setupTexPage(packages: PackageList = ['base'], options: OptionList = {}) { + MathJax.config.tex = Object.assign( + {}, + {packages: packages, inlineMath: {'[+]': [['$', '$']]}}, + throwTexErrors, + options + ); + page = async (text: string) => { + await componentPromise; + MathJax.config.startup.document = + `${text}`; + MathJax.startup.getComponents(); + const mathdoc = MathJax.startup.document; + await mathjax.handleRetriesFor(() => mathdoc.findMath().compile()); + const math = Array.from(mathdoc.math) as MATHITEM[]; + return math.map((mi) => toMathML(mi.root)); + } +} + +import {SVG} from '#js/output/svg.js'; + +/** + * Set up TeX input packages and options for tex2mml(), and create the convert() function, + * which uses MathDocument.convert() to typeset the Tex, with an SVG output jax available. + * + * @param {string[]} packages The TeX packages to configure + * @param {OptionList} options The TeX options to include + */ +export function setupTexWithOutput(packages: string[] = ['base'], options: OptionList = {}) { + const parserOptions = Object.assign({}, {packages: packages}, options); + const tex = new TeX(parserOptions); + const html = new HTMLDocument('', adaptor, {InputJax: tex, OutputJax: new SVG()}); + const visitor = new SerializedMmlVisitor(); + const toMathML = ((node: MmlNode) => visitor.visitTree(node)); + convert = (expr: string, display: boolean) => + toMathML(html.convert(expr, {display: display, end: STATE.CONVERT})); +} + +/*********************************************************************/ + +/** + * Convert TeX to MathML using MathDocument.convert + * + * @param {string} tex The math to convert + * @param {boolean} display True for display math, false for in-line math + * @returns {string} The MathML for the TeX expression + */ +export function tex2mml(tex: string, display: boolean = true): string { + return convert(tex, display); +}; + +/** + * Convert TeX to MathML using MathDocument.findMath().compile() on a document + * (allows embedded HTML tags when texhtml is present). + * + * @param {string} tex The math to convert + * @param {boolean} display True for display math, false for in-line math + * @returns {string} The MathML for the TeX expression + */ +export function render2mml(tex: string, display: boolean = true): string { + return render(tex, display); +} + +/** + * Convert TeX to MathML using MathDocument.findMath().compile() wrapped in + * handleRetriesFor() on a document (allows retries to be processed). + * + * @param {string} tex The math to convert + * @param {boolean} display True for display math, false for in-line math + * @returns {Promise} A promise for the MathML for the TeX expression + */ +export function typeset2mml(tex: string, display: boolean = true): Promise { + return typeset(tex, display); +} + +/** + * Convert TeX to MathML using MathDocument.findMath().compile() wrapped in + * handleRetriesFor() on a whole document (allowing retries to be processed). + * Returns an array of MathML, one for each expression in the page + * + * @param {string} text The serialized HTML document to process. + * @returns {Promise} A promise for the array of MathML from the document + */ +export function page2mml(text: string): Promise { + return page(text); +} + +/*********************************************************************/ + +/** + * Initialize the component framework (for typeset2mml() and + * page2mml()), setting a promise for when that is complete (the + * conversion functions with for that promise to resolve). + * @param config The MathJax configuration + */ +export async function setupComponents(config: any) { + mathjax.handlers.unregister(handler); + // + // Jest import() doesn't return a promise that is an instance of Promise, + // so wrap it in a real promise, so Package will properly identify it. + // + MathJax.config.loader.require = (file: string) => { + return new Promise((ok, fail) => import(file).then(ok).catch(e => fail(e))); + } + MathJax.config.loader.source = source; + config.startup ??= {}; + config.startup.typeset ??= false; + config = Object.assign({}, throwCompileErrors, config); + componentPromise = init(config); +} + +/*********************************************************************/ + +// Machinery for measuring the completeness of our macro tests. + +const tokens: Map> = new Map(); + +/** + * Adds a token to the token set. + * @param {string} name Table name. + * @param {string} token Token string. + */ +function addToken(name: string, token: string) { + let tokenSet = tokens.get(name); + if (!tokenSet) { + tokenSet = new Set(); + tokens.set(name, tokenSet); + } + tokenSet.add(token); +} + +/** + * Set difference. + * @param {Set} exp Expected elements. + * @param {Set} act Actual elements. + * @return {Set} Expected setminus actual. + */ +function setdifference(exp: Set, act: Set): Set { + act.forEach(x => exp.delete(x)); + return exp; +} + +/** + * Diff between macros + * @param {string} handler + * @return {[Set, number, number]} + */ +function diffMacros(handler: string): [Set, number, number] { + const expected = MapHandler.getMap(handler); + if (!expected || expected instanceof RegExpMap) { + return [null, 0, 0]; + } + const actual = tokens.get(handler); + const expSet = new Set((expected as any).map.keys()) as Set; + const expSize = expSet.size; + if (!actual) { + return [expSet, expSize, 0]; + } + return [setdifference(expSet, actual), expSize, actual.size]; +} + +interface tables { + table: string, + size: number, + actual: number, + missing: string[] +} + +/** + * Gets tested tokens for a configuration and pushes them to the intermediary + * test file. + * + * @param {string} configuration The name of the configuration. + */ +export function getTokens(configuration: string) { + const config = ConfigurationHandler.get(configuration); + if (!config) { + console.error(`Something went wrong for configuration ${configuration}`); + } + const handlers = config[ConfigurationType.HANDLER]; + // We can omit `handlers[HandlerType.DELIMITER]`. + const allHandlers = [].concat( + handlers[HandlerType.CHARACTER], + handlers[HandlerType.MACRO], + handlers[HandlerType.ENVIRONMENT]); + let tables: tables[] = []; + let outJSON: { + configuration: string, + tables: tables[] + } = {configuration: configuration, tables: tables}; + allHandlers.forEach((handler) => { + const [diff, exp, act] = diffMacros(handler); + if (diff) { + tables.push({ + table: handler, + size: exp, + actual: act, + missing: Array.from(diff) + }) + } + }); + fs.appendFileSync(tmpJsonFile, ',' + JSON.stringify(outJSON, null, 2)); +} + +// +// Force the original lookup to be called (so we get coverage for it) before we change it. +// +(function () {new CommandMap('', {}).lookup('x')})(); + +// A prototype extension for the macro table lookups. +AbstractParseMap.prototype.lookup = function(token: string) { + const result = this.map.get(token); + if (result) { + addToken(this.name, token); + } + return result; +} diff --git a/testsuite/src/texReporter.js b/testsuite/src/texReporter.js new file mode 100644 index 000000000..1f037fb44 --- /dev/null +++ b/testsuite/src/texReporter.js @@ -0,0 +1,172 @@ +/** + * Custom reporter for tex macro coverage. + */ + +import {tmpJsonFile} from './constants.js'; +import * as fs from 'fs'; + +const ESC = '\u001B'; + +export default class TexReporter { + + constructor(globalConfig, reporterOptions, reporterContext) { + this._globalConfig = globalConfig; + this._options = reporterOptions; + this._context = reporterContext; + } + + onRunStart( + aggregatedResults, options + ) { + fs.writeFileSync(tmpJsonFile, '[{}'); + } + + onRunComplete(testContexts, results) { + fs.appendFileSync(tmpJsonFile, ']'); + let coverage = JSON.parse(fs.readFileSync(tmpJsonFile)); + if (!coverage) { + return; + } + coverage = coverage.slice(1); + fs.unlinkSync(tmpJsonFile); + createCoverageOutput(coverage); + } + + // Optionally, reporters can force Jest to exit with non zero code by returning + // an `Error` from `getLastError()` method. + getLastError() { + if (this._shouldFail) { + return new Error('Custom error reported!'); + } + } +} + +/** + * Convert the array of configurations to an array of rows of data, + * sorted by package name. + * @param coverage The coverage data from the json file + * @return The array of rows of data + */ +function combineCoverage(coverage) { + const maps = []; + coverage = coverage.sort((a, b) => a.configuration < b.configuration ? -1 : 1); + for (const configuration of coverage) { + const rows = []; + let actual = 0; + let size = 0; + for (const table of configuration.tables.sort((a, b) => a.table < b.table ? -1 : 1)) { + if (table.actual > table.size) { + table.actual = table.size; + } + actual += table.actual; + size += table.size; + rows.push([' ' + table.table, table.size, table.actual, table.missing.join(', ')]); + } + maps.push([configuration.configuration, size, actual, ''], ...rows); + } + return maps; +} + +/** + * Print the coverage table + * @param coverage The converage data from the json file + */ +function createCoverageOutput(coverage) { + const rows = combineCoverage(coverage); + if (rows.length === 0) return; + const width = rows.reduce((max, row) => Math.max(row[0].length, max), 5); + const mwidth = trimMissing(rows, width); + const line = [ + makeColumn('', width).replaceAll(' ', '-'), + '--------|--------|------------|', + makeColumn('', mwidth).replaceAll(' ', '-').replace('|-', '') + ].join(''); + console.log(line); + console.log(makeColumn('Table', width, 0, true) + 'Entries | Tested | Percentage | Missing'); + console.log(line); + for (const [table, size, actual, missing] of rows) { + const color = getColor(actual, size); + console.log([ + makeColumn(table, width, color, true), + makeColumn(size, 7, color), + makeColumn(actual, 6, color), + makeColumn(percentage(actual, size), 10, color), + colorize(missing, color) + ].join('')); + } + console.log(line); + console.log(''); +} + +/** + * Trim the missing token list to fit the screen + * @param rows The rows whose data is to be trimmed + * @param width The width of the table name column + * @return The width of the missing token column + */ +function trimMissing(rows, width) { + const rest = process.stdout.columns - width - 32; + let mwidth = 8; + for (const row of rows) { + let missing = row[3]; + if (missing.length > rest) { + row[3] = missing = '...' + missing.slice(missing.length - rest + 4).replace(/.*?, /, ''); + } + if (missing.length > mwidth) { + mwidth = missing.length; + } + } + return mwidth; +} + +/** + * Sets cell content with respect to column with surronding it by whitespace. + * @param cell The string in that cell. + * @param size The column size. + * @param left Cell is left aligned if set. + * @return The string with the correctly set column + */ +function makeColumn(cell, size, color = 0, left = false) { + let length = cell.toString().length; + let column = new Array(Math.max(0, size - length + 1)).join(' '); + cell = colorize(cell, color); + if (left) { + column = cell + column; + } else { + column += cell; + } + column += ' | '; + return column; +} + +/** + * Percentage computation with two digit precision. + * @param actual The number of tested elements. + * @param size The table size. + * @return The percentage for table size to tested elements. + */ +function percentage(actual, size) { + return Math.round((actual/size) * 10000) / 100; +} + +/** + * Get the color number for the percentage of coverage + * @param actual The number of tested elements. + * @param size The table size. + * @return The color number for use in a color escape sequence + */ +function getColor(actual, size) { + const percent = actual/size * 100; + return percent >= 80 ? 32 : percent >= 50 ? 33 : 31; +} + +/** + * Add color escape sequences, if needed + * @param cell The cell contents + * @param color The color number to use in the escape sequence + * @return The cell contents with color sequences + */ +function colorize(cell, color) { + return color && process.stdout.isTTY ? `${ESC}[1m${ESC}[${color}m${cell}${ESC}[0m` : cell; +} + diff --git a/testsuite/src/xmlMatch.ts b/testsuite/src/xmlMatch.ts new file mode 100644 index 000000000..6d2e794d2 --- /dev/null +++ b/testsuite/src/xmlMatch.ts @@ -0,0 +1,46 @@ +import { expect } from '@jest/globals'; +import { xml2json } from 'xml-js'; + +expect.extend({ + /** + * An xml matcher via deep equality on JSON objects. + * + * @param {string} received The string received from the tests + * @param {string} expected The string expected to be produced by the tests + */ + toBeXmlMatch(received: string, expected: string) { + const recJson = xml2json(received); + const exptJson = xml2json(expected) + const pass = this.equals(recJson, exptJson, [this.utils.iterableEquality]); + const message = () => + `Expected: ${this.utils.printExpected(expected)}\nReceived: ${this.utils.printReceived(received)}`; + return { pass, message } + }, +}); + +/** + * Compares a result to an expected result. + * + * @param {string} received The string received from the tests + * @param {string} expected The string expected to be produced by the tests + */ +export function toXmlMatch(received: string, expected: string) { + // This is slightly awkward way of getting around ts-jest problems with custom + // matcher extensions. + (expect(received) as any).toBeXmlMatch(expected); +} + +/** + * Compares an array of results to an array of expected results. + * + * @param {string[]} received An array of strings received from the tests + * @param {string[]} expected The array of string expected to be produced by the tests + */ +export function toXmlArrayMatch(received: string[], expected: string[]) { + const r = received.length; + const e = expected.length; + expect(`${r} MathML string${r === 1 ? '' : 's'}`).toBe(`${e} MathML string${e === 1 ? '' : 's'}`); + for (let i = 0; i < received.length; i++) { + toXmlMatch(`\n${received[i]}`, `\n${expected[i]}`); + } +} diff --git a/testsuite/tests/input/tex/Action.test.ts b/testsuite/tests/input/tex/Action.test.ts new file mode 100644 index 000000000..e6a6ca175 --- /dev/null +++ b/testsuite/tests/input/tex/Action.test.ts @@ -0,0 +1,62 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/action/ActionConfiguration'; + +beforeEach(() => setupTex(['base', 'action'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Action', () => { + + /********************************************************************************/ + + it('TextTip', () => { + toXmlMatch( + tex2mml('\\texttip{A}{B}'), + ` + + A + B + + ` + ); + }); + + /********************************************************************************/ + + it('MathTip', () => { + toXmlMatch( + tex2mml('\\mathtip{A}{B}'), + ` + + A + B + + ` + ); + }); + + /********************************************************************************/ + + it('Toggle', () => { + toXmlMatch( + tex2mml('\\toggle A B C \\endtoggle'), + ` + + A + B + C + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('action')); diff --git a/testsuite/tests/input/tex/Ams.test.ts b/testsuite/tests/input/tex/Ams.test.ts new file mode 100644 index 000000000..60534b58d --- /dev/null +++ b/testsuite/tests/input/tex/Ams.test.ts @@ -0,0 +1,4555 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/ams/AmsConfiguration'; + +beforeEach(() => setupTex(['base', 'ams'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Ams', () => { + + /********************************************************************************/ + + it('Symbol', () => { + toXmlMatch( + tex2mml('\\digamma'), + ` + ϝ + ` + ); + }); + + /********************************************************************************/ + + it('Operator', () => { + toXmlMatch( + tex2mml('\\dotplus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Delimiter', () => { + toXmlMatch( + tex2mml('\\ulcorner'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Delimiter-left-right', () => { + toXmlMatch( + tex2mml('\\left\\ulcorner A \\right\\urcorner'), + ` + + + A + + + ` + ); + }); + + /********************************************************************************/ + + it('Macro', () => { + toXmlMatch( + tex2mml('A\\implies B'), + ` + A + + + + B + ` + ); + }); + + /********************************************************************************/ + + it('AMS-math-mo', () => { + toXmlMatch( + tex2mml('\\iiiint'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('AMS-math-macro', () => { + toXmlMatch( + tex2mml('\\ddddot{1}'), + ` + + + 1 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Normal Fraction', () => { + toXmlMatch( + tex2mml('\\frac{n}{k}'), + ` + + n + k + + ` + ); + }); + + /********************************************************************************/ + + it('Text Fraction', () => { + toXmlMatch( + tex2mml('\\tfrac{n}{k}'), + ` + + + n + k + + + ` + ); + }); + + /********************************************************************************/ + + it('Display Fraction', () => { + toXmlMatch( + tex2mml('\\dfrac{n}{k}'), + ` + + n + k + + ` + ); + }); + + /********************************************************************************/ + + it('Normal Sub Fraction', () => { + toXmlMatch( + tex2mml('a_\\frac{n}{k}'), + ` + + a + + n + k + + + ` + ); + }); + + /********************************************************************************/ + + it('Text Sub Fraction', () => { + toXmlMatch( + tex2mml('a_\\tfrac{n}{k}'), + ` + + a + + + n + k + + + + ` + ); + }); + + /********************************************************************************/ + + it('Display Sub Fraction', () => { + toXmlMatch( + tex2mml('a_\\dfrac{n}{k}'), + ` + + a + + + n + k + + + + ` + ); + }); + + /********************************************************************************/ + + it('Normal Binomial', () => { + toXmlMatch( + tex2mml('\\binom{n}{k}'), + ` + + + ( + + + n + k + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Text Binomial', () => { + toXmlMatch( + tex2mml('\\tbinom{n}{k}'), + ` + + + + ( + + + n + k + + + ) + + + + ` + ); + }); + + /********************************************************************************/ + + it('Display Binomial', () => { + toXmlMatch( + tex2mml('\\dbinom{n}{k}'), + ` + + + ( + + + n + k + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Normal Sub Binomial', () => { + toXmlMatch( + tex2mml('a_\\binom{n}{k}'), + ` + + a + + + ( + + + n + k + + + ) + + + + ` + ); + }); + + /********************************************************************************/ + + it('Text Sub Binomial', () => { + toXmlMatch( + tex2mml('a_\\tbinom{n}{k}'), + ` + + a + + + + ( + + + n + k + + + ) + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Display Sub Binomial', () => { + toXmlMatch( + tex2mml('a_\\dbinom{n}{k}'), + ` + + a + + + + ( + + + n + k + + + ) + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Center Fraction', () => { + toXmlMatch( + tex2mml('\\cfrac{a}{bbb}'), + ` + + + + + + + a + + + + + + + + b + b + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Left Fraction', () => { + toXmlMatch( + tex2mml('\\cfrac[l]{a}{bbb}'), + ` + + + + + + + a + + + + + + + + b + b + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Right Fraction', () => { + toXmlMatch( + tex2mml('\\cfrac[r]{a}{bbb}'), + ` + + + + + + + a + + + + + + + + b + b + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above Left Arrow', () => { + toXmlMatch( + tex2mml('\\xleftarrow{abcd}'), + ` + + + + a + b + c + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above Below Left Arrow', () => { + toXmlMatch( + tex2mml('\\xleftarrow[xyz]{abcd}'), + ` + + + + x + y + z + + + + a + b + c + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above Left Arrow in Context', () => { + toXmlMatch( + tex2mml('A\\xleftarrow{abcd}B'), + ` + A + + + + a + b + c + d + + + + B + ` + ); + }); + + /********************************************************************************/ + + it('Above Right Arrow', () => { + toXmlMatch( + tex2mml('\\xrightarrow{abcd}'), + ` + + + + a + b + c + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above Below Right Arrow', () => { + toXmlMatch( + tex2mml('\\xrightarrow[xyz]{abcd}'), + ` + + + + x + y + z + + + + a + b + c + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above Right Arrow in Context', () => { + toXmlMatch( + tex2mml('A\\xrightarrow{abcd}B'), + ` + A + + + + a + b + c + d + + + + B + ` + ); + }); + + /********************************************************************************/ + + it('Genfrac', () => { + toXmlMatch( + tex2mml('\\genfrac{[}{]}{0pt}{3}{a}{b}'), + ` + + + + [ + + + a + b + + + ] + + + + ` + ); + }); + + /********************************************************************************/ + + it('Genfrac no delimiters', () => { + toXmlMatch( + tex2mml('\\genfrac{}{}{0pt}{3}{a}{b}'), + ` + + + a + b + + + ` + ); + }); + + /********************************************************************************/ + + it('MultiInt', () => { + toXmlMatch( + tex2mml('\\idotsint'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + + it('MultiInt in Context', () => { + toXmlMatch( + tex2mml('a \\idotsint b'), + ` + a + + + + b + ` + ); + }); + + /********************************************************************************/ + + it('MultiInt with Command', () => { + toXmlMatch( + tex2mml('\\idotsint\\sin x'), + ` + + + + sin + + x + ` + ); + }); + + /********************************************************************************/ + + it('MultiInt with Limits', () => { + toXmlMatch( + tex2mml('\\idotsint\\limits_a^b+3'), + ` + + + + + + + + + + + a + b + + + + 3 + ` + ); + }); + + /********************************************************************************/ + + it('DeclareMathOp', () => { + toXmlMatch( + tex2mml('\\DeclareMathOperator{\\R}{R}a\\R b'), + ` + a + R + + b + ` + ); + }); + + /********************************************************************************/ + + it('DeclareMathOp star', () => { + toXmlMatch( + tex2mml('\\DeclareMathOperator*{\\R}{R}a\\R b'), + ` + a + R + + b + ` + ); + }); + + /********************************************************************************/ + + it('Operatorname', () => { + toXmlMatch( + tex2mml('a\\operatorname{xyz}b'), + ` + a + xyz + + b + ` + ); + }); + + /********************************************************************************/ + + it('Operatorname Complex', () => { + toXmlMatch( + tex2mml('\\operatorname{a+}'), + ` + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Operatorname Letters', () => { + toXmlMatch( + tex2mml('*\\operatorname{*c}-\\operatorname{-a}'), + ` + + *c + + -a + ` + ); + }); + + /********************************************************************************/ + + it('Operatorname Followed by CS', () => { + toXmlMatch( + tex2mml('\\operatorname{a+}\\alpha'), + ` + + a + + + + + α + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Ams Environments', () => { + + /********************************************************************************/ + + it('Subarray', () => { + toXmlMatch( + tex2mml('\\begin{subarray}{c}a\\end{subarray}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Small Matrix', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix}a\\end{smallmatrix}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Align', () => { + toXmlMatch( + tex2mml('\\begin{align} a&=b \\\\ c&=d \\end{align}'), + ` + + + + a + + + + + = + b + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Align Star', () => { + toXmlMatch( + tex2mml('\\begin{align*} a&=b \\\\ c&=d \\end{align*}'), + ` + + + + a + + + + + = + b + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Multline', () => { + toXmlMatch( + tex2mml('\\begin{multline} a\\\\ b \\\\ c \\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Multline Star', () => { + toXmlMatch( + tex2mml('\\begin{multline*} a\\\\ b \\\\ c \\end{multline*}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Split', () => { + toXmlMatch( + tex2mml( + '\\begin{align*} a&=b \\begin{split} r&=s\\\\ & =t \\end{split} \\\\ c&=d \\end{align*}' + ), + ` + + + + a + + + + + = + b + + + + r + + + + + = + s + + + + + + + + + = + t + + + + + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Gather', () => { + toXmlMatch( + tex2mml('\\begin{gather} a=b \\\\ c=d \\end{gather}'), + ` + + + + a + = + b + + + + + c + = + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Gather Star', () => { + toXmlMatch( + tex2mml('\\begin{gather*} a=b \\\\ c=d \\end{gather*}'), + ` + + + + a + = + b + + + + + c + = + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Alignat', () => { + toXmlMatch( + tex2mml('\\begin{alignat}{2} a&=b \\\\ c&=d \\end{alignat}'), + ` + + + + a + + + + + = + b + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Alignat Star', () => { + toXmlMatch( + tex2mml('\\begin{alignat*}{2} a&=b \\\\ c&=d \\end{alignat*}'), + ` + + + + a + + + + + = + b + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Alignedat', () => { + toXmlMatch( + tex2mml( + '\\begin{align*} a&=b \\begin{alignedat}{2} r&=s\\\\ & =t \\end{alignedat} \\\\ c&=d \\end{align*}' + ), + ` + + + + a + + + + + = + b + + + + r + + + + + = + s + + + + + + + + + = + t + + + + + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Aligned', () => { + toXmlMatch( + tex2mml( + '\\begin{align*} a&=b \\begin{aligned} r&=s\\\\ & =t \\end{aligned} \\\\ c&=d \\end{align*}' + ), + ` + + + + a + + + + + = + b + + + + r + + + + + = + s + + + + + + + + + = + t + + + + + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Gathered', () => { + toXmlMatch( + tex2mml( + '\\begin{align*} a&=b \\begin{gathered} r=s\\\\ =t \\end{gathered} \\\\ c&=d \\end{align*}' + ), + ` + + + + a + + + + + = + b + + + + r + = + s + + + + + = + t + + + + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Equation', () => { + toXmlMatch( + tex2mml('\\begin{equation} a \\end{equation}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Equation Star', () => { + toXmlMatch( + tex2mml('\\begin{equation*} a \\end{equation*}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Eqnarray', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray} a & = & b\\\\ c & = & d \\end{eqnarray}'), + ` + + + + a + + + + = + + + + b + + + + + + c + + + + = + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Eqnarray Star', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray*} a & = & b\\\\ c & = & d \\end{eqnarray*}'), + ` + + + + a + + + + = + + + + b + + + + + + c + + + + = + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('flalign', () => { + toXmlMatch( + tex2mml('\\begin{flalign} a & = & b\\\\ c & = & d \\end{flalign}'), + ` + + + + a + + + + + = + + + + + b + + + + + c + + + + + = + + + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('xalignat', () => { + toXmlMatch( + tex2mml('\\begin{xalignat}{2} a&b & c&d \\end{xalignat}'), + ` + + + + + a + + + + b + + + + + c + + + + d + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('xalignat error', () => { + expectTexError('\\begin{xalignat}{x} \\and{xalignat}') + .toBe('Argument to \\begin{xalignat} must be a positive integer'); + }); + + /********************************************************************************/ + + it('xxalignat', () => { + toXmlMatch( + tex2mml('\\begin{xxalignat}{2} a&b & c&d \\end{xxalignat}'), + ` + + + + a + + + + b + + + + + c + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('xalignat error 2', () => { + expectTexError('\\begin{xalignat}{1} a&b & \\end{xalignat}') + .toBe('Extra & in row of xalignat'); + }); + + /********************************************************************************/ + + it('xalignat padding', () => { + toXmlMatch( + tex2mml('\\begin{xalignat}{2} a&b \\end{xalignat}'), + ` + + + + + a + + + + b + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('xalign tagged', () => { + toXmlMatch( + tex2mml('\\begin{xalignat}{2} a & b \\tag{1}\\end{xalignat}'), + ` + + + + + (1) + + + + + a + + + + b + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('flalign small', () => { + toXmlMatch( + tex2mml('\\begin{flalign} a&b \\end{flalign}'), + ` + + + + a + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('matrix', () => { + toXmlMatch( + tex2mml('\\begin{matrix} a & b \\\\ c & d \\end{matrix}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('pmatrix', () => { + toXmlMatch( + tex2mml('\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}'), + ` + + ( + + + + a + + + b + + + + + c + + + d + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('bmatrix', () => { + toXmlMatch( + tex2mml('\\begin{bmatrix} a & b \\\\ c & d \\end{bmatrix}'), + ` + + [ + + + + a + + + b + + + + + c + + + d + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Bmatrix', () => { + toXmlMatch( + tex2mml('\\begin{Bmatrix} a & b \\\\ c & d \\end{Bmatrix}'), + ` + + { + + + + a + + + b + + + + + c + + + d + + + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Vmatrix', () => { + toXmlMatch( + tex2mml('\\begin{Vmatrix} a & b \\\\ c & d \\end{Vmatrix}'), + ` + + + + + + a + + + b + + + + + c + + + d + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('cases', () => { + toXmlMatch( + tex2mml('f(x) = \\begin{cases} 1 & \\text{if $x > 1$} \\\\ 0 & \\text{otherwise} \\end{cases}'), + ` + f + ( + x + ) + = + + { + + + + 1 + + + + if  + + x + > + 1 + + + + + + + 0 + + + otherwise + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Ams Tagged Environments', () => { + beforeEach(() => setupTex(['base', 'ams'], { tags: 'ams' })); + + /********************************************************************************/ + + it('Subarray', () => { + toXmlMatch( + tex2mml('\\begin{subarray}{c}a\\end{subarray}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Small Matrix', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix}a\\end{smallmatrix}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Align', () => { + toXmlMatch( + tex2mml('\\begin{align} a&=b \\\\ c&=d \\end{align}'), + ` + + + + (1) + + + a + + + + + = + b + + + + + + (2) + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Align Star', () => { + toXmlMatch( + tex2mml('\\begin{align*} a&=b \\\\ c&=d \\end{align*}'), + ` + + + + a + + + + + = + b + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Multline', () => { + toXmlMatch( + tex2mml('\\begin{multline} a\\\\ b \\\\ c \\end{multline}'), + ` + + + + a + + + + + b + + + + + (1) + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Multline Star', () => { + toXmlMatch( + tex2mml('\\begin{multline*} a\\\\ b \\\\ c \\end{multline*}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Split', () => { + toXmlMatch( + tex2mml( + '\\begin{align*} a&=b \\begin{split} r&=s\\\\ & =t \\end{split} \\\\ c&=d \\end{align*}' + ), + ` + + + + a + + + + + = + b + + + + r + + + + + = + s + + + + + + + + + = + t + + + + + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Gather', () => { + toXmlMatch( + tex2mml('\\begin{gather} a=b \\\\ c=d \\end{gather}'), + ` + + + + (1) + + + a + = + b + + + + + (2) + + + c + = + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Gather Star', () => { + toXmlMatch( + tex2mml('\\begin{gather*} a=b \\\\ c=d \\end{gather*}'), + ` + + + + a + = + b + + + + + c + = + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Alignat', () => { + toXmlMatch( + tex2mml('\\begin{alignat}{2} a&=b \\\\ c&=d \\end{alignat}'), + ` + + + + (1) + + + a + + + + + = + b + + + + + + (2) + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Alignat Star', () => { + toXmlMatch( + tex2mml('\\begin{alignat*}{2} a&=b \\\\ c&=d \\end{alignat*}'), + ` + + + + a + + + + + = + b + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Alignedat', () => { + toXmlMatch( + tex2mml( + '\\begin{align*} a&=b \\begin{alignedat}{2} r&=s\\\\ & =t \\end{alignedat} \\\\ c&=d \\end{align*}' + ), + ` + + + + a + + + + + = + b + + + + r + + + + + = + s + + + + + + + + + = + t + + + + + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Aligned', () => { + toXmlMatch( + tex2mml( + '\\begin{align*} a&=b \\begin{aligned} r&=s\\\\ & =t \\end{aligned} \\\\ c&=d \\end{align*}' + ), + ` + + + + a + + + + + = + b + + + + r + + + + + = + s + + + + + + + + + = + t + + + + + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Gathered', () => { + toXmlMatch( + tex2mml( + '\\begin{align*} a&=b \\begin{gathered} r=s\\\\ =t \\end{gathered} \\\\ c&=d \\end{align*}' + ), + ` + + + + a + + + + + = + b + + + + r + = + s + + + + + = + t + + + + + + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Equation', () => { + toXmlMatch( + tex2mml('\\begin{equation} a \\end{equation}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Equation Star', () => { + toXmlMatch( + tex2mml('\\begin{equation*} a \\end{equation*}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Eqnarray', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray} a & = & b\\\\ c & = & d \\end{eqnarray}'), + ` + + + + (1) + + + a + + + + = + + + + b + + + + + + (2) + + + c + + + + = + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Eqnarray Star', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray*} a & = & b\\\\ c & = & d \\end{eqnarray*}'), + ` + + + + a + + + + = + + + + b + + + + + + c + + + + = + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Align Notag', () => { + toXmlMatch( + tex2mml('\\begin{align} a&=b \\\\ &=c \\notag \\end{align}'), + ` + + + + (1) + + + a + + + + + = + b + + + + + + + + + = + c + + + + + ` + ); + }); + + /********************************************************************************/ + + it('xalignet', () => { + toXmlMatch( + tex2mml('\\begin{xalignat}{1} a&b \\end{xalignat}'), + ` + + + + + (1) + + + + + a + + + + b + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('xalignet star', () => { + toXmlMatch( + tex2mml('\\begin{xalignat*}{1} a&b \\end{xalignat*}'), + ` + + + + + a + + + + b + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('flalign', () => { + toXmlMatch( + tex2mml('\\begin{flalign} a&b & \\end{flalign}'), + ` + + + + (1) + + + a + + + + b + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('xalignet star', () => { + toXmlMatch( + tex2mml('\\begin{flalign*} a&b & \\end{flalign*}'), + ` + + + + a + + + + b + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('aligned [b]', () => { + toXmlMatch( + tex2mml('\\begin{aligned} [b] a \\\\ b \\end{aligned}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('aligned [x]', () => { + toXmlMatch( + tex2mml('\\begin{aligned} [x] a \\\\ b \\end{aligned}'), + ` + + + + [ + x + ] + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Ams Tagged Environments Left', () => { + beforeEach(() => setupTex(['base', 'ams'], { tags: 'ams', tagSide: 'left' })); + + /********************************************************************************/ + + it('xalign tagged left', () => { + toXmlMatch( + tex2mml('\\begin{xalignat}{2} a & b \\tag{1}\\end{xalignat}'), + ` + + + + + (1) + + + + + a + + + + b + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('multline tagged left', () => { + toXmlMatch( + tex2mml('\\begin{multline} a\\tag{1} \\end{multline}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Nesting error', () => { + expectTexError('\\begin{align}\\begin{align} \\end{align}\\end{align}') + .toBe('Erroneous nesting of equation structures') + }); + + /********************************************************************************/ + + it('Gather Align', () => { + toXmlMatch( + tex2mml('\\begin{gather}\\begin{align} a &= b \\end{align}\\end{gather}'), + ` + + + + (2) + + + + + + (1) + + + a + + + + + = + b + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Gather Gather', () => { + expectTexError('\\begin{gather}\\begin{gather} \\end{gather}\\end{gather}') + .toBe('Erroneous nesting of equation structures') + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Amserror', () => { + + /********************************************************************************/ + + it('Center Fraction Error', () => { + expectTexError('\\cfrac[c]{a}{b}') + .toBe('Illegal alignment specified in \\cfrac'); + }); + + /********************************************************************************/ + + it('Genfrac Error', () => { + expectTexError('\\genfrac{[}{]}{0pt}{4}{a}{b}') + .toBe('Bad math style for \\genfrac'); + }); + + /********************************************************************************/ + + it('MissingOrUnrecognizedDelim', () => { + expectTexError('\\genfrac{(}{a}{}{2}{1}{2}') + .toBe('Missing or unrecognized delimiter for \\genfrac'); + }); + + /********************************************************************************/ + + it('PositiveIntegerArg', () => { + expectTexError( + '\\begin{align*} a&=b \\begin{alignedat}{-2} r&=s \\end{alignedat} \\\\ c&=d \\end{align*}' + ) + .toBe('Argument to \\begin{alignedat} must be a positive integer'); + }); + + /********************************************************************************/ + + it('MultlineRowsOneCol', () => { + expectTexError('\\begin{multline}a\\\\b&c\\end{multline}') + .toBe('The rows within the multline environment must have exactly one column'); + }); + + /********************************************************************************/ + + it('CommandNotAllowedInEnv', () => { + expectTexError('\\begin{split}a\\tag{1}\\end{split}') + .toBe('\\tag not allowed in split environment'); + }); + + /********************************************************************************/ + + it('MultipleCommand', () => { + expectTexError('a\\tag{1}\\tag{2}') + .toBe('Multiple \\tag'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('InternalMath', () => { + + /********************************************************************************/ + + it('Mbox Eqref', () => { + toXmlMatch( + tex2mml('a\\mbox{ \\eqref{1} } c'), + ` + a + +   + + + (???) + + +   + + c + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Multirel', () => { + + /********************************************************************************/ + + it('Multirel Mathvariant 1', () => { + toXmlMatch( + tex2mml('a <\\equiv \\mathrm{=>}\\thickapprox b'), + ` + a + <≡ + + => + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Multirel Mathvariant 2', () => { + toXmlMatch( + tex2mml('a <\\equiv \\mathrm{=>}\\thickapprox\\thicksim b'), + ` + a + <≡ + + => + + ≈∼ + b + ` + ); + }); + + /********************************************************************************/ + + it('Multirel Mathvariant 3', () => { + toXmlMatch( + tex2mml('a <\\equiv =>\\thickapprox\\thicksim b'), + ` + a + <≡=> + ≈∼ + b + ` + ); + }); + + /********************************************************************************/ + + it('Multirel Mathvariant 4', () => { + toXmlMatch( + tex2mml( + 'a <\\equiv \\mathrm{=}\\mathrm{>}\\thickapprox\\thicksim\\frown\\smile=\\updownarrow b' + ), + ` + a + <≡ + + = + + + > + + ≈∼ + ⌢⌣=↕ + b + ` + ); + }); + + /********************************************************************************/ + + it('Preset Lspace Rspace', () => { + toXmlMatch( + tex2mml('a\\lesssim\\gtrsim b'), + ` + a + ≲≳ + b + ` + ); + }); + + /********************************************************************************/ + + it('Preset Rspace Lspace', () => { + toXmlMatch( + tex2mml('a\\gtrsim\\lesssim b'), + ` + a + ≳≲ + b + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('MultlineShove', () => { + + /********************************************************************************/ + + it('Shove None', () => { + toXmlMatch( + tex2mml('\\begin{multline} a\\\\ b\\\\ c\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Left Top', () => { + toXmlMatch( + tex2mml('\\begin{multline}\\shoveleft a\\\\ b\\\\ c\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Left Middle', () => { + toXmlMatch( + tex2mml('\\begin{multline} a\\\\\\shoveleft b\\\\ c\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Left Bottom', () => { + toXmlMatch( + tex2mml('\\begin{multline} a\\\\ b\\\\\\shoveleft c\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Right Top', () => { + toXmlMatch( + tex2mml('\\begin{multline}\\shoveright a\\\\ b\\\\ c\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Right Middle', () => { + toXmlMatch( + tex2mml('\\begin{multline} a\\\\\\shoveright b\\\\ c\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Right Bottom', () => { + toXmlMatch( + tex2mml('\\begin{multline} a\\\\ b\\\\\\shoveright c\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Right Left', () => { + toXmlMatch( + tex2mml( + '\\begin{multline} a\\\\\\shoveright\\shoveleft b\\\\ c\\end{multline}' + ), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Left Right', () => { + toXmlMatch( + tex2mml( + '\\begin{multline} a\\\\\\shoveleft\\shoveright b\\\\ c\\end{multline}' + ), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Shove Error Top', () => { + expectTexError('\\begin{multline}a \\shoveleft\\\\ b\\\\ c\\end{multline}') + .toBe('\\shoveleft must come at the beginning of the line'); + }); + + /********************************************************************************/ + + it('Shove Error Middle', () => { + expectTexError('\\begin{multline} a\\\\ b \\shoveleft\\\\ c\\end{multline}') + .toBe('\\shoveleft must come at the beginning of the line'); + }); + + /********************************************************************************/ + + it('Shove Error Bottom', () => { + expectTexError('\\begin{multline} a\\\\ b\\\\ c \\shoveleft\\end{multline}') + .toBe('\\shoveleft must come at the beginning of the line'); + }); + + /********************************************************************************/ + + it('Shove Error Environment', () => { + expectTexError('\\begin{align}\\shoveleft a\\end{align}') + .toBe('\\shoveleft only allowed in multline environment'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Ams Complex', () => { + + /********************************************************************************/ + + it('The Lorenz Equations', () => { + toXmlMatch( + tex2mml( + '\\begin{align}\\dot{x} & = \\sigma(y-x) \\\\\\dot{y} & = \\rho x - y - xz \\\\\\dot{z} & = -\\beta z + xy\\end{align}' + ), + ` + + + + + + x + ˙ + + + + + + + = + σ + ( + y + + x + ) + + + + + + + + y + ˙ + + + + + + + = + ρ + x + + y + + x + z + + + + + + + + z + ˙ + + + + + + + = + + β + z + + + x + y + + + + + ` + ); + }); + + /********************************************************************************/ + + it("Maxwell's Equations", () => { + toXmlMatch( + tex2mml( + '\\begin{align} \\nabla \\times \\vec{\\mathbf{B}} -\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{E}}}{\\partial t} & = \\frac{4\\pi}{c}\\vec{\\mathbf{j}} \\\\ \\nabla \\cdot \\vec{\\mathbf{E}} & = 4 \\pi \\rho \\\\ \\nabla \\times \\vec{\\mathbf{E}}\\, +\\, \\frac1c\\, \\frac{\\partial\\vec{\\mathbf{B}}}{\\partial t} & = \\vec{\\mathbf{0}} \\\\ \\nabla \\cdot \\vec{\\mathbf{B}} & = 0 \\end{align}' + ), + ` + + + + + × + + + + B + + + + + + + + 1 + c + + + + + + + + + E + + + + + + + + t + + + + + + + = + + + 4 + π + + c + + + + + j + + + + + + + + + + + + + + + E + + + + + + + + + = + 4 + π + ρ + + + + + + + × + + + + E + + + + + + + + + + 1 + c + + + + + + + + + B + + + + + + + + t + + + + + + + = + + + + 0 + + + + + + + + + + + + + + + B + + + + + + + + + = + 0 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Cubic Binomial', () => { + toXmlMatch( + tex2mml( + '\\begin{eqnarray}(x+y)^{3}&=&(x+y)(x+y)(x+y)\\\\&=&xxx+xxy+xyx+{\\underline {xyy}}+yxx+{\\underline {yxy}}+{\\underline {yyx}}+yyy\\\\&=&x^{3}+3x^{2}y+{\\underline {3xy^{2}}}+y^{3}.\\end{eqnarray}' + ), + ` + + + + ( + x + + + y + + ) + + 3 + + + + + + = + + + + + ( + x + + + y + ) + ( + x + + + y + ) + ( + x + + + y + ) + + + + + + + + = + + + + x + x + x + + + x + x + y + + + x + y + x + + + + + + x + y + y + + + + + + + y + x + x + + + + + + y + x + y + + + + + + + + + + y + y + x + + + + + + + y + y + y + + + + + + + + = + + + + + x + + 3 + + + + + 3 + + x + + 2 + + + y + + + + + + 3 + x + + y + + 2 + + + + + + + + + + y + + 3 + + + . + + + + + ` + ); + }); + + /********************************************************************************/ + + it('A Cross Product Formula', () => { + toXmlMatch( + tex2mml( + '\\mathbf{V}_1 \\times \\mathbf{V}_2 = \\begin{vmatrix} \\mathbf{i} & \\mathbf{j} & \\mathbf{k} \\\\ \\frac{\\partial X}{\\partial u} & \\frac{\\partial Y}{\\partial u} & 0 \\\\ \\frac{\\partial X}{\\partial v} & \\frac{\\partial Y}{\\partial v} & 0 \\\\ \\end{vmatrix}' + ), + ` + + + V + + 1 + + × + + + V + + 2 + + = + + | + + + + + i + + + + + j + + + + + k + + + + + + + + + X + + + + u + + + + + + + + Y + + + + u + + + + + 0 + + + + + + + + X + + + + v + + + + + + + + Y + + + + v + + + + + 0 + + + + | + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Ams SideSet', () => { + + /********************************************************************************/ + + it('Sideset Empty', () => { + toXmlMatch( + tex2mml('\\sideset{}{}{}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Simple', () => { + toXmlMatch( + tex2mml('\\sideset{}{}{a}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Simple Right', () => { + toXmlMatch( + tex2mml('\\sideset{}{\'}{a}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Simple Left', () => { + toXmlMatch( + tex2mml('\\sideset{\'}{}{a}'), + ` + + + a + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Simple Left Right', () => { + toXmlMatch( + tex2mml('\\sideset{\'}{\'}{a}'), + ` + + + a + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Simple Sum', () => { + toXmlMatch( + tex2mml('\\sideset{}{\'}\\sum_{n=0}^{k}n'), + ` + + + + + + + + + n + = + 0 + + + k + + + n + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Extra Post', () => { + toXmlMatch( + tex2mml('\\sideset{a}{b}X'), + ` + + a + X + b + + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Pre No Base', () => { + toXmlMatch( + tex2mml('\\sideset{^1{}^2}{}X'), + ` + + + + + X + + + 1 + + + + 2 + + X + + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Pre with Post Sup', () => { + toXmlMatch( + tex2mml('\\sideset{^a}{^b}{x}'), + ` + + + x + + b + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('Sideset Pre with Post Sub', () => { + toXmlMatch( + tex2mml('\\sideset{^a}{_b}{x}'), + ` + + + x + b + + + + a + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Ams symbols', () => { + + /********************************************************************************/ + + it('Delimiters', () => { + toXmlMatch( + tex2mml( + '\\left\\llcorner X \\right\\lrcorner \\left\\lvert X \\right\\rvert \\left\\lVert X \\right\\rVert' + ), + ` + + + X + + + + | + X + | + + + + X + + + ` + ); + }); + + /********************************************************************************/ + + it('Spaces', () => { + toXmlMatch( + tex2mml('\\nobreakspace\\negmedspace\\negthickspace'), + ` +   + + + ` + ); + }); + + /********************************************************************************/ + + it('Accents', () => { + toXmlMatch( + tex2mml('\\mathring A \\dddot x \\ddddot x'), + ` + + + A + ˚ + + + + + x + + + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('Limits', () => { + toXmlMatch( + tex2mml('\\injlim \\projlim \\varliminf \\varlimsup \\varinjlim \\varprojlim'), + ` + inj lim + proj lim + + + lim + + + + + + + lim + + + + + + + lim + + + + + + + lim + + + + ` + ); + }); + + /********************************************************************************/ + + it('boxed', () => { + toXmlMatch( + tex2mml('\\boxed{x}'), + ` + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('substack', () => { + toXmlMatch( + tex2mml('\\substack{a\\\\b}'), + ` + + + + + a + + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('impliedby', () => { + toXmlMatch( + tex2mml('Q \\impliedby P'), + ` + Q + + + + P + ` + ); + }); + + /********************************************************************************/ + + it('math0mi 1', () => { + toXmlMatch( + tex2mml( + '\\varkappa\\varGamma\\varDelta\\varTheta\\varLambda\\varXi\\varPi\\varSigma\\varUpsilon\\varPhi\\varPsi\\varOmega' + ), + ` + ϰ + Γ + Δ + Θ + Λ + Ξ + Π + Σ + Υ + Φ + Ψ + Ω + ` + ); + }); + + /********************************************************************************/ + + it('math0mi 2', () => { + toXmlMatch( + tex2mml( + '\\beth\\gimel\\daleth\\backprime\\hslash\\varnothing\\blacktriangle\\triangledown\\blacktriangledown\\square\\Box' + ), + ` + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('math0mi 3', () => { + toXmlMatch( + tex2mml( + '\\blacksquare\\lozenge\\Diamond\\blacklozenge\\circledS\\bigstar\\sphericalangle\\measuredangle\\nexists\\complement' + ), + ` + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('math0mi 4', () => { + toXmlMatch( + tex2mml( + '\\mho\\eth\\Finv\\diagup\\Game\\diagdown\\Bbbk\\yen\\circledR\\checkmark\\maltese' + ), + ` + + ð + + + + + k + ¥ + ® + + + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 1', () => { + toXmlMatch( + tex2mml( + '\\ltimes\\smallsetminus\\rtimes\\Cap\\doublecap\\leftthreetimes\\Cup\\doublecup\\rightthreetimes\\barwedge\\curlywedge' + ), + ` + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 2', () => { + toXmlMatch( + tex2mml( + '\\veebar\\curlyvee\\doublebarwedge\\boxminus\\circleddash\\boxtimes\\circledast\\boxdot\\circledcirc\\boxplus' + ), + ` + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 3', () => { + toXmlMatch( + tex2mml( + '\\centerdot\\divideontimes\\intercal\\leqq\\geqq\\leqslant\\geqslant\\eqslantless\\eqslantgtr\\lessapprox\\gtrapprox' + ), + ` + + + + ≦≧⩽⩾⪕⪖⪅⪆ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 4', () => { + toXmlMatch( + tex2mml( + '\\approxeq\\lessdot\\gtrdot\\lll\\llless\\ggg\\gggtr\\lessgtr\\gtrless\\lesseqgtr\\gtreqless\\lesseqqgtr\\gtreqqless' + ), + ` + ≊⋖⋗⋘⋘⋙⋙≶≷⋚⋛⪋⪌ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 5', () => { + toXmlMatch( + tex2mml( + '\\doteqdot\\Doteq\\eqcirc\\risingdotseq\\circeq\\fallingdotseq\\triangleq\\backsim\\backsimeq\\subseteqq\\supseteqq' + ), + ` + ≑≑≖≓≗≒≜∽⋍⫅⫆ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 6', () => { + toXmlMatch( + tex2mml( + '\\Subset\\Supset\\sqsubset\\sqsupset\\preccurlyeq\\succcurlyeq\\curlyeqprec\\curlyeqsucc\\precsim\\succsim\\precapprox' + ), + ` + ⋐⋑⊏⊐≼≽⋞⋟≾≿⪷ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 7', () => { + toXmlMatch( + tex2mml( + '\\succapprox\\vartriangleleft\\lhd\\vartriangleright\\rhd\\trianglelefteq\\unlhd\\trianglerighteq\\unrhd\\vDash\\Vdash' + ), + ` + ⪸⊲⊲⊳⊳⊴⊴⊵⊵⊨⊩ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 8', () => { + toXmlMatch( + tex2mml( + '\\Vvdash\\smallsmile\\shortmid\\smallfrown\\shortparallel\\bumpeq\\between\\Bumpeq\\pitchfork\\varpropto\\backepsilon' + ), + ` + + ⌣∣⌢∥ + ≏≬≎⋔ + + + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 9', () => { + toXmlMatch( + tex2mml( + '\\blacktriangleleft\\blacktriangleright\\therefore\\because\\eqsim\\vartriangle\\Join\\nless\\ngtr\\nleq\\ngeq' + ), + ` + + + ∴∵≂ + + ⋈≮≯≰≱ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 10', () => { + toXmlMatch( + tex2mml( + '\\nleqslant\\ngeqslant\\nleqq\\ngeqq\\lneq\\gneq\\lneqq\\gneqq\\lvertneqq\\gvertneqq\\lnsim\\gnsim\\lnapprox\\gnapprox' + ), + ` + ⪇⪈≰≱ + ⪇⪈≨≩ + ≨≩ + ⋦⋧⪉⪊ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 11', () => { + toXmlMatch( + tex2mml( + '\\nprec\\nsucc\\npreceq\\nsucceq\\precneqq\\succneqq\\precnsim\\succnsim\\precnapprox\\succnapprox\\nsim\\ncong' + ), + ` + ⊀⊁ + ⋠⋡ + ⪵⪶⋨⋩⪹⪺≁≇ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 12', () => { + toXmlMatch( + tex2mml( + '\\nshortmid\\nshortparallel\\nmid\\nparallel\\nvdash\\nvDash\\nVdash\\nVDash\\ntriangleleft\\ntriangleright' + ), + ` + ∤∦ + ∤∦⊬⊭⊮⊯⋪⋫ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 13', () => { + toXmlMatch( + tex2mml( + '\\ntrianglelefteq\\ntrianglerighteq\\nsubseteq\\nsupseteq\\nsubseteqq\\nsupseteqq\\subsetneq\\supsetneq\\varsubsetneq' + ), + ` + ⋬⋭⊈⊉ + ⊈⊉ + ⊊⊋ + + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 14', () => { + toXmlMatch( + tex2mml( + '\\varsupsetneq\\subsetneqq\\supsetneqq\\varsubsetneqq\\varsupsetneqq\\leftleftarrows\\rightrightarrows\\leftrightarrows' + ), + ` + + ⫋⫌ + ⫋⫌ + ⇇⇉⇆ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 15', () => { + toXmlMatch( + tex2mml( + '\\rightleftarrows\\Lleftarrow\\Rrightarrow\\twoheadleftarrow\\twoheadrightarrow\\leftarrowtail\\rightarrowtail' + ), + ` + ⇄⇚⇛↞↠↢↣ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 16', () => { + toXmlMatch( + tex2mml( + '\\looparrowleft\\looparrowright\\leftrightharpoons\\rightleftharpoons\\curvearrowleft\\curvearrowright\\circlearrowleft' + ), + ` + ↫↬⇋ + + ↶↷↺ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 17', () => { + toXmlMatch( + tex2mml( + '\\circlearrowright\\Lsh\\Rsh\\upuparrows\\downdownarrows\\upharpoonleft\\upharpoonright\\downharpoonleft\\restriction' + ), + ` + ↻↰↱⇈⇊↿↾⇃↾ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 18', () => { + toXmlMatch( + tex2mml( + '\\multimap\\downharpoonright\\leftrightsquigarrow\\rightsquigarrow\\leadsto\\dashrightarrow\\dashleftarrow\\nleftarrow' + ), + ` + ⊸⇂↭⇝⇝⇢⇠↚ + ` + ); + }); + + /********************************************************************************/ + + it('math0mo 19', () => { + toXmlMatch( + tex2mml('\\nrightarrow\\nLeftarrow\\nRightarrow\\nleftrightarrow\\nLeftrightarrow'), + ` + ↛⇍⇏↮⇎ + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('ams')); diff --git a/testsuite/tests/input/tex/Amscd.test.ts b/testsuite/tests/input/tex/Amscd.test.ts new file mode 100644 index 000000000..ff09abb12 --- /dev/null +++ b/testsuite/tests/input/tex/Amscd.test.ts @@ -0,0 +1,907 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/amscd/AmsCdConfiguration'; + +beforeEach(() => setupTex(['base', 'amscd'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('AmsCD', () => { + + /********************************************************************************/ + + it('AmsCD-1', () => { + toXmlMatch( + tex2mml('\\begin{CD}A @>a>> B\\\\@VVbV @VVcV\\\\C @>d>> D\\end{CD}'), + ` + + + + A + + + + + + + a + + + + + B + + + + + + + + + + b + + + + + + + + + + + + + c + + + + + + + + + + C + + + + + + + d + + + + + D + + + + ` + ); + }); + + /********************************************************************************/ + + it('AmsCD-2', () => { + toXmlMatch( + tex2mml('\\begin{CD}A @<<< B @>>> C\\\\@. @| @AAA\\\\@. D @= E\\end{CD}'), + ` + + + + A + + + + + + + + + + + + B + + + + + + + + + + + C + + + + + + + + + + + + + + + + + + + + + D + + + = + + + E + + + + ` + ); + }); + + /********************************************************************************/ + + it('AmsCD-3', () => { + toXmlMatch( + tex2mml('\\begin{CD}A @>a>b> B\\\\@VlVrV @AlArA\\\\C @ + + + + A + + + + + + + b + + + a + + + + + B + + + + + + + + + l + + + + + + + + r + + + + + + + + + + + + l + + + + + + + + r + + + + + + + + + + C + + + + + + + b + + + a + + + + + D + + + + ` + ); + }); + + /********************************************************************************/ + + it('AmsCD-4', () => { + toXmlMatch( + tex2mml( + '\\begin{CD}A @>>> B@>\\text{very long label}>>C\\\\@VVV @VVV @VVV\\\\D @>>> E@>>> F\\end{CD}' + ), + ` + + + + A + + + + + + + + + + + + B + + + + + + very long label + + + + + C + + + + + + + + + + + + + + + + + + + D + + + + + + + + + + + + E + + + + + + + + + + + F + + + + ` + ); + }); + + /********************************************************************************/ + + it('AmsCD-5', () => { + toXmlMatch( + tex2mml( + '\\begin{CD}A @>>> B @>{\\text{very long label}}>> C \\\\@VVV @VVV @VVV \\\\D @>>> E @>{\\phantom{\\text{very long label}}}>> F\\end{CD}' + ), + ` + + + + A + + + + + + + + + + + + B + + + + + + + very long label + + + + + + C + + + + + + + + + + + + + + + + + + + D + + + + + + + + + + + + E + + + + + + + + + very long label + + + + + + + + F + + + + ` + ); + }); + + /********************************************************************************/ + + it('AmsCD-6', () => { + toXmlMatch( + tex2mml( + '\\begin{CD}A @>>> B @>{\\text{very long label}}>> C \\\\@VVV @VVV @VVV \\\\D @>>> E @>{\\rlap{\\scriptstyle{\\ \\ \\ \\text{shorter}}}\\phantom{\\text{very long label}}}>> F\\end{CD}' + ), + ` + + + + A + + + + + + + + + + + + B + + + + + + + very long label + + + + + + C + + + + + + + + + + + + + + + + + + + D + + + + + + + + + + + + E + + + + + + + + + +   +   +   + shorter + + + + + + very long label + + + + + + + + F + + + + ` + ); + }); + + /********************************************************************************/ + + it('AmsCD-width', () => { + toXmlMatch( + tex2mml( + '\\minCDarrowwidth{5cm}\\begin{CD}A @>a>> B\\\\@VVbV @VVcV\\\\C @>d>> D\\end{CD}' + ), + ` + + + + A + + + + + + + a + + + + + B + + + + + + + + + + b + + + + + + + + + + + + + c + + + + + + + + + + C + + + + + + + d + + + + + D + + + + ` + ); + }); + + /********************************************************************************/ + + it('AmsCD-height', () => { + toXmlMatch( + tex2mml( + '\\minCDarrowheight{4cm}\\begin{CD}A @>a>> B\\\\@VVbV @VVcV\\\\C @>d>> D\\end{CD}' + ), + ` + + + + A + + + + + + + a + + + + + B + + + + + + + + + + b + + + + + + + + + + + + + c + + + + + + + + + + C + + + + + + + d + + + + + D + + + + ` + ); + }); + + /********************************************************************************/ + + it('AmsCD-both', () => { + toXmlMatch( + tex2mml( + '\\minCDarrowheight{4cm}\\minCDarrowwidth{5cm}\\begin{CD}A @>a>> B\\\\@VVbV @VVcV\\\\C @>d>> D\\end{CD}' + ), + ` + + + + A + + + + + + + a + + + + + B + + + + + + + + + + b + + + + + + + + + + + + + c + + + + + + + + + + C + + + + + + + d + + + + + D + + + + ` + ); + }); + + /********************************************************************************/ + + it('Suspicious Return', () => { + toXmlMatch( + tex2mml('\\begin{CD}A @Ra>> BaD\\end{CD}'), + ` + + + + A + + @ + + R + a + >> + B + a + D + + + + ` + ); + }); + + /********************************************************************************/ + + it('Entry with prime (#3373)', () => { + toXmlMatch( + tex2mml(`\\begin{CD}A' @>>> B\\end{CD}`), + ` + + + + + A + + + + + + + + + + + + + + B + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('AmsCD Options', () => { + + beforeEach(() => setupTex(['base', 'amscd'], { amscd: {hideHorizontalLabels: true } })); + + /********************************************************************************/ + + it('Hide Horizontal Labels', () => { + toXmlMatch( + tex2mml('\\begin{CD}A @>a>> B\\\\@VVbV @VVcV\\\\C @>d>> D\\end{CD}'), + ` + + + + A + + + + + + + + a + + + + + + B + + + + + + + + + + b + + + + + + + + + + + + + c + + + + + + + + + + C + + + + + + + + d + + + + + + D + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('amscd')); diff --git a/testsuite/tests/input/tex/Autoload.test.ts b/testsuite/tests/input/tex/Autoload.test.ts new file mode 100644 index 000000000..e8fe288ba --- /dev/null +++ b/testsuite/tests/input/tex/Autoload.test.ts @@ -0,0 +1,57 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTexTypeset, typeset2mml, setupComponents } from '#helpers'; + +setupComponents({loader: {load: ['input/tex-base', '[tex]/autoload']}}); + +/**********************************************************************************/ +/**********************************************************************************/ + +beforeEach(() => setupTexTypeset(['base', 'autoload'])); + +describe('Autoload', () => { + + /********************************************************************************/ + + test('Autoload package', async () => { + toXmlMatch( + await typeset2mml('\\bbox[red]{x}'), + ` + + x + + ` + ); + }); + + test('Autoload environment', async () => { + toXmlMatch( + await typeset2mml('\\begin{CD} a @>>> b\\end{CD}'), + ` + + + + a + + + + + + + + + + + + b + + + + ` + ); + }); +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('autoload')); diff --git a/testsuite/tests/input/tex/Base-browser.test.ts b/testsuite/tests/input/tex/Base-browser.test.ts new file mode 100644 index 000000000..a3ea1a478 --- /dev/null +++ b/testsuite/tests/input/tex/Base-browser.test.ts @@ -0,0 +1,29 @@ +import { describe, test, expect } from '@jest/globals'; + +const FILE = 'https://testing.com/testing.html'; + +const window = { + document: { + getElementsByTagName: () => [1], + location: `${FILE}#xyz`, + } +}; +(global as any).window = window; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Base Window', () => { + + test('Base Tag', async () => { + const { BaseConfiguration } = await import('#js/input/tex/base/BaseConfiguration.js'); + expect(BaseConfiguration.options.baseURL).toBe(FILE); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + diff --git a/testsuite/tests/input/tex/Base.test.ts b/testsuite/tests/input/tex/Base.test.ts new file mode 100644 index 000000000..7b70ffabe --- /dev/null +++ b/testsuite/tests/input/tex/Base.test.ts @@ -0,0 +1,14376 @@ +import { afterAll, beforeEach, describe, it, expect } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import ParseOptions from '#js/input/tex/ParseOptions.js'; + +beforeEach(() => setupTex(['base'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Identifiers', () => { + + /********************************************************************************/ + + it('Identifier', () => { + toXmlMatch( + tex2mml('x'), + ` + x + ` + ); + }); + + /********************************************************************************/ + + it('Two Identifiers', () => { + toXmlMatch( + tex2mml('xy'), + ` + x + y + ` + ); + }); + + /********************************************************************************/ + + it('Capital', () => { + toXmlMatch( + tex2mml('A'), + ` + A + ` + ); + }); + + /********************************************************************************/ + + it('Other Characters', () => { + toXmlMatch( + tex2mml('x + \u00eb'), + ` + x + + + ë + ` + ); + }); + + /********************************************************************************/ + + it('Other Character Variant', () => { + toXmlMatch( + tex2mml('\\mathbf{\u0391}\u0391\u3333'), + ` + + Α + + Α + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Sub and Superscripts', () => { + + /********************************************************************************/ + + it('Empty base', () => { + toXmlMatch( + tex2mml('^2'), + ` + + + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Empty base2', () => { + toXmlMatch( + tex2mml('{}^2'), + ` + + + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Square', () => { + toXmlMatch( + tex2mml('x^2'), + ` + + x + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Cube', () => { + toXmlMatch( + tex2mml('x^3'), + ` + + x + 3 + + ` + ); + }); + + /********************************************************************************/ + + it('Large Operator', () => { + toXmlMatch( + tex2mml('\\sum^2_1'), + ` + + + 1 + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Move Superscript', () => { + toXmlMatch( + tex2mml('\\left( \\sum_1^n \\right)^{2}'), + ` + + + ( + + + 1 + n + + ) + + + 2 + + + ` + ); + }); + + /********************************************************************************/ + + it('Empty Base Index', () => { + toXmlMatch( + tex2mml('_3'), + ` + + + 3 + + ` + ); + }); + + /********************************************************************************/ + + it('Empty Base Index2', () => { + toXmlMatch( + tex2mml('{}_3'), + ` + + + 3 + + ` + ); + }); + + /********************************************************************************/ + + it('Index', () => { + toXmlMatch( + tex2mml('x_3'), + ` + + x + 3 + + ` + ); + }); + + /********************************************************************************/ + + it('SubSup', () => { + toXmlMatch( + tex2mml('x^a_3'), + ` + + x + 3 + a + + ` + ); + }); + + /********************************************************************************/ + + it('Inline OP Sup', () => { + toXmlMatch( + tex2mml('\\mathop{X}^2', false), + ` + + + X + + 2 + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Negations', () => { + + /********************************************************************************/ + + it('Negation Simple', () => { + toXmlMatch( + tex2mml('a \\not= b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Negation Complex', () => { + toXmlMatch( + tex2mml('a \\not= b \\not\\rightarrow c \\not\\leq d'), + ` + a + + b + + c + + d + ` + ); + }); + + /********************************************************************************/ + + it('Negation Explicit', () => { + toXmlMatch( + tex2mml(' \\not\\longrightarrow'), + ` + ⟶̸ + ` + ); + }); + + /********************************************************************************/ + + it('Negation Large', () => { + toXmlMatch( + tex2mml(' \\not3'), + ` + + + + + + 3 + ` + ); + }); + + /********************************************************************************/ + + it('Negation Left Paren', () => { + toXmlMatch( + tex2mml('\\not\\left(\\right.'), + ` + + + + + + + ( + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Primes', () => { + + /********************************************************************************/ + + it('Prime', () => { + toXmlMatch( + tex2mml("x'"), + ` + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('PrimeSup', () => { + toXmlMatch( + tex2mml("x^{'}"), + ` + + x + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Double Prime', () => { + toXmlMatch( + tex2mml("x''"), + ` + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Triple Prime', () => { + toXmlMatch( + tex2mml("x'''"), + ` + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Quadruple Prime', () => { + toXmlMatch( + tex2mml("x''''"), + ` + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Quintuple Prime', () => { + toXmlMatch( + tex2mml("x'''''"), + ` + + x + ′′′′′ + + ` + ); + }); + + /********************************************************************************/ + + it('PrePrime', () => { + toXmlMatch( + tex2mml("'x"), + ` + + + + + x + ` + ); + }); + + /********************************************************************************/ + + it('Prime with subscript', () => { + expectTexError("x^'_{3}").toBe('Missing open brace for superscript'); + }); + + /********************************************************************************/ + + it('Prime on Sub', () => { + toXmlMatch( + tex2mml("x^{'_{a}}"), + ` + + x + + + + + a + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Prime on Sup', () => { + toXmlMatch( + tex2mml("x^{a^{'}}"), + ` + + x + + + a + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Sup on Prime', () => { + toXmlMatch( + tex2mml("x^{'^{a}}"), + ` + + x + + + + + + + a + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Prime on Prime', () => { + toXmlMatch( + tex2mml("x^{'^{'}}"), + ` + + x + + + + + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Digits', () => { + + /********************************************************************************/ + + it('Integer', () => { + toXmlMatch( + tex2mml('2'), + ` + 2 + ` + ); + }); + + /********************************************************************************/ + + it('Number', () => { + toXmlMatch( + tex2mml('3.14'), + ` + 3.14 + ` + ); + }); + + /********************************************************************************/ + + it('Decimal', () => { + toXmlMatch( + tex2mml('.14'), + ` + .14 + ` + ); + }); + + /********************************************************************************/ + + it('Thousands', () => { + toXmlMatch( + tex2mml('1{,}000.10'), + ` + 1,000.10 + ` + ); + }); + + /********************************************************************************/ + + it('Wrong Thousands', () => { + toXmlMatch( + tex2mml('1{,}0000.10'), + ` + 1,000 + 0.10 + ` + ); + }); + + /********************************************************************************/ + + it('Decimal Point', () => { + toXmlMatch( + tex2mml('.'), + ` + . + ` + ); + }); + + /********************************************************************************/ + + it('Integer Font', () => { + toXmlMatch( + tex2mml('\\mathbf{2}'), + ` + + 2 + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('DigitsEuropean', () => { + beforeEach(() => + setupTex(['base'], { + digits: '^(?:[0-9]+(?:\\{\\.\\}[0-9]{3})*(?:,[0-9]*)?|,[0-9]+)', + }) + ); + + /********************************************************************************/ + + it('Integer European', () => { + toXmlMatch( + tex2mml('2'), + ` + 2 + ` + ); + }); + + /********************************************************************************/ + + it('Number European', () => { + toXmlMatch( + tex2mml('3,14'), + ` + 3,14 + ` + ); + }); + + /********************************************************************************/ + + it('Thousands European', () => { + toXmlMatch( + tex2mml('1{.}000,10'), + ` + 1.000,10 + ` + ); + }); + + /********************************************************************************/ + + it('Wrong Thousands European', () => { + toXmlMatch( + tex2mml('1{.}0000,10'), + ` + 1.000 + 0,10 + ` + ); + }); + + /********************************************************************************/ + + it('Decimal European', () => { + toXmlMatch( + tex2mml(',14'), + ` + ,14 + ` + ); + }); + + /********************************************************************************/ + + it('Decimal Point European', () => { + toXmlMatch( + tex2mml(','), + ` + , + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Roots', () => { + + /********************************************************************************/ + + it('Square Root', () => { + toXmlMatch( + tex2mml('\\sqrt{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Square Root Fraction', () => { + toXmlMatch( + tex2mml('\\sqrt\\frac{a}{b}'), + ` + + + a + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Nth Root', () => { + toXmlMatch( + tex2mml('\\sqrt[n]{x}'), + ` + + x + n + + ` + ); + }); + + /********************************************************************************/ + + it('Explicit Root', () => { + toXmlMatch( + tex2mml('\\root 4 \\of x'), + ` + + x + 4 + + ` + ); + }); + + /********************************************************************************/ + + it('Tweaked Root', () => { + toXmlMatch( + tex2mml('\\sqrt[\\leftroot{-2}\\uproot{2}\\beta]{k}'), + ` + + k + + β + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Error', () => { + + /********************************************************************************/ + + it('merror node', () => { + toXmlMatch( + tex2mml('&'), + ` + + Misplaced & + + ` + ); + }); + + /********************************************************************************/ + + it('Ampersand-error', () => { + expectTexError('&').toBe('Misplaced &'); + }); + + /********************************************************************************/ + + it('Argument-error', () => { + expectTexError('\\frac{b}').toBe('Missing argument for \\frac'); + }); + + /********************************************************************************/ + + it('Undefined-CS', () => { + expectTexError('\\nonsense').toBe('Undefined control sequence \\nonsense'); + }); + + /********************************************************************************/ + + it('Undefined-Env', () => { + expectTexError('\\begin{nonsense} a \\end{nonsense}') + .toBe("Unknown environment 'nonsense'"); + }); + + /********************************************************************************/ + + it('Double-super-error', () => { + expectTexError('x^2^3').toBe('Double exponent: use braces to clarify'); + }); + + /********************************************************************************/ + + it('Double-over-error', () => { + expectTexError('\\sum^2^3').toBe('Double exponent: use braces to clarify'); + }); + + /********************************************************************************/ + + it('Limits Error', () => { + expectTexError('+\\limits^2').toBe('\\limits is allowed only on operators'); + }); + + /********************************************************************************/ + + it('Double sub error', () => { + expectTexError('x_2_3').toBe('Double subscripts: use braces to clarify'); + }); + + /********************************************************************************/ + + it('Double under error', () => { + expectTexError('\\sum_2_3').toBe('Double subscripts: use braces to clarify'); + }); + + /********************************************************************************/ + + it('Brace Superscript Error', () => { + expectTexError("x'^'").toBe('Missing open brace for superscript'); + }); + + /********************************************************************************/ + + it('Double Prime Error', () => { + expectTexError("x^\\prime'") + .toBe('Prime causes double exponent: use braces to clarify'); + }); + + /********************************************************************************/ + + it('Double Prime Error 2', () => { + expectTexError("\\sum\\limits^n'") + .toBe('Prime causes double exponent: use braces to clarify'); + }); + + /********************************************************************************/ + + it('Hash Error', () => { + expectTexError('#') + .toBe("You can't use 'macro parameter character #' in math mode"); + }); + + /********************************************************************************/ + + it('Missing Right', () => { + expectTexError('\\left(\\middle|').toBe('Extra \\left or missing \\right'); + }); + + /********************************************************************************/ + + it('Orphan Middle', () => { + expectTexError('\\middle|').toBe('Extra \\middle'); + }); + + /********************************************************************************/ + + it('Middle with Right', () => { + expectTexError('\\middle|\\right)').toBe('Extra \\middle'); + }); + + /********************************************************************************/ + + it('Misplaced Move Root', () => { + expectTexError('\\uproot{2}\\sqrt[3]{a}') + .toBe('\\uproot can appear only within a root'); + }); + + /********************************************************************************/ + + it('Multiple Move Root', () => { + expectTexError('\\sqrt[\\uproot{-2}\\uproot{2}\\beta]{k}') + .toBe('Multiple use of \\uproot'); + }); + + /********************************************************************************/ + + it('Incorrect Move Root', () => { + expectTexError('\\sqrt[\\uproot-2.5\\beta]{k}') + .toBe('The argument to \\uproot must be an integer'); + }); + + /********************************************************************************/ + + it('Double Over', () => { + expectTexError('1 \\over 2 \\over 3').toBe('Ambiguous use of \\over'); + }); + + /********************************************************************************/ + + it('MissingBeginExtraEnd', () => { + expectTexError('\\end{array}') + .toBe('Missing \\begin{array} or extra \\end{array}'); + }); + + /********************************************************************************/ + + it('ExtraCloseMissingOpen', () => { + expectTexError('x}').toBe('Extra close brace or missing open brace'); + }); + + /********************************************************************************/ + + it('MissingLeftExtraRight', () => { + expectTexError('x\\right\\}').toBe('Missing \\left or extra \\right'); + }); + + /********************************************************************************/ + + it('ExtraOpenMissingClose', () => { + expectTexError('{x').toBe('Extra open brace or missing close brace'); + }); + + /********************************************************************************/ + + it('MissingScript Sub', () => { + expectTexError('x_').toBe('Missing superscript or subscript argument'); + }); + + /********************************************************************************/ + + it('MissingScript Sup', () => { + expectTexError('x^').toBe('Missing superscript or subscript argument'); + }); + + /********************************************************************************/ + + it('MissingOpenForSup', () => { + expectTexError('x^^').toBe('Missing open brace for superscript'); + }); + + /********************************************************************************/ + + it('MissingOpenForSub', () => { + expectTexError('x__').toBe('Missing open brace for subscript'); + }); + + /********************************************************************************/ + + it('ExtraLeftMissingRight', () => { + expectTexError('\\left\\{x').toBe('Extra \\left or missing \\right'); + }); + + /********************************************************************************/ + + it('Misplaced Cr', () => { + expectTexError('a\\cr b').toBe('Misplaced \\cr'); + }); + + /********************************************************************************/ + + it('Dimension Error', () => { + expectTexError('a\\\\[abc] b').toBe('Bracket argument to \\\\ must be a dimension'); + }); + + /********************************************************************************/ + + it('MissingArgFor', () => { + expectTexError('\\sqrt').toBe('Missing argument for \\sqrt'); + }); + + /********************************************************************************/ + + it('ExtraCloseMissingOpen 2', () => { + expectTexError('\\sqrt}').toBe('Extra close brace or missing open brace'); + }); + + /********************************************************************************/ + + it('MissingCloseBrace', () => { + expectTexError('\\sqrt{').toBe('Missing close brace'); + }); + + /********************************************************************************/ + + it('ExtraCloseLooking1', () => { + expectTexError('\\sqrt[3}').toBe("Extra close brace while looking for ']'"); + }); + + /********************************************************************************/ + + it('MissingCloseBracket', () => { + expectTexError('\\sqrt[3{x}') + .toBe("Could not find closing ']' for argument to \\sqrt"); + }); + + /********************************************************************************/ + + it('MissingOrUnrecognizedDelim1', () => { + expectTexError('\\left\\alpha b') + .toBe('Missing or unrecognized delimiter for \\left'); + }); + + /********************************************************************************/ + + it('MissingOrUnrecognizedDelim2', () => { + expectTexError('\\left( b\\right') + .toBe('Missing or unrecognized delimiter for \\right'); + }); + + /********************************************************************************/ + + it('MissingDimOrUnits', () => { + expectTexError('\\rule{}').toBe('Missing dimension or its units for \\rule'); + }); + + /********************************************************************************/ + + it('TokenNotFoundForCommand', () => { + expectTexError('\\root {3] \\of 5').toBe('Could not find \\of for \\root'); + }); + + /********************************************************************************/ + + it('ExtraCloseLooking2', () => { + expectTexError('\\root [3} \\of 5 ') + .toBe('Extra close brace while looking for \\of'); + }); + + /********************************************************************************/ + + it('ErroneousNestingEq', () => { + expectTexError('\\begin{equation}\\begin{eqnarray}\\end{eqnarray}\\end{equation}') + .toBe('Erroneous nesting of equation structures'); + }); + + /********************************************************************************/ + + it('ExtraAlignTab', () => { + expectTexError('\\cases{b & l & k}') + .toBe('Extra alignment tab in \\cases text'); + }); + + /********************************************************************************/ + + it('Misplaced hline', () => { + expectTexError('\\hline').toBe('Misplaced \\hline'); + }); + + /********************************************************************************/ + + it('UnsupportedHFill', () => { + expectTexError('a\\hfill b').toBe('Unsupported use of \\hfill'); + }); + + /********************************************************************************/ + + it('InvalidEnv', () => { + expectTexError('\\begin{\\ff}kk\\end{\\ff}') + .toBe('Invalid environment name \'\\ff\''); + }); + + /********************************************************************************/ + + it('EnvBadEnd', () => { + expectTexError('\\begin{equation}a\\end{array}') + .toBe('\\begin{equation} ended with \\end{array}'); + }); + + /********************************************************************************/ + + it('EnvMissingEnd Array', () => { + expectTexError('\\begin{array}{c}a').toBe('Missing \\end{array}'); + }); + + /********************************************************************************/ + + it('MissingBoxFor', () => { + expectTexError('\\raise{2pt}').toBe('Missing box for \\raise'); + }); + + /********************************************************************************/ + + it('MissingCloseBrace2', () => { + expectTexError('\\begin{array}{c').toBe('Missing close brace'); + }); + + /********************************************************************************/ + + it('EnvMissingEnd Equation', () => { + expectTexError('\\begin{equation}a').toBe('Missing \\end{equation}'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Fenced', () => { + + /********************************************************************************/ + + it('Fenced', () => { + toXmlMatch( + tex2mml('\\left(\\frac{a}{\\left[bc\\right]}\\right)'), + ` + + ( + + a + + [ + b + c + ] + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Fenced2', () => { + toXmlMatch( + tex2mml('\\{\\frac{a}{\\uparrow bc\\downarrow}\\}'), + ` + { + + a + + + b + c + + + + } + ` + ); + }); + + /********************************************************************************/ + + it('Fenced3', () => { + toXmlMatch( + tex2mml( + '\\left\\{\\left\\vert \\left[ \\left\\| A \\right.\\right| \\right]\\right\\}' + ), + ` + + { + + | + + [ + + + A + + + | + + ] + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Middle', () => { + toXmlMatch( + tex2mml('\\left(a\\middle|b\\right)'), + ` + + ( + a + + | + + b + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Fenced Nostretch 1', () => { + toXmlMatch( + tex2mml('(\\frac{a}{[bc]})'), + ` + ( + + a + + [ + b + c + ] + + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Fenced Noleft', () => { + toXmlMatch( + tex2mml('\\left. ab \\right)'), + ` + + + a + b + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Fenced Noright', () => { + toXmlMatch( + tex2mml('\\left( ab \\right.'), + ` + + ( + a + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Fenced Arrows 5', () => { + toXmlMatch( + tex2mml( + '\\left\\{\\frac{a}{\\left\\uparrow bc\\right\\downarrow}\\right\\}' + ), + ` + + { + + a + + + b + c + + + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Fenced Arrows 1', () => { + toXmlMatch( + tex2mml('\\left\\uparrow \\frac{a}{b} \\right\\downarrow'), + ` + + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Fenced Arrows 2', () => { + toXmlMatch( + tex2mml('\\uparrow \\frac{a}{b} \\downarrow'), + ` + + + a + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Fenced Arrows 3', () => { + toXmlMatch( + tex2mml( + '\\left\\uparrow \\frac{a}{b}\\middle\\downarrow c \\right\\uparrow' + ), + ` + + + + a + b + + + + + c + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathchoice', () => { + + /********************************************************************************/ + + it('Modulo', () => { + toXmlMatch( + tex2mml('a\\mod b'), + ` + a + + mod + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Modulo Sub0', () => { + toXmlMatch( + tex2mml('X_{a\\mod b}'), + ` + + X + + a + + mod + + + + + + + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Modulo Sub1', () => { + toXmlMatch( + tex2mml('X_{1_{a\\mod b}}'), + ` + + X + + + 1 + + a + + mod + + + + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Modulo Sub2', () => { + toXmlMatch( + tex2mml('X_{1_{2_{a\\mod b}}}'), + ` + + X + + + 1 + + + 2 + + a + + mod + + + + + + + b + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Modulo Sub3', () => { + toXmlMatch( + tex2mml('X_{1_{2_{3_{a\\mod b}}}}'), + ` + + X + + + 1 + + + 2 + + + 3 + + a + + mod + + + + + + + b + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it(`Pmod`, () => { + toXmlMatch( + tex2mml('a \\pmod b'), + ` + a + + ( + mod + + b + ) + ` + ); + }); + + /********************************************************************************/ + + it(`Bmod`, () => { + toXmlMatch( + tex2mml('a \\bmod b'), + ` + a + mod + b + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Stacking expressions', () => { + + /********************************************************************************/ + + it('Frac', () => { + toXmlMatch( + tex2mml('\\frac{a}{b}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('over', () => { + toXmlMatch( + tex2mml('a \\over b'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('over complex numerator', () => { + toXmlMatch( + tex2mml('a + b \\over c'), + ` + + + a + + + b + + c + + ` + ); + }); + + /********************************************************************************/ + + it('Overset', () => { + toXmlMatch( + tex2mml('\\overset{a}{b}'), + ` + + b + a + + ` + ); + }); + + /********************************************************************************/ + + it('Overset Accent', () => { + toXmlMatch( + tex2mml('\\overset{\\rightarrow}{b}'), + ` + + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Underset', () => { + toXmlMatch( + tex2mml('\\underset{a}{b}'), + ` + + b + a + + ` + ); + }); + + /********************************************************************************/ + + it('Underset Accent', () => { + toXmlMatch( + tex2mml('\\underset{\\rightarrow}{b}'), + ` + + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Overunderset', () => { + toXmlMatch( + tex2mml('\\overunderset{a}{b}{c}'), + ` + + c + b + a + + ` + ); + }); + + /********************************************************************************/ + + it('Overunderset Accent', () => { + toXmlMatch( + tex2mml('\\overunderset{\\rightarrow}{\\leftarrow}{b}'), + ` + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Over', () => { + toXmlMatch( + tex2mml('1 \\over 2'), + ` + + 1 + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Above', () => { + toXmlMatch( + tex2mml('a \\above 1pt b'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Choose', () => { + toXmlMatch( + tex2mml('n \\choose k'), + ` + + + ( + + + n + k + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Choose Sub0', () => { + toXmlMatch( + tex2mml('X_{n \\choose k}'), + ` + + X + + + + ( + + + n + k + + + ) + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Choose Sub1', () => { + toXmlMatch( + tex2mml('X_{1_{n \\choose k}}'), + ` + + X + + + 1 + + + + ( + + + n + k + + + ) + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Choose Sub2', () => { + toXmlMatch( + tex2mml('X_{1_{2_{n \\choose k}}}'), + ` + + X + + + 1 + + + 2 + + + + ( + + + n + k + + + ) + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Choose Sub3', () => { + toXmlMatch( + tex2mml('X_{1_{2_{3_{n \\choose k}}}}'), + ` + + X + + + 1 + + + 2 + + + 3 + + + + ( + + + n + k + + + ) + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Over With Delims', () => { + toXmlMatch( + tex2mml('1 \\overwithdelims [ ] 2'), + ` + + + [ + + + 1 + 2 + + + ] + + + ` + ); + }); + + /********************************************************************************/ + + it('Over With Delims Sub0', () => { + toXmlMatch( + tex2mml('X_{1 \\overwithdelims [ ] 2}'), + ` + + X + + + + [ + + + 1 + 2 + + + ] + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Over With Delims Sub1', () => { + toXmlMatch( + tex2mml('X_{1_{1 \\overwithdelims [ ] 2}}'), + ` + + X + + + 1 + + + + [ + + + 1 + 2 + + + ] + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Over With Delims Sub2', () => { + toXmlMatch( + tex2mml('X_{1_{2_{1 \\overwithdelims [ ] 2}}}'), + ` + + X + + + 1 + + + 2 + + + + [ + + + 1 + 2 + + + ] + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Over With Delims Sub3', () => { + toXmlMatch( + tex2mml('X_{1_{2_{3_{1 \\overwithdelims [ ] 2}}}}'), + ` + + X + + + 1 + + + 2 + + + 3 + + + + [ + + + 1 + 2 + + + ] + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above With Delims', () => { + toXmlMatch( + tex2mml('a \\abovewithdelims [ ] 1pt b'), + ` + + + [ + + + a + b + + + ] + + + ` + ); + }); + + /********************************************************************************/ + + it('Above With Delims Sub0', () => { + toXmlMatch( + tex2mml('X_{a \\abovewithdelims [ ] 1pt b}'), + ` + + X + + + + [ + + + a + b + + + ] + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above With Delims Sub1', () => { + toXmlMatch( + tex2mml('X_{1_{a \\abovewithdelims [ ] 1pt b}}'), + ` + + X + + + 1 + + + + [ + + + a + b + + + ] + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above With Delims Sub2', () => { + toXmlMatch( + tex2mml('X_{1_{2_{a \\abovewithdelims [ ] 1pt b}}}'), + ` + + X + + + 1 + + + 2 + + + + [ + + + a + b + + + ] + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Above With Delims Sub3', () => { + toXmlMatch( + tex2mml('X_{1_{2_{3_{a \\abovewithdelims [ ] 1pt b}}}}'), + ` + + X + + + 1 + + + 2 + + + 3 + + + + [ + + + a + b + + + ] + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Probability', () => { + toXmlMatch( + tex2mml('P(E) = {n \\choose k} p^k (1-p)^{ n-k}'), + ` + P + ( + E + ) + = + + + + ( + + + n + k + + + ) + + + + + p + k + + ( + 1 + + p + + ) + + n + + k + + + ` + ); + }); + + /********************************************************************************/ + + it('stackrel', () => { + toXmlMatch( + tex2mml('x\\stackrel{a}{b}y'), + ` + x + + + + b + + + a + + + + y + ` + ); + }); + + /********************************************************************************/ + + it('stackbin', () => { + toXmlMatch( + tex2mml('x\\stackbin{a}{b}y'), + ` + x + + + + b + + + a + + + + y + ` + ); + }); + + /********************************************************************************/ + + it('atop', () => { + toXmlMatch( + tex2mml('a \\atop b'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('atopwithdelims', () => { + toXmlMatch( + tex2mml('a \\atopwithdelims [ ] b'), + ` + + + [ + + + a + b + + + ] + + + ` + ); + }); + + /********************************************************************************/ + + it('brack', () => { + toXmlMatch( + tex2mml('n \\brack k'), + ` + + + [ + + + n + k + + + ] + + + ` + ); + }); + + /********************************************************************************/ + + it('brace', () => { + toXmlMatch( + tex2mml('n \\brace k'), + ` + + + { + + + n + k + + + } + + + ` + ); + }); + + /********************************************************************************/ + + it('BuildRel', () => { + toXmlMatch( + tex2mml('\\buildrel{a}\\over b'), + ` + + + b + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('BuildRel Expression', () => { + toXmlMatch( + tex2mml('x\\buildrel{a}\\over b y'), + ` + x + + + b + + a + + + + y + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('MmlToken', () => { + + /********************************************************************************/ + + it('MmlToken mo', () => { + toXmlMatch( + tex2mml('\\mmlToken{mo}{rem}'), + ` + rem + ` + ); + }); + + /********************************************************************************/ + + it('MmlToken mi', () => { + toXmlMatch( + tex2mml('\\mmlToken{mi}{=}'), + ` + = + ` + ); + }); + + /********************************************************************************/ + + it('MmlToken attribute', () => { + toXmlMatch( + tex2mml('\\mmlToken{mo}[mathvariant=normal]{=}'), + ` + = + ` + ); + }); + + /********************************************************************************/ + + it('MmlToken attribute boolean', () => { + toXmlMatch( + tex2mml('\\mmlToken{mo}[mathvariant=normal,largeop=true]{=}'), + ` + = + ` + ); + }); + + /********************************************************************************/ + + it('MmlToken attribute boolean false', () => { + toXmlMatch( + tex2mml('\\mmlToken{mo}[mathvariant=normal,largeop=false]{=}'), + ` + = + ` + ); + }); + + /********************************************************************************/ + + it('Token Illegal Type', () => { + expectTexError('\\mmlToken{mk}[]{}').toBe('mk is not a token element'); + }); + + /********************************************************************************/ + + it('Token Wrong Type', () => { + expectTexError('\\mmlToken{mrow}[]{}').toBe('mrow is not a token element'); + }); + + /********************************************************************************/ + + it('Token Invalid Attribute', () => { + expectTexError('\\mmlToken{mi}[m1=true]{}') + .toBe('Invalid MathML attribute: m1=true'); + }); + + /********************************************************************************/ + + it('Token Unknown Attribute', () => { + expectTexError('\\mmlToken{mo}[nothing="something"]{}') + .toBe('nothing is not a recognized attribute for mo'); + }); + + /********************************************************************************/ + + it('Token Wrong Attribute', () => { + expectTexError('\\mmlToken{mi}[movablelimit=true]{}') + .toBe('movablelimit is not a recognized attribute for mi'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Matrix', () => { + + /********************************************************************************/ + + it('Matrix Error', () => { + expectTexError('\\matrix').toBe('Missing argument for \\matrix'); + }); + + /********************************************************************************/ + + it('Matrix Arg', () => { + toXmlMatch( + tex2mml('\\matrix a'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Braces', () => { + toXmlMatch( + tex2mml('\\matrix{a}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Columns', () => { + toXmlMatch( + tex2mml('\\array{a&b}'), + ` + + + + a + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Rows', () => { + toXmlMatch( + tex2mml('\\array{a&b\\\\ c&d}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Subscript', () => { + toXmlMatch( + tex2mml('X_{\\matrix{a&b}}'), + ` + + X + + + + + a + + + b + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Parens', () => { + toXmlMatch( + tex2mml('\\pmatrix{a&b}'), + ` + + ( + + + + a + + + b + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Parens Subscript', () => { + toXmlMatch( + tex2mml('X_{\\pmatrix{a&b}}'), + ` + + X + + + ( + + + + a + + + b + + + + ) + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Font Entry', () => { + toXmlMatch( + tex2mml('\\pmatrix{\\bf a&b}'), + ` + + ( + + + + a + + + b + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Cases', () => { + toXmlMatch( + tex2mml('\\cases{a}'), + ` + + { + + + + a + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Cases', () => { + toXmlMatch( + tex2mml('\\cases{a}'), + ` + + { + + + + a + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Cases two columns', () => { + toXmlMatch( + tex2mml('\\cases{a & b}'), + ` + + { + + + + a + + + b + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Cases two columns braces', () => { + toXmlMatch( + tex2mml('\\cases{a & {b}}'), + ` + + { + + + + a + + + {b} + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Cases two rows', () => { + toXmlMatch( + tex2mml('\\cases{a & b\\\\ c & d}'), + ` + + { + + + + a + + + b + + + + + c + + + d + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Cases text', () => { + toXmlMatch( + tex2mml('\\cases{a & \\text{b}}'), + ` + + { + + + + a + + + b + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Numbered', () => { + toXmlMatch( + tex2mml('\\eqalignno{a&b&c}'), + ` + + + + c + + + a + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Numbered Left', () => { + toXmlMatch( + tex2mml('\\leqalignno{a&b&c}'), + ` + + + + c + + + a + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Not Numbered', () => { + toXmlMatch( + tex2mml('\\eqalign{a&b&c}'), + ` + + + + a + + + b + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Displaylines', () => { + toXmlMatch( + tex2mml('\\displaylines{a\\\\ b}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('InternalMath', () => { + + /********************************************************************************/ + + it('Interspersed Text', () => { + toXmlMatch( + tex2mml('a\\text{c$d$e}b'), + ` + a + + c + + d + + e + + b + ` + ); + }); + + /********************************************************************************/ + + it('Unicode text', () => { + toXmlMatch( + tex2mml('\\text{\\U{65}}'), + ` + e + ` + ); + }); + + /********************************************************************************/ + + it('Unicode text error', () => { + expectTexError('\\text{\\U{xyz}}') + .toBe('Argument to \\U must a hexadecimal number with 1 to 6 digits'); + }); + + /********************************************************************************/ + + it('Mbox Mbox', () => { + toXmlMatch( + tex2mml('a\\mbox{ b $a\\mbox{ b c } c$ c } c'), + ` + a + +  b  + + a +  b c  + c + +  c  + + c + ` + ); + }); + + /********************************************************************************/ + + it('Mbox Math', () => { + toXmlMatch( + tex2mml('a\\mbox{ ${ab}$ } c'), + ` + a + +   + + + a + b + + +   + + c + ` + ); + }); + + /********************************************************************************/ + + it('Mbox CR', () => { + toXmlMatch( + tex2mml('a\\mbox{aa \\\\ bb} c'), + ` + a + + aa \\ bb + + c + ` + ); + }); + + /********************************************************************************/ + + it('Internal Math Error', () => { + expectTexError('a\\mbox{$}} c') + .toBe('Math mode is not properly terminated'); + }); + + /********************************************************************************/ + + it('Mbox Internal Display', () => { + toXmlMatch( + tex2mml('a\\mbox{aa \\(\\frac{a}{b}\\) bb} c'), + ` + a + + aa  + + + a + b + + +  bb + + c + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Array', () => { + + /********************************************************************************/ + + it('Array Single', () => { + toXmlMatch( + tex2mml('\\begin{array}{c}a\\end{array}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed left right', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c|}a\\end{array}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed left', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c}a\\end{array}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed right', () => { + toXmlMatch( + tex2mml('\\begin{array}{c|}a\\end{array}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed top', () => { + toXmlMatch( + tex2mml('\\begin{array}{c}\\hline a\\end{array}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed bottom', () => { + toXmlMatch( + tex2mml('\\begin{array}{c} a\\\\\\hline\\end{array}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed top bottom', () => { + toXmlMatch( + tex2mml('\\begin{array}{c}\\hline a\\\\\\hline\\end{array}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed frame solid', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c|}\\hline a\\\\\\hline\\end{array}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed frame dashed', () => { + toXmlMatch( + tex2mml('\\begin{array}{:c:}\\hline a\\\\\\hline\\end{array}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed solid dashed', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c:} a\\end{array}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array dashed column', () => { + toXmlMatch( + tex2mml('\\begin{array}{c:c}a&c\\\\b&d\\end{array}'), + ` + + + + a + + + c + + + + + b + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array solid column', () => { + toXmlMatch( + tex2mml('\\begin{array}{c|c}a&c\\\\b&d\\end{array}'), + ` + + + + a + + + c + + + + + b + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array dashed row', () => { + toXmlMatch( + tex2mml('\\begin{array}{c}a\\\\\\hdashline b\\end{array}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array solid row', () => { + toXmlMatch( + tex2mml('\\begin{array}{c}a\\\\\\hline b\\end{array}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed dashed row', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c|}a\\\\\\hdashline b\\end{array}'), + ` + + + + + a + + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed solid row', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c|}a\\\\\\hline b\\end{array}'), + ` + + + + + a + + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed dashed column', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c:c|}a&c\\\\b&d\\end{array}'), + ` + + + + + a + + + c + + + + + b + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Enclosed solid column', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c|c|}a&c\\\\b&d\\end{array}'), + ` + + + + + a + + + c + + + + + b + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array aligned', () => { + toXmlMatch( + tex2mml('\\begin{array}[b]{c}a\\end{array}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array aligned invalid', () => { + toXmlMatch( + tex2mml('\\begin{array}[x]{c}a\\end{array}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Empty Array with Template', () => { + toXmlMatch( + tex2mml('\\begin{array}{>{x}c} \\end{array}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Label', () => { + toXmlMatch( + tex2mml('\\eqalignno{a & & {\\hbox{(3)}}}'), + ` + + + + + + (3) + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Columnlines Solid None', () => { + toXmlMatch( + tex2mml('\\begin{array}{c|cc}a&b&c\\\\d&e&f\\end{array}'), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('Rowlines Solid None', () => { + toXmlMatch( + tex2mml( + '\\begin{array}{ccc}a&b&c\\\\\\hline d&e&f\\\\ g&h&i \\end{array}' + ), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + + g + + + h + + + i + + + + ` + ); + }); + + /********************************************************************************/ + + it('Column+Rowlines Solid None', () => { + toXmlMatch( + tex2mml( + '\\begin{array}{c|cc}a&b&c\\\\\\hline d&e&f\\\\ g&h&i \\end{array}' + ), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + + g + + + h + + + i + + + + ` + ); + }); + + /********************************************************************************/ + + it('Column+Rowlines Solid Dashed None', () => { + toXmlMatch( + tex2mml( + '\\begin{array}{c|c:cc}0&a&b&c\\\\\\hline 1&d&e&f\\\\\\hdashline 2&g&h&i\\\\ 3&j&k&l \\end{array}' + ), + ` + + + + 0 + + + a + + + b + + + c + + + + + 1 + + + d + + + e + + + f + + + + + 2 + + + g + + + h + + + i + + + + + 3 + + + j + + + k + + + l + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrix Test', () => { + toXmlMatch( + tex2mml( + '\\left( \\begin{array}{ccc}a & b & c \\\\d & e & f \\\\g & h & i \\end{array} \\right)' + ), + ` + + ( + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + + g + + + h + + + i + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Newcolumntype', () => { + toXmlMatch( + tex2mml('\\newcolumntype{a}{c}\\begin{array}{a|a}a&b\\\\c&d\\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Newcolumntype Option', () => { + toXmlMatch( + tex2mml('\\newcolumntype{a}[1]{m{#1}}\\begin{array}{a{1em}|a{2em}}a&b\\\\c&d\\end{array}'), + ` + + + + + a + + + + + b + + + + + + + c + + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Newcolumntype Error Argument', () => { + expectTexError('\\newcolumntype{ab}{c}\\begin{array}{a|a}a&b\\\\c&d\\end{array}') + .toBe('Column specifier must be exactly one character: ab'); + }); + + /********************************************************************************/ + + it('Newcolumntype Error Option', () => { + expectTexError('\\newcolumntype{a}[-1]{c}\\begin{array}{a|a}a&b\\\\c&d\\end{array}') + .toBe('Argument to -1 must be a positive integer'); + }); + + /********************************************************************************/ + + it('Newcolumntype Missing Option', () => { + expectTexError('\\newcolumntype{a}[1]{c}\\begin{array}{a|a}a&b\\\\c&d\\end{array}') + .toBe('Missing argument for a column declaration'); + }); + + /********************************************************************************/ + + it('Column Infinite Loop', () => { + expectTexError('\\newcolumntype{a}{a}\\begin{array}{a} x \\end{array}') + .toBe('Too many column specifiers (perhaps looping column definitions?)'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Moving limits', () => { + + /********************************************************************************/ + + it('Limits SubSup', () => { + toXmlMatch( + tex2mml('\\int^2\\limits_3'), + ` + + + 3 + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Limits UnderOver', () => { + toXmlMatch( + tex2mml('\\lim_3\\nolimits^2'), + ` + + lim + 3 + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Limits', () => { + toXmlMatch( + tex2mml('\\sum\\limits^2_3'), + ` + + + 3 + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Vector Op', () => { + toXmlMatch( + tex2mml('\\vec{+}'), + ` + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overline', () => { + toXmlMatch( + tex2mml('\\overline{a}'), + ` + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('Overline Limits', () => { + toXmlMatch( + tex2mml('\\overline{\\int\\limits^2}'), + ` + + + + + + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overline Sum', () => { + toXmlMatch( + tex2mml('\\overline{\\sum}'), + ` + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overline 1', () => { + toXmlMatch( + tex2mml('\\overline{\\sum}'), + ` + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overline 2', () => { + toXmlMatch( + tex2mml('\\overline{\\mathop{a}}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overline 3', () => { + toXmlMatch( + tex2mml('\\overline{\\mathop{a}}^2'), + ` + + + + a + + + + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Overline 4', () => { + toXmlMatch( + tex2mml('\\overline{\\sum^2_3}'), + ` + + + + + + 3 + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overline 5', () => { + toXmlMatch( + tex2mml('\\overline{\\sum}^2_3'), + ` + + + + + + 3 + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Overline 6', () => { + toXmlMatch( + tex2mml('\\overline{\\underline{\\sum}}'), + ` + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Subscripted overline with space (#3372)', () => { + toXmlMatch( + tex2mml('\\overline{X}_ {y}'), + ` + + + X + + + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Overbrace 1', () => { + toXmlMatch( + tex2mml('\\overbrace{abc}'), + ` + + + + a + b + c + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Underbrace', () => { + toXmlMatch( + tex2mml('\\underbrace{abc}'), + ` + + + + a + b + c + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overbrace Op 1', () => { + toXmlMatch( + tex2mml('\\overbrace{\\mathop{a}}'), + ` + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overbrace Op 2', () => { + toXmlMatch( + tex2mml('\\overbrace{\\mathop{a}}^2'), + ` + + + + + a + + + + + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Overbrace 2', () => { + toXmlMatch( + tex2mml('\\overbrace{\\sum}'), + ` + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Overbrace 3', () => { + toXmlMatch( + tex2mml('\\overbrace{\\sum}^2'), + ` + + + + + + + + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Underleftrightarrow', () => { + toXmlMatch( + tex2mml('\\underleftrightarrow{abc}'), + ` + + + a + b + c + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Multirel', () => { + + /********************************************************************************/ + + it('Shift Left', () => { + toXmlMatch( + tex2mml('a< + a + << + b + ` + ); + }); + + /********************************************************************************/ + + it('Less Equal', () => { + toXmlMatch( + tex2mml('a<=b'), + ` + a + <= + b + ` + ); + }); + + /********************************************************************************/ + + it('Infix Op Op', () => { + toXmlMatch( + tex2mml('a++b'), + ` + a + + + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Infix Op Rel', () => { + toXmlMatch( + tex2mml('a+=b'), + ` + a + + + = + b + ` + ); + }); + + /********************************************************************************/ + + it('Postfix Op Op', () => { + toXmlMatch( + tex2mml('a++'), + ` + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Postfix Rel Rel', () => { + toXmlMatch( + tex2mml('a=='), + ` + a + == + ` + ); + }); + + /********************************************************************************/ + + it('Infix Bars', () => { + toXmlMatch( + tex2mml('a||b'), + ` + a + | + | + b + ` + ); + }); + + /********************************************************************************/ + + it('Infix Fences', () => { + toXmlMatch( + tex2mml('a))b'), + ` + a + ) + ) + b + ` + ); + }); + + /********************************************************************************/ + + it('Infix Rel Rel', () => { + toXmlMatch( + tex2mml('a\\rightarrow=b'), + ` + a + →= + b + ` + ); + }); + + /********************************************************************************/ + + it('Infix 4Rel', () => { + toXmlMatch( + tex2mml('a=<>=b'), + ` + a + =<>= + b + ` + ); + }); + + /********************************************************************************/ + + it('Prefix Rel Rel', () => { + toXmlMatch( + tex2mml('==a'), + ` + == + a + ` + ); + }); + + /********************************************************************************/ + + it('Prefix Op Op', () => { + toXmlMatch( + tex2mml('++a'), + ` + + + + + a + ` + ); + }); + + /********************************************************************************/ + + it('Multirel Font 1', () => { + toXmlMatch( + tex2mml('a <=\\mathrm{>} b'), + ` + a + <= + + > + + b + ` + ); + }); + + /********************************************************************************/ + + it('Multirel Font 2', () => { + toXmlMatch( + tex2mml('a <=\\mathrm{=>} b'), + ` + a + <= + + => + + b + ` + ); + }); + + /********************************************************************************/ + + it('Multirel Font 3', () => { + toXmlMatch( + tex2mml('a <=\\mathrm{=}\\mathrm{>} b'), + ` + a + <= + + = + + + > + + b + ` + ); + }); + + /********************************************************************************/ + + it('Multirel Attributes 1', () => { + toXmlMatch( + tex2mml('a \\mmlToken{mo}[mathvariant=bold]{<}= b'), + ` + a + < + = + b + ` + ); + }); + it('Multirel Attributes 2', () => { + toXmlMatch( + tex2mml('a \\mmlToken{mo}[mathvariant=bold]{<}\\mmlToken{mo}[mathsize=2]{=} b'), + ` + a + < + = + b + ` + ); + }); + + /********************************************************************************/ + + it('Simple Shadow Rel', () => { + toXmlMatch( + tex2mml('a \\sim b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Extra Attribute Rel 1', () => { + toXmlMatch( + tex2mml('a =\\sim b'), + ` + a + =∼ + b + ` + ); + }); + + /********************************************************************************/ + + it('Extra Attribute Rel 2', () => { + toXmlMatch( + tex2mml('a \\sim\\simeq b'), + ` + a + ∼≃ + b + ` + ); + }); + + /********************************************************************************/ + + it('Extra Attribute Rel 3', () => { + toXmlMatch( + tex2mml('a \\sim\\asymp b'), + ` + a + ∼≍ + b + ` + ); + }); + + /********************************************************************************/ + + it('Extra Attribute Rel 4', () => { + toXmlMatch( + tex2mml('a \\sim\\simeq\\asymp b'), + ` + a + ∼≃≍ + b + ` + ); + }); + + /********************************************************************************/ + + it('Extra Attribute Rel 5', () => { + toXmlMatch( + tex2mml('a \\sim\\asymp\\simeq b'), + ` + a + ∼≍≃ + b + ` + ); + }); + + /********************************************************************************/ + + it('Extra Attribute Rel 6', () => { + toXmlMatch( + tex2mml('a \\sim\\cong b'), + ` + a + ∼≅ + b + ` + ); + }); + + /********************************************************************************/ + + it('Infix Stretchy Right', () => { + toXmlMatch( + tex2mml('a=\\rightarrow b'), + ` + a + =→ + b + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Other', () => { + + /********************************************************************************/ + + it('Other', () => { + toXmlMatch( + tex2mml('+'), + ` + + + ` + ); + }); + + /********************************************************************************/ + + it('Other Remap', () => { + toXmlMatch( + tex2mml('-'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Other Font', () => { + toXmlMatch( + tex2mml('\\mathbf{+}'), + ` + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Other Delimiter', () => { + toXmlMatch( + tex2mml('('), + ` + ( + ` + ); + }); + + /********************************************************************************/ + + it('Other Dollar', () => { + toXmlMatch( + tex2mml('$'), + ` + + $ + + ` + ); + }); + + /********************************************************************************/ + + it('Other Unicode', () => { + toXmlMatch( + tex2mml('˦'), + ` + + ˦ + + ` + ); + }); + + /********************************************************************************/ + + it('Other Surrogate', () => { + toXmlMatch( + tex2mml('𝐀'), + ` + 𝐀 + ` + ); + }); + + /********************************************************************************/ + + it('Other Arrow Range', () => { + toXmlMatch( + tex2mml('⤡'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Other Arrow Infix', () => { + toXmlMatch( + tex2mml('a⤡b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Other Arrow Prefix', () => { + toXmlMatch( + tex2mml('⤡b'), + ` + + b + ` + ); + }); + + /********************************************************************************/ + + it('Other Arrow Postfix', () => { + toXmlMatch( + tex2mml('b⤡'), + ` + b + + ` + ); + }); + + /********************************************************************************/ + + it('Vertical Bar Alone', () => { + toXmlMatch( + tex2mml('|'), + ` + | + ` + ); + }); + + /********************************************************************************/ + + it('Vertical Bar Infix', () => { + toXmlMatch( + tex2mml('a|b'), + ` + a + | + b + ` + ); + }); + + /********************************************************************************/ + + it('Vertical Bar Postfix', () => { + toXmlMatch( + tex2mml('a|'), + ` + a + | + ` + ); + }); + + /********************************************************************************/ + + it('Vertical Bar Prefix', () => { + toXmlMatch( + tex2mml('|b'), + ` + | + b + ` + ); + }); + + /********************************************************************************/ + + it('CKJ', () => { + toXmlMatch( + tex2mml('褯¥'), + ` + + + ¥ + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Base Complex', () => { + + /********************************************************************************/ + + it('Square Root Complex', () => { + toXmlMatch( + tex2mml('\\sqrt{3x-1}+(1+x)^2'), + ` + + 3 + x + + 1 + + + + ( + 1 + + + x + + ) + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('General Root', () => { + toXmlMatch( + tex2mml('\\sqrt[4]{3x-1}+(1+x)^2'), + ` + + + 3 + x + + 1 + + 4 + + + + ( + 1 + + + x + + ) + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Quadratic Formula', () => { + toXmlMatch( + tex2mml('x = \\frac{-b\\pm\\sqrt{b^2-4ac}}{2a}'), + ` + x + = + + + + b + ± + + + b + 2 + + + 4 + a + c + + + + 2 + a + + + ` + ); + }); + + /********************************************************************************/ + + it('Cauchy-Schwarz Inequality', () => { + toXmlMatch( + tex2mml( + '\\left( \\sum_{k=1}^n a_k b_k \\right)^{\\!\\!2} \\leq \\left( \\sum_{k=1}^n a_k^2 \\right) \\left( \\sum_{k=1}^n b_k^2 \\right)' + ), + ` + + + ( + + + + k + = + 1 + + n + + + a + k + + + b + k + + ) + + + + + + + + + 2 + + + + + ( + + + + k + = + 1 + + n + + + a + k + 2 + + ) + + + ( + + + + k + = + 1 + + n + + + b + k + 2 + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('An Identity of Ramanujan', () => { + toXmlMatch( + tex2mml( + '\\frac{1}{\\Bigl(\\sqrt{\\phi\\sqrt{5}}-\\phi\\Bigr) e^{\\frac25\\pi}} = 1+\\frac{e^{-2\\pi}} {1+\\frac{e^{-4\\pi}} {1+\\frac{e^{-6\\pi}} {1+\\frac{e^{-8\\pi}} {1+\\ldots} } } }' + ), + ` + + 1 + + + ( + + + ϕ + + 5 + + + + ϕ + + ) + + + e + + + 2 + 5 + + π + + + + + = + 1 + + + + + e + + + 2 + π + + + + 1 + + + + + e + + + 4 + π + + + + 1 + + + + + e + + + 6 + π + + + + 1 + + + + + e + + + 8 + π + + + + 1 + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('A Rogers-Ramanujan Identity', () => { + toXmlMatch( + tex2mml( + '1 + \\frac{q^2}{(1-q)} + \\frac{q^6}{(1-q)(1-q^2)} + \\cdots =\\prod_{j=0}^{\\infty} \\frac{1}{(1-q^{5j+2})(1-q^{5j+3})}, \\quad\\quad \\text{for $|q|<1$}.' + ), + ` + 1 + + + + + q + 2 + + + ( + 1 + + q + ) + + + + + + + q + 6 + + + ( + 1 + + q + ) + ( + 1 + + + q + 2 + + ) + + + + + + = + + + + j + = + 0 + + + + + + + 1 + + ( + 1 + + + q + + 5 + j + + + 2 + + + ) + ( + 1 + + + q + + 5 + j + + + 3 + + + ) + + + , + + + + for  + + | + q + | + < + 1 + + + . + ` + ); + }); + + /********************************************************************************/ + + it('A Summation Formula', () => { + toXmlMatch( + tex2mml('\\sum_{n=1}^\\infty {1\\over n^2} = {\\pi^2\\over 6}'), + ` + + + + n + = + 1 + + + + + + 1 + + n + 2 + + + + = + + + + π + 2 + + 6 + + + ` + ); + }); + + /********************************************************************************/ + + it('Cauchy Integral Formula', () => { + toXmlMatch( + tex2mml('f(a) = \\oint_\\gamma \\frac{f(z)}{z-a}dz'), + ` + f + ( + a + ) + = + + + γ + + + + f + ( + z + ) + + + z + + a + + + d + z + ` + ); + }); + + /********************************************************************************/ + + it('Standard Deviation', () => { + toXmlMatch( + tex2mml('\\sigma = \\sqrt{\\frac{1}{N}\\sum_{i=1}^N {(x_i-\\mu)}^2}'), + ` + σ + = + + + 1 + N + + + + + i + = + 1 + + N + + + + ( + + x + i + + + μ + ) + + 2 + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Environments', () => { + + /********************************************************************************/ + + it('Eqnarray', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}a&=&b\\end{eqnarray}'), + ` + + + + a + + + + = + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Equation', () => { + toXmlMatch( + tex2mml('\\begin{equation}a=b\\end{equation}'), + ` + a + = + b + ` + ); + }); + + /********************************************************************************/ + + it('Displaymath', () => { + toXmlMatch( + tex2mml('\\begin{displaymath}a\\end{displaymath}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('math', () => { + toXmlMatch( + tex2mml('\\begin{math}a\\end{math}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Array Center', () => { + toXmlMatch( + tex2mml('\\begin{array}{c}a\\end{array}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array Center Lines', () => { + toXmlMatch( + tex2mml('\\begin{array}{c}a\\\\b\\end{array}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array RCL', () => { + toXmlMatch( + tex2mml('\\begin{array}{rcl}a&=&b\\end{array}'), + ` + + + + a + + + = + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array RCL Lines', () => { + toXmlMatch( + tex2mml('\\begin{array}{rcl}a&=&b\\\\c&=&d\\end{array}'), + ` + + + + a + + + = + + + b + + + + + c + + + = + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Display Array Center', () => { + toXmlMatch( + tex2mml('\\begin{darray}{c}a\\end{darray}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Display Array Center Lines', () => { + toXmlMatch( + tex2mml('\\begin{darray}{c}a\\\\b\\end{darray}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Display Array RCL', () => { + toXmlMatch( + tex2mml('\\begin{darray}{rcl}a&=&b\\end{darray}'), + ` + + + + a + + + = + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Display Array RCL Lines', () => { + toXmlMatch( + tex2mml('\\begin{darray}{rcl}a&=&b\\\\c&=&d\\end{darray}'), + ` + + + + a + + + = + + + b + + + + + c + + + = + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Nested array', () => { + toXmlMatch( + tex2mml('\\begin{array}{rcl}a&{}{b}&c\\begin{array}{cc}f&h\\\\g\\end{array}\\end{array}'), + ` + + + + a + + + + + b + + + + c + + + + f + + + h + + + + + g + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('IndentAlign', () => { + toXmlMatch( + tex2mml('\\begin{indentalign}[10cm][20cm][30cm]{lcr}a\\end{indentalign}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('IndentAlign Single', () => { + toXmlMatch( + tex2mml('\\begin{indentalign}[10cm][20cm][30cm]{c}a\\end{indentalign}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('IndentAlign First Only', () => { + toXmlMatch( + tex2mml('\\begin{indentalign}[10cm]{c}a\\end{indentalign}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Environment Errors', () => { + + /********************************************************************************/ + + it('IndentAlign BadAlignment', () => { + expectTexError('\\begin{indentalign}[10cm][20cm][30cm]{lkr}a\\end{indentalign}') + .toBe('Alignment must be one to three copies of l, c, or r'); + }); + + /********************************************************************************/ + + it('IndentAlign BadDimension', () => { + expectTexError('\\begin{indentalign}[10cm][20cm][30]{lcr}a\\end{indentalign}') + .toBe('Bracket argument to \\begin{indentalign} must be a dimension'); + }); + + /********************************************************************************/ + + it('BreakAlign BadBreakAlign', () => { + expectTexError('\\begin{indentalign}[10cm][20cm][30]{lcr}a\\end{indentalign}') + .toBe('Bracket argument to \\begin{indentalign} must be a dimension'); + }); + + /********************************************************************************/ + + it('Template loop', () => { + expectTexError('\\begin{array}{r@{a\\\\b}l}a&b\\\end{array}') + .toBe('Maximum template substitutions exceeded; is there an invalid use of \\\\ in the template?'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('BreakAlign', () => { + + /********************************************************************************/ + + it('BreakAlign Case c', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}\\breakAlign{c}{t}a&=&b\\end{eqnarray}'), + ` + + + + a + + + + = + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BreakAlign Case c second cell', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}a&\\breakAlign{c}{t}=&b\\end{eqnarray}'), + ` + + + + a + + + + = + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BreakAlign Case r', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}\\breakAlign{r}{t}a&=&b\\end{eqnarray}'), + ` + + + + a + + + + = + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BreakAlign Case r second row', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}\\breakAlign{r}{t}a&=&b\\\\\\breakAlign{r}{t}c&=&d\\end{eqnarray}'), + ` + + + + a + + + + = + + + + b + + + + + + c + + + + = + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BreakAlign Case r multi split', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}\\breakAlign{r}{tbmc}a&=&b\\end{eqnarray}'), + ` + + + + a + + + + = + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BreakAlign Case t', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}\\breakAlign{t}{t}a&=&b\\end{eqnarray}'), + ` + + + + a + + + + = + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('BreakAlign Errors', () => { + + /********************************************************************************/ + + it('BreakAlign not in environment', () => { + expectTexError('\\breakAlign{c}{t}') + .toBe('\\breakAlign must be used in an alignment environment'); + }); + + /********************************************************************************/ + + it('BreakAlign Case c', () => { + expectTexError('\\begin{eqnarray}a\\breakAlign{c}{t}&=&b\\end{eqnarray}') + .toBe('\\breakAlign{c} must be at the beginning of an alignment entry'); + }); + + /********************************************************************************/ + + it('BreakAlign Case c split', () => { + expectTexError('\\begin{eqnarray}a\\breakAlign{c}{tb}&=&b\\end{eqnarray}') + .toBe('\\breakAlign{c} must be at the beginning of an alignment entry'); + }); + + /********************************************************************************/ + + it('BreakAlign Case r', () => { + expectTexError('\\begin{eqnarray}a&=&\\breakAlign{r}{t}b\\end{eqnarray}') + .toBe('\\breakAlign{r} must be at the beginning of an alignment row'); + }); + + /********************************************************************************/ + + it('BreakAlign Case t', () => { + expectTexError('\\begin{eqnarray}a&=&\\breakAlign{t}{t}b\\end{eqnarray}') + .toBe('\\breakAlign{t} must be at the beginning of an alignment'); + }); + + /********************************************************************************/ + + it('BreakAlign Case t second row', () => { + expectTexError('\\begin{eqnarray}a&=&b\\\\\\breakAlign{t}{t}c&=&d\\end{eqnarray}') + .toBe('\\breakAlign{t} must be at the beginning of an alignment'); + }); + + /********************************************************************************/ + + it('BreakAlign Case t split', () => { + expectTexError('\\begin{eqnarray}\\breakAlign{c}{tb}a&=&b\\end{eqnarray}') + .toBe('Too many alignment characters: tb'); + }); + + /********************************************************************************/ + + it('BreakAlign Case unknown', () => { + expectTexError('\\begin{eqnarray}\\breakAlign{a}{t}a&=&b\\end{eqnarray}') + .toBe('First argument to \\breakAlign must be one of c, r, or t'); + }); + + /********************************************************************************/ + + it('BreakAlign Case unknown split', () => { + expectTexError('\\begin{eqnarray}\\breakAlign{t}{a}a&=&b\\end{eqnarray}') + .toBe('Invalid alignment character: a'); + }); + + /********************************************************************************/ + +}); + + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Setting sizes', () => { + + /********************************************************************************/ + + it('tiny', () => { + toXmlMatch( + tex2mml('\\tiny a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Tiny', () => { + toXmlMatch( + tex2mml('\\Tiny a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('scriptsize', () => { + toXmlMatch( + tex2mml('\\scriptsize a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('small', () => { + toXmlMatch( + tex2mml('\\small a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('normalsize', () => { + toXmlMatch( + tex2mml('\\normalsize a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('large', () => { + toXmlMatch( + tex2mml('\\large a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Large', () => { + toXmlMatch( + tex2mml('\\Large a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('LARGE', () => { + toXmlMatch( + tex2mml('\\LARGE a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('huge', () => { + toXmlMatch( + tex2mml('\\huge a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Huge', () => { + toXmlMatch( + tex2mml('\\Huge a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Empty', () => { + toXmlMatch( + tex2mml('\\Huge'), + ` + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Spaces', () => { + + /********************************************************************************/ + + it('Positive Spacing', () => { + toXmlMatch( + tex2mml('a\\quad b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Negative Spacing', () => { + toXmlMatch( + tex2mml('a\\!\\!b'), + ` + a + + + b + ` + ); + }); + + /********************************************************************************/ + + it('spaces ,', () => { + toXmlMatch( + tex2mml('A\\,B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces :', () => { + toXmlMatch( + tex2mml('A\\:B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces >', () => { + toXmlMatch( + tex2mml('A\\>B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces ;', () => { + toXmlMatch( + tex2mml('A\\;B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces !', () => { + toXmlMatch( + tex2mml('A\\!B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces quad', () => { + toXmlMatch( + tex2mml('A\\quad B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces qquad', () => { + toXmlMatch( + tex2mml('A\\qquad B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces enspace', () => { + toXmlMatch( + tex2mml('A\\enspace B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces thinspace', () => { + toXmlMatch( + tex2mml('A\\thinspace B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('spaces negthinspace', () => { + toXmlMatch( + tex2mml('A\\negthinspace B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('Hfil', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc}a&\\hfil b\\\\d&ccc\\end{array}'), + ` + + + + a + + + b + + + + + d + + + c + c + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Hfill', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc}a&\\hfill b\\\\d&ccc\\end{array}'), + ` + + + + a + + + b + + + + + d + + + c + c + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Hfilll', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc}a&\\hfilll b\\\\d&ccc\\end{array}'), + ` + + + + a + + + b + + + + + d + + + c + c + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Hfil Centering', () => { + toXmlMatch( + tex2mml('\\begin{array}{l} \\hfil x\\hfil \\end{array}'), + ` + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + +}); + + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Delimiters', () => { + + /********************************************************************************/ + + it('<', () => { + toXmlMatch( + tex2mml('< a >'), + ` + < + a + > + ` + ); + }); + + /********************************************************************************/ + + it('left right <', () => { + toXmlMatch( + tex2mml('\\left< a \\right>'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('lt', () => { + toXmlMatch( + tex2mml('\\lt a \\gt'), + ` + < + a + > + ` + ); + }); + + /********************************************************************************/ + + it('left right lt', () => { + toXmlMatch( + tex2mml('\\left\\lt a \\right\\gt'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('/', () => { + toXmlMatch( + tex2mml('/ a \\\\'), + ` + + / + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right /', () => { + expectTexError('\\left/ a \\right\\\\') + .toBe('Missing or unrecognized delimiter for \\right'); + }); + + /********************************************************************************/ + + it('lmoustache', () => { + toXmlMatch( + tex2mml('\\lmoustache a \\rmoustache'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right lmoustache', () => { + toXmlMatch( + tex2mml('\\left\\lmoustache a \\right\\rmoustache'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('lgroup', () => { + toXmlMatch( + tex2mml('\\lgroup a \\rgroup'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right lgroup', () => { + toXmlMatch( + tex2mml('\\left\\lgroup a \\right\\rgroup'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('arrowvert', () => { + toXmlMatch( + tex2mml('\\arrowvert a \\Arrowvert'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right arrowvert', () => { + toXmlMatch( + tex2mml('\\left\\arrowvert a \\right\\Arrowvert'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('bracevert', () => { + toXmlMatch( + tex2mml('\\bracevert a \\Vert'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right bracevert', () => { + toXmlMatch( + tex2mml('\\left\\bracevert a \\right\\Vert'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('updownarrow', () => { + toXmlMatch( + tex2mml('\\updownarrow a \\Updownarrow'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right updownarrow', () => { + toXmlMatch( + tex2mml('\\left\\updownarrow a \\right\\Updownarrow'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('backslash', () => { + toXmlMatch( + tex2mml('/ a \\backslash'), + ` + + / + + a + \\ + ` + ); + }); + + /********************************************************************************/ + + it('left right left/', () => { + toXmlMatch( + tex2mml('\\left/ a \\right\\backslash'), + ` + + / + a + \\ + + ` + ); + }); + + /********************************************************************************/ + + it('Uparrow', () => { + toXmlMatch( + tex2mml('\\Uparrow a \\Downarrow'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right Uparrow', () => { + toXmlMatch( + tex2mml('\\left\\Uparrow a \\right\\Downarrow'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('rangle', () => { + toXmlMatch( + tex2mml('\\rangle a \\langle'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right rangle', () => { + toXmlMatch( + tex2mml('\\left\\rangle a \\right\\langle'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('rbrace', () => { + toXmlMatch( + tex2mml('\\rbrace a \\lbrace'), + ` + } + a + { + ` + ); + }); + + /********************************************************************************/ + + it('left right rbrace', () => { + toXmlMatch( + tex2mml('\\left\\rbrace a \\right\\lbrace'), + ` + + } + a + { + + ` + ); + }); + + /********************************************************************************/ + + it('rceil', () => { + toXmlMatch( + tex2mml('\\rceil a \\lceil'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right rceil', () => { + toXmlMatch( + tex2mml('\\left\\rceil a \\right\\lceil'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('rfloor', () => { + toXmlMatch( + tex2mml('\\rfloor a \\lfloor'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('left right rfloor', () => { + toXmlMatch( + tex2mml('\\left\\rfloor a \\right\\lfloor'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('lbrack', () => { + toXmlMatch( + tex2mml('\\lbrack a \\rbrack'), + ` + [ + a + ] + ` + ); + }); + + /********************************************************************************/ + + it('left right lbrack', () => { + toXmlMatch( + tex2mml('\\left\\lbrack a \\right\\rbrack'), + ` + + [ + a + ] + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Named Functions', () => { + + /********************************************************************************/ + + it('Limit', () => { + toXmlMatch( + tex2mml('\\lim'), + ` + lim + ` + ); + }); + + /********************************************************************************/ + + it('Named Function Arg', () => { + toXmlMatch( + tex2mml('\\sin x'), + ` + sin + + x + ` + ); + }); + + /********************************************************************************/ + + it('Named Function Parent Arg', () => { + toXmlMatch( + tex2mml('\\sin(x)'), + ` + sin + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('Fn Pos Space', () => { + toXmlMatch( + tex2mml('\\sin\\quad x'), + ` + sin + + x + ` + ); + }); + + /********************************************************************************/ + + it('Fn Neg Space', () => { + toXmlMatch( + tex2mml('\\sin\\! x'), + ` + sin + + x + ` + ); + }); + + /********************************************************************************/ + + it('Fn Stretchy', () => { + toXmlMatch( + tex2mml('\\sin \\left(\\right)'), + ` + sin + + + ( + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Fn Operator', () => { + toXmlMatch( + tex2mml('\\sin +'), + ` + sin + + + ` + ); + }); + + /********************************************************************************/ + + it('arcsin', () => { + toXmlMatch( + tex2mml('\\arcsin'), + ` + arcsin + ` + ); + }); + + /********************************************************************************/ + + it('arccos', () => { + toXmlMatch( + tex2mml('\\arccos'), + ` + arccos + ` + ); + }); + + /********************************************************************************/ + + it('arctan', () => { + toXmlMatch( + tex2mml('\\arctan'), + ` + arctan + ` + ); + }); + + /********************************************************************************/ + + it('arg', () => { + toXmlMatch( + tex2mml('\\arg'), + ` + arg + ` + ); + }); + + /********************************************************************************/ + + it('cos', () => { + toXmlMatch( + tex2mml('\\cos'), + ` + cos + ` + ); + }); + + /********************************************************************************/ + + it('cosh', () => { + toXmlMatch( + tex2mml('\\cosh'), + ` + cosh + ` + ); + }); + + /********************************************************************************/ + + it('cot', () => { + toXmlMatch( + tex2mml('\\cot'), + ` + cot + ` + ); + }); + + /********************************************************************************/ + + it('coth', () => { + toXmlMatch( + tex2mml('\\coth'), + ` + coth + ` + ); + }); + + /********************************************************************************/ + + it('csc', () => { + toXmlMatch( + tex2mml('\\csc'), + ` + csc + ` + ); + }); + + /********************************************************************************/ + + it('deg', () => { + toXmlMatch( + tex2mml('\\deg'), + ` + deg + ` + ); + }); + + /********************************************************************************/ + + it('det', () => { + toXmlMatch( + tex2mml('\\det'), + ` + det + ` + ); + }); + + /********************************************************************************/ + + it('dim', () => { + toXmlMatch( + tex2mml('\\dim'), + ` + dim + ` + ); + }); + + /********************************************************************************/ + + it('exp', () => { + toXmlMatch( + tex2mml('\\exp'), + ` + exp + ` + ); + }); + + /********************************************************************************/ + + it('gcd', () => { + toXmlMatch( + tex2mml('\\gcd'), + ` + gcd + ` + ); + }); + + /********************************************************************************/ + + it('hom', () => { + toXmlMatch( + tex2mml('\\hom'), + ` + hom + ` + ); + }); + + /********************************************************************************/ + + it('inf', () => { + toXmlMatch( + tex2mml('\\inf'), + ` + inf + ` + ); + }); + + /********************************************************************************/ + + it('ker', () => { + toXmlMatch( + tex2mml('\\ker'), + ` + ker + ` + ); + }); + + /********************************************************************************/ + + it('lg', () => { + toXmlMatch( + tex2mml('\\lg'), + ` + lg + ` + ); + }); + + /********************************************************************************/ + + it('liminf', () => { + toXmlMatch( + tex2mml('\\liminf'), + ` + lim inf + ` + ); + }); + + /********************************************************************************/ + + it('limsup', () => { + toXmlMatch( + tex2mml('\\limsup'), + ` + lim sup + ` + ); + }); + + /********************************************************************************/ + + it('ln', () => { + toXmlMatch( + tex2mml('\\ln'), + ` + ln + ` + ); + }); + + /********************************************************************************/ + + it('log', () => { + toXmlMatch( + tex2mml('\\log'), + ` + log + ` + ); + }); + + /********************************************************************************/ + + it('max', () => { + toXmlMatch( + tex2mml('\\max'), + ` + max + ` + ); + }); + + /********************************************************************************/ + + it('min', () => { + toXmlMatch( + tex2mml('\\min'), + ` + min + ` + ); + }); + + /********************************************************************************/ + + it('Pr', () => { + toXmlMatch( + tex2mml('\\Pr'), + ` + Pr + ` + ); + }); + + /********************************************************************************/ + + it('sec', () => { + toXmlMatch( + tex2mml('\\sec'), + ` + sec + ` + ); + }); + + /********************************************************************************/ + + it('sinh', () => { + toXmlMatch( + tex2mml('\\sinh'), + ` + sinh + ` + ); + }); + + /********************************************************************************/ + + it('sup', () => { + toXmlMatch( + tex2mml('\\sup'), + ` + sup + ` + ); + }); + + /********************************************************************************/ + + it('tan', () => { + toXmlMatch( + tex2mml('\\tan'), + ` + tan + ` + ); + }); + + /********************************************************************************/ + + it('tanh', () => { + toXmlMatch( + tex2mml('\\tanh'), + ` + tanh + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Greek characters', () => { + + /********************************************************************************/ + + it('alpha', () => { + toXmlMatch( + tex2mml('\\alpha'), + ` + α + ` + ); + }); + + /********************************************************************************/ + + it('beta', () => { + toXmlMatch( + tex2mml('\\beta'), + ` + β + ` + ); + }); + + /********************************************************************************/ + + it('delta', () => { + toXmlMatch( + tex2mml('\\delta'), + ` + δ + ` + ); + }); + + /********************************************************************************/ + + it('epsilon', () => { + toXmlMatch( + tex2mml('\\epsilon'), + ` + ϵ + ` + ); + }); + + /********************************************************************************/ + + it('zeta', () => { + toXmlMatch( + tex2mml('\\zeta'), + ` + ζ + ` + ); + }); + + /********************************************************************************/ + + it('eta', () => { + toXmlMatch( + tex2mml('\\eta'), + ` + η + ` + ); + }); + + /********************************************************************************/ + + it('theta', () => { + toXmlMatch( + tex2mml('\\theta'), + ` + θ + ` + ); + }); + + /********************************************************************************/ + + it('iota', () => { + toXmlMatch( + tex2mml('\\iota'), + ` + ι + ` + ); + }); + + /********************************************************************************/ + + it('kappa', () => { + toXmlMatch( + tex2mml('\\kappa'), + ` + κ + ` + ); + }); + + /********************************************************************************/ + + it('lambda', () => { + toXmlMatch( + tex2mml('\\lambda'), + ` + λ + ` + ); + }); + + /********************************************************************************/ + + it('nu', () => { + toXmlMatch( + tex2mml('\\nu'), + ` + ν + ` + ); + }); + + /********************************************************************************/ + + it('xi', () => { + toXmlMatch( + tex2mml('\\xi'), + ` + ξ + ` + ); + }); + + /********************************************************************************/ + + it('omicron', () => { + toXmlMatch( + tex2mml('\\omicron'), + ` + ο + ` + ); + }); + + /********************************************************************************/ + + it('rho', () => { + toXmlMatch( + tex2mml('\\rho'), + ` + ρ + ` + ); + }); + + /********************************************************************************/ + + it('tau', () => { + toXmlMatch( + tex2mml('\\tau'), + ` + τ + ` + ); + }); + + /********************************************************************************/ + + it('upsilon', () => { + toXmlMatch( + tex2mml('\\upsilon'), + ` + υ + ` + ); + }); + + /********************************************************************************/ + + it('chi', () => { + toXmlMatch( + tex2mml('\\chi'), + ` + χ + ` + ); + }); + + /********************************************************************************/ + + it('psi', () => { + toXmlMatch( + tex2mml('\\psi'), + ` + ψ + ` + ); + }); + + /********************************************************************************/ + + it('omega', () => { + toXmlMatch( + tex2mml('\\omega'), + ` + ω + ` + ); + }); + + /********************************************************************************/ + + it('varepsilon', () => { + toXmlMatch( + tex2mml('\\varepsilon'), + ` + ε + ` + ); + }); + + /********************************************************************************/ + + it('vartheta', () => { + toXmlMatch( + tex2mml('\\vartheta'), + ` + ϑ + ` + ); + }); + + /********************************************************************************/ + + it('varpi', () => { + toXmlMatch( + tex2mml('\\varpi'), + ` + ϖ + ` + ); + }); + + /********************************************************************************/ + + it('varrho', () => { + toXmlMatch( + tex2mml('\\varrho'), + ` + ϱ + ` + ); + }); + + /********************************************************************************/ + + it('varsigma', () => { + toXmlMatch( + tex2mml('\\varsigma'), + ` + ς + ` + ); + }); + + /********************************************************************************/ + + it('varphi', () => { + toXmlMatch( + tex2mml('\\varphi'), + ` + φ + ` + ); + }); + + /********************************************************************************/ + + it('Delta', () => { + toXmlMatch( + tex2mml('\\Delta'), + ` + Δ + ` + ); + }); + + /********************************************************************************/ + + it('Theta', () => { + toXmlMatch( + tex2mml('\\Theta'), + ` + Θ + ` + ); + }); + + /********************************************************************************/ + + it('Xi', () => { + toXmlMatch( + tex2mml('\\Xi'), + ` + Ξ + ` + ); + }); + + /********************************************************************************/ + + it('Pi', () => { + toXmlMatch( + tex2mml('\\Pi'), + ` + Π + ` + ); + }); + + /********************************************************************************/ + + it('Sigma', () => { + toXmlMatch( + tex2mml('\\Sigma'), + ` + Σ + ` + ); + }); + + /********************************************************************************/ + + it('Phi', () => { + toXmlMatch( + tex2mml('\\Phi'), + ` + Φ + ` + ); + }); + + /********************************************************************************/ + + it('Psi', () => { + toXmlMatch( + tex2mml('\\Psi'), + ` + Ψ + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathchar0mi', () => { + + /********************************************************************************/ + + it('AA', () => { + toXmlMatch( + tex2mml('\\AA'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('S', () => { + toXmlMatch( + tex2mml('\\S'), + ` + § + ` + ); + }); + + /********************************************************************************/ + + it('aleph', () => { + toXmlMatch( + tex2mml('\\aleph'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('hbar', () => { + toXmlMatch( + tex2mml('\\hbar'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('imath', () => { + toXmlMatch( + tex2mml('\\imath'), + ` + ı + ` + ); + }); + + /********************************************************************************/ + + it('jmath', () => { + toXmlMatch( + tex2mml('\\jmath'), + ` + ȷ + ` + ); + }); + + /********************************************************************************/ + + it('ell', () => { + toXmlMatch( + tex2mml('\\ell'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('wp', () => { + toXmlMatch( + tex2mml('\\wp'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Re', () => { + toXmlMatch( + tex2mml('\\Re'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Im', () => { + toXmlMatch( + tex2mml('\\Im'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('partial', () => { + toXmlMatch( + tex2mml('\\partial'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('emptyset', () => { + toXmlMatch( + tex2mml('\\emptyset'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('nabla', () => { + toXmlMatch( + tex2mml('\\nabla'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('top', () => { + toXmlMatch( + tex2mml('\\top'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bot', () => { + toXmlMatch( + tex2mml('\\bot'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('angle', () => { + toXmlMatch( + tex2mml('\\angle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('triangle', () => { + toXmlMatch( + tex2mml('\\triangle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('forall', () => { + toXmlMatch( + tex2mml('\\forall'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('exists', () => { + toXmlMatch( + tex2mml('\\exists'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('neg', () => { + toXmlMatch( + tex2mml('\\neg'), + ` + ¬ + ` + ); + }); + + /********************************************************************************/ + + it('lnot', () => { + toXmlMatch( + tex2mml('\\lnot'), + ` + ¬ + ` + ); + }); + + /********************************************************************************/ + + it('flat', () => { + toXmlMatch( + tex2mml('\\flat'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('natural', () => { + toXmlMatch( + tex2mml('\\natural'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('sharp', () => { + toXmlMatch( + tex2mml('\\sharp'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('clubsuit', () => { + toXmlMatch( + tex2mml('\\clubsuit'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('diamondsuit', () => { + toXmlMatch( + tex2mml('\\diamondsuit'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('heartsuit', () => { + toXmlMatch( + tex2mml('\\heartsuit'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('spadesuit', () => { + toXmlMatch( + tex2mml('\\spadesuit'), + ` + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathchar0mo', () => { + + /********************************************************************************/ + + it('Rightarrow', () => { + toXmlMatch( + tex2mml('\\Rightarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('surd', () => { + toXmlMatch( + tex2mml('\\surd'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + + it('coprod', () => { + toXmlMatch( + tex2mml('\\coprod'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigvee', () => { + toXmlMatch( + tex2mml('\\bigvee'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigwedge', () => { + toXmlMatch( + tex2mml('\\bigwedge'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('biguplus', () => { + toXmlMatch( + tex2mml('\\biguplus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigcap', () => { + toXmlMatch( + tex2mml('\\bigcap'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigcup', () => { + toXmlMatch( + tex2mml('\\bigcup'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('intop', () => { + toXmlMatch( + tex2mml('\\intop'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('iint', () => { + toXmlMatch( + tex2mml('\\iint'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('iiint', () => { + toXmlMatch( + tex2mml('\\iiint'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigotimes', () => { + toXmlMatch( + tex2mml('\\bigotimes'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigoplus', () => { + toXmlMatch( + tex2mml('\\bigoplus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigodot', () => { + toXmlMatch( + tex2mml('\\bigodot'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ointop', () => { + toXmlMatch( + tex2mml('\\ointop'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('oiint', () => { + toXmlMatch( + tex2mml('\\oiint'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('oiiint', () => { + toXmlMatch( + tex2mml('\\oiiint'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigsqcup', () => { + toXmlMatch( + tex2mml('\\bigsqcup'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('smallint', () => { + toXmlMatch( + tex2mml('\\smallint'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('triangleleft', () => { + toXmlMatch( + tex2mml('\\triangleleft'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('triangleright', () => { + toXmlMatch( + tex2mml('\\triangleright'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigtriangleup', () => { + toXmlMatch( + tex2mml('\\bigtriangleup'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigtriangledown', () => { + toXmlMatch( + tex2mml('\\bigtriangledown'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('wedge', () => { + toXmlMatch( + tex2mml('\\wedge'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('land', () => { + toXmlMatch( + tex2mml('\\land'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('vee', () => { + toXmlMatch( + tex2mml('\\vee'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('lor', () => { + toXmlMatch( + tex2mml('\\lor'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('cap', () => { + toXmlMatch( + tex2mml('\\cap'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('cup', () => { + toXmlMatch( + tex2mml('\\cup'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ddagger', () => { + toXmlMatch( + tex2mml('\\ddagger'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('dagger', () => { + toXmlMatch( + tex2mml('\\dagger'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('sqcap', () => { + toXmlMatch( + tex2mml('\\sqcap'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('sqcup', () => { + toXmlMatch( + tex2mml('\\sqcup'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('uplus', () => { + toXmlMatch( + tex2mml('\\uplus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('amalg', () => { + toXmlMatch( + tex2mml('\\amalg'), + ` + ⨿ + ` + ); + }); + + /********************************************************************************/ + + it('diamond', () => { + toXmlMatch( + tex2mml('\\diamond'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bullet', () => { + toXmlMatch( + tex2mml('\\bullet'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('wr', () => { + toXmlMatch( + tex2mml('\\wr'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('div', () => { + toXmlMatch( + tex2mml('\\div'), + ` + ÷ + ` + ); + }); + + /********************************************************************************/ + + it('odot', () => { + toXmlMatch( + tex2mml('\\odot'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('oslash', () => { + toXmlMatch( + tex2mml('\\oslash'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('otimes', () => { + toXmlMatch( + tex2mml('\\otimes'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ominus', () => { + toXmlMatch( + tex2mml('\\ominus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('oplus', () => { + toXmlMatch( + tex2mml('\\oplus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('mp', () => { + toXmlMatch( + tex2mml('\\mp'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('circ', () => { + toXmlMatch( + tex2mml('\\circ'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bigcirc', () => { + toXmlMatch( + tex2mml('\\bigcirc'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('setminus', () => { + toXmlMatch( + tex2mml('\\setminus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('cdot', () => { + toXmlMatch( + tex2mml('\\cdot'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ast', () => { + toXmlMatch( + tex2mml('\\ast'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('times', () => { + toXmlMatch( + tex2mml('\\times'), + ` + × + ` + ); + }); + + /********************************************************************************/ + + it('star', () => { + toXmlMatch( + tex2mml('\\star'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('propto', () => { + toXmlMatch( + tex2mml('\\propto'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('sqsubseteq', () => { + toXmlMatch( + tex2mml('\\sqsubseteq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('sqsupseteq', () => { + toXmlMatch( + tex2mml('\\sqsupseteq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('parallel', () => { + toXmlMatch( + tex2mml('\\parallel'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('mid', () => { + toXmlMatch( + tex2mml('\\mid'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('dashv', () => { + toXmlMatch( + tex2mml('\\dashv'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('vdash', () => { + toXmlMatch( + tex2mml('\\vdash'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('le', () => { + toXmlMatch( + tex2mml('\\le'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('geq', () => { + toXmlMatch( + tex2mml('\\geq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ge', () => { + toXmlMatch( + tex2mml('\\ge'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('succ', () => { + toXmlMatch( + tex2mml('\\succ'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('prec', () => { + toXmlMatch( + tex2mml('\\prec'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('approx', () => { + toXmlMatch( + tex2mml('\\approx'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('succeq', () => { + toXmlMatch( + tex2mml('\\succeq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('preceq', () => { + toXmlMatch( + tex2mml('\\preceq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('supset', () => { + toXmlMatch( + tex2mml('\\supset'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('subset', () => { + toXmlMatch( + tex2mml('\\subset'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('supseteq', () => { + toXmlMatch( + tex2mml('\\supseteq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('subseteq', () => { + toXmlMatch( + tex2mml('\\subseteq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('in', () => { + toXmlMatch( + tex2mml('\\in'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ni', () => { + toXmlMatch( + tex2mml('\\ni'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('notin', () => { + toXmlMatch( + tex2mml('\\notin'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('owns', () => { + toXmlMatch( + tex2mml('\\owns'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('gg', () => { + toXmlMatch( + tex2mml('\\gg'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ll', () => { + toXmlMatch( + tex2mml('\\ll'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('perp', () => { + toXmlMatch( + tex2mml('\\perp'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + + it('equiv', () => { + toXmlMatch( + tex2mml('\\equiv'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('smile', () => { + toXmlMatch( + tex2mml('\\smile'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('frown', () => { + toXmlMatch( + tex2mml('\\frown'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ne', () => { + toXmlMatch( + tex2mml('\\ne'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('neq', () => { + toXmlMatch( + tex2mml('\\neq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('doteq', () => { + toXmlMatch( + tex2mml('\\doteq'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('bowtie', () => { + toXmlMatch( + tex2mml('\\bowtie'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('models', () => { + toXmlMatch( + tex2mml('\\models'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('notChar', () => { + toXmlMatch( + tex2mml('\\notChar'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Leftrightarrow', () => { + toXmlMatch( + tex2mml('\\Leftrightarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Leftarrow', () => { + toXmlMatch( + tex2mml('\\Leftarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('leftrightarrow', () => { + toXmlMatch( + tex2mml('\\leftrightarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('leftarrow', () => { + toXmlMatch( + tex2mml('\\leftarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('gets', () => { + toXmlMatch( + tex2mml('\\gets'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('to', () => { + toXmlMatch( + tex2mml('\\to'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('mapsto', () => { + toXmlMatch( + tex2mml('\\mapsto'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('leftharpoonup', () => { + toXmlMatch( + tex2mml('\\leftharpoonup'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('leftharpoondown', () => { + toXmlMatch( + tex2mml('\\leftharpoondown'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('rightharpoonup', () => { + toXmlMatch( + tex2mml('\\rightharpoonup'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('rightharpoondown', () => { + toXmlMatch( + tex2mml('\\rightharpoondown'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('nearrow', () => { + toXmlMatch( + tex2mml('\\nearrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('searrow', () => { + toXmlMatch( + tex2mml('\\searrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('nwarrow', () => { + toXmlMatch( + tex2mml('\\nwarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('swarrow', () => { + toXmlMatch( + tex2mml('\\swarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('rightleftharpoons', () => { + toXmlMatch( + tex2mml('\\rightleftharpoons'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('hookrightarrow', () => { + toXmlMatch( + tex2mml('\\hookrightarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('hookleftarrow', () => { + toXmlMatch( + tex2mml('\\hookleftarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('longleftarrow', () => { + toXmlMatch( + tex2mml('\\longleftarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Longleftarrow', () => { + toXmlMatch( + tex2mml('\\Longleftarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Longrightarrow', () => { + toXmlMatch( + tex2mml('\\Longrightarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Longleftrightarrow', () => { + toXmlMatch( + tex2mml('\\Longleftrightarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('longleftrightarrow', () => { + toXmlMatch( + tex2mml('\\longleftrightarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('longmapsto', () => { + toXmlMatch( + tex2mml('\\longmapsto'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('colon', () => { + toXmlMatch( + tex2mml('\\colon'), + ` + : + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Dots', () => { + + /********************************************************************************/ + + it('Identifier Dots', () => { + toXmlMatch( + tex2mml('A\\dots B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('Operator Dots', () => { + toXmlMatch( + tex2mml('+\\dots+'), + ` + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Relation Dots', () => { + toXmlMatch( + tex2mml('x<\\dots + x + < + + < + y + ` + ); + }); + + /********************************************************************************/ + + it('Dots Left', () => { + toXmlMatch( + tex2mml('\\dots\\left( A\\right)'), + ` + + + ( + A + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Dots Open', () => { + toXmlMatch( + tex2mml('\\dots{\\alpha}'), + ` + + + α + + ` + ); + }); + + /********************************************************************************/ + + it('ldots', () => { + toXmlMatch( + tex2mml('\\ldots'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('vdots', () => { + toXmlMatch( + tex2mml('\\vdots'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + + it('cdots', () => { + toXmlMatch( + tex2mml('\\cdots'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ddots', () => { + toXmlMatch( + tex2mml('\\ddots'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('iddots', () => { + toXmlMatch( + tex2mml('\\iddots'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('dotsc', () => { + toXmlMatch( + tex2mml('\\dotsc'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('dotsb', () => { + toXmlMatch( + tex2mml('\\dotsb'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('dotsm', () => { + toXmlMatch( + tex2mml('\\dotsm'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('dotsi', () => { + toXmlMatch( + tex2mml('\\dotsi'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('dotso', () => { + toXmlMatch( + tex2mml('\\dotso'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('ldotp', () => { + toXmlMatch( + tex2mml('\\ldotp'), + ` + . + ` + ); + }); + + /********************************************************************************/ + + it('cdotp', () => { + toXmlMatch( + tex2mml('\\cdotp'), + ` + + ` + ); + }); + + /********************************************************************************/ + +}); + + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Font Simple', () => { + + /********************************************************************************/ + + it('rm', () => { + toXmlMatch( + tex2mml('\\rm a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('mit', () => { + toXmlMatch( + tex2mml('\\mit a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('oldstyle', () => { + toXmlMatch( + tex2mml('\\oldstyle 9'), + ` + 9 + ` + ); + }); + + /********************************************************************************/ + + it('it', () => { + toXmlMatch( + tex2mml('\\it a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('bf', () => { + toXmlMatch( + tex2mml('\\bf a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('sf', () => { + toXmlMatch( + tex2mml('\\sf a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('tt', () => { + toXmlMatch( + tex2mml('\\tt a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('frak', () => { + toXmlMatch( + tex2mml('\\frak a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Bbb', () => { + toXmlMatch( + tex2mml('\\Bbb a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbf', () => { + toXmlMatch( + tex2mml('\\mathbf{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('mathup', () => { + toXmlMatch( + tex2mml('\\mathup a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathnormal', () => { + toXmlMatch( + tex2mml('\\mathnormal a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbfup', () => { + toXmlMatch( + tex2mml('\\mathbfup a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathit', () => { + toXmlMatch( + tex2mml('\\mathit a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbfit', () => { + toXmlMatch( + tex2mml('\\mathbfit a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbb', () => { + toXmlMatch( + tex2mml('\\mathbb a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathfrak', () => { + toXmlMatch( + tex2mml('\\mathfrak a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbffrak', () => { + toXmlMatch( + tex2mml('\\mathbffrak a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathscr', () => { + toXmlMatch( + tex2mml('\\mathscr a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbfscr', () => { + toXmlMatch( + tex2mml('\\mathbfscr a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathsf', () => { + toXmlMatch( + tex2mml('\\mathsf a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathsfup', () => { + toXmlMatch( + tex2mml('\\mathsfup a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbfsf', () => { + toXmlMatch( + tex2mml('\\mathbfsf a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbfsfup', () => { + toXmlMatch( + tex2mml('\\mathbfsfup a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathsfit', () => { + toXmlMatch( + tex2mml('\\mathsfit a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbfsfit', () => { + toXmlMatch( + tex2mml('\\mathbfsfit a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathtt', () => { + toXmlMatch( + tex2mml('\\mathtt a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathcal', () => { + toXmlMatch( + tex2mml('\\mathcal a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('mathbfcal', () => { + toXmlMatch( + tex2mml('\\mathbfcal a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symrm', () => { + toXmlMatch( + tex2mml('\\symrm a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symup', () => { + toXmlMatch( + tex2mml('\\symup a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symnormal', () => { + toXmlMatch( + tex2mml('\\symnormal a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbf', () => { + toXmlMatch( + tex2mml('\\symbf a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbfup', () => { + toXmlMatch( + tex2mml('\\symbfup a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symit', () => { + toXmlMatch( + tex2mml('\\symit a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbfit', () => { + toXmlMatch( + tex2mml('\\symbfit a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbb', () => { + toXmlMatch( + tex2mml('\\symbb a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symfrak', () => { + toXmlMatch( + tex2mml('\\symfrak a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbffrak', () => { + toXmlMatch( + tex2mml('\\symbffrak a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symscr', () => { + toXmlMatch( + tex2mml('\\symscr a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbfscr', () => { + toXmlMatch( + tex2mml('\\symbfscr a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symsf', () => { + toXmlMatch( + tex2mml('\\symsf a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symsfup', () => { + toXmlMatch( + tex2mml('\\symsfup a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbfsf', () => { + toXmlMatch( + tex2mml('\\symbfsf a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbfsfup', () => { + toXmlMatch( + tex2mml('\\symbfsfup a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symsfit', () => { + toXmlMatch( + tex2mml('\\symsfit a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbfsfit', () => { + toXmlMatch( + tex2mml('\\symbfsfit a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symtt', () => { + toXmlMatch( + tex2mml('\\symtt a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symcal', () => { + toXmlMatch( + tex2mml('\\symcal a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('symbfcal', () => { + toXmlMatch( + tex2mml('\\symbfcal a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('textrm', () => { + toXmlMatch( + tex2mml('\\textrm a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('textup', () => { + toXmlMatch( + tex2mml('\\textup a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('textnormal', () => { + toXmlMatch( + tex2mml('\\textnormal a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('textit', () => { + toXmlMatch( + tex2mml('\\textit a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('textbf', () => { + toXmlMatch( + tex2mml('\\textbf a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('textsf', () => { + toXmlMatch( + tex2mml('\\textsf a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('texttt', () => { + toXmlMatch( + tex2mml('\\texttt a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Over Under Extenders', () => { + + /********************************************************************************/ + + it('overparen', () => { + toXmlMatch( + tex2mml('\\overparen{ab}'), + ` + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('underparen', () => { + toXmlMatch( + tex2mml('\\underparen{ab}'), + ` + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('overrightarrow', () => { + toXmlMatch( + tex2mml('\\overrightarrow{ab}'), + ` + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('underrightarrow', () => { + toXmlMatch( + tex2mml('\\underrightarrow{ab}'), + ` + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('overleftarrow', () => { + toXmlMatch( + tex2mml('\\overleftarrow{ab}'), + ` + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('underleftarrow', () => { + toXmlMatch( + tex2mml('\\underleftarrow{ab}'), + ` + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('overleftrightarrow', () => { + toXmlMatch( + tex2mml('\\overleftrightarrow{ab}'), + ` + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Math style sizes', () => { + + /********************************************************************************/ + + it('displaystyle', () => { + toXmlMatch( + tex2mml('\\displaystyle A', false), + ` + + A + + ` + ); + }); + + /********************************************************************************/ + + it('textstyle', () => { + toXmlMatch( + tex2mml('\\textstyle B', false), + ` + B + ` + ); + }); + + /********************************************************************************/ + + it('scriptstyle', () => { + toXmlMatch( + tex2mml('\\scriptstyle C', false), + ` + + C + + ` + ); + }); + + /********************************************************************************/ + + it('scriptscriptstyle', () => { + toXmlMatch( + tex2mml('\\scriptscriptstyle a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Special characters', () => { + + /********************************************************************************/ + + it('Space', () => { + toXmlMatch( + tex2mml('a b'), + ` + a + b + ` + ); + }); + + /********************************************************************************/ + + it('Tab', () => { + toXmlMatch( + tex2mml('a\tb'), + ` + a + b + ` + ); + }); + + /********************************************************************************/ + + it('CR', () => { + toXmlMatch( + tex2mml('a\rb'), + ` + a + b + ` + ); + }); + + /********************************************************************************/ + + it('Newline', () => { + toXmlMatch( + tex2mml('a\nb'), + ` + a + b + ` + ); + }); + + /********************************************************************************/ + + it('No break space', () => { + toXmlMatch( + tex2mml('a{\u00A0}b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Prime', () => { + toXmlMatch( + tex2mml('a\u2019b'), + ` + + a + + + b + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Special macros', () => { + + /********************************************************************************/ + + it('Iff', () => { + toXmlMatch( + tex2mml('A \\iff B'), + ` + A + + + + B + ` + ); + }); + + /********************************************************************************/ + + it('TeX', () => { + toXmlMatch( + tex2mml('\\TeX'), + ` + T + + + + E + + + + X + ` + ); + }); + + /********************************************************************************/ + + it('LaTeX', () => { + toXmlMatch( + tex2mml('\\LaTeX'), + ` + L + + + + + + A + + + + + + T + + + + E + + + + X + ` + ); + }); + + /********************************************************************************/ + + it('Skew 7', () => { + toXmlMatch( + tex2mml('\\skew7\\hat A'), + ` + + + + + + A + + + ^ + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Skew 20', () => { + toXmlMatch( + tex2mml('\\skew{20}\\hat A'), + ` + + + + + + A + + + ^ + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Pmb', () => { + expectTexError('a \\pmb a \\boldsymbol a') + .toBe('Undefined control sequence \\boldsymbol'); + }); + + /********************************************************************************/ + + it('Space', () => { + toXmlMatch( + tex2mml('A \\space B'), + ` + A +   + B + ` + ); + }); + + /********************************************************************************/ + + it('Space 2', () => { + toXmlMatch( + tex2mml('A \\ B'), + ` + A +   + B + ` + ); + }); + + /********************************************************************************/ + + it('Space 3', () => { + toXmlMatch( + tex2mml('A \\ B'), + ` + A +   + B + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Big Commands for Delimiters', () => { + + /********************************************************************************/ + + it('big', () => { + toXmlMatch( + tex2mml('\\big|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Big', () => { + toXmlMatch( + tex2mml('\\Big|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('bigg', () => { + toXmlMatch( + tex2mml('\\bigg|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Bigg', () => { + toXmlMatch( + tex2mml('\\Bigg|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Biggl', () => { + toXmlMatch( + tex2mml('\\Biggl|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Biggr', () => { + toXmlMatch( + tex2mml('\\Biggr|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('bigm', () => { + toXmlMatch( + tex2mml('\\bigm|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Bigm', () => { + toXmlMatch( + tex2mml('\\Bigm|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('biggm', () => { + toXmlMatch( + tex2mml('\\biggm|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Biggm', () => { + toXmlMatch( + tex2mml('\\Biggm|'), + ` + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Big with braces', () => { + toXmlMatch( + tex2mml('\\Big{\\{}'), + ` + + { + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Boxes', () => { + + /********************************************************************************/ + + it('Fbox', () => { + toXmlMatch( + tex2mml('\\fbox{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Hbox', () => { + toXmlMatch( + tex2mml('\\hbox{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Vtop', () => { + toXmlMatch( + tex2mml('\\vtop{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Vtop Hsize', () => { + toXmlMatch( + tex2mml('\\hsize{2cm}\\vtop{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Vtop Hsize =', () => { + toXmlMatch( + tex2mml('\\hsize=2cm\\vtop{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Vcenter', () => { + toXmlMatch( + tex2mml('\\vcenter{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Vcenter Hsize', () => { + toXmlMatch( + tex2mml('\\hsize{2cm}\\vcenter{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Vbox', () => { + toXmlMatch( + tex2mml('\\vbox{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Vbox Hsize', () => { + toXmlMatch( + tex2mml('\\hsize{2cm}\\vbox{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Parbox', () => { + toXmlMatch( + tex2mml('\\parbox{2cm}{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Boxed', () => { + toXmlMatch( + tex2mml('\\boxed{x}'), + ` + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('Framebox', () => { + toXmlMatch( + tex2mml('\\framebox{x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Framebox dimension', () => { + toXmlMatch( + tex2mml('\\framebox[2cm]{x}'), + ` + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('Framebox dimension position', () => { + toXmlMatch( + tex2mml('\\framebox[2cm][c]{x}'), + ` + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('Makebox', () => { + toXmlMatch( + tex2mml('\\makebox{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Makebox dimension', () => { + toXmlMatch( + tex2mml('\\makebox[2cm]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Makebox dimension position', () => { + toXmlMatch( + tex2mml('\\makebox[2cm][c]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Makebox Cap position', () => { + toXmlMatch( + tex2mml('\\makebox[2cm][C]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Rule 2D', () => { + toXmlMatch( + tex2mml('\\rule{2cm}{1cm}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Rule 2D positive raise', () => { + toXmlMatch( + tex2mml('\\rule[3cm]{2cm}{1cm}'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + + it('Rule 2D negative raise', () => { + toXmlMatch( + tex2mml('\\rule[-3cm]{2cm}{1cm}'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + + it('Rule 3D', () => { + toXmlMatch( + tex2mml('\\Rule{2cm}{2cm}{1cm}'), + ` + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Moving Elements', () => { + + /********************************************************************************/ + + it('Space 3D', () => { + toXmlMatch( + tex2mml('\\Space{2cm}{2cm}{1cm}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Strut', () => { + toXmlMatch( + tex2mml('\\strut{x}'), + ` + + + + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Phantom', () => { + toXmlMatch( + tex2mml('x\\phantom{y}z'), + ` + x + + + y + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Vertical Phantom', () => { + toXmlMatch( + tex2mml('x\\vphantom{y}z'), + ` + x + + + + y + + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Horizontal Phantom', () => { + toXmlMatch( + tex2mml('x\\hphantom{y}z'), + ` + x + + + + y + + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Smash', () => { + toXmlMatch( + tex2mml('\\smash{x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Smash Bottom', () => { + toXmlMatch( + tex2mml('\\smash[b]{x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Smash Top', () => { + toXmlMatch( + tex2mml('\\smash[t]{x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Llap', () => { + toXmlMatch( + tex2mml('\\llap{x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Rlap', () => { + toXmlMatch( + tex2mml('\\rlap{x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Rlap 2', () => { + toXmlMatch( + tex2mml('a\\mathrel{\\rlap{\\,/}{=}}b'), + ` + a + + + + + + / + + + + + = + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Llap 2', () => { + toXmlMatch( + tex2mml('a\\mathrel{{=}\\llap{/\\,}}b'), + ` + a + + + = + + + + + / + + + + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Raise In Line', () => { + toXmlMatch( + tex2mml('x\\raise{2pt}{y}z'), + ` + x + + + y + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Lower 2', () => { + toXmlMatch( + tex2mml('x\\lower{2pt}{y}z'), + ` + x + + + y + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Raise Negative', () => { + toXmlMatch( + tex2mml('x\\raise{-2pt}{y}z'), + ` + x + + + y + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Lower Negative', () => { + toXmlMatch( + tex2mml('x\\lower{-2pt}{y}z'), + ` + x + + + y + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Raise', () => { + toXmlMatch( + tex2mml('\\raise 1em {x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Lower', () => { + toXmlMatch( + tex2mml('\\lower 1em {x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Moveright', () => { + toXmlMatch( + tex2mml('\\moveright 1em {x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Moveleft', () => { + toXmlMatch( + tex2mml('\\moveleft 1em {x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Move Left Negative', () => { + toXmlMatch( + tex2mml('x\\moveleft -2pt {y} z'), + ` + x + + + y + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Move Right Negative', () => { + toXmlMatch( + tex2mml('x\\moveright -2pt {y} z'), + ` + x + + + y + + + z + ` + ); + }); + + /********************************************************************************/ + + it('Mathstrut', () => { + toXmlMatch( + tex2mml('\\mathstrut{x}'), + ` + + + + ( + + + + + x + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Linebreaks', () => { + + /********************************************************************************/ + + it('Linebreak', () => { + toXmlMatch( + tex2mml('a\\\\b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Pagebreak', () => { + toXmlMatch( + tex2mml('a\\\\*b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Custom Linebreak', () => { + toXmlMatch( + tex2mml('a\\\\[2ex]b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Custom Linebreak European', () => { + toXmlMatch( + tex2mml('a\\\\[1,5cm]b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Cr Linebreak', () => { + toXmlMatch( + tex2mml('\\array{a\\cr b}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Array Custom Linebreak', () => { + toXmlMatch( + tex2mml('\\array{a\\\\[1cm] b}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('allowbreak', () => { + toXmlMatch( + tex2mml('a\\allowbreak b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('allowbreak cdot', () => { + toXmlMatch( + tex2mml('a\\allowbreak \cdot b'), + ` + a + + c + d + o + t + b + ` + ); + }); + + /********************************************************************************/ + + it('goodbreak', () => { + toXmlMatch( + tex2mml('a\\goodbreak b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('goodbreak cdot', () => { + toXmlMatch( + tex2mml('a\\goodbreak\\cdot b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('goodbreak cdot cdot', () => { + toXmlMatch( + tex2mml('a\\cdot\\goodbreak\\cdot b'), + ` + a + + + b + ` + ); + }); + + /********************************************************************************/ + + it('goodbreak comma cdot', () => { + toXmlMatch( + tex2mml('a,\\goodbreak\\cdot b'), + ` + a + , + + b + ` + ); + }); + + /********************************************************************************/ + + it('badbreak', () => { + toXmlMatch( + tex2mml('a\\badbreak b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('badbreak cdot', () => { + toXmlMatch( + tex2mml('a\\badbreak\\cdot b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('nobreak', () => { + toXmlMatch( + tex2mml('a\\nobreak b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('nobreak cdot', () => { + toXmlMatch( + tex2mml('a\\nobreak\\cdot b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('break', () => { + toXmlMatch( + tex2mml('a\\break b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('newline', () => { + toXmlMatch( + tex2mml('a\\newline b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('goodbreak comma', () => { + toXmlMatch( + tex2mml('a,\\goodbreak b'), + ` + a + , + + b + ` + ); + }); + + /********************************************************************************/ + + it('goodbreak comma comma', () => { + toXmlMatch( + tex2mml('a,\\goodbreak, b'), + ` + a + , + , + b + ` + ); + }); + + /********************************************************************************/ + + it('goodbreak ord close', () => { + toXmlMatch( + tex2mml('\u2220\\goodbreak )\\goodbreak'), + ` + + + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('MathChar7', () => { + + /********************************************************************************/ + + it('MathChar7 Single', () => { + toXmlMatch( + tex2mml('\\#'), + ` + # + ` + ); + }); + + /********************************************************************************/ + + it('MathChar7 Single Font', () => { + toXmlMatch( + tex2mml('\\mathbf{\\#}'), + ` + + # + + ` + ); + }); + + /********************************************************************************/ + + it('MathChar7 Operator', () => { + toXmlMatch( + tex2mml('\\And'), + ` + & + ` + ); + }); + + /********************************************************************************/ + + it('MathChar7 Multi', () => { + toXmlMatch( + tex2mml('\\Lambda \\& \\Gamma \\Rightarrow \\Omega\\And\\Upsilon'), + ` + Λ + & + Γ + + Ω + & + Υ + ` + ); + }); + + /********************************************************************************/ + + it('Tilde', () => { + toXmlMatch( + tex2mml('~'), + ` +   + ` + ); + }); + + /********************************************************************************/ + + it('Tilde2', () => { + toXmlMatch( + tex2mml('a~b'), + ` + a +   + b + ` + ); + }); + + /********************************************************************************/ + + it('Underscore', () => { + toXmlMatch( + tex2mml('a\\_b'), + ` + a + _ + b + ` + ); + }); + + /********************************************************************************/ + + it('Hash', () => { + toXmlMatch( + tex2mml('a\\#b'), + ` + a + # + b + ` + ); + }); + + /********************************************************************************/ + + it('Dollar', () => { + toXmlMatch( + tex2mml('a\\$b'), + ` + a + $ + b + ` + ); + }); + + /********************************************************************************/ + + it('Percentage', () => { + toXmlMatch( + tex2mml('a\\%b'), + ` + a + % + b + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Accents', () => { + + /********************************************************************************/ + + it('Vector', () => { + toXmlMatch( + tex2mml('\\vec{a}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector Multi', () => { + toXmlMatch( + tex2mml('\\vec{\\vec{a}}'), + ` + + + + + a + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector Font', () => { + toXmlMatch( + tex2mml('\\mathrm{\\vec{a}}'), + ` + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + it('acute', () => { + toXmlMatch( + tex2mml('\\acute{a}'), + ` + + + a + ´ + + + ` + ); + }); + + /********************************************************************************/ + + it('grave', () => { + toXmlMatch( + tex2mml('\\grave{a}'), + ` + + + a + \` + + + ` + ); + }); + + /********************************************************************************/ + + it('ddot', () => { + toXmlMatch( + tex2mml('\\ddot{a}'), + ` + + + a + ¨ + + + ` + ); + }); + + /********************************************************************************/ + + it('dddot', () => { + toXmlMatch( + tex2mml('\\dddot{a}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('ddddot', () => { + toXmlMatch( + tex2mml('\\ddddot{a}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('tilde', () => { + toXmlMatch( + tex2mml('\\tilde{a}'), + ` + + + a + ~ + + + ` + ); + }); + + /********************************************************************************/ + + it('bar', () => { + toXmlMatch( + tex2mml('\\bar{a}'), + ` + + + a + ¯ + + + ` + ); + }); + + /********************************************************************************/ + + it('breve', () => { + toXmlMatch( + tex2mml('\\breve{a}'), + ` + + + a + ˘ + + + ` + ); + }); + + /********************************************************************************/ + + it('check', () => { + toXmlMatch( + tex2mml('\\check{a}'), + ` + + + a + ˇ + + + ` + ); + }); + + /********************************************************************************/ + + it('hat', () => { + toXmlMatch( + tex2mml('\\hat{a}'), + ` + + + a + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('dot', () => { + toXmlMatch( + tex2mml('\\dot{a}'), + ` + + + a + ˙ + + + ` + ); + }); + + /********************************************************************************/ + + it('widetilde', () => { + toXmlMatch( + tex2mml('\\widetilde{abc}'), + ` + + + + a + b + c + + ~ + + + ` + ); + }); + + /********************************************************************************/ + + it('widehat', () => { + toXmlMatch( + tex2mml('\\widehat{abc}'), + ` + + + + a + b + c + + ^ + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Character Class Changes', () => { + + /********************************************************************************/ + + it('Mathop', () => { + toXmlMatch( + tex2mml('\\mathop{\\rm a} b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Mathop Super', () => { + toXmlMatch( + tex2mml('\\mathop{\\rm a}^b'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Mathop Sub', () => { + toXmlMatch( + tex2mml('\\mathop{\\rm a}_b'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Mathop Sub Super', () => { + toXmlMatch( + tex2mml('\\mathop{\\rm a}_b^c'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + it('Mathop Cal', () => { + toXmlMatch( + tex2mml('\\mathop{\\cal a}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Mathrel', () => { + toXmlMatch( + tex2mml('\\mathrel{R}'), + ` + + R + + ` + ); + }); + + /********************************************************************************/ + + it('mathord', () => { + toXmlMatch( + tex2mml('a\\mathord{b}c'), + ` + a + + b + + c + ` + ); + }); + + /********************************************************************************/ + + it('mathopen', () => { + toXmlMatch( + tex2mml('a\\mathopen{b}c'), + ` + a + + b + + c + ` + ); + }); + + /********************************************************************************/ + + it('mathclose', () => { + toXmlMatch( + tex2mml('a\\mathclose{b}c'), + ` + a + + b + + c + ` + ); + }); + + /********************************************************************************/ + + it('mathbin', () => { + toXmlMatch( + tex2mml('a\\mathbin{b}c'), + ` + a + + b + + c + ` + ); + }); + + /********************************************************************************/ + + it('mathpunct', () => { + toXmlMatch( + tex2mml('a\\mathpunct{b}c'), + ` + a + + b + + c + ` + ); + }); + + /********************************************************************************/ + + it('mathinner', () => { + toXmlMatch( + tex2mml('a\\mathinner{b}c'), + ` + a + + b + + c + ` + ); + }); + + /********************************************************************************/ + +}); + + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Spacing', () => { + + /********************************************************************************/ + + it('Nonscript toplevel', () => { + toXmlMatch( + tex2mml('\\left. a \\nonscript\\;\\middle|\\nonscript\\; b \\right.'), + ` + + + a + + + | + + + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Nonscript scriptlevel', () => { + toXmlMatch( + tex2mml('X_{\\left. a \\nonscript\\;\\middle|\\nonscript\\; b \\right.}'), + ` + + X + + + + a + + | + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('hskip', () => { + toXmlMatch( + tex2mml('\\hskip{1cm}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('hspace', () => { + toXmlMatch( + tex2mml('\\hspace{1cm}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('mskip', () => { + toXmlMatch( + tex2mml('\\mskip{1cm}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('mspace', () => { + toXmlMatch( + tex2mml('\\mspace{1cm}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('mkern', () => { + toXmlMatch( + tex2mml('\\mkern{1cm}'), + ` + + ` + ); + }); + + /********************************************************************************/ + +}); + + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Complete Base Methods', () => { + + /********************************************************************************/ + + it('Comment', () => { + toXmlMatch( + tex2mml('a %comment'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Elided Times', () => { + toXmlMatch( + tex2mml('a\\* b'), + ` + a + + b + ` + ); + }); + + /********************************************************************************/ + +}); + +import { OverItem } from '#js/input/tex/base/BaseItems.js'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Complete Base Items', () => { + + /********************************************************************************/ + + it('Over toString', () => { + const over = new OverItem(null); + expect(over.toString()).toBe('over[undefined / ]'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Referencing', () => { + beforeEach(() => + setupTex(['base'], { tags: 'all' }) + ); + + /********************************************************************************/ + + it('Label', () => { + toXmlMatch( + tex2mml('a\\label{A}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Empty', () => { + toXmlMatch( + tex2mml('a\\label{}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Multiple', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}a\\label{A}\\\\c\\label{B}\\end{eqnarray}'), + ` + + + + (1) + + + a + + + + + (2) + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Multiple Error', () => { + expectTexError('a\\label{A}c\\label{B}') + .toBe('Multiple \\label'); + }); + + /********************************************************************************/ + + it('Label Multiply Defined Error', () => { + expectTexError('\\begin{eqnarray}a\\label{A}\\\\c\\label{A}\\end{eqnarray}') + .toBe("Label 'A' multiply defined"); + }); + + /********************************************************************************/ + + it('Ref', () => { + toXmlMatch( + tex2mml('a\\label{A}\\ref{A}'), + ` + + + + (1) + + + a + + ??? + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Unknown', () => { + toXmlMatch( + tex2mml('a\\label{A}\\ref{B}'), + ` + + + + (1) + + + a + + ??? + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Nonumber', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}a\\\\c\\nonumber\\end{eqnarray}'), + ` + + + + (1) + + + a + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Complete Array', () => { + + /********************************************************************************/ + + it('column r c l', () => { + toXmlMatch( + tex2mml('\\begin{array}{rcl}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c l | ', () => { + toXmlMatch( + tex2mml('\\begin{array}{r|c|l}a & b & c\\\\d & e & f\\end{array}'), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c l : ', () => { + toXmlMatch( + tex2mml('\\begin{array}{r:c:l}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c l @ ', () => { + toXmlMatch( + tex2mml('\\begin{array}{r@{h}c@{h}l}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + a + + + h + + + b + + + h + + + c + + + + + d + + + h + + + e + + + h + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c l ! ', () => { + toXmlMatch( + tex2mml('\\begin{array}{r!{h}c!{h}l}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + a + + + h + + + b + + + h + + + c + + + + + d + + + h + + + e + + + h + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column p ', () => { + toXmlMatch( + tex2mml('\\begin{array}{p{1cm}p{1cm}p{1cm}}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + + a + + + + + b + + + + + c + + + + + + + d + + + + + e + + + + + f + + + + + ` + ); + }); + + /********************************************************************************/ + + it('column m ', () => { + toXmlMatch( + tex2mml('\\begin{array}{m{1cm}m{1cm}m{1cm}}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + + a + + + + + b + + + + + c + + + + + + + d + + + + + e + + + + + f + + + + + ` + ); + }); + + /********************************************************************************/ + + it('column b ', () => { + toXmlMatch( + tex2mml('\\begin{array}{b{1cm}b{1cm}b{1cm}}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + + a + + + + + b + + + + + c + + + + + + + d + + + + + e + + + + + f + + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c l >', () => { + toXmlMatch( + tex2mml('\\begin{array}{>{A}rcl}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + A + a + + + b + + + c + + + + + A + d + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c l <', () => { + toXmlMatch( + tex2mml('\\begin{array}{r<{A}cl}a & b &c\\\\ d & e & f\\end{array}'), + ` + + + + a + A + + + b + + + c + + + + + d + A + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column c >', () => { + toXmlMatch( + tex2mml('\\begin{array}{>{A}c}a \\\\ d\\end{array}'), + ` + + + + A + a + + + + + A + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('column c <', () => { + toXmlMatch( + tex2mml('\\begin{array}{c<{A}}a\\\\ d \\end{array}'), + ` + + + + a + A + + + + + d + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('column c @ end', () => { + toXmlMatch( + tex2mml('\\begin{array}{c@{h}}a\\\\ d \\end{array}'), + ` + + + + a + + + h + + + + + d + + + h + + + + ` + ); + }); + + /********************************************************************************/ + + it('column c @&', () => { + toXmlMatch( + tex2mml('\\begin{array}{c@{\\alpha}c}a&\\hfill&b\\\\ d&\\hfill&e \\end{array}'), + ` + + + + a + + + α + + + + b + + + + + d + + + α + + + + e + + + + ` + ); + }); + + /********************************************************************************/ + + it('column c w', () => { + toXmlMatch( + tex2mml('\\begin{array}{cw{c}{1cm}c}a&b&c\\\\ d&e&f \\end{array}'), + ` + + + + a + + + + b + + + + c + + + + + d + + + + e + + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column c W', () => { + toXmlMatch( + tex2mml('\\begin{array}{cW{c}{1cm}c}a&b&c\\\\ d&e&f \\end{array}'), + ` + + + + a + + + + b + + + + c + + + + + d + + + + e + + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column repeat r c ', () => { + toXmlMatch( + tex2mml('\\begin{array}{*{2}rc}a & b & c\\\\d & e & f\\end{array}'), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r repeat c ', () => { + toXmlMatch( + tex2mml('\\begin{array}{r*{2}c}a & b & c\\\\d & e & f\\end{array}'), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c repeat | ', () => { + toXmlMatch( + tex2mml('\\begin{array}{r*{2}|c}a& b & c\\\\d & e & f\\end{array}'), + ` + + + + a + + + + + + + + b + + + c + + + + + d + + + + + + + + e + + + f + + + + ` + ); + }); + + + /********************************************************************************/ + + it('column r c repeat | {}', () => { + toXmlMatch( + tex2mml('\\begin{array}{r*{2}|c}a {\\hbox{(3)}}& b & c\\\\d & e & f\\end{array}'), + ` + + + + a + + (3) + + + + + + + + + b + + + c + + + + + d + + + + + + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c repeat | {}', () => { + toXmlMatch( + tex2mml('\\begin{array}{r*{2}|c}a {\\begin{array}{c}Q\\end{array}}& b & c\\\\d & e & f\\end{array}'), + ` + + + + a + + + + + Q + + + + + + + + + + + + b + + + c + + + + + d + + + + + + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('column r c repeat | {}', () => { + toXmlMatch( + tex2mml('\\begin{array}{r*{2}|c}a \\begin{array}{c}Q\\end{array}& b & c\\\\d & e & f\\end{array}'), + ` + + + + a + + + + Q + + + + + + + + + + + b + + + c + + + + + d + + + + + + + + e + + + f + + + + ` + ); + }); + + + /********************************************************************************/ + + it('column c @& hfil', () => { + toXmlMatch( + tex2mml('\\begin{array}{c@{\\alpha}c}a&&b\\\\ d&&e\\hfil \\end{array}'), + ` + + + + a + + + α + + + + b + + + + + d + + + α + + + + e + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Error', () => { + expectTexError('\\eqalignno{a & & {\\hbox{(3)}}') + .toBe('Missing close brace'); + }); + + /********************************************************************************/ + + it('end row spacing r c l', () => { + toXmlMatch( + tex2mml('\\begin{array}{rcl}a & b &c\\\\[2cm] d & e & f\\\\[2cm] \\end{array}'), + ` + + + + a + + + b + + + c + + + + + d + + + e + + + f + + + + ` + ); + }); + + /********************************************************************************/ + + it('eqnarray extend last row', () => { + toXmlMatch( + tex2mml('\\begin{eqnarray}{rcl}a & b \\\\d&c&c&c \\\\\\end{eqnarray}'), + ` + + + + + r + c + l + + a + + + b + + + + + d + + + c + + + + c + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('end row hline c', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c|}\\hline a\\\\\\hline b\\\\\\hline\\end{array}'), + ` + + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('column ! | @', () => { + toXmlMatch( + tex2mml('\\begin{array}{!{a}|@{b}c} X\\end{array}'), + ` + + + + a + + + + b + + + X + + + + ` + ); + }); + + /********************************************************************************/ + + it('column @ | ! c', () => { + toXmlMatch( + tex2mml('\\begin{array}{@{}|!{x}c} X \\end{array}'), + ` + + + + + + x + + + X + + + + ` + ); + }); + + /********************************************************************************/ + + it('column @ p m', () => { + toXmlMatch( + tex2mml('\\begin{array}{@{x}p{1em}m{1em}} X & Y \\end{array}'), + ` + + + + x + + + + X + + + + + Y + + + + + ` + ); + }); + + /********************************************************************************/ + + it('column c c @', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc@{x}} X & Y \\end{array}'), + ` + + + + X + + + Y + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('column c c | c', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc|c} X & Y & Z \\end{array}'), + ` + + + + X + + + Y + + + Z + + + + ` + ); + }); + + /********************************************************************************/ + + it('column > space', () => { + toXmlMatch( + tex2mml('\\begin{array}{> {x} c} X \\end{array}'), + ` + + + + x + X + + + + ` + ); + }); + + /********************************************************************************/ + + it('BadPreamToken', () => { + expectTexError('\\begin{array}a').toBe('Illegal pream-token (a)'); + }); + + /********************************************************************************/ + + it('Template Without End', () => { + expectTexError('\\begin{array}{>{x}c} a').toBe('Missing \\end{array}'); + }); + + /********************************************************************************/ + + it('column buffer size', () => { + expectTexError('\\begin{array}{cW{c}{1cm}c}a&b}&c\\\\ d&e&f \\end{array}') + .toBe('MathJax internal buffer size exceeded; is there a recursive macro call?'); + }); + + /********************************************************************************/ + + it('Bad Dimension', () => { + expectTexError('\\begin{array}{cp{xyz}c}a&b&c\\end{array}') + .toBe('Missing dimension or its units for p column declaration'); + }); + + /********************************************************************************/ + + it('Missing argument', () => { + expectTexError('\\begin{array}{c@}a&b\\end{array}') + .toBe('Missing argument for @ column declaration'); + }); + + /********************************************************************************/ + + it('Bad * argument', () => { + expectTexError('\\begin{array}{*{x}{x}} a&b \\end{array}') + .toBe('First argument to * column specifier must be a number'); + }); + + /********************************************************************************/ + +}); + +/** + * + * For completion we need define some extra commands reflecting those in other + * packages, that needed provisions in Base. + * + */ +import {Configuration} from '#js/input/tex/Configuration.js'; +import {HandlerType, ConfigurationType} from '#js/input/tex/HandlerTypes.js'; +import { CommandMap, EnvironmentMap } from '#js/input/tex/TokenMap.js'; +import BaseMethods from '#js/input/tex/base/BaseMethods.js'; +import ParseMethods from '#js/input/tex/ParseMethods.js'; +import TexParser from '#js/input/tex/TexParser.js'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('User Defined Macros', () => { + + new CommandMap('userMacros', { + eqref: [BaseMethods.HandleRef, true], + RR: [BaseMethods.Macro, '{\\bf R_{#1}}', 1, 'a'], + color: (parser: TexParser, name: string) => { + const color = parser.GetArgument(name); + const style = parser.itemFactory + .create('style') + .setProperties({ styles: { mathcolor: color } }); + parser.stack.env['color'] = color; + parser.Push(style); + } + }); + Configuration.create('userMacros', { + [ConfigurationType.HANDLER]: { + [HandlerType.MACRO]: ['userMacros'], + }}); + + beforeEach(() => setupTex(['base', 'userMacros'])); + + /********************************************************************************/ + + it('Macro with empty optional def', () => { + toXmlMatch( + tex2mml('\\RR'), + ` + + + R + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Macro with optional def', () => { + toXmlMatch( + tex2mml('\\RR[b]'), + ` + + + R + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('EqRef', () => { + toXmlMatch( + tex2mml('a\\label{A}\\eqref{A}'), + ` + a + + (???) + + ` + ); + }); + + /********************************************************************************/ + + it('Right Color', () => { + toXmlMatch( + tex2mml('\\left(A\\middle|B\\color{red}\\right)'), + ` + + ( + A + + | + + B + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Middle Color', () => { + toXmlMatch( + tex2mml('\\left(A\\color{red}\\middle|B\\right)'), + ` + + ( + A + + + | + + B + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +import NewcommandMethods from '#js/input/tex/newcommand/NewcommandMethods.js'; +import { BeginEnvItem } from '#js/input/tex/newcommand/NewcommandItems.js'; +import { MathtoolsMethods } from '#js/input/tex/mathtools/MathtoolsMethods.js'; + +describe('User Defined Environments', () => { + + new EnvironmentMap('userEnvs', ParseMethods.environment, { + smallmatrix: [ + BaseMethods.Array, + null, + null, + null, + 'c', + '1', + '.2em', + 'S', + 1, + ], + pmatrix: [BaseMethods.Array, null, '(', ')', 'c'], + crampedsubarray: [ + BaseMethods.Array, + null, + null, + null, + null, + '0em', + '0.1em', + "S'", + 1, + ], + gather: [BaseMethods.EqnArray, null, true, true, 'c', 'm'], + user: [NewcommandMethods.BeginEnv, true, 'A', 'B', 0], + mmtool: [MathtoolsMethods.Cases, null, '{', ''], + eqntest: [BaseMethods.EqnArray, null, true, true, 'rl', 'bt'], + }); + + Configuration.create('userEnvs', { + [ConfigurationType.HANDLER]: { + [HandlerType.ENVIRONMENT]: ['userEnvs'], + }, + [ConfigurationType.ITEMS]: { + [BeginEnvItem.prototype.kind]: BeginEnvItem, + } + }); + + beforeEach(() => setupTex(['base', 'userEnvs'])); + + /********************************************************************************/ + + it('smallmatrix', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix} a & b \\\\ c & d \\end{smallmatrix}'), + ` + + + + + a + + + b + + + + + c + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('pmatrix', () => { + toXmlMatch( + tex2mml('\\begin{pmatrix} a & b \\\\ c & d \\end{pmatrix}'), + ` + + ( + + + + a + + + b + + + + + c + + + d + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Crampedsubarray', () => { + toXmlMatch( + tex2mml('\\begin{crampedsubarray}{cc} a & b \\\\ c & d \\end{crampedsubarray}'), + ` + + + + + a + + + b + + + + + c + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Gather', () => { + toXmlMatch( + tex2mml('\\begin{gather}a\\end{gather}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('User', () => { + toXmlMatch( + tex2mml('\\begin{user} X \\end{user}'), + ` + A + X + B + ` + ); + }); + + /********************************************************************************/ + + it('Cases star', () => { + toXmlMatch( + tex2mml('\\begin{mmtool} a & test a\\\\ b & test b \\end{mmtool}'), + ` + + { + + + + a + + + test a + + + + + b + + + test b + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('EqnTest', () => { + toXmlMatch( + tex2mml('\\begin{eqntest} a & b \\end{eqntest}'), + ` + + + + a + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Tagged Environments', () => { + beforeEach(() => setupTex(['base', 'userEnvs'], { tags: 'all' })); + + /********************************************************************************/ + + it('EqnTest', () => { + toXmlMatch( + tex2mml('\\begin{eqntest} a & b \\end{eqntest}'), + ` + + + + (1) + + + a + + + + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Equation', () => { + toXmlMatch( + tex2mml('\\begin{equation} x \\end{equation}'), + ` + + + + (1) + + + x + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('MathStyle', () => { + + /********************************************************************************/ + + it('French', () => { + setupTex(['base', 'userEnvs'], { mathStyle: 'TeX' }); + toXmlMatch( + tex2mml('Aa\\Gamma\\gamma'), + ` + A + a + Γ + γ + ` + ); + }); + + /********************************************************************************/ + + it('French', () => { + setupTex(['base', 'userEnvs'], { mathStyle: 'French' }); + toXmlMatch( + tex2mml('Aa\\Gamma\\gamma'), + ` + A + a + Γ + γ + ` + ); + }); + + /********************************************************************************/ + + it('ISO', () => { + setupTex(['base', 'userEnvs'], { mathStyle: 'ISO' }); + toXmlMatch( + tex2mml('Aa\\Gamma\\gamma'), + ` + A + a + Γ + γ + ` + ); + }); + + /********************************************************************************/ + + it('upright', () => { + setupTex(['base', 'userEnvs'], { mathStyle: 'upright' }); + toXmlMatch( + tex2mml('Aa\\Gamma\\gamma'), + ` + A + a + Γ + γ + ` + ); + }); + + /********************************************************************************/ + + it('other', () => { + ParseOptions.getVariant.set('other', (_c: string) => ''); + setupTex(['base', 'userEnvs'], { mathStyle: 'other' }); + toXmlMatch( + tex2mml('Aa\\Gamma\\gamma'), + ` + A + a + Γ + γ + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Multiletter Indentifier', () => { + + beforeEach(() => setupTex(['base', 'userEnvs'], { identifierPattern: /^$/ })); + + /********************************************************************************/ + + it('Mismatch', () => { + toXmlMatch( + tex2mml('\\mathbf{aa}'), + ` + + a + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Postfilter', () => { + + Configuration.create('userFilters', { + [ConfigurationType.POSTPROCESSORS]: [ + ({data}: {data: ParseOptions}) => { + data.removeFromList('undefined', []); + } + ] + }); + + beforeEach(() => setupTex(['base', 'userFilters'])); + + /********************************************************************************/ + + it('Empty list', () => { + toXmlMatch( + tex2mml('x'), + ` + x + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('base')); + diff --git a/testsuite/tests/input/tex/Bbm.test.ts b/testsuite/tests/input/tex/Bbm.test.ts new file mode 100644 index 000000000..4b3ae11b1 --- /dev/null +++ b/testsuite/tests/input/tex/Bbm.test.ts @@ -0,0 +1,156 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/bbm/BbmConfiguration'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Bbm', () => { + + beforeEach(() => setupTex(['base', 'bbm'])); + + /********************************************************************************/ + + test('mathbbm', () => { + toXmlMatch( + tex2mml('\\mathbbm{Aa}'), + ` + + Aa + + ` + ); + }); + + /********************************************************************************/ + + test('mathbbmss', () => { + toXmlMatch( + tex2mml('\\mathbbmss{Aa}'), + ` + + Aa + + ` + ); + }); + + /********************************************************************************/ + + test('mathbbmtt', () => { + toXmlMatch( + tex2mml('\\mathbbmtt{Aa}'), + ` + + Aa + + ` + ); + }); + + /********************************************************************************/ + + test('mathbbm mathversion', () => { + toXmlMatch( + tex2mml('\\mathversion{bold}\\mathbbm{Aa}\\mathversion{normal}\\mathbbm{Aa}'), + ` + + Aa + + + Aa + + ` + ); + }); + + /********************************************************************************/ + + test('mathbbmss mathversion', () => { + toXmlMatch( + tex2mml('\\mathversion{bold}\\mathbbmss{Aa}\\mathversion{normal}\\mathbbmss{Aa}'), + ` + + Aa + + + Aa + + ` + ); + }); + + /********************************************************************************/ + + test('mathbbmtt mathversion', () => { + toXmlMatch( + tex2mml('\\mathversion{bold}\\mathbbmtt{Aa}\\mathversion{normal}\\mathbbmtt{Aa}'), + ` + + Aa + + + Aa + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Bbm', () => { + + beforeEach(() => setupTex(['base', 'bbm'], {bbm: {bold: true}})); + + /********************************************************************************/ + + test('mathbbm', () => { + toXmlMatch( + tex2mml('\\mathbbm{Aa}'), + ` + + Aa + + ` + ); + }); + + /********************************************************************************/ + + test('mathbbmss', () => { + toXmlMatch( + tex2mml('\\mathbbmss{Aa}'), + ` + + Aa + + ` + ); + }); + + /********************************************************************************/ + + test('mathbbmtt', () => { + toXmlMatch( + tex2mml('\\mathbbmtt{Aa}'), + ` + + Aa + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('bbm')); diff --git a/testsuite/tests/input/tex/Bboldx.test.ts b/testsuite/tests/input/tex/Bboldx.test.ts new file mode 100644 index 000000000..a45fd2690 --- /dev/null +++ b/testsuite/tests/input/tex/Bboldx.test.ts @@ -0,0 +1,581 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/bboldx/BboldxConfiguration'; +import '#js/input/tex/textmacros/TextMacrosConfiguration'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Bboldx', () => { + + beforeEach(() => setupTex(['base', 'bboldx'])); + + /********************************************************************************/ + + test('mathbb', () => { + toXmlMatch( + tex2mml('\\mathbb{Aa\u{393}\u{3B3}}'), + ` + + Aa + Γ + γ + + ` + ); + }); + + /********************************************************************************/ + + test('mathbfbb', () => { + toXmlMatch( + tex2mml('\\mathbfbb{Aa\u{393}\u{3B3}}'), + ` + + Aa + Γ + γ + + ` + ); + }); + + /********************************************************************************/ + + test('dotless', () => { + toXmlMatch( + tex2mml('\\imathbb\\jmathbb\\imathbfbb\\jmathbfbb'), + ` + ı + ȷ + ı + ȷ + ` + ); + }); + + /********************************************************************************/ + + test('UC Greek', () => { + toXmlMatch( + tex2mml('\\bbGamma\\bbDelta\\bbTheta\\bbLambda\\bbXi\\bbPi\\bbSigma\\bbUpsilon\\bbPhi\\bbPsi\\bbOmega'), + ` + Γ + + Θ + Λ + Ξ + Π + Σ + Υ + Φ + Ψ + + ` + ); + }); + + /********************************************************************************/ + + test('LC Greek 1', () => { + toXmlMatch( + tex2mml( + '\\bbalpha\\bbbeta\\bbgamma\\bbdelta\\bbepsilon\\bbzeta\\bbeta\\bbtheta\\bbiota\\bbkappa\\bblambda' + ), + ` + α + β + γ + δ + ε + ζ + η + θ + ι + κ + λ + ` + ); + }); + + /********************************************************************************/ + + test('LC Greek 2', () => { + toXmlMatch( + tex2mml( + '\\bbmu\\bbnu\\bbxi\\bbpi\\bbrho\\bbsigma\\bbtau\\bbupsilon\\bbphi\\bbchi\\bbpsi\\bbomega' + ), + ` + µ + ν + ξ + π + ρ + σ + τ + υ + φ + χ + ψ + ω + ` + ); + }); + + /********************************************************************************/ + + test('UC Greek Bf', () => { + toXmlMatch( + tex2mml( + '\\bfbbGamma\\bfbbDelta\\bfbbTheta\\bfbbLambda\\bfbbXi\\bfbbPi\\bfbbSigma\\bfbbUpsilon\\bfbbPhi\\bfbbPsi\\bfbbOmega' + ), + ` + Γ + + Θ + Λ + Ξ + Π + Σ + Υ + Φ + Ψ + + ` + ); + }); + + /********************************************************************************/ + + test('LC Greek Bf 1', () => { + toXmlMatch( + tex2mml( + '\\bfbbalpha\\bfbbbeta\\bfbbgamma\\bfbbdelta\\bfbbepsilon\\bfbbzeta\\bfbbeta\\bfbbtheta\\bfbbiota\\bfbbkappa\\bfbblambda' + ), + ` + α + β + γ + δ + ε + ζ + η + θ + ι + κ + οBB + ` + ); + }); + + /********************************************************************************/ + + test('LC Greek Bf 2', () => { + toXmlMatch( + tex2mml( + '\\bfbbmu\\bfbbnu\\bfbbxi\\bfbbpi\\bfbbrho\\bfbbsigma\\bfbbtau\\bfbbupsilon\\bfbbphi\\bfbbchi\\bfbbpsi\\bfbbomega' + ), + ` + µ + ν + ξ + π + ρ + σ + τ + υ + φ + χ + ψ + ω + ` + ); + }); + + /********************************************************************************/ + + test('Delimiters', () => { + toXmlMatch( + tex2mml('\\bbLparen\\bbRparen\\bbLbrack\\bbRbrack\\bbLangle\\bbRangle'), + ` + ( + ) + [ + ] + + + ` + ); + }); + + /********************************************************************************/ + + test('Delimiters Bf', () => { + toXmlMatch( + tex2mml('\\bfbbLparen\\bfbbRparen\\bfbbLbrack\\bfbbRbrack\\bfbbLangle\\bfbbRangle'), + ` + ( + ) + [ + ] + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Bboldx Text', () => { + + beforeEach(() => setupTex(['base', 'bboldx', 'textmacros'])); + + /********************************************************************************/ + + test('textbb', () => { + toXmlMatch( + tex2mml('\\text{\\textbb{Aa\u{393}\u{3B3}}}'), + ` + AaΓγ + ` + ); + }); + + /********************************************************************************/ + + test('textbfbb', () => { + toXmlMatch( + tex2mml('\\text{\\textbfbb{Aa\u{393}\u{3B3}}}'), + ` + AaΓγ + ` + ); + }); + + /********************************************************************************/ + + test('dotless', () => { + toXmlMatch( + tex2mml('\\text{\\itextbb\\jtextbb\\itextbfbb\\jtextbfbb}'), + ` + + ı + ȷ + ı + ȷ + + ` + ); + }); + + /********************************************************************************/ + + test('UC Greek', () => { + toXmlMatch( + tex2mml( + '\\text{\\txtbbGamma\\txtbbDelta\\txtbbTheta\\txtbbLambda\\txtbbXi\\txtbbPi\\txtbbSigma\\txtbbUpsilon\\txtbbPhi\\txtbbPsi\\txtbbOmega}' + ), + ` + + Γ + + Θ + Λ + Ξ + Π + Σ + Υ + Φ + Ψ + + + ` + ); + }); + + /********************************************************************************/ + + test('LC Greek 1', () => { + toXmlMatch( + tex2mml( + '\\text{\\txtbbalpha\\txtbbbeta\\txtbbgamma\\txtbbdelta\\txtbbepsilon\\txtbbzeta\\txtbbeta\\txtbbtheta\\txtbbiota\\txtbbkappa\\txtbblambda}' + ), + ` + + α + β + γ + δ + ε + ζ + η + θ + ι + κ + λ + + ` + ); + }); + + /********************************************************************************/ + + test('LC Greek 2', () => { + toXmlMatch( + tex2mml( + '\\text{\\txtbbmu\\txtbbnu\\txtbbxi\\txtbbpi\\txtbbrho\\txtbbsigma\\txtbbtau\\txtbbupsilon\\txtbbphi\\txtbbchi\\txtbbpsi\\txtbbomega}' + ), + ` + + µ + ν + ξ + π + ρ + σ + τ + υ + φ + χ + ψ + ω + + ` + ); + }); + + /********************************************************************************/ + + test('UC Greek Bf', () => { + toXmlMatch( + tex2mml( + '\\text{\\txtbfbbGamma\\txtbfbbDelta\\txtbfbbTheta\\txtbfbbLambda\\txtbfbbXi\\txtbfbbPi\\txtbfbbSigma\\txtbfbbUpsilon\\txtbfbbPhi\\txtbfbbPsi\\txtbfbbOmega}' + ), + ` + + Γ + + Θ + Λ + Ξ + Π + Σ + Υ + Φ + Ψ + + + ` + ); + }); + + /********************************************************************************/ + + test('LC Greek Bf 1', () => { + toXmlMatch( + tex2mml( + '\\text{\\txtbfbbalpha\\txtbfbbbeta\\txtbfbbgamma\\txtbfbbdelta\\txtbfbbepsilon\\txtbfbbzeta\\txtbfbbeta\\txtbfbbtheta\\txtbfbbiota\\txtbfbbkappa\\txtbfbblambda}' + ), + ` + + α + β + γ + δ + ε + ζ + η + θ + ι + κ + λ + + ` + ); + }); + + /********************************************************************************/ + + test('LC Greek Bf 2', () => { + toXmlMatch( + tex2mml( + '\\text{\\txtbfbbmu\\txtbfbbnu\\txtbfbbxi\\txtbfbbpi\\txtbfbbrho\\txtbfbbsigma\\txtbfbbtau\\txtbfbbupsilon\\txtbfbbphi\\txtbfbbchi\\txtbfbbpsi\\txtbfbbomega}' + ), + ` + + µ + ν + ξ + π + ρ + σ + τ + υ + φ + χ + ψ + ω + + ` + ); + }); + + /********************************************************************************/ + + test('Delimiters', () => { + toXmlMatch( + tex2mml('\\text{\\txtbbLparen\\txtbbRparen\\txtbbLbrack\\txtbbRbrack\\txtbbLangle\\txtbbRangle}'), + ` + + ( + ) + [ + ] + + + + ` + ); + }); + + /********************************************************************************/ + + test('Delimiters Bf', () => { + toXmlMatch( + tex2mml('\\text{\\txtbfbbLparen\\txtbfbbRparen\\txtbfbbLbrack\\txtbfbbRbrack\\txtbfbbLangle\\txtbfbbRangle}'), + ` + + ( + ) + [ + ] + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Bboldx light', () => { + + beforeEach(() => setupTex(['base', 'bboldx', 'textmacros'], {bboldx: {light: true}})); + + /********************************************************************************/ + + test('mathbb', () => { + toXmlMatch( + tex2mml('\\mathbb{Aa\u{393}\u{3B3}}'), + ` + + Aa + Γ + γ + + ` + ); + }); + + /********************************************************************************/ + + test('mathbfbb', () => { + toXmlMatch( + tex2mml('\\mathbfbb{Aa\u{393}\u{3B3}}'), + ` + + Aa + Γ + γ + + ` + ); + }); + + /********************************************************************************/ + + test('Some Greek', () => { + toXmlMatch( + tex2mml('\\bbGamma\\bbgamma\\bfbbGamma\\bfbbgamma'), + ` + Γ + γ + Γ + γ + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Bboldx bfbb', () => { + + beforeEach(() => setupTex(['base', 'bboldx', 'textmacros'], {bboldx: {bfbb: true}})); + + /********************************************************************************/ + + test('mathbb', () => { + toXmlMatch( + tex2mml('\\mathbb{Aa\u{393}\u{3B3}}'), + ` + + Aa + Γ + γ + + ` + ); + }); + + /********************************************************************************/ + + test('mathbfbb', () => { + toXmlMatch( + tex2mml('\\mathbfbb{Aa\u{393}\u{3B3}}'), + ` + + Aa + Γ + γ + + ` + ); + }); + + /********************************************************************************/ + + test('Some Greek', () => { + toXmlMatch( + tex2mml('\\bbGamma\\bbgamma\\bfbbGamma\\bfbbgamma'), + ` + Γ + γ + Γ + γ + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => {getTokens('bboldx'); getTokens('text-bboldx')}); diff --git a/testsuite/tests/input/tex/Bbox.test.ts b/testsuite/tests/input/tex/Bbox.test.ts new file mode 100644 index 000000000..b68cd6cda --- /dev/null +++ b/testsuite/tests/input/tex/Bbox.test.ts @@ -0,0 +1,131 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/bbox/BboxConfiguration'; + +beforeEach(() => setupTex(['base', 'bbox'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Bbox', () => { + + /********************************************************************************/ + + it('Bbox-Background', () => { + toXmlMatch( + tex2mml('\\bbox[yellow]{a}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Bbox-Padding', () => { + toXmlMatch( + tex2mml('\\bbox[5px]{a}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Bbox-Frame', () => { + toXmlMatch( + tex2mml('\\bbox[border:5px solid red]{a}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Bbox-Background-Padding', () => { + toXmlMatch( + tex2mml('\\bbox[yellow,5px]{a}'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('Bbox-Padding-Frame', () => { + toXmlMatch( + tex2mml('\\bbox[5px,border:2px solid red]{a}'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('Bbox-Background-Padding-Frame', () => { + toXmlMatch( + tex2mml('\\bbox[yellow,5px,border:2px solid red]{a}'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('Bbox-Background-Error', () => { + expectTexError('\\bbox[yellow,green]{a}') + .toBe('Background specified twice in \\bbox'); + }); + + /********************************************************************************/ + + it('Bbox-Padding-Error', () => { + expectTexError('\\bbox[5px,6px]{a}') + .toBe('Padding specified twice in \\bbox'); + }); + + /********************************************************************************/ + + it('Bbox-Frame-Error', () => { + expectTexError('\\bbox[border:2px solid red,border:2px solid green]{a}') + .toBe('Style specified twice in \\bbox'); + }); + + /********************************************************************************/ + + it('Bbox-General-Error', () => { + expectTexError('\\bbox[22-11=color]{a}') + .toBe(`"22-11=color" doesn't look like a color, a padding dimension, or a style`); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('bbox')); diff --git a/testsuite/tests/input/tex/Begingroup.test.ts b/testsuite/tests/input/tex/Begingroup.test.ts new file mode 100644 index 000000000..ccc4c7184 --- /dev/null +++ b/testsuite/tests/input/tex/Begingroup.test.ts @@ -0,0 +1,415 @@ +import { afterAll, beforeEach, describe, test, expect } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/begingroup/BegingroupConfiguration'; +import '#js/input/tex/newcommand/NewcommandConfiguration'; + +import { Configuration } from "#js/input/tex/Configuration.js"; +import { CommandMap } from "#js/input/tex/TokenMap.js"; +import TexParser from "#js/input/tex/TexParser.js"; +import { mathjax } from "#js/mathjax.js"; + +/**********************************************************************************/ +/**********************************************************************************/ + +/** + * Implement a command that forces a retry error (like \require would), + * but does nothing when called on the retry. + */ +new CommandMap('retry', { + retry(parser: TexParser, _name: string) { + if (!parser.options.retry) { + parser.options.retry = true; + mathjax.retryAfter(Promise.resolve()); + } + } +}); + +Configuration.create('retry', {handler: {macro: ['retry']}}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Begingroup', () => { + + beforeEach(() => setupTex(['base', 'begingroup', 'newcommand', 'retry'], { + formatError: (_jax: any, err: Error) => {throw err} + })); + + /********************************************************************************/ + + test('Begingroup Def Single', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\x \\begingroup \\def\\x{B} \\x \\endgroup \\x'), + ` + A + B + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Def Nested', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\x \\begingroup \\def\\x{B} \\x \\begingroup \\def\\x{C} \\x \\endgroup \\x \\endgroup \\x'), + ` + A + B + C + B + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Let Single', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\x \\begingroup \\let\\x=B \\x \\endgroup \\x'), + ` + A + B + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Let Nested', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\x \\begingroup \\let\\x=B \\x \\begingroup \\let\\x=C \\x \\endgroup \\x \\endgroup \\x'), + ` + A + B + C + B + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Env Single', () => { + toXmlMatch( + tex2mml('\\newenvironment{test}{[}{]}\\begin{test}X\\end{test}\\begingroup\\newenvironment{test}{(}{)}\\begin{test}X\\end{test}\\endgroup\\begin{test}X\\end{test}'), + ` + [ + X + ] + ( + X + ) + [ + X + ] + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Delimiter Single', () => { + toXmlMatch( + tex2mml('\\let\\x=\\| \\left\\x A\\right\\x \\begingroup \\let\\x=| \\left\\x B \\right\\x \\endgroup \\left\\x C \\right\\x'), + ` + + + A + + + + | + B + | + + + + C + + + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Delimiter Nested', () => { + toXmlMatch( + tex2mml('\\let\\x=\\| \\left\\x A\\right\\x \\begingroup \\let\\x=| \\left\\x B \\right\\x \\begingroup \\let\\x=( \\left\\x C \\right\\x \\endgroup \\left\\x D \\right\\x \\endgroup \\left\\x E \\right\\x'), + ` + + + A + + + + | + B + | + + + ( + C + ( + + + | + D + | + + + + E + + + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Global', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\x \\begingroup \\def\\x{B} \\x \\global\\def\\x{C} \\x \\endgroup \\x'), + ` + A + B + C + C + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Global Nested', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\x \\begingroup \\def\\x{B} \\x \\begingroup \\gdef\\x{C} \\x \\endgroup \\x \\endgroup \\x'), + ` + A + B + C + C + C + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Global Let', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\x \\begingroup \\let\\x=B \\x \\global\\let\\x=C \\x \\endgroup \\x'), + ` + A + B + C + C + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Persists', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\begingroup \\def\\x{B}'), + `` + ); + toXmlMatch( + tex2mml('\\x \\endgroup \\x'), + ` + B + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup Reset', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\begingroup \\def\\x{B} \\begingroupReset \\x'), + ` + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup End without Begin', () => { + expectTexError('\\endgroup').toBe('Missing \\begingroup or extra \\endgroup'); + }); + + /********************************************************************************/ + + test('Begingroup End without Begin 2', () => { + expectTexError('\\begingroup \\endgroup \\endgroup').toBe('Missing \\begingroup or extra \\endgroup'); + }); + + /********************************************************************************/ + + test('Begingroup global misplaced', () => { + expectTexError('\\global\\sqrt{x}').toBe('Invalid use of \\global'); + expectTexError('\\global x').toBe('Invalid use of \\global'); + }); + + /********************************************************************************/ + + test('Begingroup reset', () => { + expectTexError('\\begingroup \\begingroupReset \\endgroup').toBe('Missing \\begingroup or extra \\endgroup'); + }); + + /********************************************************************************/ + + test('Begingroup reset 2', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\begingroup \\def\\x{B} \\begingroupReset \\x'), + ` + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup let undefined', () => { + expectTexError('\\def\\x{A} \\begingroup \\let\\x=\\undefined \\x \\endgroup') + .toBe('Undefined control sequence \\x'); + }); + + /********************************************************************************/ + + test('Begingroup let undefined 2', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\begingroup \\let\\x=\\undefined \\endgroup \\x'), + ` + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup global def undefines local delimiter', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\x \\begingroup \\let\\x=\\| \\x \\begingroup \\gdef\\x{C} \\x \\endgroup \\x \\endgroup \\x'), + ` + A + + C + C + C + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup global let delimiter undefines local def', () => { + toXmlMatch( + tex2mml('\\let\\x=| \\x \\begingroup \\def\\x{A} \\x \\begingroup \\global\\let\\x=\\| \\x \\endgroup \\x \\endgroup \\x'), + ` + | + A + + + + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup sandbox', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\begingroupSandbox \\def\\x{B} \\begingroupReset \\x'), + ` + B + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup double sandbox', () => { + toXmlMatch( + tex2mml('\\def\\x{A} \\begingroupSandbox \\def\\x{B} \\begingroupSandbox \\x'), + ` + A + ` + ); + }); + + /********************************************************************************/ + + test('Begingroup sandbox not ended', () => { + expectTexError('\\begingroupSandbox \\endgroup').toBe('Missing \\begingroup or extra \\endgroup'); + }); + + /********************************************************************************/ + + test('Begingroup sandbox redefine', () => { + expectTexError('\\let\\begingroupSandbox=\\undefined') + .toBe("The control sequence \\begingroupSandbox can't be redefined"); + expectTexError('\\def\\begingroupSandbox{x}') + .toBe("The control sequence \\begingroupSandbox can't be redefined"); + expectTexError('\\newcommand{\\begingroupSandbox}{x}') + .toBe("The control sequence \\begingroupSandbox can't be redefined"); + }); + + /********************************************************************************/ + + test('Begingroup with retry', async () => { + await expect(mathjax.handleRetriesFor( + () => tex2mml('\\sin \\begingroup\\def\\sin{SIN}\\retry\\endgroup') + )).resolves.toBe( + ` + sin +` + ); + }); + + /********************************************************************************/ + + test('Begingroup sandbox with retry', async () => { + tex2mml('\\def\\x{A}\\begingroupSandbox'); + await expect(mathjax.handleRetriesFor( + () => tex2mml('\\x \\begingroup\\def\\x{B}\\retry\\endgroup') + )).resolves.toBe( + ` + A +` + ); + }); + + /********************************************************************************/ + + test('Begingroup retry error', async () => { + await expect(mathjax.handleRetriesFor( + () => tex2mml('\\begingroup\\retry\\endgroup\\endgroup') + ).catch((e) => e.message)).resolves.toBe('Missing \\begingroup or extra \\endgroup'); + }); + + /********************************************************************************/ + + test('Begingroup sandbox retry error', async () => { + tex2mml('\\begingroupSandbox'); + await expect(mathjax.handleRetriesFor( + () => tex2mml('\\begingroup\\retry\\endgroup\\endgroup') + ).catch((e) => e.message)).resolves.toBe('Missing \\begingroup or extra \\endgroup'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('begingroup')); diff --git a/testsuite/tests/input/tex/Boldsymbol.test.ts b/testsuite/tests/input/tex/Boldsymbol.test.ts new file mode 100644 index 000000000..ab6b34452 --- /dev/null +++ b/testsuite/tests/input/tex/Boldsymbol.test.ts @@ -0,0 +1,113 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/boldsymbol/BoldsymbolConfiguration'; + +beforeEach(() => setupTex(['base', 'boldsymbol'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Boldsymbol', () => { + + /********************************************************************************/ + + it('Boldsymbol Single', () => { + toXmlMatch( + tex2mml('\\boldsymbol{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Boldsymbol Context', () => { + toXmlMatch( + tex2mml('b\\boldsymbol{a}c'), + ` + b + a + c + ` + ); + }); + + /********************************************************************************/ + + it('Boldsymbol Operator', () => { + toXmlMatch( + tex2mml('\\boldsymbol{a+b}'), + ` + a + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Boldsymbol Fraction', () => { + toXmlMatch( + tex2mml('\\boldsymbol{\\frac{a}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Boldsymbol Recursive', () => { + toXmlMatch( + tex2mml('\\boldsymbol{a+b\\mbox{ w $c+\\boldsymbol{d+e}$ w } q-} -q'), + ` + a + + + b + +  w  + + c + + + d + + + e + +  w  + + q + + + q + ` + ); + }); + + /********************************************************************************/ + + it('Boldsymbol Variant', () => { + toXmlMatch( + tex2mml('\\boldsymbol{A\\mathbb{B}C}'), + ` + A + + B + + C + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('boldsymbol')); diff --git a/testsuite/tests/input/tex/Braket.test.ts b/testsuite/tests/input/tex/Braket.test.ts new file mode 100644 index 000000000..f651eccc5 --- /dev/null +++ b/testsuite/tests/input/tex/Braket.test.ts @@ -0,0 +1,673 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/braket/BraketConfiguration'; + +beforeEach(() => setupTex(['base', 'braket'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Braket', () => { + + /********************************************************************************/ + + it('Braket-bra', () => { + toXmlMatch( + tex2mml('\\bra{x}'), + ` + + + + x + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-bra-large', () => { + toXmlMatch( + tex2mml('\\bra{\\frac{x}{y}}'), + ` + + + + + x + y + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Bra', () => { + toXmlMatch( + tex2mml('\\Bra{\\frac{x}{y}}'), + ` + + + + + + x + y + + + | + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-ket', () => { + toXmlMatch( + tex2mml('\\ket{x}'), + ` + + | + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-ket-large', () => { + toXmlMatch( + tex2mml('\\ket{\\frac{x}{y}}'), + ` + + | + + + x + y + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Ket', () => { + toXmlMatch( + tex2mml('\\Ket{\\frac{x}{y}}'), + ` + + + | + + + x + y + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-braket', () => { + toXmlMatch( + tex2mml('\\braket{x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-braket-large', () => { + toXmlMatch( + tex2mml('\\braket{\\frac{x}{y}}'), + ` + + + + x + y + + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Braket', () => { + toXmlMatch( + tex2mml('\\Braket{\\frac{x}{y}}'), + ` + + + + x + y + + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-ketbra', () => { + toXmlMatch( + tex2mml('\\ketbra{x}{y}'), + ` + + | + + x + + + + + y + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-ketbra-large', () => { + toXmlMatch( + tex2mml('\\ketbra{\\frac{x}{y}}{z}'), + ` + + | + + + x + y + + + + + + z + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Ketbra', () => { + toXmlMatch( + tex2mml('\\Ketbra{\\frac{x}{y}}{z}'), + ` + + + | + + + x + y + + + + + + + + z + + | + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Set-small', () => { + toXmlMatch( + tex2mml('\\set{x}'), + ` + + { + x + } + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Set', () => { + toXmlMatch( + tex2mml('\\Set{x}'), + ` + + { + + x + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Set-large', () => { + toXmlMatch( + tex2mml('\\Set{\\frac{x}{y}}'), + ` + + { + + + x + y + + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Set-Bar', () => { + toXmlMatch( + tex2mml('\\Set{x|\\frac{x}{y}}'), + ` + + { + + x + + | + + + x + y + + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Set-over', () => { + toXmlMatch( + tex2mml('\\Set{x\\over y}'), + ` + + { + + + x + y + + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-bar-small', () => { + toXmlMatch( + tex2mml('\\braket{x|y}'), + ` + + + x + | + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-bar-large', () => { + toXmlMatch( + tex2mml('\\braket{\\frac{x}{y}|z}'), + ` + + + + x + y + + | + z + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Bar', () => { + toXmlMatch( + tex2mml('\\Braket{\\frac{x}{y}|z}'), + ` + + + + x + y + + + | + + z + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Bar1', () => { + toXmlMatch( + tex2mml('\\Braket{\\frac{x}{y}||z||y}'), + ` + + + + x + y + + + + + z + + + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Bar2', () => { + toXmlMatch( + tex2mml('\\Braket{\\frac{x}{y}\\||z||y}'), + ` + + + + x + y + + + + + + | + + z + + + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Bar3', () => { + toXmlMatch( + tex2mml('\\Braket{\\frac{x}{y}|||z||y}'), + ` + + + + x + y + + + + + + | + + z + + + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Bar4', () => { + toXmlMatch( + tex2mml('\\Braket{\\frac{x}{y}|||z|||y}'), + ` + + + + x + y + + + + + + | + + z + + + + + | + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Bar-Set', () => { + toXmlMatch( + tex2mml('\\Set{\\frac{x}{y}||y||z}'), + ` + + { + + + x + y + + + + + y + | + | + z + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Bar-Set2', () => { + toXmlMatch( + tex2mml('\\Set{\\frac{x}{y}\\||y\\||z}'), + ` + + { + + + x + y + + + + + | + y + + | + z + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Space', () => { + toXmlMatch( + tex2mml('\\braket {a|b}'), + ` + + + a + | + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-No-Braces-Simple', () => { + toXmlMatch( + tex2mml('\\braket a|b'), + ` + + + a + + + | + b + ` + ); + }); + + /********************************************************************************/ + + it('Braket-No-Braces-Complex', () => { + toXmlMatch( + tex2mml('\\braket \\frac{a}{c}|b'), + ` + + + + a + c + + + + | + b + ` + ); + }); + + /********************************************************************************/ + + it('Braket-Nested', () => { + toXmlMatch( + tex2mml('\\braket {\\braket{a|b}c}'), + ` + + + + + a + | + b + + + c + + + ` + ); + }); + + /********************************************************************************/ + + it('Braket-error', () => { + expectTexError('\\braket') + .toBe('Missing argument for \\braket'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('braket')); diff --git a/testsuite/tests/input/tex/Bussproofs.test.ts b/testsuite/tests/input/tex/Bussproofs.test.ts new file mode 100644 index 000000000..5ef5b0275 --- /dev/null +++ b/testsuite/tests/input/tex/Bussproofs.test.ts @@ -0,0 +1,2976 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTexWithOutput, tex2mml } from '#helpers'; +import '#js/input/tex/bussproofs/BussproofsConfiguration'; +import '#js/input/tex/ams/AmsConfiguration'; + +beforeEach(() => setupTexWithOutput(['base', 'ams', 'bussproofs'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('BussproofsRegInf', () => { + + /********************************************************************************/ + + it('Single Axiom', () => { + toXmlMatch( + tex2mml('\\begin{prooftree}\\AxiomC{A}\\end{prooftree}'), + ` + + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('Unary Inference', () => { + toXmlMatch( + tex2mml('\\begin{prooftree}\\AxiomC{A}\\UnaryInfC{B}\\end{prooftree}'), + ` + + + + + + + + + A + + + + + + + + + + + + B + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Binary Inference', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{A}\\AxiomC{B}\\BinaryInfC{C}\\end{prooftree}' + ), + ` + + + + + + + + + A + + + + + + + + B + + + + + + + + + + + + C + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Trinary Inference', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{A}\\AxiomC{B}\\AxiomC{C}\\TrinaryInfC{D}\\end{prooftree}' + ), + ` + + + + + + + + + A + + + + + + + + B + + + + + + + + C + + + + + + + + + + + + D + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Quaternary Inference', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{A}\\AxiomC{B}\\AxiomC{C}\\AxiomC{D}\\QuaternaryInfC{E}\\end{prooftree}' + ), + ` + + + + + + + + + A + + + + + + + + B + + + + + + + + C + + + + + + + + D + + + + + + + + + + + + E + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Quinary Inference', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{A}\\AxiomC{B}\\AxiomC{C}\\AxiomC{D}\\AxiomC{E}\\QuinaryInfC{F}\\end{prooftree}' + ), + ` + + + + + + + + + A + + + + + + + + B + + + + + + + + C + + + + + + + + D + + + + + + + + E + + + + + + + + + + + + F + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Left', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{A}\\LeftLabel{L}\\UnaryInfC{B}\\end{prooftree}' + ), + ` + + + + L + + + + + + + + + + + A + + + + + + + + + + + + B + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Right', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{A}\\RightLabel{R}\\UnaryInfC{B}\\end{prooftree}' + ), + ` + + + + + + + + + + A + + + + + + + + + + + + B + + + + + + + + R + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Both', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{A}\\LeftLabel{L}\\RightLabel{R}\\UnaryInfC{B}\\end{prooftree}' + ), + ` + + + + L + + + + + + + + + + + A + + + + + + + + + + + + B + + + + + + + + R + + + + ` + ); + }); + + /********************************************************************************/ + + it('Single Axiom Abbr', () => { + toXmlMatch( + tex2mml('\\begin{prooftree}\\AXC{A}\\end{prooftree}'), + ` + + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('Unary Inference Abbr', () => { + toXmlMatch( + tex2mml('\\begin{prooftree}\\AXC{A}\\UIC{B}\\end{prooftree}'), + ` + + + + + + + + + A + + + + + + + + + + + + B + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Binary Inference Abbr', () => { + toXmlMatch( + tex2mml('\\begin{prooftree}\\AXC{A}\\AXC{B}\\BIC{C}\\end{prooftree}'), + ` + + + + + + + + + A + + + + + + + + B + + + + + + + + + + + + C + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Trinary Inference Abbr', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AXC{A}\\AXC{B}\\AXC{C}\\TIC{D}\\end{prooftree}' + ), + ` + + + + + + + + + A + + + + + + + + B + + + + + + + + C + + + + + + + + + + + + D + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Left Abbr', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AXC{A}\\LeftLabel{L}\\UIC{B}\\end{prooftree}' + ), + ` + + + + L + + + + + + + + + + + A + + + + + + + + + + + + B + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Right Abbr', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AXC{A}\\RightLabel{R}\\UIC{B}\\end{prooftree}' + ), + ` + + + + + + + + + + A + + + + + + + + + + + + B + + + + + + + + R + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Both Abbr', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AXC{A}\\LeftLabel{L}\\RightLabel{R}\\UIC{B}\\end{prooftree}' + ), + ` + + + + L + + + + + + + + + + + A + + + + + + + + + + + + B + + + + + + + + R + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('BussproofsRegProofs', () => { + + /********************************************************************************/ + + it('Simple Proof', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{D}\\AxiomC{A}\\AxiomC{B}\\AxiomC{R}\\BinaryInfC{$C \\rightarrow D \\rightarrow Q$}\\BinaryInfC{E}\\BinaryInfC{F}\\end{prooftree}' + ), + ` + + + + + + + + + + D + + + + + + + + + + + + + + + A + + + + + + + + + + + + + + B + + + + + + + + R + + + + + + + + + + + + + C + + D + + Q + + + + + + + + + + + + + + + + E + + + + + + + + + + + + + + + + + F + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Simple Proof Noise', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{D}\\AxiomC{A}\\AxiomC{B}\\AxiomC{R}$\\alpha$\\BinaryInfC{$C \\rightarrow D \\rightarrow Q$}\\BinaryInfC{E}\\BinaryInfC{F}\\end{prooftree}' + ), + ` + + + $ + + α + + $ + + + + + + + + + + D + + + + + + + + + + + + + + + A + + + + + + + + + + + + + + B + + + + + + + + R + + + + + + + + + + + + + C + + D + + Q + + + + + + + + + + + + + + + + E + + + + + + + + + + + + + + + + + F + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Simple Proof Large', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{D}\\AxiomC{A1}\\AxiomC{A2}\\TrinaryInfC{Q}\\AxiomC{A}\\AxiomC{B}\\AxiomC{R}\\BinaryInfC{$C \\rightarrow D \\rightarrow Q$}\\BinaryInfC{E}\\BinaryInfC{F}\\AxiomC{M}\\BinaryInfC{$N \\rightarrow R$}\\end{prooftree}' + ), + ` + + + + + + + + + + + + + + + + + + + + + + + + + + + D + + + + + + + + A1 + + + + + + + + A2 + + + + + + + + + + + + Q + + + + + + + + + + + + + + + + + + + A + + + + + + + + + + + + + + B + + + + + + + + R + + + + + + + + + + + + + C + + D + + Q + + + + + + + + + + + + + + + + E + + + + + + + + + + + + + + + + + F + + + + + + + + + + + + + + M + + + + + + + + + + + + + N + + R + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Simple Proofs Right Labels', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{D}\\AxiomC{A1}\\AxiomC{A2}\\TrinaryInfC{Q}\\RightLabel{AAAA}\\AxiomC{A}\\AxiomC{B}\\AxiomC{R}\\BinaryInfC{$C \\rightarrow D \\rightarrow Q$}\\RightLabel{BBB}\\BinaryInfC{E}\\RightLabel{CCCCC}\\BinaryInfC{F}\\RightLabel{QERE}\\AxiomC{M}\\BinaryInfC{$N \\rightarrow R$}\\RightLabel{Nowhere}\\end{prooftree}' + ), + ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D + + + + + + + + A1 + + + + + + + + A2 + + + + + + + + + + + + Q + + + + + + + + + + + + + + + + + + + + A + + + + + + + + + + + + + + + + B + + + + + + + + R + + + + + + + + + + + + + C + + D + + Q + + + + + + + + AAAA + + + + + + + + + + + + + + E + + + + + + + BBB + + + + + + + + + + + + + + F + + + + + + + CCCCC + + + + + + + + + + + + M + + + + + + + + + + + + + N + + R + + + + + + + + + QERE + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Simple Proofs Left Labels', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{D}\\AxiomC{A1}\\AxiomC{A2}\\TrinaryInfC{Q}\\LeftLabel{AAAA}\\AxiomC{A}\\AxiomC{B}\\AxiomC{R}\\BinaryInfC{$C \\rightarrow D \\rightarrow Q$}\\LeftLabel{BBB}\\BinaryInfC{E}\\LeftLabel{CCCCC}\\BinaryInfC{F}\\LeftLabel{QERE}\\AxiomC{M}\\BinaryInfC{$N \\rightarrow R$}\\LeftLabel{Nowhere}\\end{prooftree}' + ), + ` + + + + + + QERE + + + + + + + + + + + + + + + + CCCCC + + + + + + + + + + + + + + + + + + D + + + + + + + + A1 + + + + + + + + A2 + + + + + + + + + + + + Q + + + + + + + + + + + + + BBB + + + + + + + + + + A + + + + + + + + AAAA + + + + + + + + + + B + + + + + + + + R + + + + + + + + + + + + + C + + D + + Q + + + + + + + + + + + + + + + + + E + + + + + + + + + + + + + + + + + + F + + + + + + + + + + + + + + + + M + + + + + + + + + + + + + N + + R + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Simple Proofs Mixed Labels', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{D}\\AxiomC{A1}\\AxiomC{A2}\\TrinaryInfC{Q}\\RightLabel{AAAA}\\AxiomC{A}\\AxiomC{B}\\AxiomC{R}\\BinaryInfC{$C \\rightarrow D \\rightarrow Q$}\\LeftLabel{BBB}\\BinaryInfC{E}\\LeftLabel{CCCCC}\\BinaryInfC{F}\\RightLabel{QERE}\\LeftLabel{DD}\\AxiomC{M}\\BinaryInfC{$N \\rightarrow R$}\\LeftLabel{Nowhere}\\end{prooftree}' + ), + ` + + + + + + DD + + + + + + + + + + + + + + + + CCCCC + + + + + + + + + + + + + + + + + + D + + + + + + + + A1 + + + + + + + + A2 + + + + + + + + + + + + Q + + + + + + + + + + + + + BBB + + + + + + + + + + A + + + + + + + + + + + + + + + + B + + + + + + + + R + + + + + + + + + + + + + C + + D + + Q + + + + + + + + AAAA + + + + + + + + + + + + + + E + + + + + + + + + + + + + + + + + + F + + + + + + + + + + + + + + + + M + + + + + + + + + + + + + N + + R + + + + + + + + + QERE + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Proof Very Right Label', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AxiomC{D}\\AxiomC{A1}\\AxiomC{A2}\\RightLabel{AAAA}\\TrinaryInfC{Q}\\RightLabel{Nowhere}\\AxiomC{A}\\AxiomC{B}\\AxiomC{R}\\BinaryInfC{$C \\rightarrow D \\rightarrow Q$}\\RightLabel{BBB}\\BinaryInfC{E}\\RightLabel{CCCCC}\\BinaryInfC{F}\\RightLabel{QERE}\\AxiomC{M}\\UnaryInfC{More and more}\\UnaryInfC{More and more}\\UnaryInfC{More and more}\\BinaryInfC{$N \\rightarrow R$}\\end{prooftree}' + ), + ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D + + + + + + + + A1 + + + + + + + + A2 + + + + + + + + + + + + Q + + + + + + + AAAA + + + + + + + + + + + + + + + + + A + + + + + + + + + + + + + + + + B + + + + + + + + R + + + + + + + + + + + + + C + + D + + Q + + + + + + + + Nowhere + + + + + + + + + + + + + + E + + + + + + + BBB + + + + + + + + + + + + + + F + + + + + + + CCCCC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + M + + + + + + + + + + + + More and more + + + + + + + QERE + + + + + + + + + + + + + + More and more + + + + + + + + + + + + + + + More and more + + + + + + + + + + + + + + + + N + + R + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Proof Complex', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\AXC{}\\RL{$Hyp^{1}$}\\UIC{$P$}\\AXC{$P\\rightarrow Q$}\\RL{$\\rightarrow_E$}\\solidLine\\BIC{$Q^2$}\\AXC{$Q\\rightarrow R$} \\RL{$\\rightarrow_E$} \\BIC{$R$} \\AXC{$Q$}\\RL{Rit$^2$} \\UIC{$Q$}\\RL{$\\wedge_I$}\\BIC{$Q\\wedge R$}\\RL{${\\rightarrow_I}^1$}\\UIC{$P\\rightarrow Q\\wedge R$}\\end{prooftree}' + ), + ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + P + + + + + + + + + H + y + + p + + 1 + + + + + + + + + + + + P + + Q + + + + + + + + + + + + + + + Q + 2 + + + + + + + + + + + + E + + + + + + + + + + + + Q + + R + + + + + + + + + + + + + + R + + + + + + + + + + + E + + + + + + + + + + + + + + + + + + + + + Q + + + + + + + + + + + + + + Q + + + + + + + + + Rit + + + + 2 + + + + + + + + + + + + + + + + + + Q + + R + + + + + + + + + + + I + + + + + + + + + + + + + + + + + + + P + + Q + + R + + + + + + + + + + + + + + I + + + 1 + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Proof Mixing Order', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\alwaysRootAtTop\\AXC{}\\RL{$Hyp^{1}$}\\UIC{$P$}\\AXC{$P\\rightarrow Q$}\\RL{$\\rightarrow_E$}\\solidLine\\BIC{$Q^2$}\\alwaysRootAtBottom\\AXC{$Q\\rightarrow R$} \\RL{$\\rightarrow_E$} \\BIC{$R$} \\AXC{$Q$}\\RL{Rit$^2$} \\UIC{$Q$}\\RL{$\\wedge_I$}\\BIC{$Q\\wedge R$}\\RL{\${\\rightarrow_I}^1$}\\UIC{$P\\rightarrow Q\\wedge R$}\\end{prooftree}' + ), + ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Q + 2 + + + + + + + + + + + + + + + + + + + P + + + + + + + + + + + + + + + + + + + + H + y + + p + + 1 + + + + + + + + + + + + P + + Q + + + + + + + + + + + + + + E + + + + + + + + + + + + Q + + R + + + + + + + + + + + + + + R + + + + + + + + + + + E + + + + + + + + + + + + + + + + + + + + + Q + + + + + + + + + + + + + + Q + + + + + + + + + Rit + + + + 2 + + + + + + + + + + + + + + + + + + Q + + R + + + + + + + + + + + I + + + + + + + + + + + + + + + + + + + P + + Q + + R + + + + + + + + + + + + + + I + + + 1 + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Extreme', () => { + toXmlMatch( + tex2mml( + '\\begin{prooftree}\\LL{HHHHH}\\RL{11111111111111111}\\AxiomC{D}\\AxiomC{A1}\\AxiomC{A2}\\TrinaryInfC{Q}\\RightLabel{AAAA}\\AxiomC{A}\\AxiomC{B}\\AxiomC{R}\\LL{qqqq}\\BinaryInfC{$C \\rightarrow D \\rightarrow Q$}\\LeftLabel{BBBB}\\RightLabel{MMM}\\BinaryInfC{E}\\RightLabel{CCCCC}\\LL{WWW}\\BinaryInfC{F}\\RightLabel{QERE}\\AxiomC{M}\\LL{BBB}\\BinaryInfC{$N \\rightarrow R$}\\RightLabel{Nowhere}\\end{prooftree}' + ), + ` + + + + + + BBB + + + + + + + + + + + + + + + WWW + + + + + + + + + + + + HHHHH + + + + + + + + + + D + + + + + + + + A1 + + + + + + + + A2 + + + + + + + + + + + + Q + + + + + + + 11111111111111111 + + + + + + + + + + BBBB + + + + + + + + + + A + + + + + + + + + qqqq + + + + + + + + + + B + + + + + + + + R + + + + + + + + + + + + + C + + D + + Q + + + + + + + + AAAA + + + + + + + + + + + + + + E + + + + + + + MMM + + + + + + + + + + + + + + F + + + + + + + CCCCC + + + + + + + + + + + + M + + + + + + + + + + + + + N + + R + + + + + + + + + QERE + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('bussproofs')); diff --git a/testsuite/tests/input/tex/Cancel.test.ts b/testsuite/tests/input/tex/Cancel.test.ts new file mode 100644 index 000000000..a74ecbedd --- /dev/null +++ b/testsuite/tests/input/tex/Cancel.test.ts @@ -0,0 +1,133 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/cancel/CancelConfiguration'; + +beforeEach(() => setupTex(['base', 'cancel'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Cancel', () => { + + /********************************************************************************/ + + it('Cancel', () => { + toXmlMatch( + tex2mml('\\cancel{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('BCancel', () => { + toXmlMatch( + tex2mml('\\bcancel{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('XCancel', () => { + toXmlMatch( + tex2mml('\\xcancel{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('CancelTo', () => { + toXmlMatch( + tex2mml('\\cancelto{x}{y}'), + ` + + + y + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Cancel Attr', () => { + toXmlMatch( + tex2mml('\\cancel[color=red]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Cancel Attrs', () => { + toXmlMatch( + tex2mml('\\cancel[mathcolor=green,mathbackground=yellow]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Cancel Attr Not Allowed', () => { + toXmlMatch( + tex2mml('\\cancel[nothing=green]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('CancelTo Attrs', () => { + toXmlMatch( + tex2mml('\\cancelto[data-padding=5,data-arrowhead=15]{x}{y}'), + ` + + + y + + + x + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('cancel')); diff --git a/testsuite/tests/input/tex/Cases.test.ts b/testsuite/tests/input/tex/Cases.test.ts new file mode 100644 index 000000000..870e4d7ee --- /dev/null +++ b/testsuite/tests/input/tex/Cases.test.ts @@ -0,0 +1,510 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/cases/CasesConfiguration'; +import '#js/input/tex/empheq/EmpheqConfiguration'; +import '#js/input/tex/ams/AmsConfiguration'; + +beforeEach(() => setupTex(['base', 'ams', 'cases'], {tags: 'cases'})); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Cases', () => { + + /********************************************************************************/ + + test('Numcases', () => { + toXmlMatch( + tex2mml('\\begin{numcases}{f(x)=} 1 & if $x > 0$ \\\\ 0 & otherwise \\end{numcases}'), + ` + + + + (1) + + + + + f + ( + x + ) + = + { + + + + + + + (1) + + + 1 + + + + + if  + + x + > + 0 + +   + + + + + + + + + + (2) + + + 0 + + + + otherwise  + + + + + + + + + + + + + + + + (1) + + + 1 + + + + + if  + + x + > + 0 + +   + + + + + + + + + + + + + + 1 + + + + + if  + + x + > + 0 + +   + + + + + + + + + + (2) + + + + 0 + + + + otherwise  + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('subnumcases', () => { + toXmlMatch( + tex2mml('\\begin{subnumcases}{f(x)=} 1 & if $x > 0$ \\\\ 0 & otherwise \\end{subnumcases}'), + ` + + + + (1a) + + + + + f + ( + x + ) + = + { + + + + + + + (1a) + + + 1 + + + + + if  + + x + > + 0 + +   + + + + + + + + + + (1b) + + + 0 + + + + otherwise  + + + + + + + + + + + + + + + + (1a) + + + 1 + + + + + if  + + x + > + 0 + +   + + + + + + + + + + + + + + 1 + + + + + if  + + x + > + 0 + +   + + + + + + + + + + (1b) + + + + 0 + + + + otherwise  + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Numcases with macro', () => { + toXmlMatch( + tex2mml('\\begin{numcases}{A=} 1 & if {x\\\\y}\\$ \\end{numcases}'), + ` + + + + (1) + + + + + A + = + { + + + + + + + (1) + + + 1 + + + + if {x\\y}$  + + + + + + + + + + + + + + + + (1) + + + 1 + + + + if {x\\y}$  + + + + + + + + + + + + + 1 + + + + if {x\\y}$  + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('numcases extra brace', () => { + expectTexError('\\begin{numcases}{A=} x & } \\end{numcases}') + .toBe('Extra close brace or missing open brace'); + }); + + /********************************************************************************/ + + test('numcases extra column', () => { + expectTexError('\\begin{numcases}{A=} x & y & z \\end{numcases}') + .toBe('Extra alignment tab in text for numcase environment'); + }); + + /********************************************************************************/ + + test('entry not in numcases', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} x & y \\end{array}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('numcases with explicit tag', () => { + toXmlMatch( + tex2mml('\\begin{numcases}{A=} x\\tag{A} & y \\end{numcases}'), + ` + + + + (A) + + + + + A + = + { + + + + + + + (A) + + + x + + + + + + + + + + + + + + + + + + + + (A) + + + x + + + + + + + + + + + + + + + + + x + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('numcases not complete', () => { + expectTexError('\\begin{numcases}{A=} x & y\\') + .toBe('Missing \\end{numcases}'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('cases')); diff --git a/testsuite/tests/input/tex/Centernot.test.ts b/testsuite/tests/input/tex/Centernot.test.ts new file mode 100644 index 000000000..c99f19cd1 --- /dev/null +++ b/testsuite/tests/input/tex/Centernot.test.ts @@ -0,0 +1,71 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/centernot/CenternotConfiguration'; + +beforeEach(() => setupTex(['base', 'centernot'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Centernot', () => { + + /********************************************************************************/ + + test('Centernot', () => { + toXmlMatch( + tex2mml('\\centernot{\\longrightarrow}'), + ` + + + + + + + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Centerover', () => { + toXmlMatch( + tex2mml('\\centerOver{\\bigcirc}{1}'), + ` + + + + + + + 1 + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('centernot')); diff --git a/testsuite/tests/input/tex/Color.test.ts b/testsuite/tests/input/tex/Color.test.ts new file mode 100644 index 000000000..a30270636 --- /dev/null +++ b/testsuite/tests/input/tex/Color.test.ts @@ -0,0 +1,559 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/color/ColorConfiguration'; + +beforeEach(() => setupTex(['base', 'color'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Color named', () => { + + /********************************************************************************/ + + test('Color extent', () => { + toXmlMatch( + tex2mml('\\color{red} x+y'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + test('Color limited', () => { + toXmlMatch( + tex2mml('{\\color{red} x}+y'), + ` + + + x + + + + + y + ` + ); + }); + + /********************************************************************************/ + + test('Color known', () => { + toXmlMatch( + tex2mml('{\\color{Peach} x}'), + ` + + + x + + + ` + ); + }); + + /********************************************************************************/ + + test('Textcolor', () => { + toXmlMatch( + tex2mml('\\textcolor{red}{a b} + c'), + ` + + a + b + + + + c + ` + ); + }); + + /********************************************************************************/ + + test('Textcolor nested', () => { + toXmlMatch( + tex2mml('\\textcolor{red}{\\textcolor{blue}{a} b}'), + ` + + + a + + b + + ` + ); + }); + + /********************************************************************************/ + + test('Colorbox', () => { + toXmlMatch( + tex2mml('\\colorbox{red}{a b}'), + ` + + a b + + ` + ); + }); + + /********************************************************************************/ + + test('Fcolorbox', () => { + toXmlMatch( + tex2mml('\\fcolorbox{red}{yellow}{a b}'), + ` + + a b + + ` + ); + }); + + /********************************************************************************/ + + test('Definecolor', () => { + toXmlMatch( + tex2mml('\\definecolor{test}{named}{#48C}\\color{test} a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Color rgb', () => { + + /********************************************************************************/ + + test('Color extent', () => { + toXmlMatch( + tex2mml('\\color[rgb]{1,0,0} x+y'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + test('Color limited', () => { + toXmlMatch( + tex2mml('{\\color[rgb]{1,0,0} x}+y'), + ` + + + x + + + + + y + ` + ); + }); + + /********************************************************************************/ + + test('Textcolor', () => { + toXmlMatch( + tex2mml('\\textcolor[rgb]{1,0,0}{a b} + c'), + ` + + a + b + + + + c + ` + ); + }); + + /********************************************************************************/ + + test('Textcolor nested', () => { + toXmlMatch( + tex2mml('\\textcolor[rgb]{1,0,0}{\\textcolor[rgb]{0,0,1}{a} b}'), + ` + + + a + + b + + ` + ); + }); + + /********************************************************************************/ + + test('Colorbox', () => { + toXmlMatch( + tex2mml('\\colorbox[rgb]{1,0,0}{a b}'), + ` + + a b + + ` + ); + }); + + /********************************************************************************/ + + test('Fcolorbox', () => { + toXmlMatch( + tex2mml('\\fcolorbox[rgb]{1,0,0}[rgb]{1,1,0}{a b}'), + ` + + a b + + ` + ); + }); + + /********************************************************************************/ + + test('Definecolor', () => { + toXmlMatch( + tex2mml('\\definecolor{test}{rgb}{.25,.5,.75}\\color{test} a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Color RGB', () => { + + /********************************************************************************/ + + test('Color extent', () => { + toXmlMatch( + tex2mml('\\color[RGB]{255,0,0} x+y'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + test('Color limited', () => { + toXmlMatch( + tex2mml('{\\color[RGB]{255,0,0} x}+y'), + ` + + + x + + + + + y + ` + ); + }); + + /********************************************************************************/ + + test('Textcolor', () => { + toXmlMatch( + tex2mml('\\textcolor[RGB]{255,0,0}{a b} + c'), + ` + + a + b + + + + c + ` + ); + }); + + /********************************************************************************/ + + test('Textcolor nested', () => { + toXmlMatch( + tex2mml('\\textcolor[RGB]{255,0,0}{\\textcolor[RGB]{0,0,255}{a} b}'), + ` + + + a + + b + + ` + ); + }); + + /********************************************************************************/ + + test('Colorbox', () => { + toXmlMatch( + tex2mml('\\colorbox[RGB]{255,0,0}{a b}'), + ` + + a b + + ` + ); + }); + + /********************************************************************************/ + + test('Fcolorbox', () => { + toXmlMatch( + tex2mml('\\fcolorbox[RGB]{255,0,0}[RGB]{255,255,0}{a b}'), + ` + + a b + + ` + ); + }); + + /********************************************************************************/ + + test('Definecolor', () => { + toXmlMatch( + tex2mml('\\definecolor{test}{RGB}{8,128,200}\\color{test} a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Color gray', () => { + + /********************************************************************************/ + + test('Color extent', () => { + toXmlMatch( + tex2mml('\\color[gray]{.5} x+y'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + test('Color limited', () => { + toXmlMatch( + tex2mml('{\\color[gray]{.5} x}+y'), + ` + + + x + + + + + y + ` + ); + }); + + /********************************************************************************/ + + test('Textcolor', () => { + toXmlMatch( + tex2mml('\\textcolor[gray]{.5}{a b} + c'), + ` + + a + b + + + + c + ` + ); + }); + + /********************************************************************************/ + + test('Textcolor nested', () => { + toXmlMatch( + tex2mml('\\textcolor[gray]{.5}{\\textcolor[gray]{.75}{a} b}'), + ` + + + a + + b + + ` + ); + }); + + /********************************************************************************/ + + test('Colorbox', () => { + toXmlMatch( + tex2mml('\\colorbox[gray]{.5}{a b}'), + ` + + a b + + ` + ); + }); + + /********************************************************************************/ + + test('Fcolorbox', () => { + toXmlMatch( + tex2mml('\\fcolorbox[gray]{.5}[gray]{.25}{a b}'), + ` + + a b + + ` + ); + }); + + /********************************************************************************/ + + test('Definecolor', () => { + toXmlMatch( + tex2mml('\\definecolor{test}{gray}{.02}\\color{test} a'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Color errors', () => { + + /********************************************************************************/ + + test('UndefinedColormodel', () => { + expectTexError('\\color[error]{error} x') + .toBe("Color model 'error' not defined"); + }); + + /********************************************************************************/ + + test('ModelArg1 rgb', () => { + expectTexError('\\definecolor{test}{rgb}{1}') + .toBe('Color values for the rgb model require 3 numbers'); + }); + + /********************************************************************************/ + + test('InvalidDecimalNumber rgb', () => { + expectTexError('\\definecolor{test}{rgb}{x,x,x}') + .toBe('Invalid decimal number'); + }); + + /********************************************************************************/ + + test('ModelArg2 rgb', () => { + expectTexError('\\definecolor{test}{rgb}{10,10,10}') + .toBe('Color values for the rgb model must be between 0 and 1'); + }); + + /********************************************************************************/ + + test('ModelArg1 RGB', () => { + expectTexError('\\definecolor{test}{RGB}{1}') + .toBe('Color values for the RGB model require 3 numbers'); + }); + + /********************************************************************************/ + + test('InvalidDecimalNumber RGB', () => { + expectTexError('\\definecolor{test}{RGB}{x,x,x}') + .toBe('Invalid number'); + }); + + /********************************************************************************/ + + test('ModelArg2 RGB', () => { + expectTexError('\\definecolor{test}{RGB}{1000,1000,1000}') + .toBe('Color values for the RGB model must be between 0 and 255'); + }); + + /********************************************************************************/ + + test('InvalidDecimalNumber gray', () => { + expectTexError('\\definecolor{test}{gray}{x}') + .toBe('Invalid decimal number'); + }); + + /********************************************************************************/ + + test('ModelArg2 gray', () => { + expectTexError('\\definecolor{test}{gray}{10}') + .toBe('Color values for the gray model must be between 0 and 1'); + }); + + /********************************************************************************/ + + test('BadColorValue', () => { + expectTexError('\\definecolor{error}{}{a;b}') + .toBe('Invalid color value'); + }); + + /********************************************************************************/ + + test('BadColorValue named', () => { + expectTexError('\\color[named]{a;b}{x}') + .toBe('Invalid color value'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('color')); diff --git a/testsuite/tests/input/tex/Colortbl.test.ts b/testsuite/tests/input/tex/Colortbl.test.ts new file mode 100644 index 000000000..1a0244457 --- /dev/null +++ b/testsuite/tests/input/tex/Colortbl.test.ts @@ -0,0 +1,436 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import { ColorArrayItem } from '#js/input/tex/colortbl/ColortblConfiguration.js'; +import '#js/input/tex/color/ColorConfiguration.js'; + +import { Configuration } from '#js/input/tex/Configuration.js'; +import { ConfigurationType } from '#js/input/tex/HandlerTypes.js'; + +beforeEach(() => setupTex(['base', 'colortbl'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Colortbl', () => { + + /********************************************************************************/ + + test('cellcolor', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & \\cellcolor{red} b \\\\ \\cellcolor{yellow} c & d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('cellcolor late', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & b \\cellcolor{red} \\end{array}'), + ` + + + + a + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + test('rowcolor', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & b \\\\ \\rowcolor{yellow} c & d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('rowcolor late', () => { + expectTexError('\\begin{array}{cc} a & b \\\\ c & \\rowcolor{yellow} d \\end{array}') + .toBe('\\rowcolor must be at the beginning of a row'); + }); + + /********************************************************************************/ + + test('columncolor', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & \\columncolor{yellow} b \\\\ c & d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('columncolor late', () => { + expectTexError('\\begin{array}{cc} a & b \\\\ c & \\columncolor{yellow} d \\end{array}') + .toBe('\\columncolor must be in the top row or preamble'); + }); + + /********************************************************************************/ + + test('columncolor in preamble', () => { + toXmlMatch( + tex2mml('\\begin{array}{c>{\\columncolor{yellow}}c} a & b \\\\ c & d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('cellcolor in preamble', () => { + toXmlMatch( + tex2mml('\\begin{array}{c>{\\cellcolor{yellow}}c} a & b \\\\ c & d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('cellcolor with rowcolor', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & b \\\\ \\rowcolor{red} c & \\cellcolor{yellow} d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('cellcolor with columncolor', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & \\columncolor{red} b \\\\ c & \\cellcolor{yellow} d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('columncolor and rowcolor', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & \\columncolor{red} b \\\\ \\rowcolor{yellow} c & d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('cellcolor with columncolor and rowcolor', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & \\columncolor{red} b \\\\ \\rowcolor{yellow} c & \\cellcolor{green} d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('columncolor ignore overlap', () => { + toXmlMatch( + tex2mml('\\begin{array}{cc} a & \\columncolor{red}[ignore][ignore] b \\\\ c & d \\end{array}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('cellcolor outside of table', () => { + expectTexError('\\cellcolor{red}') + .toBe('Unsupported use of \\cellcolor'); + }); + + /********************************************************************************/ + + test('cellcolor nested', () => { + expectTexError('\\begin{array}{c} \\frac{\\cellcolor{red} a}{b} \\end{array}') + .toBe('Unsupported use of \\cellcolor'); + }); + + /********************************************************************************/ + + test('cellcolor with frame', () => { + toXmlMatch( + tex2mml('\\begin{array}{|c|} \\cellcolor{red} a \\end{array}'), + ` + + + + + a + + + + + ` + ); + }); + + /********************************************************************************/ + + test('cellcolor in pmatrix', () => { + toXmlMatch( + tex2mml('\\pmatrix{ \\cellcolor{red} a }'), + ` + + ( + + + + a + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('cellcolor with color model', () => { + toXmlMatch( + tex2mml('\\matrix{ \\cellcolor[rgb]{1,0,0} a }'), + ` + + + + a + + + + ` + ) + }); + + /********************************************************************************/ + + test('color with no frame', () => { + class myArrayItem extends ColorArrayItem { + createMml() { + this.setProperty('arrayPadding', null); + return super.createMml(); + } + } + Configuration.create('nopadding', { + [ConfigurationType.ITEMS]: {array: myArrayItem}, + [ConfigurationType.PRIORITY]: 20 + }); + setupTex(['base', 'colortbl', 'nopadding']); + toXmlMatch( + tex2mml('\\matrix{ \\cellcolor[rgb]{1,0,0} a }'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('colortbl')); diff --git a/testsuite/tests/input/tex/Colorv2.test.ts b/testsuite/tests/input/tex/Colorv2.test.ts new file mode 100644 index 000000000..524f7c668 --- /dev/null +++ b/testsuite/tests/input/tex/Colorv2.test.ts @@ -0,0 +1,84 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/colorv2/ColorV2Configuration'; + +beforeEach(() => setupTex(['base', 'colorv2'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('ColorV2', () => { + + /********************************************************************************/ + + it('Color Open', () => { + toXmlMatch( + tex2mml('\\color{red}{ab}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Color Enclosed', () => { + toXmlMatch( + tex2mml('\\color{red}ab'), + ` + + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Color Frac', () => { + toXmlMatch( + tex2mml('\\frac{{\\cal \\color{red}{X}}}{\\color{blue}{\\sf y}}'), + ` + + + + X + + + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Color Nested', () => { + toXmlMatch( + tex2mml('\\color{red}{a\\color{blue}{b}c}'), + ` + + a + + b + + c + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('colorv2')); diff --git a/testsuite/tests/input/tex/ConfigMacros.test.ts b/testsuite/tests/input/tex/ConfigMacros.test.ts new file mode 100644 index 000000000..2f00538d1 --- /dev/null +++ b/testsuite/tests/input/tex/ConfigMacros.test.ts @@ -0,0 +1,133 @@ +import { beforeEach, describe, it } from '@jest/globals'; +import { toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/configmacros/ConfigMacrosConfiguration'; + +beforeEach(() => {}); + +function runMacroTests( + macros: {[key: string]: any}, + expected: string, + control: string, + macro: string) { + setupTex(['base', 'configmacros'], macros); + toXmlMatch(tex2mml(control), expected.replace('PH', control)); + toXmlMatch(tex2mml(macro), expected.replace('PH', macro)); +} + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Config Macros Active', () => { + + /********************************************************************************/ + + it('Macros Simple', () => { + runMacroTests( + {active: {"@": "~"}}, + ` + A +   + a + `, + 'A~a', + 'A@a' + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Config Macros Commands', () => { + + /********************************************************************************/ + + it('Commands Simple', () => { + runMacroTests( + {macros: {"RR": "{\\bf R}"}}, + ` + + R + + `, + '{\\bf R}', + '\\RR' + ); + }); + + /********************************************************************************/ + + it('Commands Argument', () => { + runMacroTests( + {macros: {"bold": ["{\\bf #1}", 1]}}, + ` + + b + o + l + d + + `, + '{\\bf bold}', + '\\bold{bold}' + ); + }); + + /********************************************************************************/ + + it('Commands Aux Argument', () => { + runMacroTests( + {macros: {"foo": ["\\mbox{first } #1 \\mbox{ second } #2", 2, ["[", "]"]]}}, + ` + + first  + + h + i + +  second  + + t + h + e + r + e + `, + '\\mbox{first } hi \\mbox{ second } there', + '\\foo[hi]{there}' + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Config Macros Environment', () => { + + /********************************************************************************/ + + it('Environment Simple', () => { + runMacroTests( + {environments: {"myHeartEnv": ["\\heartsuit", "\\spadesuit"]}}, + ` + + a + + `, + '\\begin{myHeartEnv}a\\end{myHeartEnv}', + '\\begin{myHeartEnv}a\\end{myHeartEnv}' + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/input/tex/Dsfont.test.ts b/testsuite/tests/input/tex/Dsfont.test.ts new file mode 100644 index 000000000..eb975f930 --- /dev/null +++ b/testsuite/tests/input/tex/Dsfont.test.ts @@ -0,0 +1,56 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/dsfont/DsfontConfiguration'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Dsfont', () => { + + beforeEach(() => setupTex(['base', 'dsfont'])); + + /********************************************************************************/ + + test('mathds', () => { + toXmlMatch( + tex2mml('\\mathds{Aa}'), + ` + + Aa + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Dsfont sans', () => { + + beforeEach(() => setupTex(['base', 'dsfont'], {dsfont: {sans: true}})); + + /********************************************************************************/ + + test('mathds', () => { + toXmlMatch( + tex2mml('\\mathds{Aa}'), + ` + + Aa + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('dsfont')); diff --git a/testsuite/tests/input/tex/Empheq.test.ts b/testsuite/tests/input/tex/Empheq.test.ts new file mode 100644 index 000000000..9837bb308 --- /dev/null +++ b/testsuite/tests/input/tex/Empheq.test.ts @@ -0,0 +1,922 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/empheq/EmpheqConfiguration'; +import '#js/input/tex/cases/CasesConfiguration'; +import '#js/input/tex/ams/AmsConfiguration'; + +beforeEach(() => setupTex(['base', 'ams', 'empheq', 'cases'], {tags: 'ams'})); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Empheq', () => { + + /********************************************************************************/ + + test('Empheq Left', () => { + toXmlMatch( + tex2mml('\\begin{empheq}[left=L\\Rightarrow]{align} a&=b\\\\ c&=d \\end{empheq}'), + ` + + + + (1) + + + + + L + + + + + + + (1) + + + a + + + + + = + b + + + + + + (2) + + + c + + + + + = + d + + + + + + + + + + + + + (1) + + + a + + + + + = + b + + + + + + + + + + a + + + + + = + b + + + + + + (2) + + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Empheq Right', () => { + toXmlMatch( + tex2mml('\\begin{empheq}[right=\\Leftarrow R]{align} a&=b\\\\ c&=d \\end{empheq}'), + ` + + + + (1) + + + a + + + + + = + b + + + + + + + R + + + + + + (1) + + + a + + + + + = + b + + + + + + (2) + + + c + + + + + = + d + + + + + + + + + + + + + (1) + + + a + + + + + = + b + + + + + + + + + + + + (2) + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Numcases with label', () => { + toXmlMatch( + tex2mml('\\begin{numcases}{A=\\label{test}} a&=b \\end{numcases}'), + ` + + + + (1) + + + + + A + = + { + + + + + + + (1) + + + a + + + + =b  + + + + + + + + + + + + + + + + (1) + + + a + + + + =b  + + + + + + + + + + + + + a + + + + =b  + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Numcases empty right', () => { + toXmlMatch( + tex2mml('\\begin{empheq}[right=x]{align} \\end{empheq}'), + ` + + + + + + x + + + + + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Numcases empty left', () => { + toXmlMatch( + tex2mml('\\begin{empheq}[left=x]{multline} \\end{empheq}'), + ` + + + + + + x + + + + + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Numcases ', () => { + toXmlMatch( + tex2mml('\\begin{empheq}[right=x]{align} a \\\\ b&=c \\end{empheq}'), + ` + + + + (1) + + + a + + + + + + x + + + + + + (1) + + + a + + + + + (2) + + + b + + + + + = + c + + + + + + + + + + + + + (1) + + + a + + + + + + + + + + + (2) + + + b + + + + + = + c + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Numcases alignedat', () => { + toXmlMatch( + tex2mml('\\begin{empheq}{alignat=2} a & b & c & d \\end{empheq}'), + ` + + + + (1) + + + a + + + + b + + + + c + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Numcases invalid env', () => { + expectTexError('\\begin{empheq}{split} \\end{empheq}') + .toBe('Invalid environment "split" for empheq'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Empheq Characters', () => { + + /********************************************************************************/ + + test('empheqlbrace', () => { + toXmlMatch( + tex2mml('\\empheqlbrace'), + ` + { + ` + ); + }); + + /********************************************************************************/ + + test('empheqlbrace', () => { + toXmlMatch( + tex2mml('\\empheqlbrace'), + ` + { + ` + ); + }); + + /********************************************************************************/ + + test('empheqrbrace', () => { + toXmlMatch( + tex2mml('\\empheqrbrace'), + ` + } + ` + ); + }); + + /********************************************************************************/ + + test('empheqlbrack', () => { + toXmlMatch( + tex2mml('\\empheqlbrack'), + ` + [ + ` + ); + }); + + /********************************************************************************/ + + test('empheqrbrack', () => { + toXmlMatch( + tex2mml('\\empheqrbrack'), + ` + ] + ` + ); + }); + + /********************************************************************************/ + + test('empheqlangle', () => { + toXmlMatch( + tex2mml('\\empheqlangle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqrangle', () => { + toXmlMatch( + tex2mml('\\empheqrangle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqlparen', () => { + toXmlMatch( + tex2mml('\\empheqlparen'), + ` + ( + ` + ); + }); + + /********************************************************************************/ + + test('empheqrparen', () => { + toXmlMatch( + tex2mml('\\empheqrparen'), + ` + ) + ` + ); + }); + + /********************************************************************************/ + + test('empheqlvert', () => { + toXmlMatch( + tex2mml('\\empheqlvert'), + ` + | + ` + ); + }); + + /********************************************************************************/ + + test('empheqrvert', () => { + toXmlMatch( + tex2mml('\\empheqrvert'), + ` + | + ` + ); + }); + + /********************************************************************************/ + + test(' empheqlVert', () => { + toXmlMatch( + tex2mml('\\empheqlVert'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqrVert', () => { + toXmlMatch( + tex2mml('\\empheqrVert'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqlfloor', () => { + toXmlMatch( + tex2mml('\\empheqlfloor'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqrfloor', () => { + toXmlMatch( + tex2mml('\\empheqrfloor'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqlceil', () => { + toXmlMatch( + tex2mml('\\empheqlceil'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqrceil', () => { + toXmlMatch( + tex2mml('\\empheqrceil'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqbiglbrace', () => { + toXmlMatch( + tex2mml('\\empheqbiglbrace'), + ` + { + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigrbrace', () => { + toXmlMatch( + tex2mml('\\empheqbigrbrace'), + ` + } + ` + ); + }); + + /********************************************************************************/ + + test('empheqbiglbrack', () => { + toXmlMatch( + tex2mml('\\empheqbiglbrack'), + ` + [ + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigrbrack', () => { + toXmlMatch( + tex2mml('\\empheqbigrbrack'), + ` + ] + ` + ); + }); + + /********************************************************************************/ + + test('empheqbiglangle', () => { + toXmlMatch( + tex2mml('\\empheqbiglangle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigrangle', () => { + toXmlMatch( + tex2mml('\\empheqbigrangle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqbiglparen', () => { + toXmlMatch( + tex2mml('\\empheqbiglparen'), + ` + ( + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigrparen', () => { + toXmlMatch( + tex2mml('\\empheqbigrparen'), + ` + ) + ` + ); + }); + + /********************************************************************************/ + + test('empheqbiglvert', () => { + toXmlMatch( + tex2mml('\\empheqbiglvert'), + ` + | + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigrvert', () => { + toXmlMatch( + tex2mml('\\empheqbigrvert'), + ` + | + ` + ); + }); + + /********************************************************************************/ + + test('empheqbiglVert', () => { + toXmlMatch( + tex2mml('\\empheqbiglVert'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigrVert', () => { + toXmlMatch( + tex2mml('\\empheqbigrVert'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqbiglfloor', () => { + toXmlMatch( + tex2mml('\\empheqbiglfloor'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigrfloor', () => { + toXmlMatch( + tex2mml('\\empheqbigrfloor'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqbiglceil', () => { + toXmlMatch( + tex2mml('\\empheqbiglceil'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigrceil', () => { + toXmlMatch( + tex2mml('\\empheqbigrceil'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('empheql', () => { + toXmlMatch( + tex2mml('\\empheql('), + ` + ( + ` + ); + }); + + /********************************************************************************/ + + test('empheqr',() => { + toXmlMatch( + tex2mml('\\empheqr)'), + ` + ) + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigl', () => { + toXmlMatch( + tex2mml('\\empheqbigl('), + ` + ( + ` + ); + }); + + /********************************************************************************/ + + test('empheqbigr', () => { + toXmlMatch( + tex2mml('\\empheqbigr)'), + ` + ) + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('empheq')); diff --git a/testsuite/tests/input/tex/Enclose.test.ts b/testsuite/tests/input/tex/Enclose.test.ts new file mode 100644 index 000000000..8c2b07515 --- /dev/null +++ b/testsuite/tests/input/tex/Enclose.test.ts @@ -0,0 +1,97 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/enclose/EncloseConfiguration'; + +beforeEach(() => setupTex(['base', 'enclose'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Enclose', () => { + + /********************************************************************************/ + + it('Enclose 1', () => { + toXmlMatch( + tex2mml('\\enclose{updiagonalstrike}{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Enclose 2', () => { + toXmlMatch( + tex2mml('\\enclose{circle}{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Enclose 3', () => { + toXmlMatch( + tex2mml('\\enclose{horizontalstrike}{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Enclose Attr 2', () => { + toXmlMatch( + tex2mml('\\enclose{updiagonalarrow}[mathbackground=red]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Enclose Attr 1', () => { + toXmlMatch( + tex2mml('\\enclose{horizontalstrike}[data-thickness=5]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Enclose Attrs', () => { + toXmlMatch( + tex2mml('\\enclose{circle}[data-thickness=10,data-padding=5]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('enclose')); diff --git a/testsuite/tests/input/tex/Extpfeil.test.ts b/testsuite/tests/input/tex/Extpfeil.test.ts new file mode 100644 index 000000000..a9f0181f0 --- /dev/null +++ b/testsuite/tests/input/tex/Extpfeil.test.ts @@ -0,0 +1,192 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/extpfeil/ExtpfeilConfiguration'; + +beforeEach(() => setupTex(['base', 'extpfeil'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Extpfeil', () => { + + /********************************************************************************/ + + it('Xtwoheadrightarrow', () => { + toXmlMatch( + tex2mml('\\xtwoheadrightarrow{abcxyz}'), + ` + + + + a + b + c + x + y + z + + + + ` + ); + }); + + /********************************************************************************/ + + it('Xtwoheadleftarrow', () => { + toXmlMatch( + tex2mml('\\xtwoheadleftarrow{abcxyz}'), + ` + + + + a + b + c + x + y + z + + + + ` + ); + }); + + /********************************************************************************/ + + it('Xmapsto', () => { + toXmlMatch( + tex2mml('\\xmapsto{abcxyz}'), + ` + + + + a + b + c + x + y + z + + + + ` + ); + }); + + /********************************************************************************/ + + it('Xlongequal', () => { + toXmlMatch( + tex2mml('\\xlongequal{abcxyz}'), + ` + + = + + a + b + c + x + y + z + + + + ` + ); + }); + + /********************************************************************************/ + + it('Xtofrom', () => { + toXmlMatch( + tex2mml('\\xtofrom{abcxyz}'), + ` + + + + a + b + c + x + y + z + + + + ` + ); + }); + + /********************************************************************************/ + + it('Newextarrow', () => { + toXmlMatch( + tex2mml('\\Newextarrow{\\ab}{10,20}{8672}\\ab{xyz}'), + ` + + + + x + y + z + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Extpfeil Errors', () => { + + /********************************************************************************/ + + it('NewextarrowArg1', () => { + expectTexError('\\Newextarrow{ab}{10,20}{8672}\\ab{xyz}') + .toBe('First argument to \\Newextarrow must be a control sequence name'); + }); + + /********************************************************************************/ + + it('NewextarrowArg2 One', () => { + expectTexError('\\Newextarrow{\\ab}{10}{8672}\\ab{xyz}') + .toBe('Second argument to \\Newextarrow must be two integers separated by a comma'); + }); + + /********************************************************************************/ + + it('NewextarrowArg2 Two', () => { + expectTexError('\\Newextarrow{\\ab}{10 20}{8672}\\ab{xyz}') + .toBe('Second argument to \\Newextarrow must be two integers separated by a comma'); + }); + + /********************************************************************************/ + + it('NewextarrowArg2 Three', () => { + expectTexError('\\Newextarrow{\\ab}{aa}{8672}\\ab{xyz}') + .toBe('Second argument to \\Newextarrow must be two integers separated by a comma'); + }); + + /********************************************************************************/ + + it('NewextarrowArg3', () => { + expectTexError('\\Newextarrow{\\ab}{10,20}{AG}\\ab{xyz}') + .toBe('Third argument to \\Newextarrow must be a unicode character number'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('extpfeil')); diff --git a/testsuite/tests/input/tex/Gensymb.test.ts b/testsuite/tests/input/tex/Gensymb.test.ts new file mode 100644 index 000000000..7e950e127 --- /dev/null +++ b/testsuite/tests/input/tex/Gensymb.test.ts @@ -0,0 +1,74 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/gensymb/GensymbConfiguration'; + +beforeEach(() => setupTex(['base', 'gensymb'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Gensymb', () => { + + /********************************************************************************/ + + test('ohm', () => { + toXmlMatch( + tex2mml('\\ohm'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('degree', () => { + toXmlMatch( + tex2mml('\\degree'), + ` + ° + ` + ); + }); + + /********************************************************************************/ + + test('celcius', () => { + toXmlMatch( + tex2mml('\\celsius'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('perthousand', () => { + toXmlMatch( + tex2mml('\\perthousand'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('micro', () => { + toXmlMatch( + tex2mml('\\micro'), + ` + µ + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('gensymb')); diff --git a/testsuite/tests/input/tex/Html.test.ts b/testsuite/tests/input/tex/Html.test.ts new file mode 100644 index 000000000..f0a59f507 --- /dev/null +++ b/testsuite/tests/input/tex/Html.test.ts @@ -0,0 +1,229 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/html/HtmlConfiguration'; + +beforeEach(() => setupTex(['base', 'html'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Html', () => { + + /********************************************************************************/ + + it('Html Href Simple', () => { + toXmlMatch( + tex2mml('\\href{https://mathjax.org}{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Html Href Complex', () => { + toXmlMatch( + tex2mml('\\href{https://mathjax.org}{\\frac{a}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Html Href Inner', () => { + toXmlMatch( + tex2mml('\\frac{a}{\\href{https://mathjax.org}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Html Style Simple', () => { + toXmlMatch( + tex2mml('\\style{color:green;background-color:blue}{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Html Style Complex', () => { + toXmlMatch( + tex2mml('\\style{color:green;background-color:blue}{\\frac{a}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Html Style Inner', () => { + toXmlMatch( + tex2mml('\\frac{a}{\\style{color:green;background-color:blue}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Html Style Nested', () => { + toXmlMatch( + tex2mml('\\style{color:red}{\\style{background:blue}{x}}'), + ` + x + ` + ); + }); + + /********************************************************************************/ + + it('Html Style Row', () => { + toXmlMatch( + tex2mml('\\style{color:red}{x+y}'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + it('Html Class Simple', () => { + toXmlMatch( + tex2mml('\\class{myclass}{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Html Class Medium', () => { + toXmlMatch( + tex2mml('\\class{myclass}{\\frac{a}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Html Class Complex', () => { + toXmlMatch( + tex2mml('\\frac{a}{\\class{myclass}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Html Class nested', () => { + toXmlMatch( + tex2mml('\\class{class1}{\\class{class2}{x}}'), + ` + x + ` + ); + }); + + /********************************************************************************/ + + it('Html Id Inner', () => { + toXmlMatch( + tex2mml('\\cssId{myid-0}{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Html Id Simple', () => { + toXmlMatch( + tex2mml('\\cssId{myid-1}{\\frac{a}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Html Id Complex', () => { + toXmlMatch( + tex2mml('\\frac{a}{\\cssId{myid-2}{b}}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Html Data', () => { + toXmlMatch( + tex2mml('\\data{test1=fu, test2=bar}{x}'), + ` + x + ` + ); + }); + + /********************************************************************************/ + + it('Html Data Invalid', () => { + expectTexError('\\data{a/b=bar}{x}').toBe('Invalid HTML attribute: data-a/b'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('html')); diff --git a/testsuite/tests/input/tex/Mathtools.test.ts b/testsuite/tests/input/tex/Mathtools.test.ts new file mode 100644 index 000000000..c9975c4d7 --- /dev/null +++ b/testsuite/tests/input/tex/Mathtools.test.ts @@ -0,0 +1,6440 @@ +import { afterAll, beforeEach, describe, test, expect } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError, trapErrors } from '#helpers'; +import '#js/input/tex/mathtools/MathtoolsConfiguration'; +import '#js/input/tex/ams/AmsConfiguration'; +import '#js/input/tex/boldsymbol/BoldsymbolConfiguration'; +import '#js/input/tex/bbox/BboxConfiguration'; + +import { Configuration } from '#js/input/tex/Configuration.js'; +import { ConfigurationType } from '#js/input/tex/HandlerTypes.js'; +import { AbstractTags } from '#js/input/tex/Tags.js'; + +beforeEach(() => setupTex(['base', 'ams', 'boldsymbol', 'mathtools'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Spacing Control', () => { + + /********************************************************************************/ + + test('mathllap', () => { + toXmlMatch( + tex2mml('\\mathord{=}\\mathllap{x}\\quad \\mathord{=}\\mathllap[\\scriptstyle]{x}'), + ` + + = + + + + + x + + + + + + = + + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + test('mathrlap', () => { + toXmlMatch( + tex2mml('\\mathrlap{x}\\mathord{=}\\quad \\mathrlap[\\scriptstyle]{x}\\mathord{=}'), + ` + + + + x + + + + + = + + + + + + x + + + + + = + + ` + ); + }); + + /********************************************************************************/ + + test('mathclap', () => { + toXmlMatch( + tex2mml('X = \\sum_{\\mathclap{1\\le i\\le j\\le n}} X_{ij}'), + ` + X + = + + + + + + + 1 + + i + + j + + n + + + + + + + X + + i + j + + + ` + ); + }); + + /********************************************************************************/ + + test('clap', () => { + toXmlMatch( + tex2mml('X = \\sum_{\\clap{long text under}} X_{ij}'), + ` + X + = + + + + + + long text under + + + + + + X + + i + j + + + ` + ); + }); + + /********************************************************************************/ + + test('mathmakebox', () => { + toXmlMatch( + tex2mml('\\mathmakebox[3em][l]{x+y}'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + test('mathmakebox [r]', () => { + toXmlMatch( + tex2mml('\\mathmakebox[3em][r]{x+y}'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + test('mathmakebox [R]', () => { + toXmlMatch( + tex2mml('\\mathmakebox[3em][R]{x+y}'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + test('mathmbox', () => { + toXmlMatch( + tex2mml('\\mathmbox{x+y}'), + ` + + x + + + y + + ` + ); + }); + + /********************************************************************************/ + + test('textllap', () => { + toXmlMatch( + tex2mml('\\mathord{==}\\textllap{a b}'), + ` + + == + + + + a b + + + ` + ); + }); + + /********************************************************************************/ + + test('textrlap', () => { + toXmlMatch( + tex2mml('\\textrlap{a b}\\mathord{==}'), + ` + + + a b + + + + == + + ` + ); + }); + + /********************************************************************************/ + + test('textclap', () => { + toXmlMatch( + tex2mml('ab\\sum_{\\textclap{long text}}cd'), + ` + a + b + + + + + + long text + + + + + c + d + ` + ); + }); + + /********************************************************************************/ + + test('cramped', () => { + toXmlMatch( + tex2mml('x^2\\cramped{x^2}\\quad{\\scriptstyle x^2}\\cramped[\\scriptstyle]{x^2}'), + ` + + x + 2 + + + + x + 2 + + + + + + + x + 2 + + + + + + x + 2 + + + ` + ); + }); + + /********************************************************************************/ + + test('crampedllap', () => { + toXmlMatch( + tex2mml('\\mathord{==}\\crampedllap{x^2}'), + ` + + == + + + + + + x + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + test('crampedrlap', () => { + toXmlMatch( + tex2mml('\\crampedrlap{x^2}\\mathord{==}'), + ` + + + + + x + 2 + + + + + + == + + ` + ); + }); + + /********************************************************************************/ + + test('crampedclap', () => { + toXmlMatch( + tex2mml('\\sum_{\\crampedclap{x^2}}'), + ` + + + + + + + + x + 2 + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('crampedsubstack', () => { + toXmlMatch( + tex2mml('\\sum_{\\crampedsubstack{x^2\\\\y^2}}'), + ` + + + + + + + + x + 2 + + + + + + + y + 2 + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('adjustlimits', () => { + toXmlMatch( + tex2mml('\\adjustlimits\\lim_{n\\to\\infty} \\max_{p^2\\ge n}'), + ` + + + + lim + + + + + + max + + + + + + + + n + + + + + + + + + p + 2 + + + n + + + + + + + + + + + max + + + + + + lim + + + + + + + + + p + 2 + + + n + + + + + + n + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Tagging', () => { + + /********************************************************************************/ + + test('newtagform', () => { + toXmlMatch( + tex2mml('\\newtagform{brackets}{[}{]}\\usetagform{brackets} E=mc^2\\tag{1}'), + ` + + + + [1] + + + E + = + m + + c + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + test('newtagform styled', () => { + toXmlMatch( + tex2mml('\\newtagform{bfbrackets}[\\textbf]{[}{]}\\usetagform{bfbrackets} E=mc^2\\tag{1}'), + ` + + + + [\\textbf{1}] + + + E + = + m + + c + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + test('newtagform duplicate', () => { + expectTexError('\\newtagform{a}{(}{)}\\newtagform{a}{((}{))}') + .toBe('Duplicate tag form: a'); + }); + + /********************************************************************************/ + + test('newtagform empty name', () => { + expectTexError('\\newtagform{}{(}{)}') + .toBe("Tag form name can't be empty"); + }); + + /********************************************************************************/ + + test('usetagform undefined name', () => { + expectTexError('\\usetagform{error}') + .toBe('Undefined tag form: error'); + }); + + /********************************************************************************/ + + test('renewtagform', () => { + toXmlMatch( + tex2mml('\\newtagform{a}{(}{)}\\renewtagform{a}{((}{))}\\usetagform{a} E=mc^2\\tag{1}'), + ` + + + + ((1)) + + + E + = + m + + c + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + test('refeq', () => { + toXmlMatch( + tex2mml('\\begin{align}E=mc^2\\label{test}\\tag*{\\textsf{A}}\\\\ \\refeq{test}\\end{align}'), + ` + + + + \\textsf{A} + + + E + = + m + + c + 2 + + + + + + + \\textsf{A} + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Tags add', () => { + setupTex(['base', 'ams', 'mathtools'], {tags: 'ams'}); + toXmlMatch( + tex2mml('\\newtagform{bars}||\\usetagform{bars} x\\tag{1}'), + ` + + + + |1| + + + x + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Symbols', () => { + + /********************************************************************************/ + + test('Delimiters', () => { + toXmlMatch( + tex2mml('\\left\\lparen X \\right\\rparen'), + ` + + ( + X + ) + + ` + ); + }); + + /********************************************************************************/ + + test('Other', () => { + toXmlMatch( + tex2mml('\\ndownarrow \\nuparrow \\bigtimes_n'), + ` + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + × + + + + n + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools stretchy', () => { + + /********************************************************************************/ + + test('xleftrightarrow', () => { + toXmlMatch( + tex2mml('\\xleftrightarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xLeftarrow', () => { + toXmlMatch( + tex2mml('\\xLeftarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xRightarrow', () => { + toXmlMatch( + tex2mml('\\xRightarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xLeftrightarrow', () => { + toXmlMatch( + tex2mml('\\xLeftrightarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xhookleftarrow', () => { + toXmlMatch( + tex2mml('\\xhookleftarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xhookrightarrow', () => { + toXmlMatch( + tex2mml('\\xhookrightarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xmapsto', () => { + toXmlMatch( + tex2mml('\\xmapsto{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xrightharpoondown', () => { + toXmlMatch( + tex2mml('\\xrightharpoondown{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xleftharpoondown', () => { + toXmlMatch( + tex2mml('\\xleftharpoondown{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xrightleftharpoons', () => { + toXmlMatch( + tex2mml('\\xrightleftharpoons{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xleftrightharpoons', () => { + toXmlMatch( + tex2mml('\\xleftrightharpoons{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xrightharpoonup', () => { + toXmlMatch( + tex2mml('\\xrightharpoonup{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xleftharpoonup', () => { + toXmlMatch( + tex2mml('\\xleftharpoonup{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xlongleftarrow', () => { + toXmlMatch( + tex2mml('\\xlongleftarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xLongleftarrow', () => { + toXmlMatch( + tex2mml('\\xLongleftarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xlongrightarrow', () => { + toXmlMatch( + tex2mml('\\xlongrightarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('xLongrightarrow', () => { + toXmlMatch( + tex2mml('\\xLongrightarrow{x+y}'), + ` + + + + x + + + y + + + + ` + ); + }); + + /********************************************************************************/ + + test('underbracket', () => { + toXmlMatch( + tex2mml('\\underbracket{x+y+z}_{\\text{$n$ times}}'), + ` + + + + + + x + + + y + + + z + + + + x + + + y + + + z + + + + + + + + + n + +  times + + + + ` + ); + }); + + /********************************************************************************/ + + test('underbracket thickness', () => { + toXmlMatch( + tex2mml('\\underbracket[3px]{x+y+z}_{\\text{$n$ times}}'), + ` + + + + + + x + + + y + + + z + + + + x + + + y + + + z + + + + + + + + + n + +  times + + + + ` + ); + }); + + /********************************************************************************/ + + test('underbracket height', () => { + toXmlMatch( + tex2mml('\\underbracket[][10px]{x+y+z}_{\\text{$n$ times}}'), + ` + + + + + + x + + + y + + + z + + + + x + + + y + + + z + + + + + + + + + n + +  times + + + + ` + ); + }); + + /********************************************************************************/ + + test('underbracket thickness height', () => { + toXmlMatch( + tex2mml('\\underbracket[3px][10px]{x+y+z}_{\\text{$n$ times}}'), + ` + + + + + + x + + + y + + + z + + + + x + + + y + + + z + + + + + + + + + n + +  times + + + + ` + ); + }); + + /********************************************************************************/ + + test('overbracket', () => { + toXmlMatch( + tex2mml('\\overbracket{x+y+z}^{\\text{$n$ times}}'), + ` + + + + + + x + + + y + + + z + + + + x + + + y + + + z + + + + + + + + + n + +  times + + + + ` + ); + }); + + /********************************************************************************/ + + test('overbracket thickness', () => { + toXmlMatch( + tex2mml('\\overbracket[3px]{x+y+z}^{\\text{$n$ times}}'), + ` + + + + + + x + + + y + + + z + + + + x + + + y + + + z + + + + + + + + + n + +  times + + + + ` + ); + }); + + /********************************************************************************/ + + test('overbracket height', () => { + toXmlMatch( + tex2mml('\\overbracket[][10px]{x+y+z}^{\\text{$n$ times}}'), + ` + + + + + + x + + + y + + + z + + + + x + + + y + + + z + + + + + + + + + n + +  times + + + + ` + ); + }); + + /********************************************************************************/ + + test('overbracket thickness height', () => { + toXmlMatch( + tex2mml('\\overbracket[3px][10px]{x+y+z}^{\\text{$n$ times}}'), + ` + + + + + + x + + + y + + + z + + + + x + + + y + + + z + + + + + + + + + n + +  times + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Matrix Environments', () => { + + /********************************************************************************/ + + test('matrix*', () => { + toXmlMatch( + tex2mml('\\begin{matrix*} -1 & 3 \\\\ 2 & -4 \\end{matrix*}'), + ` + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ` + ); + }); + + /********************************************************************************/ + + test('matrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{matrix*}[l] -1 & 3 \\\\ 2 & -4 \\end{matrix*}'), + ` + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ` + ); + }); + + /********************************************************************************/ + + test('matrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{matrix*}[c] -1 & 3 \\\\ 2 & -4 \\end{matrix*}'), + ` + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ` + ); + }); + + /********************************************************************************/ + + test('matrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{matrix*}[r] -1 & 3 \\\\ 2 & -4 \\end{matrix*}'), + ` + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ` + ); + }); + + /********************************************************************************/ + + test('pmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{pmatrix*} -1 & 3 \\\\ 2 & -4 \\end{pmatrix*}'), + ` + + ( + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('pmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{pmatrix*}[l] -1 & 3 \\\\ 2 & -4 \\end{pmatrix*}'), + ` + + ( + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('pmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{pmatrix*}[c] -1 & 3 \\\\ 2 & -4 \\end{pmatrix*}'), + ` + + ( + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('pmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{pmatrix*}[r] -1 & 3 \\\\ 2 & -4 \\end{pmatrix*}'), + ` + + ( + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('bmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{bmatrix*} -1 & 3 \\\\ 2 & -4 \\end{bmatrix*}'), + ` + + [ + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('bmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{bmatrix*}[l] -1 & 3 \\\\ 2 & -4 \\end{bmatrix*}'), + ` + + [ + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('bmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{bmatrix*}[c] -1 & 3 \\\\ 2 & -4 \\end{bmatrix*}'), + ` + + [ + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('bmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{bmatrix*}[r] -1 & 3 \\\\ 2 & -4 \\end{bmatrix*}'), + ` + + [ + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('Bmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{Bmatrix*} -1 & 3 \\\\ 2 & -4 \\end{Bmatrix*}'), + ` + + { + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('Bmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{Bmatrix*}[l] -1 & 3 \\\\ 2 & -4 \\end{Bmatrix*}'), + ` + + { + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('Bmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{Bmatrix*}[c] -1 & 3 \\\\ 2 & -4 \\end{Bmatrix*}'), + ` + + { + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('Bmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{Bmatrix*}[r] -1 & 3 \\\\ 2 & -4 \\end{Bmatrix*}'), + ` + + { + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('vmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{vmatrix*} -1 & 3 \\\\ 2 & -4 \\end{vmatrix*}'), + ` + + | + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('vmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{vmatrix*}[l] -1 & 3 \\\\ 2 & -4 \\end{vmatrix*}'), + ` + + | + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('vmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{vmatrix*}[c] -1 & 3 \\\\ 2 & -4 \\end{vmatrix*}'), + ` + + | + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('vmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{vmatrix*}[r] -1 & 3 \\\\ 2 & -4 \\end{vmatrix*}'), + ` + + | + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('Vmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{Vmatrix*} -1 & 3 \\\\ 2 & -4 \\end{Vmatrix*}'), + ` + + + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Vmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{Vmatrix*}[l] -1 & 3 \\\\ 2 & -4 \\end{Vmatrix*}'), + ` + + + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Vmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{Vmatrix*}[c] -1 & 3 \\\\ 2 & -4 \\end{Vmatrix*}'), + ` + + + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Vmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{Vmatrix*}[r] -1 & 3 \\\\ 2 & -4 \\end{Vmatrix*}'), + ` + + + + + + + 1 + + + 3 + + + + + 2 + + + + 4 + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Small Matrix Environments', () => { + + /********************************************************************************/ + + test('smallmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix*} -a & b \\\\ c & -d \\end{smallmatrix*}'), + ` + + + + + + a + + + b + + + + + c + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('smallmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix*}[l] -a & b \\\\ c & -d \\end{smallmatrix*}'), + ` + + + + + + a + + + b + + + + + c + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('smallmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix*}[c] -a & b \\\\ c & -d \\end{smallmatrix*}'), + ` + + + + + + a + + + b + + + + + c + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('smallmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix*}[r] -a & b \\\\ c & -d \\end{smallmatrix*}'), + ` + + + + + + a + + + b + + + + + c + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('psmallmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{psmallmatrix*} -a & b \\\\ c & -d \\end{psmallmatrix*}'), + ` + + ( + + + + + + a + + + b + + + + + c + + + + d + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('psmallmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{psmallmatrix*}[l] -a & b \\\\ c & -d \\end{psmallmatrix*}'), + ` + + ( + + + + + + a + + + b + + + + + c + + + + d + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('psmallmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{psmallmatrix*}[c] -a & b \\\\ c & -d \\end{psmallmatrix*}'), + ` + + ( + + + + + + a + + + b + + + + + c + + + + d + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('psmallmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{psmallmatrix*}[r] -a & b \\\\ c & -d \\end{psmallmatrix*}'), + ` + + ( + + + + + + a + + + b + + + + + c + + + + d + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('bsmallmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{bsmallmatrix*} -a & b \\\\ c & -d \\end{bsmallmatrix*}'), + ` + + [ + + + + + + a + + + b + + + + + c + + + + d + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('bsmallmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{bsmallmatrix*}[l] -a & b \\\\ c & -d \\end{bsmallmatrix*}'), + ` + + [ + + + + + + a + + + b + + + + + c + + + + d + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('bsmallmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{bsmallmatrix*}[c] -a & b \\\\ c & -d \\end{bsmallmatrix*}'), + ` + + [ + + + + + + a + + + b + + + + + c + + + + d + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('bsmallmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{bsmallmatrix*}[r] -a & b \\\\ c & -d \\end{bsmallmatrix*}'), + ` + + [ + + + + + + a + + + b + + + + + c + + + + d + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('Bsmallmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{Bsmallmatrix*} -a & b \\\\ c & -d \\end{Bsmallmatrix*}'), + ` + + { + + + + + + a + + + b + + + + + c + + + + d + + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('Bsmallmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{Bsmallmatrix*}[l] -a & b \\\\ c & -d \\end{Bsmallmatrix*}'), + ` + + { + + + + + + a + + + b + + + + + c + + + + d + + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('Bsmallmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{Bsmallmatrix*}[c] -a & b \\\\ c & -d \\end{Bsmallmatrix*}'), + ` + + { + + + + + + a + + + b + + + + + c + + + + d + + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('Bsmallmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{Bsmallmatrix*}[r] -a & b \\\\ c & -d \\end{Bsmallmatrix*}'), + ` + + { + + + + + + a + + + b + + + + + c + + + + d + + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('vsmallmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{vsmallmatrix*} -a & b \\\\ c & -d \\end{vsmallmatrix*}'), + ` + + | + + + + + + a + + + b + + + + + c + + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('vsmallmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{vsmallmatrix*}[l] -a & b \\\\ c & -d \\end{vsmallmatrix*}'), + ` + + | + + + + + + a + + + b + + + + + c + + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('vsmallmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{vsmallmatrix*}[c] -a & b \\\\ c & -d \\end{vsmallmatrix*}'), + ` + + | + + + + + + a + + + b + + + + + c + + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('vsmallmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{vsmallmatrix*}[r] -a & b \\\\ c & -d \\end{vsmallmatrix*}'), + ` + + | + + + + + + a + + + b + + + + + c + + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('Vsmallmatrix*', () => { + toXmlMatch( + tex2mml('\\begin{Vsmallmatrix*} -a & b \\\\ c & -d \\end{Vsmallmatrix*}'), + ` + + + + + + + + a + + + b + + + + + c + + + + d + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Vsmallmatrix*[l]', () => { + toXmlMatch( + tex2mml('\\begin{Vsmallmatrix*}[l] -a & b \\\\ c & -d \\end{Vsmallmatrix*}'), + ` + + + + + + + + a + + + b + + + + + c + + + + d + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Vsmallmatrix*[c]', () => { + toXmlMatch( + tex2mml('\\begin{Vsmallmatrix*}[c] -a & b \\\\ c & -d \\end{Vsmallmatrix*}'), + ` + + + + + + + + a + + + b + + + + + c + + + + d + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Vsmallmatrix*[r]', () => { + toXmlMatch( + tex2mml('\\begin{Vsmallmatrix*}[r] -a & b \\\\ c & -d \\end{Vsmallmatrix*}'), + ` + + + + + + + + a + + + b + + + + + c + + + + d + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('smallmatrix', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix} -a & b \\\\ c & -d \\end{smallmatrix}'), + ` + + + + + + a + + + b + + + + + c + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('smallmatrix', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix} -a & b \\\\ c & -d \\end{smallmatrix}'), + ` + + + + + + a + + + b + + + + + c + + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('psmallmatrix', () => { + toXmlMatch( + tex2mml('\\begin{psmallmatrix} -a & b \\\\ c & -d \\end{psmallmatrix}'), + ` + + ( + + + + + + a + + + b + + + + + c + + + + d + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('bsmallmatrix', () => { + toXmlMatch( + tex2mml('\\begin{bsmallmatrix} -a & b \\\\ c & -d \\end{bsmallmatrix}'), + ` + + [ + + + + + + a + + + b + + + + + c + + + + d + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + test('Bsmallmatrix', () => { + toXmlMatch( + tex2mml('\\begin{Bsmallmatrix} -a & b \\\\ c & -d \\end{Bsmallmatrix}'), + ` + + { + + + + + + a + + + b + + + + + c + + + + d + + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('vsmallmatrix', () => { + toXmlMatch( + tex2mml('\\begin{vsmallmatrix} -a & b \\\\ c & -d \\end{vsmallmatrix}'), + ` + + | + + + + + + a + + + b + + + + + c + + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('Vsmallmatrix', () => { + toXmlMatch( + tex2mml('\\begin{Vsmallmatrix} -a & b \\\\ c & -d \\end{Vsmallmatrix}'), + ` + + + + + + + + a + + + b + + + + + c + + + + d + + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools More Environments', () => { + + /********************************************************************************/ + + test('multlined', () => { + toXmlMatch( + tex2mml( + 'A = \\begin{multlined}[t]\\framebox[4cm]{first}\\\\\\framebox[4cm]{last}\\end{multlined} B' + ), + ` + A + = + + + + + + + first + + + + + + + + + + + + + last + + + + + + + B + ` + ); + }); + + /********************************************************************************/ + + test('multlined [b] width', () => { + toXmlMatch( + tex2mml( + '\\begin{multlined}[b][7cm]\\framebox[4cm]{first}\\\\\\framebox[4cm]{last}\\end{multlined} = B' + ), + ` + + + + + + + first + + + + + + + + + + + + + last + + + + + + + = + B + ` + ); + }); + + /********************************************************************************/ + + test('multlined [c] width', () => { + toXmlMatch( + tex2mml( + '\\begin{multlined}[c][7cm]\\framebox[4cm]{first}\\\\\\framebox[4cm]{last}\\end{multlined} = B' + ), + ` + + + + + + + first + + + + + + + + + + + + + last + + + + + + + = + B + ` + ); + }); + + /********************************************************************************/ + + test('multlined [t] width', () => { + toXmlMatch( + tex2mml( + '\\begin{multlined}[t][7cm]\\framebox[4cm]{first}\\\\\\framebox[4cm]{last}\\end{multlined} = B' + ), + ` + + + + + + + first + + + + + + + + + + + + + last + + + + + + + = + B + ` + ); + }); + + /********************************************************************************/ + + test('multlined width', () => { + toXmlMatch( + tex2mml('\\begin{multlined}[7cm]\\framebox[4cm]{first}\\\\\\framebox[4cm]{last}\\end{multlined}'), + ` + + + + + + + first + + + + + + + + + + + + + last + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('multlined shoved', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{multlined}[c][7cm]', + '\\framebox[4cm]{first} \\\\', + '\\shoveright{\\framebox[4cm]{second}} \\\\', + '\\shoveleft{\\framebox[4cm]{third}} \\\\', + '\\framebox[4cm]{last}', + '\\end{multlined}' + ].join('') + ), + ` + + + + + + + first + + + + + + + + + + + + second + + + + + + + + + + + third + + + + + + + + + + + + last + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('multlined shoved distance', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{multlined}[c][7cm]', + '\\framebox[4cm]{first} \\\\', + '\\shoveright[1cm]{\\framebox[4cm]{second}} \\\\', + '\\shoveleft[1cm]{\\framebox[4cm]{third}} \\\\', + '\\framebox[4cm]{last}', + '\\end{multlined}' + ].join('') + ), + ` + + + + + + + first + + + + + + + + + + + + + second + + + + + + + + + + + + + + + third + + + + + + + + + + + + + last + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('shoved outside multline', () => { + expectTexError('\\shoveleft') + .toBe('\\shoveleft can only appear within the multline or multlined environments'); + }); + + /********************************************************************************/ + + test('multlined shoved misplaced', () => { + expectTexError( + [ + '\\begin{multlined}[c][7cm]', + '\\framebox[4cm]{first}\\shoveleft \\\\', + '\\end{multlined}' + ].join('') + ).toBe('\\shoveleft must come at the beginning of the line'); + }); + + /********************************************************************************/ + + test('multlined bad width', () => { + expectTexError('\\begin{multlined}[abc] \\end{multlined}') + .toBe('Width for \\begin{multlined} must be a dimension'); + }); + + /********************************************************************************/ + + test('multlined empty row', () => { + toXmlMatch( + tex2mml('\\begin{multlined} a \\\\ \\end{multlined}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + test('dcases', () => { + toXmlMatch( + tex2mml('\\begin{dcases} 1 & x>0 \\\\ -1 & x\\le 0 \\end{dcases}'), + ` + + { + + + + 1 + + + x + > + 0 + + + + + + 1 + + + x + + 0 + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('dcases*', () => { + toXmlMatch( + tex2mml('\\begin{dcases*} 1 & if $x>0$ \\\\ -1 & otherwise \\end{dcases*}'), + ` + + { + + + + 1 + + + + if  + + x + > + 0 + + + + + + + + 1 + + + + otherwise + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('rcases', () => { + toXmlMatch( + tex2mml('\\begin{rcases} 1 & x>0 \\\\ -1 & x\\le 0 \\end{rcases}'), + ` + + + + + + 1 + + + x + > + 0 + + + + + + 1 + + + x + + 0 + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('rcases*', () => { + toXmlMatch( + tex2mml('\\begin{rcases*} 1 & if $x>0$ \\\\ -1 & otherwise \\end{rcases*}'), + ` + + + + + + 1 + + + + if  + + x + > + 0 + + + + + + + + 1 + + + otherwise + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('drcases', () => { + toXmlMatch( + tex2mml('\\begin{drcases} 1 & x>0 \\\\ -1 & x\\le 0 \\end{drcases}'), + ` + + + + + + 1 + + + x + > + 0 + + + + + + 1 + + + x + + 0 + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('drcases*', () => { + toXmlMatch( + tex2mml('\\begin{drcases*} 1 & if $x>0$ \\\\ -1 & otherwise \\end{drcases*}'), + ` + + + + + + 1 + + + + if  + + x + > + 0 + + + + + + + + 1 + + + + otherwise + + + + + } + + ` + ); + }); + + /********************************************************************************/ + + test('cases*', () => { + toXmlMatch( + tex2mml('\\begin{cases*} 1 & if $x>0$ \\\\ -1 & otherwise \\end{cases*}'), + ` + + { + + + + 1 + + + + if  + + x + > + 0 + + + + + + + + 1 + + + otherwise + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('MoveEqLeft', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{align*}', + '\\MoveEqLeft \\framebox[10cm][c]{Long first line} \\\\', + ' & = \\framebox[6cm][c]{ \\vphantom{g} 2nd line} \\\\', + ' & \\leq \\dots', + '\\end{align*}' + ].join('') + ), + ` + + + + + + + + + + + + Long first line + + + + + + + + + + + + = + + + +  \\vphantom{g} 2nd line + + + + + + + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Spreadlines', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{spreadlines}{20pt}', + '\\begin{gather}', + 'a=b\\\\', + 'c=d', + '\\end{gather}', + '\\end{spreadlines}' + ].join('') + ), + ` + + + + a + = + b + + + + + c + = + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('Spreadlines no environment', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{spreadlines}{20pt}', + 'a=b', + '\\end{spreadlines}' + ].join('') + ), + ` + a + = + b + ` + ); + }); + + /********************************************************************************/ + + test('Spreadlines multiple environments', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{spreadlines}{20pt}', + '\\begin{gather}', + 'a=b\\\\', + 'c=d', + '\\end{gather}', + '\\\\', + '\\begin{gather}', + 'x=y\\\\', + 'z', + '\\end{gather}', + '\\end{spreadlines}' + ].join('') + ), + ` + + + + a + = + b + + + + + c + = + d + + + + + + + + x + = + y + + + + + z + + + + ` + ); + }); + + /********************************************************************************/ + + test('lgathered', () => { + toXmlMatch( + tex2mml('\\begin{lgathered} a+b+c \\\\ d \\end{lgathered}'), + ` + + + + a + + + b + + + c + + + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('rgathered', () => { + toXmlMatch( + tex2mml('\\begin{rgathered} a+b+c \\\\ d \\end{rgathered}'), + ` + + + + a + + + b + + + c + + + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('ArrowBetweenLines', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{alignat*}{2}', + '&& \\framebox[1.5cm]{} &= \\framebox[3cm]{} \\\\', + '\\ArrowBetweenLines', + '&& \\framebox[1.5cm]{} &= \\framebox[2cm]{}', + '\\end{alignat*}' + ].join('') + ), + ` + + + + + + + + + + + + + + + + + = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + = + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('ArrowBetweenLines*', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{alignat*}{2}', + '&& \\framebox[1.5cm]{} &= \\framebox[3cm]{} &&\\\\', + '\\ArrowBetweenLines*[\\Downarrow]', + '&& \\framebox[1.5cm]{} &= \\framebox[2cm]{} &&', + '\\end{alignat*}' + ].join('') + ), + ` + + + + + + + + + + + + + + + + + = + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + = + + + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('ArrowBetweenLines misplaced', () => { + expectTexError('\\begin{aligned} a \\ArrowBetweenLines \\end{aligned}') + .toBe('\\ArrowBetweenLines must be on a row by itself'); + }); + + /********************************************************************************/ + + test('ArrowBetweenLines error', () => { + expectTexError('\\ArrowBetweenLines') + .toBe('\\ArrowBetweenLines can only be used in aligment environments'); + }); + + /********************************************************************************/ + + test('vdotswithin smallvdotswithin', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{align*}', + 'a &= b \\\\', + '& \\vdotswithin{=} \\\\', + '& = c \\\\', + '\\shortvdotswithin{=}', + '& = d', + '\\end{align*}' + ].join('') + ), + ` + + + + a + + + + + = + b + + + + + + + + + + + + + + = + + + + + + + + + + + + = + c + + + + + + + + + + + + + + = + + + + + + + + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + test('smallvdotswithin star', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{aligned}', + 'A&+ B \\\\', + '&\\shortvdotswithin*{+}', + 'C &+ D', + '\\end{aligned}' + ].join('') + ), + ` + + + + A + + + + + + + B + + + + + + + + + + + + + + + + + + + + + + + + C + + + + + + + D + + + + + ` + ); + }); + + /********************************************************************************/ + + test('vdotswithin smallvdotswithin', () => { + toXmlMatch( + tex2mml( + [ + '\\begin{alignat*}{3}', + 'A&+ B &&= C &&+ D \\\\', + '\\MTFlushSpaceAbove', + '&\\vdotswithin{+} &&&& \\vdotswithin{+}', + '\\MTFlushSpaceBelow ', + 'C &+ D &&= Y &&+K', + '\\end{alignat*}' + ].join('') + ), + ` + + + + A + + + + + + + B + + + + + + + = + C + + + + + + + + + D + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + C + + + + + + + D + + + + + + + = + Y + + + + + + + + + K + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Paired Delimiters', () => { + + /********************************************************************************/ + + test('DeclarePairedDelimiter', () => { + toXmlMatch( + tex2mml('\\DeclarePairedDelimiter\\abs{\\lvert}{\\rvert} \\abs{\\frac{a}{b}}'), + ` + | + + a + b + + | + ` + ); + }); + + /********************************************************************************/ + + test('DeclarePairedDelimiter star', () => { + toXmlMatch( + tex2mml('\\DeclarePairedDelimiter\\abs{\\lvert}{\\rvert} \\abs*{\\frac{a}{b}}'), + ` + + + | + + a + b + + | + + + + ` + ); + }); + + /********************************************************************************/ + + test('DeclarePairedDelimiter size', () => { + toXmlMatch( + tex2mml('\\DeclarePairedDelimiter\\abs{\\lvert}{\\rvert} \\abs[\\Bigg]{\\frac{a}{b}}'), + ` + + | + + + a + b + + + | + + ` + ); + }); + + /********************************************************************************/ + + test('DeclarePairedDelimiter duplicate', () => { + expectTexError('\\DeclarePairedDelimiter\\abs{\\lvert}{\\rvert} \\DeclarePairedDelimiter\\abs{|}{|}') + .toBe('Command \\abs already defined'); + }); + + /********************************************************************************/ + + test('DeclarePairedDelimiterX', () => { + toXmlMatch( + tex2mml('\\DeclarePairedDelimiterX\\x[1]{\\lvert}{\\rvert}{a#1b} \\x{X}'), + ` + | + a + X + b + | + ` + ); + }); + + /********************************************************************************/ + + test('DeclarePairedDelimiterXPP', () => { + toXmlMatch( + tex2mml('\\DeclarePairedDelimiterXPP\\x[1]{A}{\\lvert}{\\rvert}{B}{a#1b} \\x{X}'), + ` + A + | + a + X + b + | + B + ` + ); + }); + + /********************************************************************************/ + + test('DeclarePairedDelimiters Backward Compatibility', () => { + toXmlMatch( + tex2mml( + [ + '\\DeclarePairedDelimiters\\a{|}{|}', + '\\DeclarePairedDelimitersX\\b[1]{|}{|}{#1}', + '\\DeclarePairedDelimitersXPP\\c[1]{A}{|}{|}{B}{#1}', + ].join('') + ), + `` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Boxed Equations', () => { + + /********************************************************************************/ + + test('Aboxed', () => { + toXmlMatch( + tex2mml('\\begin{align*}\\Aboxed{ a & = b} \\\\ & = c \\end{align*}'), + ` + + + + + + + + + a + + = + b + + + + + + + + + a + + + + + + + + + = + b + + + + + + + + + + + + = + c + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Aboxed error', () => { + expectTexError('\\Aboxed{ a & = b}') + .toBe('\\Aboxed can only be used in aligment environments'); + }); + + /********************************************************************************/ + + test('Aboxed odd column', () => { + toXmlMatch( + tex2mml('\\begin{aligned} & \\Aboxed{ a & = b} \\end{aligned}'), + ` + + + + + + + + + + + + + a + + = + b + + + + + + + + + a + + + + + + + + + = + b + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('MakeAboxedCommand', () => { + toXmlMatch( + tex2mml('\\MakeAboxedCommand\\Afbox\\fbox \\begin{align}\\Afbox{a &= b}\\end{align}'), + ` + + + + + + + + + a + + = + b + + + + + + + + + a + + + + + + + + + = + b + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('MakeAboxedCommand star', () => { + setupTex(['base', 'ams', 'newcommand', 'bbox', 'mathtools']); + toXmlMatch( + tex2mml( + '\\def\\mybox#1{\\bbox[yellow, 5px, border:2px solid]{#1}}\\MakeAboxedCommand*\\Afbox\\mybox \\begin{align}\\Afbox{a &= b}\\end{align}' + ), + ` + + + + + + + + a + + = + b + + + + + + + + a + + + + + + + + + = + b + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('MakeAboxedCommand no cs', () => { + expectTexError('\\MakeAboxedCommand x') + .toBe('\\MakeAboxedCommand must be followed by a control sequence'); + }); + + /********************************************************************************/ + + test('MakeAboxedCommand no box', () => { + expectTexError('\\MakeAboxedCommand\\x x') + .toBe('\\MakeAboxedCommand\\x must be followed by a control sequence'); + }); + + /********************************************************************************/ + + test('MakeAboxedCommand redefined', () => { + expectTexError('\\MakeAboxedCommand*\\x\\boxed \\MakeAboxedCommand\\x\\fbox') + .toBe('\\x is already defined'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Centered Colons', () => { + + /********************************************************************************/ + + test(':=', () => { + toXmlMatch( + tex2mml('a := b'), + ` + a + := + b + ` + ); + }); + + /********************************************************************************/ + + test('vcentercolon', () => { + toXmlMatch( + tex2mml('a \\vcentercolon= b'), + ` + a + + : + + = + b + ` + ); + }); + + /********************************************************************************/ + + test('ordinarycolon', () => { + toXmlMatch( + tex2mml('a \\ordinarycolon= b'), + ` + a + := + b + ` + ); + }); + + /********************************************************************************/ + + test('coloneq', () => { + toXmlMatch( + tex2mml('a \\coloneq b'), + ` + a + + + : + + = + + b + ` + ); + }); + + /********************************************************************************/ + + test('Coloneq', () => { + toXmlMatch( + tex2mml('a \\Coloneq b'), + ` + a + + + : + + + : + + = + + b + ` + ); + }); + + /********************************************************************************/ + + test('coloneqq', () => { + toXmlMatch( + tex2mml('a \\coloneqq b'), + ` + a + + + : + + = + + b + ` + ); + }); + + /********************************************************************************/ + + test('Coloneqq', () => { + toXmlMatch( + tex2mml('a \\Coloneqq b'), + ` + a + + + : + + + : + + = + + b + ` + ); + }); + + /********************************************************************************/ + + test('eqqcolon', () => { + toXmlMatch( + tex2mml('a \\eqqcolon b'), + ` + a + + = + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('Eqqcolon', () => { + toXmlMatch( + tex2mml('a \\Eqqcolon b'), + ` + a + + = + + : + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('eqcolon', () => { + toXmlMatch( + tex2mml('a \\eqcolon b'), + ` + a + + = + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('Eqcolon', () => { + toXmlMatch( + tex2mml('a \\Eqcolon b'), + ` + a + + = + + : + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('colonapprox', () => { + toXmlMatch( + tex2mml('a \\colonapprox b'), + ` + a + + + : + + + + b + ` + ); + }); + + /********************************************************************************/ + + test('Colonapprox', () => { + toXmlMatch( + tex2mml('a \\Colonapprox b'), + ` + a + + + : + + + : + + + + b + ` + ); + }); + + /********************************************************************************/ + + test('colonsim', () => { + toXmlMatch( + tex2mml('a \\colonsim b'), + ` + a + + + : + + + + b + ` + ); + }); + + /********************************************************************************/ + + test('Colonsim', () => { + toXmlMatch( + tex2mml('a \\Colonsim b'), + ` + a + + + : + + + : + + + + b + ` + ); + }); + + /********************************************************************************/ + + test('dblcolon', () => { + toXmlMatch( + tex2mml('a \\dblcolon b'), + ` + a + + + : + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('approxcolon', () => { + toXmlMatch( + tex2mml('a \\approxcolon b'), + ` + a + + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('Approxcolon', () => { + toXmlMatch( + tex2mml('a \\Approxcolon b'), + ` + a + + + + : + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('simcolon', () => { + toXmlMatch( + tex2mml('a \\simcolon b'), + ` + a + + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('Simcolon', () => { + toXmlMatch( + tex2mml('a \\Simcolon b'), + ` + a + + + + : + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('colondash', () => { + toXmlMatch( + tex2mml('a \\colondash b'), + ` + a + + + : + + + + + + b + ` + ); + }); + + /********************************************************************************/ + + test('Colondash', () => { + toXmlMatch( + tex2mml('a \\Colondash b'), + ` + a + + + : + + + : + + + + + + b + ` + ); + }); + + /********************************************************************************/ + + test('dashcolon', () => { + toXmlMatch( + tex2mml('a \\dashcolon b'), + ` + a + + + + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + + test('Dashcolon', () => { + toXmlMatch( + tex2mml('a \\Dashcolon b'), + ` + a + + + + + + : + + + : + + + b + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Prescripts', () => { + + /********************************************************************************/ + + test('prescripts sub sup', () => { + toXmlMatch( + tex2mml('\\prescript{a}{b}{X}^{c}_{d}'), + ` + + X + + d + + + c + + + b + a + + ` + ); + }); + + /********************************************************************************/ + + test('prescripts sub', () => { + toXmlMatch( + tex2mml('\\prescript{a}{}{X}^{c}_{d}'), + ` + + X + + d + + + c + + + + a + + ` + ); + }); + + /********************************************************************************/ + + test('prescripts sup', () => { + toXmlMatch( + tex2mml('\\prescript{}{b}{X}^{c}_{d}'), + ` + + X + + d + + + c + + + b + + + ` + ); + }); + + /********************************************************************************/ + + test('prescripts no post sub', () => { + toXmlMatch( + tex2mml('\\prescript{}{b}{X}^{c}'), + ` + + X + + + c + + + b + + + ` + ); + }); + + /********************************************************************************/ + + test('prescripts no post sup', () => { + toXmlMatch( + tex2mml('\\prescript{}{b}{X}_{d}'), + ` + + X + + d + + + + b + + + ` + ); + }); + + /********************************************************************************/ + + test('prescripts no postscripts', () => { + toXmlMatch( + tex2mml('\\prescript{a}{b}{X}'), + ` + + X + + b + a + + ` + ); + }); + + /********************************************************************************/ + + test('prescripts empty', () => { + toXmlMatch( + tex2mml('\\prescript{\\mathbf{}}{}{X}^{c}_{d}'), + ` + + X + + d + + + c + + + ` + ); + }); + + /********************************************************************************/ + + test('prescripts empty no postscripts', () => { + toXmlMatch( + tex2mml('\\prescript{\\mathbf{}}{}{X}'), + ` + X + ` + ); + }); + + /********************************************************************************/ + + test('prescript filter ingores others', () => { + toXmlMatch( + tex2mml('\\sideset{^a}{C}{_b}'), + ` + + + + + b + + + + a + + C + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools Split Fractions', () => { + + /********************************************************************************/ + + test('splitfrac', () => { + toXmlMatch( + tex2mml('\\frac{\\splitfrac{x + y}{+ x + y}}{z}=\\frac{\\splitdfrac{x + y}{+ x + y}}{z}'), + ` + + + + x + + + y + + + + + + + + + x + + + y + + + z + + = + + + + + x + + + y + + + + + + + + + x + + + y + + + + z + + ` + ); + }); + + /********************************************************************************/ + + test('splitfrac nested', () => { + toXmlMatch( + tex2mml('\\frac{\\splitfrac{x + x + z}{\\splitfrac{\\mathstrut x + y + z}{+ x + y + z}}}{z}'), + ` + + + + x + + + x + + + z + + + + + + + + + + + + ( + + + + x + + + y + + + z + + + + + + + + + x + + + y + + + z + + + + + z + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools struts', () => { + + /********************************************************************************/ + + test('xmathstrut', () => { + toXmlMatch( + tex2mml('\\xmathstrut{0.1}'), + ` + + + + ( + + + + ` + ); + }); + + /********************************************************************************/ + + test('xmathstrut', () => { + toXmlMatch( + tex2mml('\\xmathstrut[0.2]{0.1}'), + ` + + + + ( + + + + ` + ); + }); + + /********************************************************************************/ + + test('xmathstrut error', () => { + expectTexError('\\xmathstrut{abc}') + .toBe('Argument to \\xmathstrut is not a number'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools setoptions', () => { + + /********************************************************************************/ + + test('multlined gap and pos', () => { + toXmlMatch( + tex2mml( + [ + '\\mathtoolsset{multlined-gap=2em,multlined-pos=b}', + 'a+\\begin{multlined} a \\\\ b \\end{multlined}+b' + ].join('') + ), + ` + a + + + + + + a + + + + + + + b + + + + + + b + ` + ); + }); + + /********************************************************************************/ + + test('multlined-pos override', () => { + toXmlMatch( + tex2mml( + [ + '\\mathtoolsset{multlined-gap=2em,multlined-pos=b}', + 'a+\\begin{multlined}[b] a \\\\ b \\end{multlined}+b' + ].join('') + ), + ` + a + + + + + + a + + + + + + + b + + + + + + b + ` + ); + }); + + /********************************************************************************/ + + test('multlined skips', () => { + toXmlMatch( + tex2mml( + [ + '\\mathtoolsset{multlined-gap=2em,firstline-afterskip=3em,lastline-preskip=1em}', + '\\begin{multlined}[b] a \\\\ b \\end{multlined}' + ].join('') + ), + ` + + + + a + + + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + test('multlined width', () => { + toXmlMatch( + tex2mml( + [ + '\\mathtoolsset{multlined-width=5em}', + '\\begin{multlined} a \\\\ b \\end{multlined}' + ].join('') + ), + ` + + + + a + + + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + test('smallmatrix-align', () => { + toXmlMatch( + tex2mml( + [ + '\\mathtoolsset{smallmatrix-align=r}', + '\\begin{psmallmatrix*} a \\\\ -b \\end{psmallmatrix*}' + ].join('') + ), + ` + + ( + + + + + a + + + + + + b + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + test('contercolon', () => { + toXmlMatch( + tex2mml('\\mathtoolsset{centercolon=true} a := b'), + ` + a + + : + + = + b + ` + ); + }); + + /********************************************************************************/ + + test('contercolon-offset', () => { + toXmlMatch( + tex2mml('\\mathtoolsset{centercolon-offset=.6em} a \\vcentercolon= b'), + ` + a + + : + + = + b + ` + ); + }); + + /********************************************************************************/ + + test('thincolor dx and dw', () => { + toXmlMatch( + tex2mml('\\mathtoolsset{thincolon-dx=-.06em,thincolon-dw=.12em} a \\coloneq b'), + ` + a + + + : + + = + + b + ` + ); + }); + + /********************************************************************************/ + + test('use-unicode', () => { + toXmlMatch( + tex2mml( + '\\mathtoolsset{use-unicode=true}\\coloneq\\Coloneqq\\coloneq\\Coloneqq\\eqqcolon\\eqcolon\\dblcolon\\dashcolon' + ), + ` + ≔⩴≔⩴≕≕∷∹ + ` + ); + }); + + /********************************************************************************/ + + test('prescript formats', () => { + toXmlMatch( + tex2mml( + [ + '\\mathtoolsset{prescript-sub-format=\\mathbf,prescript-sup-format=\\mathsf}', + '\\mathtoolsset{prescript-arg-format=\\mathfrak}', + '\\prescript{a}{b}{X}^{c}_{d}' + ].join('') + ), + ` + + + X + + + d + + + c + + + + b + + + a + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mathtools options', () => { + + beforeEach(() => {}); + + /********************************************************************************/ + + test('setoptions', () => { + setupTex(['base', 'mathtools'], {mathtools: {'allow-mathtoolsset': false}}); + expectTexError('\\mathtoolsset{use-unicode=true}') + .toBe('\\mathtoolsset is disabled'); + }); + + /********************************************************************************/ + + test('tagforms', () => { + setupTex(['base', 'ams', 'mathtools'], { + mathtools: { + tagforms: { + bold: ['[[', ']]', '\\mathbf'] + } + } + }); + toXmlMatch( + tex2mml('\\usetagform{bold} a=b\\tag{x}'), + ` + + + + [[\\mathbf{x}]] + + + a + = + b + + + + ` + ); + }); + + /********************************************************************************/ + + test('tagforms error', () => { + expect(trapErrors(() => { + setupTex(['base', 'ams', 'mathtools'], { + mathtools: { + tagforms: { + bold: ['[[', ']]', '\\mathbf', 'error'] + } + } + }); + })).toBe('The tag form definition for "bold" should be an array of three strings'); + }); + + /********************************************************************************/ + + test('tagforms reset', () => { + setupTex(['base', 'ams', 'mathtools'], { + mathtools: { + tagforms: { + bold: ['[[', ']]', '\\mathbf'] + } + } + }); + toXmlMatch( + tex2mml('\\usetagform{bold} \\usetagform{} a\\tag{1}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + test('non-ams tags', () => { + class myTags extends AbstractTags { + formatTag(tag: string) {return `[[${tag}]]`} + }; + Configuration.create('mytags', { + [ConfigurationType.TAGS]: {mytags: myTags}, + [ConfigurationType.CONFIG]: (config: any, jax: any) => { + jax.parseOptions.options.tags = 'mytags'; + jax.constructor.tags(jax.parseOptions, config); + } + }); + setupTex(['base', 'ams', 'mathtools', ['mytags', 10]], {tags: 'ams'}); + expectTexError('\\newtagform{a}()') + .toBe('\\newtagform can only be used with ams or mathtools tags'); + expectTexError('\\usetagform{bold}') + .toBe('\\usetagform can only be used with ams or mathtools tags'); + }); + + /********************************************************************************/ + + test('pairedDelimiters', () => { + setupTex(['base', 'ams', 'mathtools'], { + mathtools: { + pairedDelimiters: { + aaa: ['[', ']'], + bbb: ['|', '|', '[#1]', 1], + ccc: ['\\{', '\\}', '[#1]', 1, '\\Rightarrow', '\\Leftarrow'], + } + } + }); + toXmlMatch( + tex2mml('\\aaa{x} \\aaa*{x} \\aaa[\\bigg]{x}'), + ` + [ + x + ] + + + [ + x + ] + + + + + [ + + x + + ] + + ` + ); + toXmlMatch( + tex2mml('\\bbb{x} \\bbb*{x} \\bbb[\\bigg]{x}'), + ` + | + [ + x + ] + | + + + | + [ + x + ] + | + + + + + | + + [ + x + ] + + | + + ` + ); + toXmlMatch( + tex2mml('\\ccc{x} \\ccc*{x} \\ccc[\\bigg]{x}'), + ` + + { + [ + x + ] + } + ⇐⇒ + + + { + [ + x + ] + } + + + + ⇐⇒ + + { + + [ + x + ] + + } + + + ` + ); + }); + + /********************************************************************************/ + + test('mathtoolsset', () => { + setupTex(['base', 'ams', 'mathtools']); + toXmlMatch( + tex2mml('\\mathtoolsset{multlined-pos={}}\\begin{multlined} a \\end{multlined}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + test('mathtoolsset legacycolonsymbols', () => { + setupTex(['base', 'ams', 'mathtools']); + toXmlMatch( + tex2mml('\\mathtoolsset{legacycolonsymbols}\\coloneq\\Coloneq\\eqcolon\\Eqcolon'), + ` + + + : + + + + + + + + : + + + : + + + + + + + + + + + : + + + + + + + + : + + + : + + + ` + ); + }); + + /********************************************************************************/ + + test('legacycolonsymbols option', () => { + setupTex(['base', 'ams', 'mathtools'], {mathtools: {legacycolonsymbols: true}}); + toXmlMatch( + tex2mml('\\coloneq\\Coloneq\\eqcolon\\Eqcolon'), + ` + + + : + + + + + + + + : + + + : + + + + + + + + + + + : + + + + + + + + : + + + : + + + ` + ); + toXmlMatch( + tex2mml('\\mathtoolsset{legacycolonsymbols=false}\\coloneq\\Coloneq\\eqcolon\\Eqcolon'), + ` + + + : + + = + + + + : + + + : + + = + + + = + + : + + + + = + + : + + + : + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('mathtools')); diff --git a/testsuite/tests/input/tex/Mhchem.test.ts b/testsuite/tests/input/tex/Mhchem.test.ts new file mode 100644 index 000000000..31fe0ab06 --- /dev/null +++ b/testsuite/tests/input/tex/Mhchem.test.ts @@ -0,0 +1,5619 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/mhchem/MhchemConfiguration'; +import '#js/input/tex/ams/AmsConfiguration'; + +beforeEach(() => setupTex(['base', 'mhchem'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem0', () => { + + /********************************************************************************/ + + it('Chem-1', () => { + toXmlMatch( + tex2mml('\\ce{CO2 + C -> 2 CO}'), + ` + + + CO + + + + + + + A + + + + + + + + 2 + + + + + + + + + + C + + + + + + + 2 + + + CO + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-3', () => { + toXmlMatch( + tex2mml('C_p[\\ce{H2O(l)}] = \\pu{75.3 J // mol K}'), + ` + + C + p + + [ + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ( + + l + + ) + + ] + = + + 75.3 +   + + + + J + + + + mol + + + + K + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-4', () => { + toXmlMatch( + tex2mml('\\ce{H2O}'), + ` + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-5', () => { + toXmlMatch( + tex2mml('\\ce{Sb2O3}'), + ` + + + Sb + + + + + + + A + + + + + + + + 2 + + + + + + O + + + + + + + A + + + + + + + + 3 + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-6', () => { + toXmlMatch( + tex2mml('\\ce{H+}'), + ` + + + H + + + + + + + A + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-7', () => { + toXmlMatch( + tex2mml('\\ce{CrO4^2-}'), + ` + + + CrO + + + + + + + A + + + + + + + + 4 + + + + + + + + + + A + + + + + + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-8', () => { + toXmlMatch( + tex2mml('\\ce{[AgCl2]-}'), + ` + + [ + + AgCl + + + + + + + A + + + + + + + + 2 + + + + + ] + + + + + + A + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-9', () => { + toXmlMatch( + tex2mml('\\ce{Y^99+}'), + ` + + + Y + + + + + + + A + + + + + + 99 + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem1', () => { + + /********************************************************************************/ + + it('Chem-10', () => { + toXmlMatch( + tex2mml('\\ce{Y^{99+}}'), + ` + + + Y + + + + + + + A + + + + + + 99 + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-11', () => { + toXmlMatch( + tex2mml('\\ce{2 H2O}'), + ` + + 2 + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-12', () => { + toXmlMatch( + tex2mml('\\ce{2H2O}'), + ` + + 2 + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-13', () => { + toXmlMatch( + tex2mml('\\ce{0.5 H2O}'), + ` + + 0.5 + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-14', () => { + toXmlMatch( + tex2mml('\\ce{1/2 H2O}'), + ` + + + + 1 + 2 + + + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-15', () => { + toXmlMatch( + tex2mml('\\ce{(1/2) H2O}'), + ` + + ( + 1 + + / + + 2 + ) + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-16', () => { + toXmlMatch( + tex2mml('\\ce{$n$ H2O}'), + ` + + n + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-17', () => { + toXmlMatch( + tex2mml('\\ce{^{227}_{90}Th+}'), + ` + + + + + + + A + + + + + + + + + 90 + + + + + + + + + 227 + + + + + + + + + + + + A + + + + + + + + + 2 + + + + + + + + 90 + + + + + + + + + + + + 2 + + + + + + + + 227 + + + + + + Th + + + + + + + A + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-18', () => { + toXmlMatch( + tex2mml('\\ce{^227_90Th+}'), + ` + + + + + + + A + + + + + + + + + 90 + + + + + + + + + 227 + + + + + + + + + + + + A + + + + + + + + + 2 + + + + + + + + 90 + + + + + + + + + + + + 2 + + + + + + + + 227 + + + + + + Th + + + + + + + A + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-19', () => { + toXmlMatch( + tex2mml('\\ce{^{0}_{-1}n^{-}}'), + ` + + + + + + + A + + + + + + + + + + 1 + + + + + + + + + 0 + + + + + + + + + + + + A + + + + + + + + + 2 + + + + + + + + + 1 + + + + + + + + + + + + 2 + + + + + + + + 0 + + + + + + n + + + + + + + A + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem2', () => { + + /********************************************************************************/ + + it('Chem-20', () => { + toXmlMatch( + tex2mml('\\ce{^0_-1n-}'), + ` + + + + + + + A + + + + + + + + + + 1 + + + + + + + + + 0 + + + + + + + + + + + + A + + + + + + + + + 2 + + + + + + + + + 1 + + + + + + + + + + + + 2 + + + + + + + + 0 + + + + + + n + + + + + + + A + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-21', () => { + toXmlMatch( + tex2mml('\\ce{H{}^3HO}'), + ` + + + H + + + + + + + + A + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + A + + + + + + + + + 2 + + + + + + + + + + + + + + + + + + 2 + + + + + + + + 3 + + + + + + HO + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-22', () => { + toXmlMatch( + tex2mml('\\ce{H^3HO}'), + ` + + + H + + + + + + + + A + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + A + + + + + + + + + 2 + + + + + + + + + + + + + + + + + + 2 + + + + + + + + 3 + + + + + + HO + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-23', () => { + toXmlMatch( + tex2mml('\\ce{A -> B}'), + ` + + + A + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-24', () => { + toXmlMatch( + tex2mml('\\ce{A <- B}'), + ` + + + A + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-25', () => { + toXmlMatch( + tex2mml('\\ce{A <-> B}'), + ` + + + A + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-26', () => { + toXmlMatch( + tex2mml('\\ce{A <--> B}'), + ` + + + A + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-27', () => { + toXmlMatch( + tex2mml('\\ce{A <=> B}'), + ` + + + A + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-28', () => { + toXmlMatch( + tex2mml('\\ce{A <=>> B}'), + ` + + + A + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-29', () => { + toXmlMatch( + tex2mml('\\ce{A <<=> B}'), + ` + + + A + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem3', () => { + + /********************************************************************************/ + + it('Chem-33', () => { + toXmlMatch( + tex2mml('\\ce{(NH4)2S}'), + ` + + ( + + NH + + + + + + + A + + + + + + + + 4 + + + + + ) + + + + + + A + + + + + + + + 2 + + + + + + S + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-34', () => { + toXmlMatch( + tex2mml('\\ce{[\\{(X2)3\\}2]^3+}'), + ` + + [ + { + ( + + X + + + + + + + A + + + + + + + + 2 + + + + + ) + + + + + + A + + + + + + + + 3 + + + + + } + + + + + + A + + + + + + + + 2 + + + + + ] + + + + + + A + + + + + + 3 + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-35', () => { + toXmlMatch( + tex2mml('\\ce{CH4 + 2 $\\left( \\ce{O2 + 79/21 N2} \\right)$}'), + ` + + + CH + + + + + + + A + + + + + + + + 4 + + + + + + + + + 2 + + + ( + + O + + + + + + + A + + + + + + + + 2 + + + + + + + + + + + 79 + 21 + + + + + N + + + + + + + A + + + + + + + + 2 + + + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-36', () => { + toXmlMatch( + tex2mml('\\ce{H2(aq)}'), + ` + + + H + + + + + + + A + + + + + + + + 2 + + + + + + ( + + aq + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-37', () => { + toXmlMatch( + tex2mml('\\ce{CO3^2-_{(aq)}}'), + ` + + + CO + + + + + + + A + + + + + + + + 3 + + + + + + + + + + A + + + + + + 2 + + + + + + + + + A + + + + + + + + + ( + + aq + + ) + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-38', () => { + toXmlMatch( + tex2mml('\\ce{NaOH(aq,$\\infty$)}'), + ` + + + NaOH + + + ( + + aq + + , + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-39', () => { + toXmlMatch( + tex2mml('\\ce{ZnS($c$)}'), + ` + + + ZnS + + + ( + c + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem4', () => { + + /********************************************************************************/ + + it('Chem-40', () => { + toXmlMatch( + tex2mml('\\ce{ZnS(\\ca$c$)}'), + ` + + + ZnS + + + ( + + + + c + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-41', () => { + toXmlMatch( + tex2mml('\\ce{NO_x}'), + ` + + + NO + + + + + + + A + + + + + + + + x + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-42', () => { + toXmlMatch( + tex2mml('\\ce{Fe^n+}'), + ` + + + Fe + + + + + + + A + + + + + + n + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-44', () => { + toXmlMatch( + tex2mml('\\ce{\\mu-Cl}'), + ` + + + μ + + - + + Cl + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-45', () => { + toXmlMatch( + tex2mml('\\ce{[Pt(\\eta^2-C2H4)Cl3]-}'), + ` + + [ + + Pt + + ( + + η + + + + + + + A + + + + + + 2 + + + - + + C + + + + + + + A + + + + + + + + 2 + + + + + + H + + + + + + + A + + + + + + + + 4 + + + + + ) + + Cl + + + + + + + A + + + + + + + + 3 + + + + + ] + + + + + + A + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-46', () => { + toXmlMatch( + tex2mml('\\ce{\\beta +}'), + ` + + + β + + + + + + + A + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-47', () => { + toXmlMatch( + tex2mml('\\ce{^40_18Ar + \\gamma{} + \\nu_e}'), + ` + + + + + + + A + + + + + + + + + 18 + + + + + + + + + 40 + + + + + + + + + + + + A + + + + + + + + + 2 + + + + + + + + 18 + + + + + + + + + + + + 2 + + + + + + + + 40 + + + + + + Ar + + + + + + + γ + + + + + + + + ν + + + + + + + A + + + + + + + + e + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-48', () => { + toXmlMatch( + tex2mml('\\ce{NaOH(aq,$\\infty$)}'), + ` + + + NaOH + + + ( + + aq + + , + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-49', () => { + toXmlMatch( + tex2mml('\\ce{Fe(CN)_{$\\frac{6}{2}$}}'), + ` + + + Fe + + ( + + CN + + ) + + + + + + A + + + + + + + + + 6 + 2 + + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem5', () => { + + /********************************************************************************/ + + it('Chem-50', () => { + toXmlMatch( + tex2mml('\\ce{X_{$i$}^{$x$}}'), + ` + + + X + + + + + + + A + + + + + + + + i + + + + + + + + + + A + + + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-51', () => { + toXmlMatch( + tex2mml('\\ce{X_$i$^$x$}'), + ` + + + X + + + + + + + A + + + + + + + + i + + + + + + + + + + A + + + + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-52', () => { + toXmlMatch( + tex2mml('\\ce{$cis${-}[PtCl2(NH3)2]}'), + ` + + c + i + s + + - + + [ + + PtCl + + + + + + + A + + + + + + + + 2 + + + + + ( + + NH + + + + + + + A + + + + + + + + 3 + + + + + ) + + + + + + A + + + + + + + + 2 + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-53', () => { + toXmlMatch( + tex2mml('\\ce{CuS($hP12$)}'), + ` + + + CuS + + ( + h + P + 12 + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-54', () => { + toXmlMatch( + tex2mml('\\ce{{Gluconic Acid} + H2O2}'), + ` + + + Gluconic Acid + + + + + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + + + + + A + + + + + + + + 2 + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-55', () => { + toXmlMatch( + tex2mml('\\ce{X_{{red}}}'), + ` + + + X + + + + + + + A + + + + + + + + red + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-56', () => { + toXmlMatch( + tex2mml('\\ce{{(+)}_589{-}[Co(en)3]Cl3}'), + ` + + + (+) + + + + + + + A + + + + + + + + 589 + + + + + + - + + [ + + Co + + ( + + en + + ) + + + + + + A + + + + + + + + 3 + + + + + ] + + Cl + + + + + + + A + + + + + + + + 3 + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-57', () => { + toXmlMatch( + tex2mml('\\ce{C6H5-CHO}'), + ` + + + C + + + + + + + A + + + + + + + + 6 + + + + + + H + + + + + + + A + + + + + + + + 5 + + + + + + + + + CHO + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-58', () => { + toXmlMatch( + tex2mml('\\ce{A-B=C#D}'), + ` + + + A + + + + + + B + + + = + + + C + + + + + + D + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-59', () => { + toXmlMatch( + tex2mml('\\ce{A\\bond{-}B\\bond{=}C\\bond{#}D}'), + ` + + + A + + + + + + B + + + = + + + C + + + + + + D + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem6', () => { + + /********************************************************************************/ + + it('Chem-60', () => { + toXmlMatch( + tex2mml('\\ce{A\\bond{1}B\\bond{2}C\\bond{3}D}'), + ` + + + A + + + + + + B + + + = + + + C + + + + + + D + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-61', () => { + toXmlMatch( + tex2mml('\\ce{A\\bond{~}B\\bond{~-}C}'), + ` + + + A + + + + + + B + + + + + + C + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-62', () => { + toXmlMatch( + tex2mml('\\ce{A\\bond{~--}B\\bond{~=}C\\bond{-~-}D}'), + ` + + + A + + + + + + B + + + + + + C + + + + + + D + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-63', () => { + toXmlMatch( + tex2mml('\\ce{A\\bond{...}B\\bond{....}C}'), + ` + + + A + + + + + + + + + + + + + + B + + + + + + + + + + + + + + + + + C + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-64', () => { + toXmlMatch( + tex2mml('\\ce{A\\bond{->}B\\bond{<-}C}'), + ` + + + A + + + + + + B + + + + + + C + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-65', () => { + toXmlMatch( + tex2mml('\\ce{KCr(SO4)2*12H2O}'), + ` + + + KCr + + ( + + SO + + + + + + + A + + + + + + + + 4 + + + + + ) + + + + + + A + + + + + + + + 2 + + + + + + + + + + 12 + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-66', () => { + toXmlMatch( + tex2mml('\\ce{KCr(SO4)2.12H2O}'), + ` + + + KCr + + ( + + SO + + + + + + + A + + + + + + + + 4 + + + + + ) + + + + + + A + + + + + + + + 2 + + + + + + + + + + 12 + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-67', () => { + toXmlMatch( + tex2mml('\\ce{KCr(SO4)2 * 12 H2O}'), + ` + + + KCr + + ( + + SO + + + + + + + A + + + + + + + + 4 + + + + + ) + + + + + + A + + + + + + + + 2 + + + + + + + + + + 12 + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-68', () => { + toXmlMatch( + tex2mml('\\ce{Fe^{II}Fe^{III}2O4}'), + ` + + + Fe + + + + + + + A + + + + + + + II + + + + + Fe + + + + + + + A + + + + + + + III + + + + + + + + + A + + + + + + + + 2 + + + + + + O + + + + + + + A + + + + + + + + 4 + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-69', () => { + toXmlMatch( + tex2mml('\\ce{OCO^{.-}}'), + ` + + + OCO + + + + + + + A + + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem7', () => { + + /********************************************************************************/ + + it('Chem-70', () => { + toXmlMatch( + tex2mml('\\ce{NO^{(2.)-}}'), + ` + + + NO + + + + + + + A + + + + + + ( + 2 + + + + ) + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-71', () => { + toXmlMatch( + tex2mml("\\ce{O''_{i,x}}"), + ` + + + O + + + + + + + A + + + + + + + + + i + + + , + + + x + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-72', () => { + toXmlMatch( + tex2mml('\\ce{M^{..}_i}'), + ` + + + M + + + + + + + A + + + + + + + + + i + + + + + + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-73', () => { + toXmlMatch( + tex2mml("\\ce{$V$^{4'}_{Ti}}"), + ` + + V + + + + + + A + + + + + + + + + Ti + + + + + + 4 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-74', () => { + toXmlMatch( + tex2mml('\\ce{V_{V,1}C_{C,0.8}$V$_{C,0.2}}'), + ` + + + V + + + + + + + A + + + + + + + + + V + + + , + + + 1 + + + + + + C + + + + + + + A + + + + + + + + + C + + + , + + + 0.8 + + + + + V + + + + + + A + + + + + + + + + C + + + , + + + 0.2 + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-75', () => { + toXmlMatch( + tex2mml('\\ce{A + B}'), + ` + + + A + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-76', () => { + toXmlMatch( + tex2mml('\\ce{A - B}'), + ` + + + A + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-77', () => { + toXmlMatch( + tex2mml('\\ce{A = B}'), + ` + + + A + + + = + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-78', () => { + toXmlMatch( + tex2mml('\\ce{A \\pm B}'), + ` + + + A + + + ± + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-79', () => { + toXmlMatch( + tex2mml('\\ce{SO4^2- + Ba^2+ -> BaSO4 v}'), + ` + + + SO + + + + + + + A + + + + + + + + 4 + + + + + + + + + + A + + + + + + 2 + + + + + + + + + Ba + + + + + + + A + + + + + + 2 + + + + + + + + + + + BaSO + + + + + + + A + + + + + + + + 4 + + + + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem8', () => { + + /********************************************************************************/ + + it('Chem-80', () => { + toXmlMatch( + tex2mml('\\ce{A v B (v) -> B ^ B (^)}'), + ` + + + A + + + +   + + B + + + + + + + + + + B + + + +   + + B + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-81', () => { + toXmlMatch( + tex2mml('\\ce{NO^*}'), + ` + + + NO + + + + + + + A + + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-82', () => { + toXmlMatch( + tex2mml('\\ce{1s^2-N}'), + ` + + 1 + + s + + + + + + + A + + + + + + 2 + + + - + + N + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-83', () => { + toXmlMatch( + tex2mml('\\ce{n-Pr}'), + ` + + n + - + + Pr + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-84', () => { + toXmlMatch( + tex2mml('\\ce{iPr}'), + ` + + + iPr + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-85', () => { + toXmlMatch( + tex2mml('\\ce{\\ca Fe}'), + ` + + + + + + Fe + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-86', () => { + toXmlMatch( + tex2mml('\\ce{A, B, C; F}'), + ` + + + A + + + , + + + + B + + + , + + + + C + + + ; + + + + F + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-87', () => { + toXmlMatch( + tex2mml('\\ce{{and others}}'), + ` + + + and others + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-88', () => { + toXmlMatch( + tex2mml( + '\\ce{Zn^2+ <=>[+ 2OH-][+ 2H+] $\\underset{\\text{amphoteres Hydroxid}}{\\ce{Zn(OH)2 v}}$ <=>[+ 2OH-][+ 2H+] $\\underset{\\text{Hydroxozikat}}{\\ce{[Zn(OH)4]^2-}}$}' + ), + ` + + + Zn + + + + + + + A + + + + + + 2 + + + + + + + + + + + + + + + 2 + + + + + OH + + + + + + + A + + + + + + + + + + + + + + + + + + 2 + + + + + H + + + + + + + A + + + + + + + + + + + + + + + + + + Zn + + ( + + OH + + ) + + + + + + A + + + + + + + + 2 + + + + + + + + amphoteres Hydroxid + + + + + + + + + + + + 2 + + + + + OH + + + + + + + A + + + + + + + + + + + + + + + + + + 2 + + + + + H + + + + + + + A + + + + + + + + + + + + + + + + + [ + + Zn + + ( + + OH + + ) + + + + + + A + + + + + + + + 4 + + + + + ] + + + + + + A + + + + + + 2 + + + + + Hydroxozikat + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-89', () => { + toXmlMatch( + tex2mml('\\ce{$K = \\frac{[\\ce{Hg^2+}][\\ce{Hg}]}{[\\ce{Hg2^2+}]}$}'), + ` + + K + = + + + [ + + + Hg + + + + + + + A + + + + + + 2 + + + + + + ] + [ + + + Hg + + + ] + + + [ + + + Hg + + + + + + + A + + + + + + + + 2 + + + + + + + + + + A + + + + + + 2 + + + + + + ] + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem9', () => { + + /********************************************************************************/ + + it('Chem-90', () => { + toXmlMatch( + tex2mml('\\ce{$K = \\ce{\\frac{[Hg^2+][Hg]}{[Hg2^2+]}}$}'), + ` + + K + = + + + [ + + Hg + + + + + + + A + + + + + + 2 + + + + + ] + [ + + Hg + + ] + + + [ + + Hg + + + + + + + A + + + + + + + + 2 + + + + + + + + + + A + + + + + + 2 + + + + + ] + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-92', () => { + toXmlMatch( + tex2mml('\\pu{123 kJ}'), + ` + + 123 +   + + kJ + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-93', () => { + toXmlMatch( + tex2mml('\\pu{123 mm2}'), + ` + + 123 +   + + + mm + + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-94', () => { + toXmlMatch( + tex2mml('\\pu{123 J s}'), + ` + + 123 +   + + J + + + + s + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-95', () => { + toXmlMatch( + tex2mml('\\pu{123 J*s}'), + ` + + 123 +   + + J + + + + + + + + s + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-96', () => { + toXmlMatch( + tex2mml('\\pu{123 kJ/mol}'), + ` + + 123 +   + + kJ + + + / + + + mol + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-97', () => { + toXmlMatch( + tex2mml('\\pu{123 kJ//mol}'), + ` + + 123 +   + + + + kJ + + + mol + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-98', () => { + toXmlMatch( + tex2mml('\\pu{123 kJ mol-1}'), + ` + + 123 +   + + kJ + + + + + mol + + + 1 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-99', () => { + toXmlMatch( + tex2mml('\\pu{123 kJ*mol-1}'), + ` + + 123 +   + + kJ + + + + + + + + + mol + + + 1 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-100', () => { + toXmlMatch( + tex2mml('\\pu{1.2e3 kJ}'), + ` + + 1.2 + + + 10 + + 3 + + +   + + kJ + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-101', () => { + toXmlMatch( + tex2mml('\\pu{1,2e3 kJ}'), + ` + + 1 + + , + + 2 + + + 10 + + 3 + + +   + + kJ + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-102', () => { + toXmlMatch( + tex2mml('\\pu{1.2E3 kJ}'), + ` + + 1.2 + × + + 10 + + 3 + + +   + + kJ + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-103', () => { + toXmlMatch( + tex2mml('\\pu{1,2E3 kJ}'), + ` + + 1 + + , + + 2 + × + + 10 + + 3 + + +   + + kJ + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Mhchem-Ams', () => { + beforeEach(() => setupTex(['base', 'ams', 'mhchem'])); + + /********************************************************************************/ + + it('Chem-2', () => { + toXmlMatch( + tex2mml('\\ce{Hg^2+ ->[I-] HgI2 ->[I-] [Hg^{II}I4]^2-}'), + ` + + + Hg + + + + + + + A + + + + + + 2 + + + + + + + + + + + I + + + + + + + A + + + + + + + + + + + + + + + HgI + + + + + + + A + + + + + + + + 2 + + + + + + + + + + + I + + + + + + + A + + + + + + + + + + + + + + [ + + Hg + + + + + + + A + + + + + + + II + + + + + I + + + + + + + A + + + + + + + + 4 + + + + + ] + + + + + + A + + + + + + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-30', () => { + toXmlMatch( + tex2mml('\\ce{A ->[H2O] B}'), + ` + + + A + + + + + + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-31', () => { + toXmlMatch( + tex2mml('\\ce{A ->[{text above}][{text below}] B}'), + ` + + + A + + + + + + + + + text below + + + + + + + text above + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-32', () => { + toXmlMatch( + tex2mml('\\ce{A ->[$x$][$x_i$] B}'), + ` + + + A + + + + + + + + + x + i + + + + + + x + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-43', () => { + toXmlMatch( + tex2mml('\\ce{x Na(NH4)HPO4 ->[\\Delta] (NaPO3)_x + x NH3 ^ + x H2O}'), + ` + + x + + + Na + + ( + + NH + + + + + + + A + + + + + + + + 4 + + + + + ) + + HPO + + + + + + + A + + + + + + + + 4 + + + + + + + + + + + Δ + + + + + + + ( + + NaPO + + + + + + + A + + + + + + + + 3 + + + + + ) + + + + + + A + + + + + + + + x + + + + + + + + + x + + + NH + + + + + + + A + + + + + + + + 3 + + + + + + + + + + + x + + + H + + + + + + + A + + + + + + + + 2 + + + + + + O + + + ` + ); + }); + + /********************************************************************************/ + + it('Chem-91', () => { + toXmlMatch( + tex2mml( + '\\ce{Hg^2+ ->[I-] $\\underset{\\mathrm{red}}{\\ce{HgI2}}$ ->[I-] $\\underset{\\mathrm{red}}{\\ce{[Hg^{II}I4]^2-}}$}' + ), + ` + + + Hg + + + + + + + A + + + + + + 2 + + + + + + + + + + + I + + + + + + + A + + + + + + + + + + + + + + + + + HgI + + + + + + + A + + + + + + + + 2 + + + + + + + red + + + + + + + + + I + + + + + + + A + + + + + + + + + + + + + + + + [ + + Hg + + + + + + + A + + + + + + + II + + + + + I + + + + + + + A + + + + + + + + 4 + + + + + ] + + + + + + A + + + + + + 2 + + + + + + red + + + + ` + ); + }); + + /********************************************************************************/ + + it('Mhchem Error', () => { + expectTexError('\\ce{A\\bond{x}B}') + .toBe('mhchem bug T. Please report.'); + }); + + /********************************************************************************/ + + it('Mhchem stretchy <-', () => { + toXmlMatch( + tex2mml('\\ce{A <-[text] B}'), + ` + + + A + + + + + + + + text + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Mhchem stretchy ->', () => { + toXmlMatch( + tex2mml('\\ce{A->[text]B}'), + ` + + + A + + + + + + + + text + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Mhchem stretchy <->', () => { + toXmlMatch( + tex2mml('\\ce{A<->[text]B}'), + ` + + + A + + + + + + + + text + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Mhchem stretchy <-->', () => { + toXmlMatch( + tex2mml('\\ce{A<-->[text]B}'), + ` + + + A + + + + + + + + text + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Mhchem stretchy <=>', () => { + toXmlMatch( + tex2mml('\\ce{A <=>[text] B}'), + ` + + + A + + + + + + + + text + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Mhchem stretchy <=>>', () => { + toXmlMatch( + tex2mml('\\ce{A <=>>[text] B}'), + ` + + + A + + + + + + + + text + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Mhchem stretchy <<=>', () => { + toXmlMatch( + tex2mml('\\ce{A <<=>[text] B}'), + ` + + + A + + + + + + + + text + + + + + + + + B + + + ` + ); + }); + + /********************************************************************************/ + + it('Mhchem leftrightarrrow', () => { + toXmlMatch( + tex2mml('\\ce{A\\leftrightarrow B}'), + ` + + + A + + + + B + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('mhchem')); diff --git a/testsuite/tests/input/tex/Newcommand.test.ts b/testsuite/tests/input/tex/Newcommand.test.ts new file mode 100644 index 000000000..4a036e365 --- /dev/null +++ b/testsuite/tests/input/tex/Newcommand.test.ts @@ -0,0 +1,1366 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/newcommand/NewcommandConfiguration'; +import '#js/input/tex/ams/AmsConfiguration'; +import '#js/input/tex/colorv2/ColorV2Configuration'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Newcommand', () => { + beforeEach(() => setupTex(['base', 'newcommand'])); + + /********************************************************************************/ + + it('Newcommand Simple', () => { + toXmlMatch( + tex2mml('\\newcommand{\\sum}{2 + 3}\\sum'), + ` + 2 + + + 3 + ` + ); + }); + + /********************************************************************************/ + + it('Newcommand Arg', () => { + toXmlMatch( + tex2mml('\\renewcommand{\\sum}[1]{2 #1 3}\\sum{*}'), + ` + 2 + + 3 + ` + ); + }); + + /********************************************************************************/ + + it('Newcommand Optional', () => { + toXmlMatch( + tex2mml('\\renewcommand{\\sum}[1][+]{2 #1 3}\\sum\\sum[*]'), + ` + 2 + + + 3 + 2 + + 3 + ` + ); + }); + + /********************************************************************************/ + + it('Newcommand Arg Optional', () => { + toXmlMatch( + tex2mml('\\renewcommand{\\sum}[2][+]{2 #1 3 #2 4}\\sum{+}\\sum[*]{+}'), + ` + 2 + + + 3 + + + 4 + 2 + + 3 + + + 4 + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Optional', () => { + toXmlMatch( + tex2mml( + '\\newenvironment{argument}[1][a]{\\textbf{Argument #1:}}{aa}\\begin{argument}[c]b\\end{argument}' + ), + ` + Argument c: + b + a + a + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Optional Noarg', () => { + toXmlMatch( + tex2mml( + '\\newenvironment{argument}[1][a]{\\textbf{Argument #1:}}{aa}\\begin{argument}b\\end{argument}' + ), + ` + Argument a: + b + a + a + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Arg Optional', () => { + toXmlMatch( + tex2mml( + '\\renewenvironment{argument}[2][a]{\\textbf{Argument #1(#2):}}{aa}\\begin{argument}[c]{3}b\\end{argument}' + ), + ` + Argument c(3): + b + a + a + ` + ); + }); + + /********************************************************************************/ + + it('Def Double Let', () => { + toXmlMatch( + tex2mml( + '\\def\\bar{h}\\let\\fooi\\bar\\def\\fooii{\\bar}\\fooi +\\fooii\\def\\bar{g}\\fooi +\\fooii' + ), + ` + h + + + h + h + + + g + ` + ); + }); + + /********************************************************************************/ + + it('Def ReDef', () => { + toXmlMatch( + tex2mml( + '\\def\\foo{a + b}\\foo\\def\\foo#1{a #1 b}\\foo{-}\\def\\foo#1#2{#2 #1 b}\\foo{-}{x}' + ), + ` + a + + + b + a + + b + x + + b + ` + ); + }); + + /********************************************************************************/ + + it('Let Brace Equal', () => { + toXmlMatch( + tex2mml('\\let\\be={ \\be a}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Let Brace', () => { + toXmlMatch( + tex2mml('\\let\\be{ \\be a}'), + ` + + a + + ` + ); + }); + + /********************************************************************************/ + + it('Let Caret', () => { + toXmlMatch( + tex2mml('\\let\\car^ a\\car b'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Let Brace Delim', () => { + toXmlMatch( + tex2mml('\\let\\lb=\\{ \\lb \\frac{1}{2} \\}'), + ` + { + + 1 + 2 + + } + ` + ); + }); + + /********************************************************************************/ + + it('Let Paren Delim', () => { + toXmlMatch( + tex2mml('\\let\\lb( \\lb \\frac{1}{2})'), + ` + ( + + 1 + 2 + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Let Relet', () => { + toXmlMatch( + tex2mml('\\let\\al\\alpha\\al\\alpha\\let\\al\\aleph\\al\\alpha'), + ` + α + α + + α + ` + ); + }); + + /********************************************************************************/ + + it('Let Let', () => { + toXmlMatch( + tex2mml('\\let\\al\\alpha\\al\\alpha\\let\\alpha\\beta\\al\\alpha'), + ` + α + α + α + β + ` + ); + }); + + /********************************************************************************/ + + it('Def Let', () => { + toXmlMatch( + tex2mml('\\def\\bar[#1]#2{#1 + #2}\\bar[a]{b}\\let\\foo\\bar\\foo[c]{d}'), + ` + a + + + b + c + + + d + ` + ); + }); + + /********************************************************************************/ + + it('Newcommand Let', () => { + toXmlMatch( + tex2mml( + '\\newcommand{\\bar}[2][1]{#1 + #2}\\bar[a]{b}\\let\\foo\\bar\\foo[c]{d}' + ), + ` + a + + + b + c + + + d + ` + ); + }); + + /********************************************************************************/ + + it('Let Circular Macro', () => { + toXmlMatch( + tex2mml( + '\\let\\kk\\alpha\\kk\\let\\rr\\beta\\rr\\let\\rr\\kk\\let\\kk\\beta\\kk\\rr' + ), + ` + α + β + β + α + ` + ); + }); + + /********************************************************************************/ + + it('Let Brace Equal Stretchy', () => { + toXmlMatch( + tex2mml('\\let\\lb=\\{\\left\\lb \\frac{1}{2} \\right\\}'), + ` + + { + + 1 + 2 + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Let Paren Stretchy', () => { + toXmlMatch( + tex2mml('\\let\\lb( \\left\\lb \\frac{1}{2} \\right)'), + ` + + ( + + 1 + 2 + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Let Fn', () => { + toXmlMatch( + tex2mml('\\let\\ll\\sin\\ll(x)'), + ` + sin + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('Let Fn Double', () => { + toXmlMatch( + tex2mml('\\let\\ll\\sin\\ll(x)\\let\\rr\\ll\\let\\ll\\cos\\rr(x)\\ll(x)'), + ` + sin + + ( + x + ) + sin + + ( + x + ) + cos + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('Let Fn Circular', () => { + toXmlMatch( + tex2mml( + '\\let\\save\\sin\\let\\sin\\cos\\let\\cos\\tan\\let\\tan\\save\\sin(x)\\cos(x)\\tan(x)' + ), + ` + cos + + ( + x + ) + tan + + ( + x + ) + sin + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('Let Paren Circular', () => { + toXmlMatch( + tex2mml( + '\\let\\lp(\\let\\rp)\\let\\mp\\rp\\left\\lp \\frac{a}{b}\\middle\\mp c \\right\\rp' + ), + ` + + ( + + a + b + + + ) + + c + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Let Angle Circular', () => { + toXmlMatch( + tex2mml( + '\\let\\lp\\langle\\let\\rp\\rangle\\let\\mp\\rp\\left\\lp \\frac{a}{b}\\middle\\mp c \\right\\rp' + ), + ` + + + + a + b + + + + + c + + + ` + ); + }); + + /********************************************************************************/ + + it('Let Circular Character', () => { + toXmlMatch( + tex2mml( + '\\let\\a a\\let\\b b\\a \\b\\let\\c\\a\\let\\a c\\c \\a\\let\\d=\\c\\let\\c\\b\\d \\c' + ), + ` + a + b + a + c + a + b + ` + ); + }); + + /********************************************************************************/ + + it('Let Self', () => { + expectTexError('\\let\\x\\x \\x') + .toBe('Undefined control sequence \\x'); + }); + + /********************************************************************************/ + + it('Let Overwrite Sqrt Choose', () => { + toXmlMatch( + tex2mml('\\let\\sqrt\\choose a\\sqrt b'), + ` + + + ( + + + a + b + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Def Optional Brace', () => { + toXmlMatch( + tex2mml('\\def\\bar[#1]#2{#1 + #2}\\bar[{a}]{b}'), + ` + a + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Def Options CS', () => { + toXmlMatch( + tex2mml('\\def\\bar[#1]#2{#1 + #2}\\bar[\\sqrt{2}]{b}'), + ` + + 2 + + + + b + ` + ); + }); + + /********************************************************************************/ + + it('Def Template Matching', () => { + toXmlMatch( + tex2mml('\\def\\ending{+}\\def\\test#1\\end{[#1]} \\test a\\ending b\\end'), + ` + [ + a + + + b + ] + ` + ); + }); + + /********************************************************************************/ + + it('Def Template Brace Removal', () => { + toXmlMatch( + tex2mml('\\def\\test#1\\end{\\text{#1}} \\test{a b}\\end'), + ` + a b + ` + ); + }); + + /********************************************************************************/ + + it('Def Template Brace Retention', () => { + toXmlMatch( + tex2mml('\\def\\test#1\\end{\\text{#1}} \\test{a}{b}\\end'), + ` + {a}{b} + ` + ); + }); + + /********************************************************************************/ + + it('Def Hash Replacement', () => { + toXmlMatch( + tex2mml('\\def\\x#1{\\def\\y##1#1{[##1]}\\y} \\x\\X abc \\X'), + ` + [ + a + b + c + ] + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Newcommand Color v2', () => { + beforeEach(() => setupTex(['base', 'newcommand', 'colorv2'])); + + /********************************************************************************/ + + it('Newenvironment Empty', () => { + toXmlMatch( + tex2mml( + '\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\begin{myHeartEnv}\\end{myHeartEnv}' + ), + ` + + + + + + + +  forever + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Content', () => { + toXmlMatch( + tex2mml( + '\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\begin{myHeartEnv} 2+3\\end{myHeartEnv}' + ), + ` + + + + + + + + 2 + + + 3 +  forever + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Nested Double', () => { + toXmlMatch( + tex2mml( + '\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\end{yourHeartEnv}\\end{myHeartEnv}' + ), + ` + + + + + + + + + + + + + + + a +  never +  forever + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Nested Double 2', () => { + toXmlMatch( + tex2mml( + '\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\newenvironment{theirHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\end{yourHeartEnv}\\begin{theirHeartEnv}b\\end{theirHeartEnv}\\end{myHeartEnv}' + ), + ` + + + + + + + + + + + + + + + a +  never + + + + + + + + b +  never +  forever + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Nested Triple', () => { + toXmlMatch( + tex2mml( + '\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\newenvironment{theirHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\begin{theirHeartEnv}b\\end{theirHeartEnv}\\end{yourHeartEnv}\\end{myHeartEnv}' + ), + ` + + + + + + + + + + + + + + + a + + + + + + + + b +  never +  never +  forever + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Nested Triple Text', () => { + toXmlMatch( + tex2mml( + '\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\newenvironment{theirHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\begin{theirHeartEnv}b\\end{theirHeartEnv}c\\end{yourHeartEnv}d\\end{myHeartEnv}' + ), + ` + + + + + + + + + + + + + + + a + + + + + + + + b +  never + c +  never + d +  forever + ` + ); + }); + + /********************************************************************************/ + + it('Newenvironment Nested Error', () => { + expectTexError( + '\\newenvironment{myHeartEnv}{\\color{purple}{\\heartsuit}\\kern-2.5pt\\color{green}{\\heartsuit}}{\\text{ forever}}\\newenvironment{yourHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\newenvironment{theirHeartEnv}{\\color{blue}{\\heartsuit}\\kern-2.5pt\\color{black}{\\heartsuit}}{\\text{ never}}\\begin{myHeartEnv}\\begin{yourHeartEnv}a\\begin{theirHeartEnv}b\\end{yourHeartEnv}\\end{theirHeartEnv}\\end{myHeartEnv}' + ) + .toBe('\\begin{theirHeartEnv} ended with \\end{yourHeartEnv}'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Newcommand Ams', () => { + beforeEach(() => setupTex(['base', 'newcommand', 'ams'])); + + /********************************************************************************/ + + it('Newenvironment Align', () => { + expectTexError( + '\\newenvironment{proof}{\\textbf{Proof:}}{\\begin{align} \\blacksquare \\end{align}}\\begin{proof}a=b\\end{proof}' + ).toBe('Erroneous nesting of equation structures'); + }); + + /********************************************************************************/ + + it('Newenvironment Align End', () => { + expectTexError( + '\\newenvironment{proof}{\\begin{align}\\textbf{Proof:}}{\\end{align}}\\begin{proof}a=b\\end{proof}' + ).toBe('Erroneous nesting of equation structures'); + }); + + /********************************************************************************/ + + it('Newenvironment Align Split', () => { + expectTexError( + '\\newenvironment{proof}{\\begin{align}\\textbf{Proof:}&}{ \\begin{split} 5 \\end{split}&& \\blacksquare\\end{align}}\\begin{proof}a&=b\\end{proof}' + ).toBe('Erroneous nesting of equation structures'); + }); + + /********************************************************************************/ + + it('Let Bar', () => { + toXmlMatch( + tex2mml('\\let\\b\\lvert\\let\\lvert\\langle\\vert\\b\\lvert'), + ` + | + | + + ` + ); + }); + + /********************************************************************************/ + + it('Let Bar Stretchy', () => { + toXmlMatch( + tex2mml('\\let\\b\\lvert\\let\\lvert\\langle\\left\\b q \\right\\lvert'), + ` + + | + q + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('NewcommandError', () => { + beforeEach(() => setupTex(['base', 'newcommand'])); + + /********************************************************************************/ + + it('No Sequence', () => { + expectTexError('\\def\\bar[#1]#3{}') + .toBe('Parameters for \\bar must be numbered sequentially'); + }); + + /********************************************************************************/ + + it('No CS', () => { + expectTexError('\\def{\\bar}[#1]#2{}') + .toBe('\\def must be followed by a control sequence'); + }); + + /********************************************************************************/ + + it('Illegal Hash', () => { + expectTexError('\\def\\bar[##1]#2{#1}') + .toBe('Illegal use of # in template for \\bar'); + }); + + /********************************************************************************/ + + it('No Replacement', () => { + expectTexError('\\def\\bar[#1]#2') + .toBe('Missing replacement string for definition of \\def'); + }); + + /********************************************************************************/ + + it('Runaway Argument', () => { + expectTexError('\\def\\bar[#1]#2{}\\bar[') + .toBe('Runaway argument for \\bar?'); + }); + + /********************************************************************************/ + + it('Illegal CS', () => { + expectTexError('\\newcommand{\\11}{a}') + .toBe('Illegal control sequence name for \\newcommand'); + }); + + /********************************************************************************/ + + it('Illegal Parameter Number', () => { + expectTexError('\\newenvironment{hh}[a]{}{}') + .toBe('Illegal number of parameters specified in \\newenvironment'); + }); + + /********************************************************************************/ + + it('Let Undefined CS', () => { + expectTexError('\\let\\aa\\bb \\aa') + .toBe('Undefined control sequence \\aa'); + }); + + /********************************************************************************/ + + it('Missing Arguments', () => { + expectTexError('\\def\\bar[#1]#2#3{c + c}\\bar') + .toBe('Use of \\bar doesn\'t match its definition'); + }); + + /********************************************************************************/ + + it('Single Let Error', () => { + expectTexError('\\let\\aa\\textbf\\let\\bb\\aa\\aa') + .toBe('Missing argument for \\aa'); + }); + + /********************************************************************************/ + + it('Double Let Error', () => { + expectTexError('\\let\\aa\\textbf\\let\\bb\\aa\\bb') + .toBe('Missing argument for \\bb'); + }); + + /********************************************************************************/ + + it('Triple Let Error', () => { + expectTexError('\\let\\aa\\textbf\\let\\bb\\aa\\let\\textbf\\sqrt\\textbf[1]') + .toBe('Missing argument for \\textbf'); + }); + + /********************************************************************************/ + + it('Illegal Argument Number', () => { + expectTexError('\\newcommand{\\foo}[a]{#1 + #2}') + .toBe('Illegal number of parameters specified in \\newcommand'); + }); + + /********************************************************************************/ + + it('Optional Brace Error', () => { + expectTexError('\\def\\bar[{#1}]#2{#1 + #2}') + .toBe("You can't use 'macro parameter character #' in math mode"); + }); + + /********************************************************************************/ + + it('Missing End Error', () => { + expectTexError('\\newenvironment{env}{aa}{bb}\\begin{env}cc') + .toBe('Missing \\end{env}'); + }); + + /********************************************************************************/ + + it('Hash Error', () => { + expectTexError('\\def\\x#1{a #1 b #c} \\x{a}') + .toBe('Illegal macro parameter reference'); + }); + + /********************************************************************************/ + + it('Recursive Macro', () => { + expectTexError('\\def\\x{\\x} \\x') + .toBe('MathJax maximum macro substitution count exceeded; is here a recursive macro call?'); + }); + + /********************************************************************************/ + + it('Recursive Environment', () => { + expectTexError('\\newenvironment{error}{\\begin{error}}{\\end{error}} \\begin{error}\\end{error}') + .toBe('MathJax maximum substitution count exceeded; is there a recursive latex environment?'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Newcommand Overrides', () => { + beforeEach(() => setupTex(['base', 'newcommand'])); + + /********************************************************************************/ + + it('Let def macro be undefined', () => { + expectTexError('\\def\\test{error} \\let\\test=\\undefined \\test') + .toBe('Undefined control sequence \\test'); + }); + + /********************************************************************************/ + + it('Let existing macro be undefined', () => { + expectTexError('\\let\\sqrt=\\undefined \\sqrt{x}') + .toBe('Undefined control sequence \\sqrt'); + }); + + /********************************************************************************/ + + it('Let existing delimiter be undefined', () => { + expectTexError('\\let\\|=\\undefined \\left\\| X \\right\\|') + .toBe('Missing or unrecognized delimiter for \\left'); + }); + + /********************************************************************************/ + + it('Let after def of existing macro be undefined', () => { + expectTexError('\\def\\sqrt{X} \\let\\sqrt=\\undefined \\sqrt{x}') + .toBe('Undefined control sequence \\sqrt'); + }); + + /********************************************************************************/ + + it('Def overrides let delimiter', () => { + expectTexError('\\let\\test=\\| \\def\\test{x} \\left\\test X \\right\\test') + .toBe('Missing or unrecognized delimiter for \\left'); + }); + + /********************************************************************************/ + + it('Def overrides let delimiter as macro', () => { + toXmlMatch( + tex2mml('\\let\\test=\\| \\def\\test{x} \\test'), + ` + x + ` + ); + }); + + /********************************************************************************/ + + it('Def overrides existing delimiter', () => { + expectTexError('\\def\\|{x} \\left\\| X \\right\\|') + .toBe('Missing or unrecognized delimiter for \\left'); + }); + + /********************************************************************************/ + + it('Def overrides existing delimiter as macro', () => { + toXmlMatch( + tex2mml('\\def\\|{x} \\|'), + ` + x + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides def macro', () => { + toXmlMatch( + tex2mml('\\def\\test{x} \\let\\test=\\| \\test X \\test'), + ` + + X + + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides def macro as delimiter', () => { + toXmlMatch( + tex2mml('\\def\\test{x} \\let\\test=\\| \\left\\test X \\right\\test'), + ` + + + X + + + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides existing macro', () => { + toXmlMatch( + tex2mml('\\let\\sqrt=\\| \\sqrt X'), + ` + + X + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides existing macro as delimiter', () => { + toXmlMatch( + tex2mml('\\let\\sqrt=\\| \\left\\sqrt X \\right\\sqrt'), + ` + + + X + + + ` + ); + }); + + /********************************************************************************/ + + it('Let overrides delimiter', () => { + expectTexError('\\let\\|=\\sqrt \\left\\| X \\right\\|') + .toBe('Missing or unrecognized delimiter for \\left'); + }); + + /********************************************************************************/ + + it('Let overrides delimiter as macro', () => { + toXmlMatch( + tex2mml('\\let\\|=\\sqrt \\| X'), + ` + + X + + ` + ); + }); + + /********************************************************************************/ + + it('Let of character macro overrides delimiter', () => { + expectTexError('\\let\\|=\\alpha \\left\\| X \\right\\|') + .toBe('Missing or unrecognized delimiter for \\left'); + }); + + /********************************************************************************/ + + it('Let of character creates delimiter', () => { + toXmlMatch( + tex2mml('\\let\\test=< \\left\\test X \\right\\test'), + ` + + + X + + + ` + ); + }); + + /********************************************************************************/ + + it('Let of character overrides def', () => { + toXmlMatch( + tex2mml('\\def\\test{X}\\let\\test=< \\test'), + ` + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Nested Environments', () => { + beforeEach(() => setupTex(['base', 'ams', 'newcommand'])); + + /********************************************************************************/ + + it('Newenvironment with Begin', () => { + toXmlMatch( + tex2mml( + [ + '\\newenvironment{boxed}{\\begin{array}{|c|c|}\\hline}{\\\\\\hline\\end{array}}', + '\\begin{boxed}a&b\\\\c&d\\end{boxed}' + ].join('') + ), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Environments Nested', () => { + toXmlMatch( + tex2mml( + [ + '\\newenvironment{boxed}{\\begin{array}{|c|c|}\\hline}{\\\\\\hline\\end{array}}', + '\\begin{boxed}\\begin{boxed}a&b\\\\c&d\\end{boxed} & X \\\end{boxed}' + ].join('') + ), + ` + + + + + + + a + + + b + + + + + c + + + d + + + + + + X + + + + ` + ); + }); + + /********************************************************************************/ + + it('Environments Intermixed', () => { + toXmlMatch( + tex2mml( + [ + '\\newenvironment{a}{\\begin{b}}{\\end{b}}', + '\\newenvironment{b}{x}{y}', + '\\begin{a} ... \\end{b}\\begin{b}\\end{a}' + ].join('') + ), + ` + x + . + . + . + y + x + y + ` + ); + }); + + /********************************************************************************/ + + it('Nested Begins', () => { + toXmlMatch( + tex2mml('\\newenvironment{a}{x}{y}\\newenvironment{b}{p}{q}\\begin{a}\\begin{b}X\\end{b}\\end{a}'), + ` + x + p + X + q + y + ` + ); + }); + + /********************************************************************************/ + + it('Dangling End', () => { + expectTexError('\\newenvironment{a}{x}{y\\end{a}}\\begin{a} ... \\end{a}') + .toBe('Missing \\begin{a} or extra \\end{a}'); + }); + + /********************************************************************************/ + + it('Nested Dangling End', () => { + expectTexError( + '\\newenvironment{a}{\\begin{b}}{\\end{b}}\\newenvironment{b}{x}{y\\end{b}}\\begin{a}X\\end{a}') + .toBe('\\begin{a} ended with \\end{b}'); + }); + + /********************************************************************************/ + + it('Badly Nested Begins', () => { + expectTexError( + '\\newenvironment{a}{x}{y}\\newenvironment{b}{p}{q}\\begin{a}\\begin{b} ... \\end{a}\\end{b}' + ).toBe('\\begin{b} ended with \\end{a}'); + }); + + /********************************************************************************/ + + it('Ended by Wrong Environment', () => { + expectTexError('\\newenvironment{a}{x}{y}\\begin{a} X \\end{cases}') + .toBe('\\begin{a} ended with \\end{cases}'); + }); + + /********************************************************************************/ + + it('Unbalanced Ends 1', () => { + expectTexError( + '\\newenvironment{a}{a}{b\\end{a}}\\newenvironment{b}{x}{y}\\begin{a}\\begin{b}...\\end{b}\\end{a}' + ).toBe('Missing \\begin{a} or extra \\end{a}'); + }); + + /********************************************************************************/ + + it('Unbalanced Ends 2', () => { + expectTexError( + '\\newenvironment{a}{a}{b\\end{a}}\\newenvironment{b}{x}{y}\\begin{b}\\begin{a}...\\end{a}\\end{b}' + ).toBe('\\begin{b} ended with \\end{a}'); + }); + + /********************************************************************************/ + + it('Triple Nesting', () => { + expectTexError( + [ + '\\newenvironment{c}{x}{\\end{a}y}', + '\\newenvironment{b}{begin{c}x}{\\end{c}y}', + '\\newenvironment{a}{\\begin{b}x}{\\end{b}y}', + '\\begin{a} ... ' + ].join('') + ).toBe('Missing \\end{b}'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('newcommand')); diff --git a/testsuite/tests/input/tex/Noerrors.test.ts b/testsuite/tests/input/tex/Noerrors.test.ts new file mode 100644 index 000000000..dfc87d3d3 --- /dev/null +++ b/testsuite/tests/input/tex/Noerrors.test.ts @@ -0,0 +1,747 @@ +import { beforeEach, describe, it } from '@jest/globals'; +import { toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/noerrors/NoErrorsConfiguration'; + +beforeEach(() => setupTex(['base', 'noerrors'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('NoError', () => { + + /********************************************************************************/ + + it('Ampersand-error', () => { + toXmlMatch( + tex2mml('&'), + ` + + & + + ` + ); + }); + + /********************************************************************************/ + + it('Argument-error', () => { + toXmlMatch( + tex2mml('\\frac{b}'), + ` + + \\frac{b} + + ` + ); + }); + + /********************************************************************************/ + + it('Undefined-CS', () => { + toXmlMatch( + tex2mml('\\nonsense'), + ` + + \\nonsense + + ` + ); + }); + + /********************************************************************************/ + + it('Undefined-Env', () => { + toXmlMatch( + tex2mml('\\begin{nonsense} a \\end{nonsense}'), + ` + + \\begin{nonsense} a \\end{nonsense} + + ` + ); + }); + + /********************************************************************************/ + + it('Double-super-error', () => { + toXmlMatch( + tex2mml('x^2^3'), + ` + + x^2^3 + + ` + ); + }); + + /********************************************************************************/ + + it('Double-over-error', () => { + toXmlMatch( + tex2mml('\\sum^2^3'), + ` + + \\sum^2^3 + + ` + ); + }); + + /********************************************************************************/ + + it('Limits Error', () => { + toXmlMatch( + tex2mml('+\\limits^2'), + ` + + +\\limits^2 + + ` + ); + }); + + /********************************************************************************/ + + it('Double sub error', () => { + toXmlMatch( + tex2mml('x_2_3'), + ` + + x_2_3 + + ` + ); + }); + + /********************************************************************************/ + + it('Double under error', () => { + toXmlMatch( + tex2mml('\\sum_2_3'), + ` + + \\sum_2_3 + + ` + ); + }); + + /********************************************************************************/ + + it('Brace Superscript Error', () => { + toXmlMatch( + tex2mml("x'^'"), + ` + + x\'^\' + + ` + ); + }); + + /********************************************************************************/ + + it('Double Prime Error', () => { + toXmlMatch( + tex2mml("x^\\prime'"), + ` + + x^\\prime\' + + ` + ); + }); + + /********************************************************************************/ + + it('Hash Error', () => { + toXmlMatch( + tex2mml('#'), + ` + + # + + ` + ); + }); + + /********************************************************************************/ + + it('Missing Right', () => { + toXmlMatch( + tex2mml('\\left(\\middle|'), + ` + + \\left(\\middle| + + ` + ); + }); + + /********************************************************************************/ + + it('Orphan Middle', () => { + toXmlMatch( + tex2mml('\\middle|'), + ` + + \\middle| + + ` + ); + }); + + /********************************************************************************/ + + it('Middle with Right', () => { + toXmlMatch( + tex2mml('\\middle|\\right)'), + ` + + \\middle|\\right) + + ` + ); + }); + + /********************************************************************************/ + + it('Misplaced Move Root', () => { + toXmlMatch( + tex2mml('\\uproot{2}\\sqrt[3]{a}'), + ` + + \\uproot{2}\\sqrt[3]{a} + + ` + ); + }); + + /********************************************************************************/ + + it('Multiple Move Root', () => { + toXmlMatch( + tex2mml('\\sqrt[\\uproot{-2}\\uproot{2}\\beta]{k}'), + ` + + \\sqrt[\\uproot{-2}\\uproot{2}\\beta]{k} + + ` + ); + }); + + /********************************************************************************/ + + it('Incorrect Move Root', () => { + toXmlMatch( + tex2mml('\\sqrt[\\uproot-2.5\\beta]{k}'), + ` + + \\sqrt[\\uproot-2.5\\beta]{k} + + ` + ); + }); + + /********************************************************************************/ + + it('Double Over', () => { + toXmlMatch( + tex2mml('1 \\over 2 \\over 3'), + ` + + 1 \\over 2 \\over 3 + + ` + ); + }); + + /********************************************************************************/ + + it('Token Illegal Type', () => { + toXmlMatch( + tex2mml('\\mmlToken{mk}[]{}'), + ` + + \\mmlToken{mk}[]{} + + ` + ); + }); + + /********************************************************************************/ + + it('Token Wrong Type', () => { + toXmlMatch( + tex2mml('\\mmlToken{mrow}[]{}'), + ` + + \\mmlToken{mrow}[]{} + + ` + ); + }); + + /********************************************************************************/ + + it('Token Invalid Attribute', () => { + toXmlMatch( + tex2mml('\\mmlToken{mi}[m1=true]{}'), + ` + + \\mmlToken{mi}[m1=true]{} + + ` + ); + }); + + /********************************************************************************/ + + it('Token Unknown Attribute', () => { + toXmlMatch( + tex2mml('\\mmlToken{mo}[nothing="something"]{}'), + ` + + \\mmlToken{mo}[nothing="something"]{} + + ` + ); + }); + + /********************************************************************************/ + + it('Token Wrong Attribute', () => { + toXmlMatch( + tex2mml('\\mmlToken{mi}[movablelimit=true]{}'), + ` + + \\mmlToken{mi}[movablelimit=true]{} + + ` + ); + }); + + /********************************************************************************/ + + it('MissingBeginExtraEnd', () => { + toXmlMatch( + tex2mml('\\end{array}'), + ` + + \\end{array} + + ` + ); + }); + + /********************************************************************************/ + + it('ExtraCloseMissingOpen', () => { + toXmlMatch( + tex2mml('x}'), + ` + + x} + + ` + ); + }); + + /********************************************************************************/ + + it('MissingLeftExtraRight', () => { + toXmlMatch( + tex2mml('x\\right\\}'), + ` + + x\\right\\} + + ` + ); + }); + + /********************************************************************************/ + + it('ExtraOpenMissingClose', () => { + toXmlMatch( + tex2mml('{x'), + ` + + {x + + ` + ); + }); + + /********************************************************************************/ + + it('MissingScript Sub', () => { + toXmlMatch( + tex2mml('x_'), + ` + + x_ + + ` + ); + }); + + /********************************************************************************/ + + it('MissingScript Sup', () => { + toXmlMatch( + tex2mml('x^'), + ` + + x^ + + ` + ); + }); + + /********************************************************************************/ + + it('MissingOpenForSup', () => { + toXmlMatch( + tex2mml('x^^'), + ` + + x^^ + + ` + ); + }); + + /********************************************************************************/ + + it('MissingOpenForSub', () => { + toXmlMatch( + tex2mml('x__'), + ` + + x__ + + ` + ); + }); + + /********************************************************************************/ + + it('ExtraLeftMissingRight', () => { + toXmlMatch( + tex2mml('\\left\\{x'), + ` + + \\left\\{x + + ` + ); + }); + + /********************************************************************************/ + + it('Misplaced Cr', () => { + toXmlMatch( + tex2mml('a\\cr b'), + ` + + a\\cr b + + ` + ); + }); + + /********************************************************************************/ + + it('Dimension Error', () => { + toXmlMatch( + tex2mml('a\\\\[abc] b'), + ` + + a\\\\[abc] b + + ` + ); + }); + + /********************************************************************************/ + + it('MissingArgFor', () => { + toXmlMatch( + tex2mml('\\sqrt'), + ` + + \\sqrt + + ` + ); + }); + + /********************************************************************************/ + + it('ExtraCloseMissingOpen 2', () => { + toXmlMatch( + tex2mml('\\sqrt}'), + ` + + \\sqrt} + + ` + ); + }); + + /********************************************************************************/ + + it('MissingCloseBrace', () => { + toXmlMatch( + tex2mml('\\sqrt{'), + ` + + \\sqrt{ + + ` + ); + }); + + /********************************************************************************/ + + it('ExtraCloseLooking1', () => { + toXmlMatch( + tex2mml('\\sqrt[3}'), + ` + + \\sqrt[3} + + ` + ); + }); + + /********************************************************************************/ + + it('MissingCloseBracket', () => { + toXmlMatch( + tex2mml('\\sqrt[3{x}'), + ` + + \\sqrt[3{x} + + ` + ); + }); + + /********************************************************************************/ + + it('MissingOrUnrecognizedDelim1', () => { + toXmlMatch( + tex2mml('\\left\\alpha b'), + ` + + \\left\\alpha b + + ` + ); + }); + + /********************************************************************************/ + + it('MissingOrUnrecognizedDelim2', () => { + toXmlMatch( + tex2mml('\\left( b\\right'), + ` + + \\left( b\\right + + ` + ); + }); + + /********************************************************************************/ + + it('MissingDimOrUnits', () => { + toXmlMatch( + tex2mml('\\rule{}'), + ` + + \\rule{} + + ` + ); + }); + + /********************************************************************************/ + + it('TokenNotFoundForCommand', () => { + toXmlMatch( + tex2mml('\\root {3] \\of 5'), + ` + + \\root {3] \\of 5 + + ` + ); + }); + + /********************************************************************************/ + + it('ExtraCloseLooking2', () => { + toXmlMatch( + tex2mml('\\root [3} \\of 5 '), + ` + + \\root [3} \\of 5 + + ` + ); + }); + + /********************************************************************************/ + + it('MissingOrUnrecognizedDelim', () => { + toXmlMatch( + tex2mml('\\genfrac{(}{a}{}{2}{1}{2}'), + ` + + \\genfrac{(}{a}{}{2}{1}{2} + + ` + ); + }); + + /********************************************************************************/ + + it('ErroneousNestingEq', () => { + toXmlMatch( + tex2mml( + '\\begin{equation}\\begin{eqnarray}\\end{eqnarray}\\end{equation}' + ), + ` + + \\begin{equation}\\begin{eqnarray}\\end{eqnarray}\\end{equation} + + ` + ); + }); + + /********************************************************************************/ + + it('ExtraAlignTab', () => { + toXmlMatch( + tex2mml('\\cases{b & l & k}'), + ` + + \\cases{b & l & k} + + ` + ); + }); + + /********************************************************************************/ + + it('Misplaced hline', () => { + toXmlMatch( + tex2mml('\\hline'), + ` + + \\hline + + ` + ); + }); + + /********************************************************************************/ + + it('UnsupportedHFill', () => { + toXmlMatch( + tex2mml('a\\hfill b'), + ` + + a\\hfill b + + ` + ); + }); + + /********************************************************************************/ + + it('InvalidEnv', () => { + toXmlMatch( + tex2mml('\\begin{\\ff}kk\\end{\\ff}'), + ` + + \\begin{\\ff}kk\\end{\\ff} + + ` + ); + }); + + /********************************************************************************/ + + it('EnvBadEnd', () => { + toXmlMatch( + tex2mml('\\begin{equation}a\\end{array}'), + ` + + \\begin{equation}a\\end{array} + + ` + ); + }); + + /********************************************************************************/ + + it('EnvMissingEnd Array', () => { + toXmlMatch( + tex2mml('\\begin{array}a'), + ` + + \\begin{array}a + + ` + ); + }); + + /********************************************************************************/ + + it('MissingBoxFor', () => { + toXmlMatch( + tex2mml('\\raise{2pt}'), + ` + + \\raise{2pt} + + ` + ); + }); + + /********************************************************************************/ + + it('MissingCloseBrace2', () => { + toXmlMatch( + tex2mml('\\begin{array}{c'), + ` + + \\begin{array}{c + + ` + ); + }); + + /********************************************************************************/ + + it('EnvMissingEnd Equation', () => { + toXmlMatch( + tex2mml('\\begin{equation}a'), + ` + + \\begin{equation}a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/input/tex/Noundefined.test.ts b/testsuite/tests/input/tex/Noundefined.test.ts new file mode 100644 index 000000000..18f5ea74a --- /dev/null +++ b/testsuite/tests/input/tex/Noundefined.test.ts @@ -0,0 +1,41 @@ +import { beforeEach, describe, it } from '@jest/globals'; +import { toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/noundefined/NoUndefinedConfiguration'; + +beforeEach(() => setupTex(['base', 'noundefined'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Noundefined', () => { + + /********************************************************************************/ + + it('Noundefined Single', () => { + toXmlMatch( + tex2mml('\\a'), + ` + \\a + ` + ); + }); + + /********************************************************************************/ + + it('Noundefined Context', () => { + toXmlMatch( + tex2mml('a\\b c'), + ` + a + \\b + c + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/input/tex/Physics.test.ts b/testsuite/tests/input/tex/Physics.test.ts new file mode 100644 index 000000000..31b928dfc --- /dev/null +++ b/testsuite/tests/input/tex/Physics.test.ts @@ -0,0 +1,16199 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/physics/PhysicsConfiguration'; + + +beforeEach(() => setupTex(['base', 'physics'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics1_0', () => { + + /********************************************************************************/ + + it('Quantities_Quantities_0', () => { + toXmlMatch( + tex2mml('\\quantity'), + ` + + ( + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_1', () => { + toXmlMatch( + tex2mml('\\quantity a'), + ` + + ( + + ) + + a + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_2', () => { + expectTexError('\\quantity\\bigg a') + .toBe('Missing or unrecognized delimiter for \\bigg'); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_3', () => { + toXmlMatch( + tex2mml('\\quantity[c]'), + ` + + [ + c + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_4', () => { + toXmlMatch( + tex2mml('\\quantity\\sin'), + ` + + ( + + ) + + sin + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_5', () => { + expectTexError('\\qty\\Bigg ab') + .toBe('Missing or unrecognized delimiter for \\Bigg'); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_6', () => { + expectTexError('\\quantity\\bigg\\sin') + .toBe('Missing or unrecognized delimiter for \\bigg'); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_7', () => { + toXmlMatch( + tex2mml('\\qty(a)'), + ` + + ( + a + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_8', () => { + toXmlMatch( + tex2mml('\\qty(\\frac{a}{\\frac{c}{b}})'), + ` + + ( + + a + + c + b + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_9', () => { + toXmlMatch( + tex2mml('\\qty[\\frac{a}{\\frac{c}{b}}]'), + ` + + [ + + a + + c + b + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Quantities_10', () => { + toXmlMatch( + tex2mml('\\qty\\Bigg{a}'), + ` + + { + + a + + } + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics1_1', () => { + + /********************************************************************************/ + + it('Quantities_Empty_0', () => { + toXmlMatch( + tex2mml('\\qty\\big{}[]'), + ` + + { + + + } + + [ + ] + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_1', () => { + toXmlMatch( + tex2mml('\\qty\\Bigg{}[]'), + ` + + { + + + } + + [ + ] + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_2', () => { + toXmlMatch( + tex2mml('\\qty\\Bigg{}\\Bigg[]'), + ` + + { + + + } + + + [ + + ] + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_3', () => { + toXmlMatch( + tex2mml('\\qty\\Bigg{}\\qty\\Bigg[]'), + ` + + { + + + } + + + + [ + + + ] + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_4', () => { + toXmlMatch( + tex2mml('\\Bigg[]'), + ` + + [ + + ] + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_5', () => { + toXmlMatch( + tex2mml('\\Bigg[ \\times \\Bigg]'), + ` + + [ + + × + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_6', () => { + toXmlMatch( + tex2mml('\\Biggl[ \\times \\Biggr]'), + ` + + [ + + × + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_7', () => { + toXmlMatch( + tex2mml('\\qty\\Bigg[\\times]'), + ` + + + [ + + × + + ] + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_8', () => { + toXmlMatch( + tex2mml('\\qty\\Bigg{\\times}'), + ` + + { + + × + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_9', () => { + toXmlMatch( + tex2mml('\\qty(\\frac{a}{b})\\langle\\rangle'), + ` + + ( + + a + b + + ) + + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Empty_10', () => { + toXmlMatch( + tex2mml('\\qty<\\frac{a}{b}>\\langle\\rangle'), + ` + + ( + + ) + + < + + a + b + + > + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics1_2', () => { + + /********************************************************************************/ + + it('Quantities_Big_0', () => { + toXmlMatch( + tex2mml('\\quantity\\big(\\frac{a}{b})'), + ` + + + ( + + + a + b + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_1', () => { + toXmlMatch( + tex2mml('\\quantity\\bigg(\\frac{a}{b})'), + ` + + + ( + + + a + b + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_2', () => { + toXmlMatch( + tex2mml('\\quantity\\Big(\\frac{a}{b})'), + ` + + + ( + + + a + b + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_3', () => { + toXmlMatch( + tex2mml('\\quantity\\Bigg(\\frac{a}{b})'), + ` + + + ( + + + a + b + + + ) + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_4', () => { + toXmlMatch( + tex2mml('\\pqty\\Bigg{} '), + ` + + ( + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_5', () => { + toXmlMatch( + tex2mml('\\pqty{\\frac{a}{b}}'), + ` + + ( + + a + b + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_6', () => { + toXmlMatch( + tex2mml('\\pqty\\Bigg{\\frac{a}{b}}'), + ` + + ( + + + a + b + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_7', () => { + toXmlMatch( + tex2mml('\\pqty\\big{\\frac{a}{b}}'), + ` + + ( + + + a + b + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_8', () => { + toXmlMatch( + tex2mml('\\Bqty{\\frac{a}{b}}'), + ` + + { + + a + b + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_9', () => { + toXmlMatch( + tex2mml('\\Bqty\\Bigg{\\frac{a}{b}}'), + ` + + { + + + a + b + + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_10', () => { + toXmlMatch( + tex2mml('\\Bqty\\big{\\frac{a}{b}}'), + ` + + { + + + a + b + + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Big_11', () => { + toXmlMatch( + tex2mml('\\quantity*\\Bigg(\\frac{a}{b})'), + ` + + ( + + ) + + + + ( + + + a + b + + ) + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics1_3', () => { + + /********************************************************************************/ + + it('Quantities_Absval_0', () => { + toXmlMatch( + tex2mml('\\absolutevalue\\Bigg{\\frac{a}{b}}'), + ` + + | + + + a + b + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Absval_1', () => { + toXmlMatch( + tex2mml('\\absolutevalue{}'), + ` + + | + | + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Absval_2', () => { + toXmlMatch( + tex2mml('\\abs\\Bigg{\\frac{a}{b}}'), + ` + + | + + + a + b + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Absval_3', () => { + toXmlMatch( + tex2mml('\\abs*\\Bigg{\\frac{a}{b}}'), + ` + | + + a + b + + | + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Absval_4', () => { + toXmlMatch( + tex2mml('\\norm\\Bigg{\\frac{a}{b}}'), + ` + + + + + a + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Absval_5', () => { + toXmlMatch( + tex2mml('\\norm*\\Bigg{\\frac{a}{b}}'), + ` + + + a + b + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Absval_6', () => { + toXmlMatch( + tex2mml('\\norm{}'), + ` + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics1_4', () => { + + /********************************************************************************/ + + it('Quantities_Eval_0', () => { + toXmlMatch( + tex2mml('\\evaluated{x}_0^\\infty'), + ` + + + + x + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_1', () => { + toXmlMatch( + tex2mml('\\eval{x}_0^\\infty'), + ` + + + + x + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_2', () => { + toXmlMatch( + tex2mml('\\eval*{x}_0^\\infty'), + ` + + + + + + x + + + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_3', () => { + toXmlMatch( + tex2mml('\\eval[x|_0^\\infty'), + ` + + + [ + x + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_4', () => { + toXmlMatch( + tex2mml('\\eval*(x|_0^\\infty'), + ` + + + ( + + + x + + + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_5', () => { + toXmlMatch( + tex2mml('\\eval*{\\frac{A}{\\frac{A}{\\int x}}}_0^\\infty'), + ` + + + + + + + A + + A + + + x + + + + + + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_6', () => { + toXmlMatch( + tex2mml('\\eval{\\frac{A}{\\frac{A}{\\int x}}}_0^\\infty'), + ` + + + + + A + + A + + + x + + + + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_7', () => { + toXmlMatch( + tex2mml('\\eval*(\\frac{A}{\\frac{A}{\\int x}}|_0^\\infty'), + ` + + + ( + + + + A + + A + + + x + + + + + + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_8', () => { + toXmlMatch( + tex2mml('\\eval(\\frac{A}{\\frac{A}{\\int x}}|_0^\\infty'), + ` + + + ( + + A + + A + + + x + + + + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_9', () => { + toXmlMatch( + tex2mml('\\eval*[\\frac{A}{\\frac{A}{\\int x}}|_0^\\infty'), + ` + + + [ + + + + A + + A + + + x + + + + + + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_10', () => { + toXmlMatch( + tex2mml('\\eval[\\frac{A}{\\frac{A}{\\int x}}|_0^\\infty'), + ` + + + [ + + A + + A + + + x + + + + + + + + + + + | + + 0 + + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Eval_11', () => { + toXmlMatch( + tex2mml('\\eval_0^\\infty'), + ` + + + + + + + + + + + | + + 0 + + + ` + ); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics1_5', () => { + + /********************************************************************************/ + + it('Quantities_Order_0', () => { + toXmlMatch( + tex2mml('\\order{}'), + ` + O + + + ( + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Order_1', () => { + toXmlMatch( + tex2mml('\\order{x^2}'), + ` + O + + + ( + + x + 2 + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Order_2', () => { + toXmlMatch( + tex2mml('\\order\\Bigg{x^2}'), + ` + O + + + ( + + + x + 2 + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Order_3', () => { + toXmlMatch( + tex2mml('\\order{\\frac{A}{\\frac{A}{\\int x}}}'), + ` + O + + + ( + + A + + A + + + x + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Order_4', () => { + toXmlMatch( + tex2mml('\\order*{\\frac{A}{\\frac{A}{\\int x}}}'), + ` + O + + ( + + A + + A + + + x + + + + ) + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics1_6', () => { + + /********************************************************************************/ + + it('Quantities_Comm_0', () => { + toXmlMatch( + tex2mml('\\comm{A}{B}'), + ` + + [ + A + , + B + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Comm_1', () => { + toXmlMatch( + tex2mml('\\comm{\\frac{A}{\\frac{A}{\\int x}}}{B}'), + ` + + [ + + A + + A + + + x + + + + , + B + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Comm_2', () => { + toXmlMatch( + tex2mml('\\comm\\Bigg{A}{B}'), + ` + + [ + + A + , + B + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Comm_3', () => { + toXmlMatch( + tex2mml('\\comm*{\\frac{A}{\\frac{A}{\\int x}}}{B}'), + ` + [ + + A + + A + + + x + + + + , + B + ] + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Comm_4', () => { + toXmlMatch( + tex2mml('\\comm*\\Bigg{\\frac{X}{Y}}{B}'), + ` + [ + + X + Y + + , + B + ] + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Comm_5', () => { + toXmlMatch( + tex2mml('\\comm{A}B'), + ` + + [ + A + , + B + ] + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics1_7', () => { + + /********************************************************************************/ + + it('Quantities_Acomm_0', () => { + toXmlMatch( + tex2mml('\\acomm{A}{B}'), + ` + + { + A + , + B + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Acomm_1', () => { + toXmlMatch( + tex2mml('\\anticommutator{A}{B}'), + ` + + { + A + , + B + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Acomm_2', () => { + toXmlMatch( + tex2mml('\\poissonbracket{A}{B}'), + ` + + { + A + , + B + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Acomm_3', () => { + toXmlMatch( + tex2mml('\\pb{A}{B}'), + ` + + { + A + , + B + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Acomm_4', () => { + toXmlMatch( + tex2mml('\\acomm{\\frac{A}{\\frac{A}{\\int x}}}{B}'), + ` + + { + + A + + A + + + x + + + + , + B + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Acomm_5', () => { + toXmlMatch( + tex2mml('\\acomm\\Bigg{A}{B}'), + ` + + { + + A + , + B + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Acomm_6', () => { + toXmlMatch( + tex2mml('\\acomm*{\\frac{A}{\\frac{A}{\\int x}}}{B}'), + ` + { + + A + + A + + + x + + + + , + B + } + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Acomm_7', () => { + toXmlMatch( + tex2mml('\\acomm{A}B'), + ` + + { + A + , + B + } + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics2_0', () => { + + /********************************************************************************/ + + it('Vector_Bold_0', () => { + toXmlMatch( + tex2mml('\\vectorbold{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_1', () => { + toXmlMatch( + tex2mml('\\vectorbold*{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_2', () => { + toXmlMatch( + tex2mml('\\vb{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_3', () => { + toXmlMatch( + tex2mml('\\vb{\\Gamma}\\Gamma'), + ` + Γ + Γ + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_4', () => { + toXmlMatch( + tex2mml('\\vb{2}2'), + ` + 2 + 2 + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_5', () => { + toXmlMatch( + tex2mml('\\vb{\\theta}'), + ` + θ + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_6', () => { + toXmlMatch( + tex2mml( + '\\vb{\\theta\\Gamma a\\delta \\frac{\\theta}{b}}\\frac{\\theta}{b}' + ), + ` + θ + Γ + a + δ + + θ + b + + + θ + b + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_7', () => { + toXmlMatch( + tex2mml('\\vb*{a}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_8', () => { + toXmlMatch( + tex2mml('\\vb*{2}'), + ` + 2 + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_9', () => { + toXmlMatch( + tex2mml('\\vb*{\\Gamma}'), + ` + Γ + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Bold_10', () => { + toXmlMatch( + tex2mml('\\vb*{\\theta}'), + ` + θ + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics2_1', () => { + + /********************************************************************************/ + + it('Vector_Special_0', () => { + toXmlMatch( + tex2mml('\\vb{\\mbox{ab}}'), + ` + + ab + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_1', () => { + toXmlMatch( + tex2mml('\\vb{B}'), + ` + B + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_2', () => { + toXmlMatch( + tex2mml('\\vb{\\mathcal{B}}'), + ` + + B + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_3', () => { + toXmlMatch( + tex2mml('\\mathcal{\\vb{B}}'), + ` + + B + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_4', () => { + toXmlMatch( + tex2mml('\\mathit{\\vb{B}}'), + ` + + B + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_5', () => { + toXmlMatch( + tex2mml('\\vb{\\mathit{B}}'), + ` + + B + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_6', () => { + toXmlMatch( + tex2mml('\\vb{\\mathit{a}b}'), + ` + + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_7', () => { + toXmlMatch( + tex2mml('\\vb{a+\\theta}{\\bf +}'), + ` + a + + + θ + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_8', () => { + toXmlMatch( + tex2mml('\\vb{\\hat{a}}'), + ` + + + a + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_9', () => { + toXmlMatch( + tex2mml('\\vb{[}['), + ` + [ + [ + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_10', () => { + toXmlMatch( + tex2mml('\\vb{\\hat{}}'), + ` + + + + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_11', () => { + toXmlMatch( + tex2mml('\\vb{=}'), + ` + = + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Special_12', () => { + toXmlMatch( + tex2mml('\\vb{\\hat{=}}\\hat{=}'), + ` + + + = + ^ + + + + + = + ^ + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics2_2', () => { + + /********************************************************************************/ + + it('Vector_Arrow_0', () => { + toXmlMatch( + tex2mml('\\va{=}'), + ` + + + = + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_1', () => { + toXmlMatch( + tex2mml('\\vectorarrow{a}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_2', () => { + toXmlMatch( + tex2mml('\\va{a}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_3', () => { + toXmlMatch( + tex2mml('\\va{\\Gamma}\\Gamma'), + ` + + + Γ + + + + Γ + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_4', () => { + toXmlMatch( + tex2mml('\\va{2}2'), + ` + + + 2 + + + + 2 + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_5', () => { + toXmlMatch( + tex2mml('\\va{\\theta}'), + ` + + + θ + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_6', () => { + toXmlMatch( + tex2mml( + '\\va{\\theta\\Gamma a\\delta \\frac{\\theta}{b}}\\frac{\\theta}{b}' + ), + ` + + + + θ + Γ + a + δ + + θ + b + + + + + + + θ + b + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_7', () => { + toXmlMatch( + tex2mml('\\vectorarrow*{a}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_8', () => { + toXmlMatch( + tex2mml('\\va*{a}'), + ` + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_9', () => { + toXmlMatch( + tex2mml('\\va*{2}'), + ` + + + 2 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_10', () => { + toXmlMatch( + tex2mml('\\va*{\\Gamma}'), + ` + + + Γ + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_11', () => { + toXmlMatch( + tex2mml('\\va*{\\theta}'), + ` + + + θ + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Arrow_12', () => { + toXmlMatch( + tex2mml('\\va{a}\\vec{a}'), + ` + + + a + + + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics2_3', () => { + + /********************************************************************************/ + + it('Vector_Unit_0', () => { + toXmlMatch( + tex2mml('\\vu{=}'), + ` + + + = + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_1', () => { + toXmlMatch( + tex2mml('\\vectorunit{a}'), + ` + + + a + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_2', () => { + toXmlMatch( + tex2mml('\\vu{a}'), + ` + + + a + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_3', () => { + toXmlMatch( + tex2mml('\\vu{\\Gamma}\\Gamma'), + ` + + + Γ + ^ + + + Γ + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_4', () => { + toXmlMatch( + tex2mml('\\vu{2}2'), + ` + + + 2 + ^ + + + 2 + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_5', () => { + toXmlMatch( + tex2mml('\\vu{\\theta}'), + ` + + + θ + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_6', () => { + toXmlMatch( + tex2mml( + '\\vu{\\theta\\Gamma a\\delta \\frac{\\theta}{b}}\\frac{\\theta}{b}' + ), + ` + + + + θ + Γ + a + δ + + θ + b + + + ^ + + + + θ + b + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_7', () => { + toXmlMatch( + tex2mml('\\vectorunit*{a}'), + ` + + + a + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_8', () => { + toXmlMatch( + tex2mml('\\vu*{a}'), + ` + + + a + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_9', () => { + toXmlMatch( + tex2mml('\\vu*{2}'), + ` + + + 2 + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_10', () => { + toXmlMatch( + tex2mml('\\vu*{\\Gamma}'), + ` + + + Γ + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_11', () => { + toXmlMatch( + tex2mml('\\vu*{\\theta}'), + ` + + + θ + ^ + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Unit_12', () => { + toXmlMatch( + tex2mml('\\vu{a}\\hat{a}'), + ` + + + a + ^ + + + + + a + ^ + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics2_4', () => { + + /********************************************************************************/ + + it('Vector_Gradient_0', () => { + toXmlMatch( + tex2mml('\\gradient '), + ` + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Gradient_1', () => { + toXmlMatch( + tex2mml('\\gradient(\\frac{a}{b})'), + ` + + + + + + + + ( + + a + b + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Gradient_2', () => { + toXmlMatch( + tex2mml('\\gradient[\\frac{a}{b}]'), + ` + + + + + + + + [ + + a + b + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Gradient_3', () => { + toXmlMatch( + tex2mml('\\gradient{\\frac{a}{b}}'), + ` + + + + + + + + a + b + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Gradient_4', () => { + toXmlMatch( + tex2mml('\\grad '), + ` + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Gradient_5', () => { + toXmlMatch( + tex2mml('\\grad(\\frac{a}{b})'), + ` + + + + + + + + ( + + a + b + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Gradient_6', () => { + toXmlMatch( + tex2mml('\\grad[\\frac{a}{b}]'), + ` + + + + + + + + [ + + a + b + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Gradient_7', () => { + toXmlMatch( + tex2mml('\\grad{\\frac{a}{b}}'), + ` + + + + + + + + a + b + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics2_5', () => { + + /********************************************************************************/ + + it('Vector_Divergence_0', () => { + toXmlMatch( + tex2mml('a\\dotproduct b \\vdot c'), + ` + a + + b + + c + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Divergence_1', () => { + toXmlMatch( + tex2mml('\\divergence{\\frac{a}{b}c}'), + ` + + + + + + + + a + b + + c + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Divergence_2', () => { + toXmlMatch( + tex2mml('\\div{\\frac{a}{b}c}'), + ` + + + + + + + + a + b + + c + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Divergence_3', () => { + toXmlMatch( + tex2mml('\\div{(\\frac{a}{b}c)}'), + ` + + + + + + + ( + + a + b + + c + ) + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Divergence_4', () => { + toXmlMatch( + tex2mml('\\div(\\frac{a}{b}c)'), + ` + + + + + + + + ( + + a + b + + c + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Divergence_5', () => { + toXmlMatch( + tex2mml('{\\bf\\nabla} \\cdot \\left(\\frac{a}{b}c\\right)'), + ` + + + + + + ( + + a + b + + c + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics2_6', () => { + + /********************************************************************************/ + + it('Vector_Curl_0', () => { + toXmlMatch( + tex2mml('\\curl '), + ` + + + + + + × + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Curl_1', () => { + toXmlMatch( + tex2mml('\\curl(\\frac{a}{b})'), + ` + + + + + + × + + ( + + a + b + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Curl_2', () => { + toXmlMatch( + tex2mml('\\curl[\\frac{a}{b}]'), + ` + + + + + + × + + [ + + a + b + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Curl_3', () => { + toXmlMatch( + tex2mml('\\curl{\\frac{a}{b}}'), + ` + + + + + + × + + a + b + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics2_7', () => { + + /********************************************************************************/ + + it('Vector_Laplace_0', () => { + toXmlMatch( + tex2mml('\\laplacian '), + ` + + + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Laplace_1', () => { + toXmlMatch( + tex2mml('\\laplacian(\\frac{a}{b})'), + ` + + + 2 + + + + ( + + a + b + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Laplace_2', () => { + toXmlMatch( + tex2mml('\\laplacian[\\frac{a}{b}]'), + ` + + + 2 + + + + [ + + a + b + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Vector_Laplace_3', () => { + toXmlMatch( + tex2mml('\\laplacian{\\frac{a}{b}}'), + ` + + + 2 + + + + a + b + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics3_0', () => { + + /********************************************************************************/ + + it('Operators_Trig_0', () => { + toXmlMatch( + tex2mml('\\sin(x)'), + ` + sin + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_1', () => { + toXmlMatch( + tex2mml('\\sinh(x)'), + ` + sinh + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_2', () => { + toXmlMatch( + tex2mml('\\arcsin(x)'), + ` + arcsin + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_3', () => { + toXmlMatch( + tex2mml('\\asin(x)'), + ` + asin + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_4', () => { + toXmlMatch( + tex2mml('\\cos(x)'), + ` + cos + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_5', () => { + toXmlMatch( + tex2mml('\\cosh(x)'), + ` + cosh + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_6', () => { + toXmlMatch( + tex2mml('\\arccos(x)'), + ` + arccos + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_7', () => { + toXmlMatch( + tex2mml('\\acos(x)'), + ` + acos + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_8', () => { + toXmlMatch( + tex2mml('\\tan(x)'), + ` + tan + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_9', () => { + toXmlMatch( + tex2mml('\\tanh(x)'), + ` + tanh + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_10', () => { + toXmlMatch( + tex2mml('\\arctan(x)'), + ` + arctan + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Trig_11', () => { + toXmlMatch( + tex2mml('\\atan(x)'), + ` + atan + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics3_1', () => { + + /********************************************************************************/ + + it('Operators_Arc_0', () => { + toXmlMatch( + tex2mml('\\csc(x)'), + ` + csc + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_1', () => { + toXmlMatch( + tex2mml('\\csch(x)'), + ` + csch + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_2', () => { + toXmlMatch( + tex2mml('\\arccsc(x)'), + ` + arccsc + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_3', () => { + toXmlMatch( + tex2mml('\\acsc(x)'), + ` + acsc + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_4', () => { + toXmlMatch( + tex2mml('\\sec(x)'), + ` + sec + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_5', () => { + toXmlMatch( + tex2mml('\\sech(x)'), + ` + sech + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_6', () => { + toXmlMatch( + tex2mml('\\arcsec(x)'), + ` + arcsec + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_7', () => { + toXmlMatch( + tex2mml('\\asec(x)'), + ` + asec + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_8', () => { + toXmlMatch( + tex2mml('\\cot(x)'), + ` + cot + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_9', () => { + toXmlMatch( + tex2mml('\\coth(x)'), + ` + coth + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_10', () => { + toXmlMatch( + tex2mml('\\arccot(x)'), + ` + arccot + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Arc_11', () => { + toXmlMatch( + tex2mml('\\acot(x)'), + ` + acot + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics3_2', () => { + + /********************************************************************************/ + + it('Operators_TrigLarge_0', () => { + toXmlMatch( + tex2mml('\\sin(\\frac{x}{y})'), + ` + sin + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_1', () => { + toXmlMatch( + tex2mml('\\sinh(\\frac{x}{y})'), + ` + sinh + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_2', () => { + toXmlMatch( + tex2mml('\\arcsin(\\frac{x}{y})'), + ` + arcsin + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_3', () => { + toXmlMatch( + tex2mml('\\asin(\\frac{x}{y})'), + ` + asin + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_4', () => { + toXmlMatch( + tex2mml('\\cos(\\frac{x}{y})'), + ` + cos + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_5', () => { + toXmlMatch( + tex2mml('\\cosh(\\frac{x}{y})'), + ` + cosh + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_6', () => { + toXmlMatch( + tex2mml('\\arccos(\\frac{x}{y})'), + ` + arccos + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_7', () => { + toXmlMatch( + tex2mml('\\acos(\\frac{x}{y})'), + ` + acos + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_8', () => { + toXmlMatch( + tex2mml('\\tan(\\frac{x}{y})'), + ` + tan + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_9', () => { + toXmlMatch( + tex2mml('\\tanh(\\frac{x}{y})'), + ` + tanh + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_10', () => { + toXmlMatch( + tex2mml('\\arctan(\\frac{x}{y})'), + ` + arctan + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_TrigLarge_11', () => { + toXmlMatch( + tex2mml('\\atan(\\frac{x}{y})'), + ` + atan + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics3_3', () => { + + /********************************************************************************/ + + it('Operators_ArcLarge_0', () => { + toXmlMatch( + tex2mml('\\csc(\\frac{x}{y})'), + ` + csc + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_1', () => { + toXmlMatch( + tex2mml('\\csch(\\frac{x}{y})'), + ` + csch + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_2', () => { + toXmlMatch( + tex2mml('\\arccsc(\\frac{x}{y})'), + ` + arccsc + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_3', () => { + toXmlMatch( + tex2mml('\\acsc(\\frac{x}{y})'), + ` + acsc + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_4', () => { + toXmlMatch( + tex2mml('\\sec(\\frac{x}{y})'), + ` + sec + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_5', () => { + toXmlMatch( + tex2mml('\\sech(\\frac{x}{y})'), + ` + sech + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_6', () => { + toXmlMatch( + tex2mml('\\arcsec(\\frac{x}{y})'), + ` + arcsec + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_7', () => { + toXmlMatch( + tex2mml('\\asec(\\frac{x}{y})'), + ` + asec + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_8', () => { + toXmlMatch( + tex2mml('\\cot(\\frac{x}{y})'), + ` + cot + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_9', () => { + toXmlMatch( + tex2mml('\\coth(\\frac{x}{y})'), + ` + coth + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_10', () => { + toXmlMatch( + tex2mml('\\arccot(\\frac{x}{y})'), + ` + arccot + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_ArcLarge_11', () => { + toXmlMatch( + tex2mml('\\acot(\\frac{x}{y})'), + ` + acot + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics3_4', () => { + + /********************************************************************************/ + + it('Operators_Exp_0', () => { + toXmlMatch( + tex2mml('\\sin x'), + ` + sin + + x + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_1', () => { + toXmlMatch( + tex2mml('\\sin{x}'), + ` + sin + + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_2', () => { + toXmlMatch( + tex2mml('\\sin[x]'), + ` + + sin + x + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_3', () => { + toXmlMatch( + tex2mml('\\sin[2]{x}'), + ` + + sin + 2 + + + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_4', () => { + toXmlMatch( + tex2mml('\\sin[2]x'), + ` + + sin + 2 + + + x + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_5', () => { + toXmlMatch( + tex2mml('\\sin[2]'), + ` + + sin + 2 + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_6', () => { + toXmlMatch( + tex2mml('\\sin|\\frac{x}{y}|'), + ` + sin + + | + + x + y + + | + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_7', () => { + toXmlMatch( + tex2mml('\\sin[\\frac{x}{y}]'), + ` + + sin + + x + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_8', () => { + toXmlMatch( + tex2mml("\\sin['](\\frac{x}{y})"), + ` + + sin + + + + + + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_9', () => { + toXmlMatch( + tex2mml("\\sin[']{\\frac{x}{y}}"), + ` + + sin + + + + + + + + + x + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_10', () => { + toXmlMatch( + tex2mml('\\sine(\\frac{x}{y})'), + ` + sin + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_11', () => { + toXmlMatch( + tex2mml('\\hypsine'), + ` + sinh + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_12', () => { + toXmlMatch( + tex2mml('\\log[2](x)'), + ` + + log + 2 + + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_13', () => { + toXmlMatch( + tex2mml('\\ln[2](x)'), + ` + + ln + 2 + + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_14', () => { + toXmlMatch( + tex2mml('\\exp[2](x)'), + ` + exp + + [ + 2 + ] + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_15', () => { + toXmlMatch( + tex2mml('\\det[2](x)'), + ` + det + + [ + 2 + ] + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Exp_16', () => { + toXmlMatch( + tex2mml('\\Pr[2](x)'), + ` + Pr + + [ + 2 + ] + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics3_5', () => { + + /********************************************************************************/ + + it('Operators_Operators_0', () => { + toXmlMatch( + tex2mml('\\tr\\rho'), + ` + tr + + ρ + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_1', () => { + toXmlMatch( + tex2mml('\\tr(\\frac{x}{y})'), + ` + tr + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_2', () => { + toXmlMatch( + tex2mml('\\tr[2](\\frac{x}{y})'), + ` + tr + + [ + 2 + ] + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_3', () => { + toXmlMatch( + tex2mml('\\rank\\rho'), + ` + rank + + ρ + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_4', () => { + toXmlMatch( + tex2mml('\\rank(\\frac{x}{y})'), + ` + rank + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_5', () => { + toXmlMatch( + tex2mml('\\rank[2](\\frac{x}{y})'), + ` + rank + + [ + 2 + ] + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_6', () => { + toXmlMatch( + tex2mml('\\erf\\rho'), + ` + erf + + ρ + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_7', () => { + toXmlMatch( + tex2mml('\\erf(\\frac{x}{y})'), + ` + erf + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_8', () => { + toXmlMatch( + tex2mml('\\erf[2](\\frac{x}{y})'), + ` + erf + + [ + 2 + ] + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_9', () => { + toXmlMatch( + tex2mml('\\Res\\rho'), + ` + + Res + + + ρ + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_10', () => { + toXmlMatch( + tex2mml('\\Res(\\frac{x}{y})'), + ` + + Res + + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_11', () => { + toXmlMatch( + tex2mml('\\Res[\\frac{x}{y}]'), + ` + + Res + + + + [ + + x + y + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_12', () => { + toXmlMatch( + tex2mml('\\Res{\\frac{x}{y}}'), + ` + + Res + + + + { + + x + y + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_13', () => { + toXmlMatch( + tex2mml('\\Res|\\frac{x}{y}|'), + ` + + Res + + + | + + x + y + + | + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_14', () => { + toXmlMatch( + tex2mml('\\Res \\frac{x}{y}'), + ` + + Res + + + + x + y + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Operators_15', () => { + toXmlMatch( + tex2mml('\\Res[2](\\frac{x}{y})'), + ` + + Res + + + + [ + 2 + ] + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics3_6', () => { + + /********************************************************************************/ + + it('Operators_PV_0', () => { + toXmlMatch( + tex2mml('\\principalvalue{\\int f(z) \\dd{z}}'), + ` + + P + + + + f + ( + z + ) + + + d + + z + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_1', () => { + toXmlMatch( + tex2mml('\\pv{\\int f(z) \\dd{z}}'), + ` + + P + + + + f + ( + z + ) + + + d + + z + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_2', () => { + toXmlMatch( + tex2mml('\\pv{\\int f(z) \\dd{z}}a'), + ` + + P + + + + f + ( + z + ) + + + d + + z + + a + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_3', () => { + toXmlMatch( + tex2mml('\\pv\\int f(z) \\dd{z}a'), + ` + + P + + + + f + ( + z + ) + + + d + + z + + a + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_4', () => { + toXmlMatch( + tex2mml('\\pv(\\int f(z))'), + ` + + P + + + ( + + f + ( + z + ) + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_5', () => { + toXmlMatch( + tex2mml('\\pv|\\int f(z)|'), + ` + + P + + + | + + f + ( + z + ) + | + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_6', () => { + toXmlMatch( + tex2mml('\\pv[\\int f(z)]'), + ` + + P + + + [ + + f + ( + z + ) + ] + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_7', () => { + toXmlMatch( + tex2mml('\\PV{\\int f(z) \\dd{z}}'), + ` + + P + . + V + . + + + + f + ( + z + ) + + + d + + z + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_8', () => { + toXmlMatch( + tex2mml('\\PV{\\int f(z) \\dd{z}}a'), + ` + + P + . + V + . + + + + f + ( + z + ) + + + d + + z + + a + ` + ); + }); + + /********************************************************************************/ + + it('Operators_PV_9', () => { + toXmlMatch( + tex2mml('\\PV\\int f(z) \\dd{z}a'), + ` + + P + . + V + . + + + + f + ( + z + ) + + + d + + z + + a + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics3_7', () => { + + /********************************************************************************/ + + it('Operators_Imaginary_0', () => { + toXmlMatch( + tex2mml('\\Re\\rho'), + ` + + Re + + + ρ + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_1', () => { + toXmlMatch( + tex2mml('\\Re(\\frac{x}{y})'), + ` + + Re + + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_2', () => { + toXmlMatch( + tex2mml('\\Re[\\frac{x}{y}]'), + ` + + Re + + + [ + + x + y + + ] + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_3', () => { + toXmlMatch( + tex2mml('\\Re{\\frac{x}{y}}'), + ` + + Re + + + + { + + x + y + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_4', () => { + toXmlMatch( + tex2mml('\\Re|\\frac{x}{y}|'), + ` + + Re + + + | + + x + y + + | + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_5', () => { + toXmlMatch( + tex2mml('\\Re \\frac{x}{y}'), + ` + + Re + + + + x + y + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_6', () => { + toXmlMatch( + tex2mml('\\Re[2](\\frac{x}{y})'), + ` + + Re + + + [ + 2 + ] + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_7', () => { + toXmlMatch( + tex2mml('\\real'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_8', () => { + toXmlMatch( + tex2mml('\\real{x}'), + ` + + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_9', () => { + toXmlMatch( + tex2mml('\\Im\\rho'), + ` + + Im + + + ρ + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_10', () => { + toXmlMatch( + tex2mml('\\Im(\\frac{x}{y})'), + ` + + Im + + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_11', () => { + toXmlMatch( + tex2mml('\\Im[\\frac{x}{y}]'), + ` + + Im + + + [ + + x + y + + ] + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_12', () => { + toXmlMatch( + tex2mml('\\Im{\\frac{x}{y}}'), + ` + + Im + + + + { + + x + y + + } + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_13', () => { + toXmlMatch( + tex2mml('\\Im|\\frac{x}{y}|'), + ` + + Im + + + | + + x + y + + | + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_14', () => { + toXmlMatch( + tex2mml('\\Im \\frac{x}{y}'), + ` + + Im + + + + x + y + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_15', () => { + toXmlMatch( + tex2mml('\\Im[2](\\frac{x}{y})'), + ` + + Im + + + [ + 2 + ] + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_16', () => { + toXmlMatch( + tex2mml('\\imaginary'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Operators_Imaginary_17', () => { + toXmlMatch( + tex2mml('\\imaginary{x}'), + ` + + + x + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics4_0', () => { + + /********************************************************************************/ + + it('QuickQuad_0_0', () => { + toXmlMatch( + tex2mml('\\qcc'), + ` + + c.c. + + ` + ); + }); + + /********************************************************************************/ + + it('QuickQuad_0_1', () => { + toXmlMatch( + tex2mml('\\qand'), + ` + + and + + ` + ); + }); + + /********************************************************************************/ + + it('QuickQuad_0_2', () => { + toXmlMatch( + tex2mml('a\\qc b'), + ` + a + , + + b + ` + ); + }); + + /********************************************************************************/ + + it('QuickQuad_0_3', () => { + toXmlMatch( + tex2mml('a\\qqtext{hello}b'), + ` + a + + hello + + b + ` + ); + }); + + /********************************************************************************/ + + it('QuickQuad_0_4', () => { + toXmlMatch( + tex2mml('a\\qqtext*{hello}b'), + ` + a + hello + + b + ` + ); + }); + + /********************************************************************************/ + + it('QuickQuad_0_5', () => { + toXmlMatch( + tex2mml('a\\qqtext ab'), + ` + a + + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('QuickQuad_0_6', () => { + toXmlMatch( + tex2mml('a\\qqtext* ab'), + ` + a + a + + b + ` + ); + }); + + /********************************************************************************/ + + it('QuickQuad_0_7', () => { + toXmlMatch( + tex2mml('three\\qif two'), + ` + t + h + r + e + e + + if + + t + w + o + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics5_0', () => { + + /********************************************************************************/ + + it('Derivatives_Deriv_0', () => { + toXmlMatch( + tex2mml('\\dv x'), + ` + + + d + + + + d + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_1', () => { + toXmlMatch( + tex2mml('\\dv x(ll)'), + ` + + + d + + + + d + + x + + + + ( + l + l + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_2', () => { + toXmlMatch( + tex2mml('\\dv{x}{y}'), + ` + + + + d + + x + + + + d + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_3', () => { + toXmlMatch( + tex2mml('\\dv[n]{f}{x}'), + ` + + + + + d + + + n + + + f + + + + d + + + x + + n + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_4', () => { + toXmlMatch( + tex2mml('\\dv{f}{x}{y}'), + ` + + + + d + + f + + + + d + + x + + + + y + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_5', () => { + toXmlMatch( + tex2mml('\\dv{f}{x}y'), + ` + + + + d + + f + + + + d + + x + + + y + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_6', () => { + toXmlMatch( + tex2mml('\\dv{x}y'), + ` + + + d + + + + d + + x + + + y + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_7', () => { + toXmlMatch( + tex2mml('\\dv[n]{f}(\\frac{x}{y})'), + ` + + + + d + + + n + + + + + d + + + f + + n + + + + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_8', () => { + toXmlMatch( + tex2mml('\\dv[n]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + + d + + + n + + + f + + + + d + + + x + + n + + + + + + y + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_9', () => { + toXmlMatch( + tex2mml('\\dv*[n]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + + d + + + n + + + f + + / + + + d + + + x + + n + + + + + + y + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_10', () => { + toXmlMatch( + tex2mml('\\dv*[]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + + d + + + + f + + / + + + d + + + x + + + + + + y + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_11', () => { + toXmlMatch( + tex2mml('\\dv[]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + + d + + + + f + + + + d + + + x + + + + + + y + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_12', () => { + toXmlMatch( + tex2mml('\\dv[5](\\frac{x}{y})'), + ` + + + + d + + + 5 + + + + + d + + + ( + + 5 + + + + + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_13', () => { + toXmlMatch( + tex2mml('\\dv[5]{f}'), + ` + + + + d + + + 5 + + + + + d + + + f + + 5 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Deriv_14', () => { + toXmlMatch( + tex2mml('\\dv{f}'), + ` + + + d + + + + d + + f + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics5_1', () => { + + /********************************************************************************/ + + it('Derivatives_Partial_0', () => { + toXmlMatch( + tex2mml('\\flatfrac{x}{y}'), + ` + + + x + + / + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_1', () => { + toXmlMatch( + tex2mml('\\flatfrac{x^2}{y}'), + ` + + + + x + 2 + + + / + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_2', () => { + toXmlMatch( + tex2mml('\\pdv x'), + ` + + + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_3', () => { + toXmlMatch( + tex2mml('\\pdv x(ll)'), + ` + + + + + x + + + + ( + l + l + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_4', () => { + toXmlMatch( + tex2mml('\\pdv{f}'), + ` + + + + + f + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_5', () => { + toXmlMatch( + tex2mml('\\pdv{x}{y}'), + ` + + + + x + + + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_6', () => { + toXmlMatch( + tex2mml('\\pdv[n]{f}{x}'), + ` + + + + + + n + + + f + + + + + x + + n + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_7', () => { + toXmlMatch( + tex2mml('\\pdv{f}{x}{y}'), + ` + + + + + + 2 + + + f + + + + x + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_8', () => { + toXmlMatch( + tex2mml('\\pdv{f}{x}y'), + ` + + + + f + + + + x + + + y + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_9', () => { + toXmlMatch( + tex2mml('\\pdv{x}y'), + ` + + + + + x + + + y + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_10', () => { + toXmlMatch( + tex2mml('\\pdv*{f}{x}'), + ` + + + + f + + / + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_11', () => { + toXmlMatch( + tex2mml('\\pdv*[3]{f}{x}'), + ` + + + + + + 3 + + + f + + / + + + + x + + 3 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_12', () => { + toXmlMatch( + tex2mml('\\pdv[n]{f}(\\frac{x}{y})'), + ` + + + + + n + + + + + + f + + n + + + + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_13', () => { + toXmlMatch( + tex2mml('\\pdv[n]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + + + 2 + + + f + + + + x + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_14', () => { + toXmlMatch( + tex2mml('\\pdv*[n]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + + + 2 + + + f + + / + + + x + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_15', () => { + toXmlMatch( + tex2mml('\\pdv*[]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + + + 2 + + + f + + / + + + x + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_16', () => { + toXmlMatch( + tex2mml('\\pdv[]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + + + 2 + + + f + + + + x + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_17', () => { + toXmlMatch( + tex2mml('\\pdv[5](\\frac{x}{y})'), + ` + + + + + 5 + + + + + + ( + + 5 + + + + + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Partial_18', () => { + toXmlMatch( + tex2mml('\\pdv[5]{f}'), + ` + + + + + 5 + + + + + + f + + 5 + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics5_2', () => { + + /********************************************************************************/ + + it('Derivatives_Functional_0', () => { + toXmlMatch( + tex2mml('\\fdv x'), + ` + + δ + + δ + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_1', () => { + toXmlMatch( + tex2mml('\\fdv x(ll)'), + ` + + δ + + δ + x + + + + ( + l + l + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_2', () => { + toXmlMatch( + tex2mml('\\fdv{x}{y}'), + ` + + + δ + x + + + δ + y + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_3', () => { + toXmlMatch( + tex2mml('\\fdv{f}'), + ` + + δ + + δ + f + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_4', () => { + toXmlMatch( + tex2mml('\\fdv[n]{f}{x}'), + ` + + + + δ + + n + + + f + + + δ + + x + + n + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_5', () => { + toXmlMatch( + tex2mml('\\fdv{f}{x}{y}'), + ` + + + δ + f + + + δ + x + + + + y + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_6', () => { + toXmlMatch( + tex2mml('\\fdv{f}{x}y'), + ` + + + δ + f + + + δ + x + + + y + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_7', () => { + toXmlMatch( + tex2mml('\\fdv{x}y'), + ` + + δ + + δ + x + + + y + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_8', () => { + toXmlMatch( + tex2mml('\\functionalderivative*{F}{x}'), + ` + + + δ + F + + / + + δ + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_9', () => { + toXmlMatch( + tex2mml('\\fderivative*{F}{x}'), + ` + + + δ + F + + / + + δ + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_10', () => { + toXmlMatch( + tex2mml('\\fdv*{F}{x}'), + ` + + + δ + F + + / + + δ + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_11', () => { + toXmlMatch( + tex2mml('\\fdv{F}{x}'), + ` + + + δ + F + + + δ + x + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_12', () => { + toXmlMatch( + tex2mml('\\fdv[2]{F}{x}'), + ` + + + + δ + + 2 + + + F + + + δ + + x + + 2 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_13', () => { + toXmlMatch( + tex2mml('\\fdv[n]{f}(\\frac{x}{y})'), + ` + + + δ + + n + + + + δ + + f + + n + + + + + + ( + + x + y + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_14', () => { + toXmlMatch( + tex2mml('\\fdv[n]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + δ + + n + + + f + + + δ + + x + + n + + + + + + y + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_15', () => { + toXmlMatch( + tex2mml('\\fdv*[n]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + δ + + n + + + f + + / + + δ + + x + + n + + + + + + y + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_16', () => { + toXmlMatch( + tex2mml('\\fdv*[]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + δ + + + f + + / + + δ + + x + + + + + + y + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_17', () => { + toXmlMatch( + tex2mml('\\fdv[]{f}{x}{y}(\\frac{x}{y})'), + ` + + + + δ + + + f + + + δ + + x + + + + + + y + + ( + + x + y + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Functional_18', () => { + toXmlMatch( + tex2mml('\\fdv[5]{f}'), + ` + + + δ + + 5 + + + + δ + + f + + 5 + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics5_3', () => { + + /********************************************************************************/ + + it('Derivatives_Var_0', () => { + toXmlMatch( + tex2mml('\\var A'), + ` + δ + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_1', () => { + toXmlMatch( + tex2mml('\\var{A}'), + ` + + δ + A + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_2', () => { + toXmlMatch( + tex2mml('\\var{A}{B}'), + ` + + δ + A + + + B + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_3', () => { + toXmlMatch( + tex2mml('\\var[4]{A} B'), + ` + + + δ + + 4 + + + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_4', () => { + toXmlMatch( + tex2mml('\\var{F[g(x)]}'), + ` + + δ + F + [ + g + ( + x + ) + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_5', () => { + toXmlMatch( + tex2mml('\\var(E-TS)'), + ` + δ + + ( + E + + T + S + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_6', () => { + toXmlMatch( + tex2mml('\\var{F[g(\\frac{x}{y})]}'), + ` + + δ + F + [ + g + ( + + x + y + + ) + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_7', () => { + toXmlMatch( + tex2mml('\\var{F[g\\left(\\frac{x}{y}\\right)]}'), + ` + + δ + F + [ + g + + ( + + x + y + + ) + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_8', () => { + toXmlMatch( + tex2mml('\\var(\\frac{a}{b})'), + ` + δ + + ( + + a + b + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_9', () => { + toXmlMatch( + tex2mml('A \\var A B'), + ` + A + δ + A + B + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_10', () => { + toXmlMatch( + tex2mml('A \\var{A} B'), + ` + A + + δ + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_11', () => { + toXmlMatch( + tex2mml('A \\var{A}{B} B'), + ` + A + + δ + A + + + B + + B + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Var_12', () => { + toXmlMatch( + tex2mml('A \\var[4]{A} B'), + ` + A + + + δ + + 4 + + + A + + B + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics5_4', () => { + + /********************************************************************************/ + + it('Derivatives_Differ_0', () => { + toXmlMatch( + tex2mml('\\dd'), + ` + + d + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_1', () => { + toXmlMatch( + tex2mml('\\dd x'), + ` + + d + + x + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_2', () => { + toXmlMatch( + tex2mml('\\dd{x}'), + ` + + + d + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_3', () => { + toXmlMatch( + tex2mml('\\dd[3]{x}'), + ` + + + + d + + + 3 + + + x + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_4', () => { + toXmlMatch( + tex2mml('\\dd[3]x'), + ` + + + d + + + 3 + + + x + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_5', () => { + toXmlMatch( + tex2mml('\\dd(\\frac{\\frac{\\cos}{\\theta}}{\\theta})'), + ` + + d + + + ( + + + cos + θ + + θ + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_6', () => { + toXmlMatch( + tex2mml('\\dd[4](\\frac{\\frac{\\cos}{\\theta}}{\\theta})'), + ` + + + d + + + 4 + + + + ( + + + cos + θ + + θ + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_7', () => { + toXmlMatch( + tex2mml('\\dd{x}(\\frac{\\frac{\\cos}{\\theta}}{\\theta})'), + ` + + + d + + x + + ( + + + cos + θ + + θ + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_8', () => { + toXmlMatch( + tex2mml('\\dd[4]{x}(\\frac{\\frac{\\cos}{\\theta}}{\\theta})'), + ` + + + + d + + + 4 + + + x + + ( + + + cos + θ + + θ + + ) + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_9', () => { + toXmlMatch( + tex2mml('\\dd[5]'), + ` + + + d + + + 5 + + + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_Differ_10', () => { + toXmlMatch( + tex2mml('{\\dd}'), + ` + + + d + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics5_5', () => { + + /********************************************************************************/ + + it('Derivatives_PDiff_0', () => { + toXmlMatch( + tex2mml('A\\dd A'), + ` + A + + d + + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_1', () => { + toXmlMatch( + tex2mml('A\\dd x A'), + ` + A + + d + + x + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_2', () => { + toXmlMatch( + tex2mml('A\\dd{x} A'), + ` + A + + + d + + x + + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_3', () => { + toXmlMatch( + tex2mml('A\\dd xA'), + ` + A + + d + + x + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_4', () => { + toXmlMatch( + tex2mml('A{{\\rm d}(\\it x)}A'), + ` + A + + + d + + ( + x + ) + + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_5', () => { + toXmlMatch( + tex2mml('A\\dd[3]{x} A'), + ` + A + + + + d + + + 3 + + + x + + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_6', () => { + toXmlMatch( + tex2mml('A\\dd[3]x A'), + ` + A + + + d + + + 3 + + + x + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_7', () => { + toXmlMatch( + tex2mml('A\\dd(\\frac{\\frac{\\cos}{\\theta}}{\\theta}) A'), + ` + A + + d + + + ( + + + cos + θ + + θ + + ) + + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_8', () => { + toXmlMatch( + tex2mml('A\\dd[4](\\frac{\\frac{\\cos}{\\theta}}{\\theta})A'), + ` + A + + + d + + + 4 + + + + ( + + + cos + θ + + θ + + ) + + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_9', () => { + toXmlMatch( + tex2mml('A\\dd{x}(\\frac{\\frac{\\cos}{\\theta}}{\\theta})A'), + ` + A + + + d + + x + + ( + + + cos + θ + + θ + + ) + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_10', () => { + toXmlMatch( + tex2mml('A\\dd[4]{x}(\\frac{\\frac{\\cos}{\\theta}}{\\theta})A'), + ` + A + + + + d + + + 4 + + + x + + ( + + + cos + θ + + θ + + ) + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_11', () => { + toXmlMatch( + tex2mml( + 'A{\\rm d}\\left(\\frac{\\frac{\\cos}{\\theta}}{\\theta}\\right) A' + ), + ` + A + + d + + + ( + + + cos + θ + + θ + + ) + + A + ` + ); + }); + + /********************************************************************************/ + + it('Derivatives_PDiff_12', () => { + toXmlMatch( + tex2mml( + 'A{\\rm d}{\\left(\\frac{\\frac{\\cos}{\\theta}}{\\theta}\\right)} A' + ), + ` + A + + d + + + + ( + + + cos + θ + + θ + + ) + + + A + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics6_0', () => { + + /********************************************************************************/ + + it('BraKet_Bra_0', () => { + toXmlMatch( + tex2mml('\\bra{\\phi}\\ket{\\psi}'), + ` + + + + ϕ + + + | + + + ψ + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_1', () => { + toXmlMatch( + tex2mml('\\bra{A}\\ket{B}'), + ` + + + + A + + + | + + + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_2', () => { + toXmlMatch( + tex2mml('\\bra{\\phi}\\dyad{\\psi}{\\xi}'), + ` + + + + ϕ + + | + + + + | + + ψ + + + + + + + + + + ξ + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_3', () => { + toXmlMatch( + tex2mml('\\bra A \\ket B'), + ` + + + + A + + + | + + + + + B + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_4', () => { + toXmlMatch( + tex2mml('\\bra*{\\frac{a}{b}} \\ket{\\frac{a}{b}}'), + ` + + + + a + b + + + | + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_5', () => { + toXmlMatch( + tex2mml('\\bra{\\frac{a}{b}} \\ket*{\\frac{a}{b}}'), + ` + + + + a + b + + + | + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_6', () => { + toXmlMatch( + tex2mml('\\bra A\\ket{B}'), + ` + + + + A + + + | + + + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_7', () => { + toXmlMatch( + tex2mml('\\bra A\\ket '), + ` + + + + A + + + | + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_8', () => { + toXmlMatch( + tex2mml('\\bra {A}\\ket '), + ` + + + + A + + + | + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_9', () => { + toXmlMatch( + tex2mml('\\bra {A}\\ket B'), + ` + + + + A + + + | + + + + + B + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_10', () => { + toXmlMatch( + tex2mml('\\bra {\\frac{a}{b}} \\ket* \\alpha'), + ` + + + + + a + b + + + + | + + + + + + α + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_11', () => { + toXmlMatch( + tex2mml('\\ket{A}'), + ` + + | + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_12', () => { + toXmlMatch( + tex2mml('\\ket{\\frac{a}{b}}'), + ` + + | + + + a + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_13', () => { + toXmlMatch( + tex2mml('\\ket*{A}'), + ` + | + + A + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_14', () => { + toXmlMatch( + tex2mml('\\ket a'), + ` + + | + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_15', () => { + toXmlMatch( + tex2mml('\\ket* a'), + ` + | + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_16', () => { + toXmlMatch( + tex2mml('\\ket \\alpha'), + ` + + | + + α + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Bra_17', () => { + toXmlMatch( + tex2mml('\\bra*{\\frac{1}{2}}'), + ` + + + + 1 + 2 + + + | + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics6_1', () => { + + /********************************************************************************/ + + it('BraKet_Braket_0', () => { + toXmlMatch( + tex2mml('\\braket{A}'), + ` + + + + A + + + | + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_1', () => { + toXmlMatch( + tex2mml('\\braket{\\frac{a}{b}}'), + ` + + + + + a + b + + + + | + + + + a + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_2', () => { + toXmlMatch( + tex2mml('\\braket*{A}'), + ` + + + A + + | + + A + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_3', () => { + toXmlMatch( + tex2mml('\\braket*{\\frac{a}{b}}'), + ` + + + + a + b + + + | + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_4', () => { + toXmlMatch( + tex2mml('\\braket a'), + ` + + + + a + + + | + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_5', () => { + toXmlMatch( + tex2mml('\\braket* a'), + ` + + + a + + | + + a + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_6', () => { + toXmlMatch( + tex2mml('\\braket \\alpha'), + ` + + + + α + + + | + + + α + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_7', () => { + toXmlMatch( + tex2mml('\\braket{\\frac{a}{b}}{A}'), + ` + + + + + a + b + + + + | + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_8', () => { + toXmlMatch( + tex2mml('\\braket*{\\frac{a}{b}}{A}'), + ` + + + + a + b + + + | + + A + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_9', () => { + toXmlMatch( + tex2mml('\\braket{\\frac{a}{b}} A'), + ` + + + + + a + b + + + + | + + + + a + b + + + + + A + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_10', () => { + toXmlMatch( + tex2mml('\\braket*{\\frac{a}{b}} A'), + ` + + + + a + b + + + | + + + a + b + + + + A + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_11', () => { + toXmlMatch( + tex2mml('\\braket{\\frac{a}{b}}{} '), + ` + + + + + a + b + + + + | + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Braket_12', () => { + toXmlMatch( + tex2mml('\\braket*{\\frac{a}{b}}{}'), + ` + + + + a + b + + + | + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics6_2', () => { + + /********************************************************************************/ + + it('BraKet_Ketbra_0', () => { + toXmlMatch( + tex2mml('\\ketbra{A}'), + ` + + | + + A + + + + + + + + + + A + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_1', () => { + toXmlMatch( + tex2mml('\\ketbra{\\frac{a}{b}}'), + ` + + | + + + a + b + + + + + + + + + + + + a + b + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_2', () => { + toXmlMatch( + tex2mml('\\ketbra*{A}'), + ` + | + + A + + + + + + A + + | + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_3', () => { + toXmlMatch( + tex2mml('\\ketbra*{\\frac{a}{b}}'), + ` + | + + + a + b + + + + + + + + a + b + + + | + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_4', () => { + toXmlMatch( + tex2mml('\\ketbra a'), + ` + + | + + a + + + + + + + + + + a + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_5', () => { + toXmlMatch( + tex2mml('\\ketbra* a'), + ` + | + + a + + + + + + a + + | + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_6', () => { + toXmlMatch( + tex2mml('\\ketbra \\alpha'), + ` + + | + + α + + + + + + + + + + α + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_7', () => { + toXmlMatch( + tex2mml('\\ketbra{\\frac{a}{b}}{A}'), + ` + + | + + + a + b + + + + + + + + + + + A + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_8', () => { + toXmlMatch( + tex2mml('\\ketbra*{\\frac{a}{b}}{A}'), + ` + | + + + a + b + + + + + + + A + + | + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_9', () => { + toXmlMatch( + tex2mml('\\ketbra{\\frac{a}{b}} A'), + ` + + | + + + a + b + + + + + + + + + + + + a + b + + + | + + A + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_10', () => { + toXmlMatch( + tex2mml('\\ketbra*{\\frac{a}{b}} A'), + ` + | + + + a + b + + + + + + + + a + b + + + | + A + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_11', () => { + toXmlMatch( + tex2mml('\\ketbra{\\frac{a}{b}}{} '), + ` + + | + + + a + b + + + + + + + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_12', () => { + toXmlMatch( + tex2mml('\\ketbra*{\\frac{a}{b}}{}'), + ` + | + + + a + b + + + + + + + | + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_13', () => { + toXmlMatch( + tex2mml('\\left\\vert A \\middle\\rangle\\middle\\langle B\\right\\vert'), + ` + + | + A + + + + + + + B + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_14', () => { + toXmlMatch( + tex2mml('\\ketbra{A}{B}'), + ` + + | + + A + + + + + + + + + + B + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_15', () => { + toXmlMatch( + tex2mml('\\outerproduct{A}{B}'), + ` + + | + + A + + + + + + + + + + B + + | + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Ketbra_16', () => { + toXmlMatch( + tex2mml('\\dyad{a}{b}'), + ` + + | + + a + + + + + + + + + + b + + | + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics6_3', () => { + + /********************************************************************************/ + + it('BraKet_Expect_0', () => { + toXmlMatch( + tex2mml('\\ev{A}'), + ` + + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_1', () => { + toXmlMatch( + tex2mml('\\ev{\\frac{A}{B}}'), + ` + + + + + A + B + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_2', () => { + toXmlMatch( + tex2mml('\\ev*{\\frac{A}{B}}'), + ` + + + + A + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_3', () => { + toXmlMatch( + tex2mml('\\ev**{\\frac{A}{B}}'), + ` + + + + A + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_4', () => { + toXmlMatch( + tex2mml('\\ev{A}{\\frac{A}{B}}'), + ` + + + + + A + B + + + | + + + A + + + | + + + A + B + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_5', () => { + toXmlMatch( + tex2mml('\\ev{\\frac{A}{B}}{A}'), + ` + + + + A + + | + + + + A + B + + + + | + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_6', () => { + toXmlMatch( + tex2mml('\\ev*{A}{\\frac{A}{B}}'), + ` + + + + A + B + + + | + + A + + | + + + A + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_7', () => { + toXmlMatch( + tex2mml('\\ev**{A} {\\frac{A}{B}}'), + ` + + + + + A + B + + + + | + + + A + + + | + + + + A + B + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_8', () => { + toXmlMatch( + tex2mml('\\ev A B'), + ` + + + + A + + + + B + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_9', () => { + toXmlMatch( + tex2mml('\\ev A {\\frac{A}{B}}'), + ` + + + + + A + B + + + | + + + A + + + | + + + A + B + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_10', () => { + toXmlMatch( + tex2mml('\\ev {\\frac{A}{B}} A'), + ` + + + + + A + B + + + + + A + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_11', () => { + toXmlMatch( + tex2mml('\\ev* A {\\frac{A}{B}}'), + ` + + + + A + B + + + | + + A + + | + + + A + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_12', () => { + toXmlMatch( + tex2mml('\\ev** A {\\frac{A}{B}}'), + ` + + + + + A + B + + + + | + + + A + + + | + + + + A + B + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_13', () => { + toXmlMatch( + tex2mml('\\ev{\\frac{A}{B}}{\\frac{\\Psi}{\\Phi}}'), + ` + + + + + Ψ + Φ + + + | + + + + A + B + + + + | + + + Ψ + Φ + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_14', () => { + toXmlMatch( + tex2mml('\\ev{\\frac{A}{B}}{{\\Psi}}'), + ` + + + + + Ψ + + + | + + + + A + B + + + + | + + + Ψ + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_15', () => { + toXmlMatch( + tex2mml('\\ev*{\\frac{A}{B}}{\\frac{\\Psi}{\\Phi}}'), + ` + + + + Ψ + Φ + + + | + + + A + B + + + | + + + Ψ + Φ + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_Expect_16', () => { + toXmlMatch( + tex2mml('\\ev**{\\frac{A}{B}}{\\frac{\\Psi}{\\Phi}}'), + ` + + + + + Ψ + Φ + + + + | + + + + A + B + + + + | + + + + Ψ + Φ + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics6_4', () => { + + /********************************************************************************/ + + it('BraKet_MatrixEl_0', () => { + toXmlMatch( + tex2mml('\\matrixel{n}{A}{m}'), + ` + + + + n + + | + + + A + + + | + + m + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_MatrixEl_1', () => { + toXmlMatch( + tex2mml('\\mel{n}{A}{m}'), + ` + + + + n + + | + + + A + + + | + + m + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_MatrixEl_2', () => { + toXmlMatch( + tex2mml('\\mel{\\frac{a}{b}}{\\frac{a}{b}}{\\frac{a}{b}}'), + ` + + + + + a + b + + + | + + + + a + b + + + + | + + + a + b + + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_MatrixEl_3', () => { + toXmlMatch( + tex2mml('\\mel A B C'), + ` + + + + A + + | + + + B + + + | + + C + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_MatrixEl_4', () => { + toXmlMatch( + tex2mml('\\mel*{n}{\\frac{a}{b}}{m}'), + ` + + + n + + | + + + a + b + + + | + + m + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_MatrixEl_5', () => { + toXmlMatch( + tex2mml('\\mel*{\\frac{a}{b}}{\\frac{a}{b}}{\\frac{a}{b}}'), + ` + + + + a + b + + + | + + + a + b + + + | + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_MatrixEl_6', () => { + toXmlMatch( + tex2mml('\\mel**{n}{\\frac{a}{b}}{m}'), + ` + + + + n + + + | + + + + a + b + + + + | + + + m + + + + ` + ); + }); + + /********************************************************************************/ + + it('BraKet_MatrixEl_7', () => { + toXmlMatch( + tex2mml('\\mel**{\\frac{a}{b}}{\\frac{a}{b}}{\\frac{a}{b}}'), + ` + + + + + a + b + + + + | + + + + a + b + + + + | + + + + a + b + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_0', () => { + + /********************************************************************************/ + + it('Matrices_Quantity_0', () => { + toXmlMatch( + tex2mml('\\matrixquantity{Q}'), + ` + + + + Q + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_1', () => { + toXmlMatch( + tex2mml('\\matrixquantity*{a & b \\\\ c & d}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_2', () => { + toXmlMatch( + tex2mml('\\matrixquantity*(a & b \\\\ c & d)'), + ` + + + + + + a + + + b + + + + + c + + + d + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_3', () => { + toXmlMatch( + tex2mml('\\matrixquantity(a & b \\\\ c & d)'), + ` + + ( + + + + a + + + b + + + + + c + + + d + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_4', () => { + toXmlMatch( + tex2mml('\\matrixquantity[a & b \\\\ c & d]'), + ` + + [ + + + + a + + + b + + + + + c + + + d + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_5', () => { + toXmlMatch( + tex2mml('\\matrixquantity|a & b \\\\ c & d|'), + ` + + | + + + + a + + + b + + + + + c + + + d + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_6', () => { + toXmlMatch( + tex2mml('\\mqty{a & b \\\\ c & d}'), + ` + + + + a + + + b + + + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_7', () => { + toXmlMatch( + tex2mml('\\mqty(a & b \\\\ c & d)'), + ` + + ( + + + + a + + + b + + + + + c + + + d + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_8', () => { + toXmlMatch( + tex2mml('\\mqty*(a & b \\\\ c & d)'), + ` + + + + + + a + + + b + + + + + c + + + d + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_9', () => { + toXmlMatch( + tex2mml('\\mqty[a & b \\\\ c & d]'), + ` + + [ + + + + a + + + b + + + + + c + + + d + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_10', () => { + toXmlMatch( + tex2mml('\\mqty|a & b \\\\ c & d|'), + ` + + | + + + + a + + + b + + + + + c + + + d + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Quantity_11', () => { + toXmlMatch( + tex2mml('\\mqty*|a & b\\\\ c& d|'), + ` + + | + + + + a + + + b + + + + + c + + + d + + + + | + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_10', () => { + + /********************************************************************************/ + + it('Matrices_Adiag_0', () => { + toXmlMatch( + tex2mml('\\mqty(\\admat{1,2&3\\\\4&5})'), + ` + + ( + + + + + + + + 1 + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Adiag_1', () => { + toXmlMatch( + tex2mml('\\mqty(\\admat 1)'), + ` + + ( + + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Adiag_2', () => { + toXmlMatch( + tex2mml('\\mqty(\\admat 1,2)'), + ` + + ( + + + + 1 + , + 2 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Adiag_3', () => { + toXmlMatch( + tex2mml('\\mqty(\\admat{1,2&3\\\\4&5&6,7,8})'), + ` + + ( + + + + + + + + + + 1 + + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + 6 + + + + + + + + + + + + 7 + + + + + + + + + + + 8 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Adiag_4', () => { + toXmlMatch( + tex2mml('\\mqty(\\admat{1,2&3\\\\4&5,6,7,8})'), + ` + + ( + + + + + + + + + + + 1 + + + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + 7 + + + + + + + + + + + 8 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Adiag_5', () => { + toXmlMatch( + tex2mml('\\mqty(\\admat{1,2&3\\\\4&5&6,7,8,\\dmat{9,10}})'), + ` + + ( + + + + + + + + + + + 1 + + + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + 8 + + + + + + + + + + + + + + 9 + + + + + + + + + + + + 10 + + + + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_11', () => { + + /********************************************************************************/ + + it('Matrices_Other_0', () => { + toXmlMatch( + tex2mml('\\mqty a'), + ` + + ( + + ) + + a + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_1', () => { + toXmlMatch( + tex2mml('\\mqty1'), + ` + + ( + + ) + + 1 + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_2', () => { + toXmlMatch( + tex2mml('\\pmqty* 34'), + ` + + ( + + + + + + + + ) + + 34 + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_3', () => { + toXmlMatch( + tex2mml( + '\\mqty(\\dmat{1,2&3,4&4&5\\\\4&5,33,4,5,7,8\\\\0\\\\10&20\\\\3,200}) ' + ), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + 3 + + + + + + + + + + + + + 4 + + + 4 + + + 5 + + + + + 4 + + + 5 + + + + + + + + + + + + + + 33 + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + + + + 8 + + + + + 0 + + + + + 10 + + + 20 + + + + + 3 + + + + + + + + + + + + + + + + + + + 200 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_4', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat{1,2&3\\\\4&5}) '), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_5', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat{1,2&3\\\\4&5&6,\\imat{3},7,8,\\dmat{9,10}})'), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + 6 + + + + + + + + + + + + + 1 + + + 0 + + + 0 + + + + + 0 + + + 1 + + + 0 + + + + + 0 + + + 0 + + + 1 + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + + + + + 9 + + + + + + + + + + + + 10 + + + + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_6', () => { + toXmlMatch( + tex2mml( + '\\mqty(\\mqty{1}\\\\ & \\mqty{2 & 3\\\\ 4 & 5 & 6}\\\\ & & \\mqty{\\imat{3}} \\\\ & & & \\mqty{7})' + ), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + 6 + + + + + + + + + + + + + 1 + + + 0 + + + 0 + + + + + 0 + + + 1 + + + 0 + + + + + 0 + + + 0 + + + 1 + + + + + + + + + + + + + + 7 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_7', () => { + toXmlMatch( + tex2mml('\\left\\lgroup\\frac{a}{b}\\right\\rgroup'), + ` + + + + a + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_8', () => { + toXmlMatch( + tex2mml('\\begin{smallmatrix} a & b \\\\ c & d \\end{smallmatrix}'), + ` + + + + + a + + + b + + + + + c + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_9', () => { + toXmlMatch( + tex2mml('\\smqty{\\imat{3}}'), + ` + + + + + + 1 + + + 0 + + + 0 + + + + + 0 + + + 1 + + + 0 + + + + + 0 + + + 0 + + + 1 + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Other_10', () => { + toXmlMatch( + tex2mml('\\mqty{\\imat{10}}'), + ` + + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_1', () => { + + /********************************************************************************/ + + it('Matrices_Fenced_0', () => { + toXmlMatch( + tex2mml('\\pmqty{Q} \\mqty(R)'), + ` + + ( + + + + Q + + + + ) + + + ( + + + + R + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Fenced_1', () => { + toXmlMatch( + tex2mml('\\Pmqty{Q} \\mqty*(R)'), + ` + + + + + + Q + + + + + + + + + + + R + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Fenced_2', () => { + toXmlMatch( + tex2mml('\\bmqty{Q} \\mqty[R]'), + ` + + [ + + + + Q + + + + ] + + + [ + + + + R + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Fenced_3', () => { + toXmlMatch( + tex2mml('\\vmqty{Q} \\mqty|R|'), + ` + + | + + + + Q + + + + | + + + | + + + + R + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Fenced_4', () => { + toXmlMatch( + tex2mml('\\pmqty{a & b \\\\ c & d}'), + ` + + ( + + + + a + + + b + + + + + c + + + d + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Fenced_5', () => { + toXmlMatch( + tex2mml('\\Pmqty{a & b \\\\ c & d}'), + ` + + + + + + a + + + b + + + + + c + + + d + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Fenced_6', () => { + toXmlMatch( + tex2mml('\\bmqty{a & b \\\\ c & d}'), + ` + + [ + + + + a + + + b + + + + + c + + + d + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Fenced_7', () => { + toXmlMatch( + tex2mml('\\vmqty{a & b \\\\ c & d}'), + ` + + | + + + + a + + + b + + + + + c + + + d + + + + | + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_2', () => { + + /********************************************************************************/ + + it('Matrices_Small_0', () => { + toXmlMatch( + tex2mml('\\smallmatrixquantity{Q}'), + ` + + + + + + Q + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_1', () => { + toXmlMatch( + tex2mml('\\smallmatrixquantity*{a & b \\\\ c & d}'), + ` + + + + + + a + + + b + + + + + c + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_2', () => { + toXmlMatch( + tex2mml('\\smallmatrixquantity*(a & b \\\\ c & d)'), + ` + + + + + + + + a + + + b + + + + + c + + + d + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_3', () => { + toXmlMatch( + tex2mml('\\smallmatrixquantity(a & b \\\\ c & d)'), + ` + + ( + + + + + + a + + + b + + + + + c + + + d + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_5', () => { + toXmlMatch( + tex2mml('\\smallmatrixquantity|a & b \\\\ c & d|'), + ` + + | + + + + + + a + + + b + + + + + c + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_6', () => { + toXmlMatch( + tex2mml('\\smqty{a & b \\\\ c & d}'), + ` + + + + + + a + + + b + + + + + c + + + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_7', () => { + toXmlMatch( + tex2mml('\\smqty(a & b \\\\ c & d)'), + ` + + ( + + + + + + a + + + b + + + + + c + + + d + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_8', () => { + toXmlMatch( + tex2mml('\\smqty*(a & b \\\\ c & d)'), + ` + + + + + + + + a + + + b + + + + + c + + + d + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_9', () => { + toXmlMatch( + tex2mml('\\smqty[a & b \\\\ c & d]'), + ` + + [ + + + + + + a + + + b + + + + + c + + + d + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Small_10', () => { + toXmlMatch( + tex2mml('\\smqty|a & b \\\\ c & d|'), + ` + + | + + + + + + a + + + b + + + + + c + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_3', () => { + + /********************************************************************************/ + + it('Matrices_SmallFenced_0', () => { + toXmlMatch( + tex2mml('\\spmqty{Q} \\smqty(R)'), + ` + + ( + + + + + + Q + + + + + ) + + + ( + + + + + + R + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_SmallFenced_1', () => { + toXmlMatch( + tex2mml('\\sPmqty{Q} \\smqty*(R)'), + ` + + + + + + + + Q + + + + + + + + + + + + + + R + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_SmallFenced_2', () => { + toXmlMatch( + tex2mml('\\sbmqty{Q} \\smqty[R]'), + ` + + [ + + + + + + Q + + + + + ] + + + [ + + + + + + R + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_SmallFenced_3', () => { + toXmlMatch( + tex2mml('\\svmqty{Q} \\smqty|R|'), + ` + + | + + + + + + Q + + + + + | + + + | + + + + + + R + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_SmallFenced_4', () => { + toXmlMatch( + tex2mml('\\spmqty{a & b \\\\ c & d}'), + ` + + ( + + + + + + a + + + b + + + + + c + + + d + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_SmallFenced_5', () => { + toXmlMatch( + tex2mml('\\sPmqty{a & b \\\\ c & d}'), + ` + + + + + + + + a + + + b + + + + + c + + + d + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_SmallFenced_6', () => { + toXmlMatch( + tex2mml('\\sbmqty{a & b \\\\ c & d}'), + ` + + [ + + + + + + a + + + b + + + + + c + + + d + + + + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_SmallFenced_7', () => { + toXmlMatch( + tex2mml('\\svmqty{a & b \\\\ c & d}'), + ` + + | + + + + + + a + + + b + + + + + c + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_4', () => { + + /********************************************************************************/ + + it('Matrices_Det_0', () => { + toXmlMatch( + tex2mml('\\matrixdeterminant{a & b \\\\ c & d}'), + ` + + | + + + + a + + + b + + + + + c + + + d + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Det_1', () => { + toXmlMatch( + tex2mml('\\mdet{a & b \\\\ c & d}'), + ` + + | + + + + a + + + b + + + + + c + + + d + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Det_2', () => { + toXmlMatch( + tex2mml('\\smdet{a & b \\\\ c & d} '), + ` + + | + + + + + + a + + + b + + + + + c + + + d + + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Det_3', () => { + toXmlMatch( + tex2mml('\\matrixdeterminant a b'), + ` + + | + + + + a + + + + | + + b + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Det_4', () => { + toXmlMatch( + tex2mml('\\mdet a b'), + ` + + | + + + + a + + + + | + + b + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Det_5', () => { + toXmlMatch( + tex2mml('\\smdet a b'), + ` + + | + + + + + + a + + + + + | + + b + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_5', () => { + + /********************************************************************************/ + + it('Matrices_Identity_0', () => { + toXmlMatch( + tex2mml('\\mqty{\\imat{3}}'), + ` + + + + 1 + + + 0 + + + 0 + + + + + 0 + + + 1 + + + 0 + + + + + 0 + + + 0 + + + 1 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Identity_1', () => { + toXmlMatch( + tex2mml('\\vmqty{\\imat{5}}'), + ` + + | + + + + 1 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 1 + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 1 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 1 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + 0 + + + 1 + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Identity_2', () => { + toXmlMatch( + tex2mml('\\vmqty{\\imat{0}}'), + ` + + | + + + + 1 + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Identity_3', () => { + toXmlMatch( + tex2mml('\\vmqty{\\imat{1}}'), + ` + + | + + + + 1 + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Identity_4', () => { + toXmlMatch( + tex2mml('\\vmqty{\\imat{-1}}'), + ` + + | + + + + 1 + + + + | + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Identity_5', () => { + toXmlMatch( + tex2mml('\\pmqty{\\imat{3}\\pmat{0}}'), + ` + + ( + + + + 1 + + + 0 + + + 0 + + + + + 0 + + + 1 + + + 0 + + + + + 0 + + + 0 + + + 1 + 1 + + + 0 + + + + + 0 + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_6', () => { + + /********************************************************************************/ + + it('Matrices_XMatrix_0', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat{1}{2}{3})'), + ` + + ( + + + + + + 1 + + + 1 + + + 1 + + + + + 1 + + + 1 + + + 1 + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_1', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat{a}{3}{3}) '), + ` + + ( + + + + + + a + + + a + + + a + + + + + a + + + a + + + a + + + + + a + + + a + + + a + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_2', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat{a}{3}{1}) '), + ` + + ( + + + + + + a + + + + + a + + + + + a + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_3', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat{a}{1}{3})'), + ` + + ( + + + + + + a + + + a + + + a + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_4', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat*{1}{2}{3})'), + ` + + ( + + + + + + + 1 + + + 1 + + + 1 + + + + + + + 1 + + + 1 + + + 2 + + + + + + + 1 + + + 1 + + + 3 + + + + + + + + + 1 + + + 2 + + + 1 + + + + + + + 1 + + + 2 + + + 2 + + + + + + + 1 + + + 2 + + + 3 + + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_5', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat*{a}{3}{3})'), + ` + + ( + + + + + + + a + + + 1 + + + 1 + + + + + + + a + + + 1 + + + 2 + + + + + + + a + + + 1 + + + 3 + + + + + + + + + a + + + 2 + + + 1 + + + + + + + a + + + 2 + + + 2 + + + + + + + a + + + 2 + + + 3 + + + + + + + + + a + + + 3 + + + 1 + + + + + + + a + + + 3 + + + 2 + + + + + + + a + + + 3 + + + 3 + + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_6', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat*{a}{3}{1})'), + ` + + ( + + + + + + + a + + 1 + + + + + + + + a + + 2 + + + + + + + + a + + 3 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_7', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat*{a}{1}{3})'), + ` + + ( + + + + + + + a + + 1 + + + + + + a + + 2 + + + + + + a + + 3 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_8', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat*{a}{1}{1})'), + ` + + ( + + + + + + a + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_9', () => { + toXmlMatch( + tex2mml('\\smqty(\\xmat*{a}{-1}{-1})'), + ` + + ( + + + + + + a + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_10', () => { + toXmlMatch( + tex2mml('\\smqty(\\zmat{1}{3})'), + ` + + ( + + + + + + 0 + + + 0 + + + 0 + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_11', () => { + toXmlMatch( + tex2mml('\\smqty(\\zmat{2}{3})'), + ` + + ( + + + + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_XMatrix_12', () => { + toXmlMatch( + tex2mml('\\smqty(\\zmat{3}{1})'), + ` + + ( + + + + + + 0 + + + + + 0 + + + + + 0 + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_7', () => { + + /********************************************************************************/ + + it('Matrices_Pauli_0', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{0}}'), + ` + + + + 1 + + + 0 + + + + + 0 + + + 1 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_1', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{0}}'), + ` + + ( + + + + 1 + + + 0 + + + + + 0 + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_2', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{1}}'), + ` + + + + 0 + + + 1 + + + + + 1 + + + 0 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_3', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{2}}'), + ` + + + + 0 + + + + i + + + + + i + + + 0 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_4', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{3}}'), + ` + + + + 1 + + + 0 + + + + + 0 + + + + 1 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_5', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{4}}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_6', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{x}}'), + ` + + + + 0 + + + 1 + + + + + 1 + + + 0 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_7', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{y}}'), + ` + + + + 0 + + + + i + + + + + i + + + 0 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_8', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{z}}'), + ` + + + + 1 + + + 0 + + + + + 0 + + + + 1 + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_9', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{a}}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_10', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{a}}'), + ` + + ( + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_11', () => { + toXmlMatch( + tex2mml('\\mqty{\\pmat{aa}}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Pauli_12', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{0.a}}'), + ` + + ( + + + + . + a + 1 + + + 0 + + + + + 0 + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_8', () => { + + /********************************************************************************/ + + it('Matrices_PauliFenced_0', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{1}}'), + ` + + ( + + + + 0 + + + 1 + + + + + 1 + + + 0 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_PauliFenced_1', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{2}}'), + ` + + ( + + + + 0 + + + + i + + + + + i + + + 0 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_PauliFenced_2', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{3}}'), + ` + + ( + + + + 1 + + + 0 + + + + + 0 + + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_PauliFenced_3', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{4}}'), + ` + + ( + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_PauliFenced_4', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{x}}'), + ` + + ( + + + + 0 + + + 1 + + + + + 1 + + + 0 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_PauliFenced_5', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{y}}'), + ` + + ( + + + + 0 + + + + i + + + + + i + + + 0 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_PauliFenced_6', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{z}}'), + ` + + ( + + + + 1 + + + 0 + + + + + 0 + + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_PauliFenced_7', () => { + toXmlMatch( + tex2mml('\\pmqty{\\pmat{aa}}'), + ` + + ( + + + + a + + + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics7_9', () => { + + /********************************************************************************/ + + it('Matrices_Diag_0', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat{1,2&3\\\\4&5})'), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Diag_1', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat 1)'), + ` + + ( + + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Diag_2', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat 1,2)'), + ` + + ( + + + + 1 + , + 2 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Diag_3', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat{1,2&3\\\\4&5&6,7,8})'), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + 8 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Diag_4', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat{1,2&3\\\\4&5,6,7,8})'), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + + + + + + + + + + + 6 + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + 8 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Diag_5', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat{1,2\\\\3\\\\4\\\\5\\\\6,7,8})'), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + 8 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Matrices_Diag_6', () => { + toXmlMatch( + tex2mml('\\mqty(\\dmat{1,2&3\\\\4&5&6,7,8,\\dmat{9,10}})'), + ` + + ( + + + + + + + 1 + + + + + + + + + + + + 2 + + + 3 + + + + + 4 + + + 5 + + + 6 + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + + + + 9 + + + + + + + + + + + + 10 + + + + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Physics Errors', () => { + + /********************************************************************************/ + + it('MissingArgFor Quantity', () => { + expectTexError('\\pqty').toBe('Missing argument for \\pqty'); + }); + + /********************************************************************************/ + + it('MissingArgFor Commutator 1', () => { + expectTexError('\\commutator\\nix') + .toBe('Missing argument for \\commutator'); + }); + + /********************************************************************************/ + + it('MissingArgFor Commutator 2', () => { + expectTexError('\\commutator') + .toBe('Missing argument for \\commutator'); + }); + + /********************************************************************************/ + + it('InvalidNumber IdentityMatrix', () => { + expectTexError('\\smqty(\\identitymatrix{a})').toBe('Invalid number'); + }); + + /********************************************************************************/ + + it('InvalidNumber XMatrix n', () => { + expectTexError('\\smqty(\\xmatrix{a}{a}{2})').toBe('Invalid number'); + }); + + /********************************************************************************/ + + it('InvalidNumber XMatrix m', () => { + expectTexError('\\smqty(\\xmatrix{a}{2}{a})').toBe('Invalid number'); + }); + + /********************************************************************************/ + + it('InvalidNumber XMatrix n+', () => { + expectTexError('\\smqty(\\xmatrix{a}{2.0}{2})').toBe('Invalid number'); + }); + + /********************************************************************************/ + + it('InvalidNumber XMatrix m+', () => { + expectTexError('\\smqty(\\xmatrix{a}{2}{2.0})').toBe('Invalid number'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Automatic Bracing Macros Rest', () => { + + /********************************************************************************/ + + it('Quantities_Bracket', () => { + toXmlMatch( + tex2mml('\\bqty\\Bigg{a}'), + ` + + [ + + a + + ] + + ` + ); + }); + + /********************************************************************************/ + + it('Quantities_Vert', () => { + toXmlMatch( + tex2mml('\\vqty\\Bigg{a}'), + ` + + | + + a + + | + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Vector Mo Rest', () => { + + /********************************************************************************/ + + it('dotproduct', () => { + toXmlMatch( + tex2mml('A \\dotproduct B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('vdot', () => { + toXmlMatch( + tex2mml('A \\vdot B'), + ` + A + + B + ` + ); + }); + + /********************************************************************************/ + + it('cross', () => { + toXmlMatch( + tex2mml('A \\cross B'), + ` + A + × + B + ` + ); + }); + + /********************************************************************************/ + + it('cp', () => { + toXmlMatch( + tex2mml('A \\cp B'), + ` + A + × + B + ` + ); + }); + + /********************************************************************************/ + + it('divsymbol', () => { + toXmlMatch( + tex2mml('A \\divsymbol B'), + ` + A + ÷ + B + ` + ); + }); + + /********************************************************************************/ + + it('divisionsymbol', () => { + toXmlMatch( + tex2mml('A \\divisionsymbol B'), + ` + A + ÷ + B + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Expressions Macros Rest', () => { + + /********************************************************************************/ + + it('trace', () => { + toXmlMatch( + tex2mml('\\trace(x)'), + ` + tr + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Tr', () => { + toXmlMatch( + tex2mml('\\Tr(x)'), + ` + Tr + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Trace', () => { + toXmlMatch( + tex2mml('\\Trace(x)'), + ` + Tr + + + ( + x + ) + + ` + ); + }); + + /********************************************************************************/ + + it('arcsine', () => { + toXmlMatch( + tex2mml('\\arcsine(x)'), + ` + arcsin + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('asine', () => { + toXmlMatch( + tex2mml('\\asine(x)'), + ` + asin + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('cosine', () => { + toXmlMatch( + tex2mml('\\cosine(x)'), + ` + cos + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('hypcosine', () => { + toXmlMatch( + tex2mml('\\hypcosine(x)'), + ` + cosh + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('arccosine', () => { + toXmlMatch( + tex2mml('\\arccosine(x)'), + ` + arccos + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('acosine', () => { + toXmlMatch( + tex2mml('\\acosine(x)'), + ` + acos + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('tangent', () => { + toXmlMatch( + tex2mml('\\tangent(x)'), + ` + tan + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('hyptangent', () => { + toXmlMatch( + tex2mml('\\hyptangent(x)'), + ` + tanh + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('arctangent', () => { + toXmlMatch( + tex2mml('\\arctangent(x)'), + ` + arctan + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('atangent', () => { + toXmlMatch( + tex2mml('\\atangent(x)'), + ` + atan + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('cosecant', () => { + toXmlMatch( + tex2mml('\\cosecant(x)'), + ` + csc + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('hypcosecant', () => { + toXmlMatch( + tex2mml('\\hypcosecant(x)'), + ` + csch + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('arccosecant', () => { + toXmlMatch( + tex2mml('\\arccosecant(x)'), + ` + arccsc + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('acosecant', () => { + toXmlMatch( + tex2mml('\\acosecant(x)'), + ` + acsc + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('secant', () => { + toXmlMatch( + tex2mml('\\secant(x)'), + ` + sec + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('hypsecant', () => { + toXmlMatch( + tex2mml('\\hypsecant(x)'), + ` + sech + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('arcsecant', () => { + toXmlMatch( + tex2mml('\\arcsecant(x)'), + ` + arcsec + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('asecant', () => { + toXmlMatch( + tex2mml('\\asecant(x)'), + ` + asec + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('cotangent', () => { + toXmlMatch( + tex2mml('\\cotangent(x)'), + ` + cot + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('hypcotangent', () => { + toXmlMatch( + tex2mml('\\hypcotangent(x)'), + ` + coth + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('arccotangent', () => { + toXmlMatch( + tex2mml('\\arccotangent(x)'), + ` + arccot + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('acotangent', () => { + toXmlMatch( + tex2mml('\\acotangent(x)'), + ` + acot + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('exponential', () => { + toXmlMatch( + tex2mml('\\exponential(x)'), + ` + exp + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('logarithm', () => { + toXmlMatch( + tex2mml('\\logarithm(x)'), + ` + log + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('naturallogarithm', () => { + toXmlMatch( + tex2mml('\\naturallogarithm(x)'), + ` + ln + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('determinant', () => { + toXmlMatch( + tex2mml('\\determinant(x)'), + ` + det + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + + it('Probability', () => { + toXmlMatch( + tex2mml('\\Probability(x)'), + ` + Pr + + ( + x + ) + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Derivative Macros Rest', () => { + + /********************************************************************************/ + + it('differential', () => { + toXmlMatch( + tex2mml('\\differential'), + ` + + d + + ` + ); + }); + + /********************************************************************************/ + + it('variation', () => { + toXmlMatch( + tex2mml('\\variation'), + ` + δ + ` + ); + }); + + /********************************************************************************/ + + it('derivative one arg', () => { + toXmlMatch( + tex2mml('\\derivative{x}'), + ` + + + d + + + + d + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('derivative two arg', () => { + toXmlMatch( + tex2mml('\\derivative{x}{y}'), + ` + + + + d + + x + + + + d + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('derivative three arg', () => { + toXmlMatch( + tex2mml('\\derivative{x}{y}{z}'), + ` + + + + d + + x + + + + d + + y + + + + z + + ` + ); + }); + + /********************************************************************************/ + + it('partialderivative one arg', () => { + toXmlMatch( + tex2mml('\\partialderivative{x}'), + ` + + + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('partialderivative two arg', () => { + toXmlMatch( + tex2mml('\\partialderivative{x}{y}'), + ` + + + + x + + + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('partialderivative three arg', () => { + toXmlMatch( + tex2mml('\\partialderivative{x}{y}{z}'), + ` + + + + + + 2 + + + x + + + + y + + z + + + ` + ); + }); + + /********************************************************************************/ + + it('partialderivative four arg', () => { + toXmlMatch( + tex2mml('\\partialderivative{x}{y}{z}{a}'), + ` + + + + + + 2 + + + x + + + + y + + z + + + + a + + ` + ); + }); + + /********************************************************************************/ + + it('pderivative one arg', () => { + toXmlMatch( + tex2mml('\\pderivative{x}'), + ` + + + + + x + + + ` + ); + }); + + /********************************************************************************/ + + it('pderivative two arg', () => { + toXmlMatch( + tex2mml('\\pderivative{x}{y}'), + ` + + + + x + + + + y + + + ` + ); + }); + + /********************************************************************************/ + + it('pderivative three arg', () => { + toXmlMatch( + tex2mml('\\pderivative{x}{y}{z}'), + ` + + + + + + 2 + + + x + + + + y + + z + + + ` + ); + }); + + /********************************************************************************/ + + it('pderivative four arg', () => { + toXmlMatch( + tex2mml('\\pderivative{x}{y}{z}{a}'), + ` + + + + + + 2 + + + x + + + + y + + z + + + + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Quick Quad Macros Rest', () => { + + /********************************************************************************/ + + it('qq', () => { + toXmlMatch( + tex2mml('A \\qq B'), + ` + A + + B + + ` + ); + }); + + /********************************************************************************/ + + it('qcomma', () => { + toXmlMatch( + tex2mml('A \\qcomma B'), + ` + A + , + + B + ` + ); + }); + + /********************************************************************************/ + + it('qthen', () => { + toXmlMatch( + tex2mml('A \\qthen B'), + ` + A + + then + + B + ` + ); + }); + + /********************************************************************************/ + + it('qelse', () => { + toXmlMatch( + tex2mml('A \\qelse B'), + ` + A + + else + + B + ` + ); + }); + + /********************************************************************************/ + + it('qotherwise', () => { + toXmlMatch( + tex2mml('A \\qotherwise B'), + ` + A + + otherwise + + B + ` + ); + }); + + /********************************************************************************/ + + it('qunless', () => { + toXmlMatch( + tex2mml('A \\qunless B'), + ` + A + + unless + + B + ` + ); + }); + + /********************************************************************************/ + + it('qgiven', () => { + toXmlMatch( + tex2mml('A \\qgiven B'), + ` + A + + given + + B + ` + ); + }); + + /********************************************************************************/ + + it('qusing', () => { + toXmlMatch( + tex2mml('A \\qusing B'), + ` + A + + using + + B + ` + ); + }); + + /********************************************************************************/ + + it('qassume', () => { + toXmlMatch( + tex2mml('A \\qassume B'), + ` + A + + assume + + B + ` + ); + }); + + /********************************************************************************/ + + it('qsince', () => { + toXmlMatch( + tex2mml('A \\qsince B'), + ` + A + + since + + B + ` + ); + }); + + /********************************************************************************/ + + it('qlet', () => { + toXmlMatch( + tex2mml('A \\qlet B'), + ` + A + + let + + B + ` + ); + }); + + /********************************************************************************/ + + it('qfor', () => { + toXmlMatch( + tex2mml('A \\qfor B'), + ` + A + + for + + B + ` + ); + }); + + /********************************************************************************/ + + it('qall', () => { + toXmlMatch( + tex2mml('A \\qall B'), + ` + A + + all + + B + ` + ); + }); + + /********************************************************************************/ + + it('qeven', () => { + toXmlMatch( + tex2mml('A \\qeven B'), + ` + A + + even + + B + ` + ); + }); + + /********************************************************************************/ + + it('qodd', () => { + toXmlMatch( + tex2mml('A \\qodd B'), + ` + A + + odd + + B + ` + ); + }); + + /********************************************************************************/ + + it('qinteger', () => { + toXmlMatch( + tex2mml('A \\qinteger B'), + ` + A + + integer + + B + ` + ); + }); + + /********************************************************************************/ + + it('qor', () => { + toXmlMatch( + tex2mml('A \\qor B'), + ` + A + + or + + B + ` + ); + }); + + /********************************************************************************/ + + it('qas', () => { + toXmlMatch( + tex2mml('A \\qas B'), + ` + A + + as + + B + ` + ); + }); + + /********************************************************************************/ + + it('qin', () => { + toXmlMatch( + tex2mml('A \\qin B'), + ` + A + + in + + B + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Bra-Ket Macros Rest', () => { + + /********************************************************************************/ + + it('innerproduct arg one', () => { + toXmlMatch( + tex2mml('\\innerproduct{A}'), + ` + + + + A + + + | + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('innerproduct arg two', () => { + toXmlMatch( + tex2mml('\\innerproduct{A}{B}'), + ` + + + + A + + + | + + + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('innerproduct arg three', () => { + toXmlMatch( + tex2mml('\\innerproduct{A}{B}{C}'), + ` + + + + A + + + | + + + B + + + + + C + + ` + ); + }); + + /********************************************************************************/ + + it('ip arg one', () => { + toXmlMatch( + tex2mml('\\ip{A}'), + ` + + + + A + + + | + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('ip arg two', () => { + toXmlMatch( + tex2mml('\\ip{A}{B}'), + ` + + + + A + + + | + + + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('ip arg three', () => { + toXmlMatch( + tex2mml('\\ip{A}{B}{C}'), + ` + + + + A + + + | + + + B + + + + + C + + ` + ); + }); + + /********************************************************************************/ + + it('op arg one', () => { + toXmlMatch( + tex2mml('\\op{A}'), + ` + + | + + A + + + + + + + + + + A + + | + + ` + ); + }); + + /********************************************************************************/ + + it('op arg two', () => { + toXmlMatch( + tex2mml('\\op{A}{B}'), + ` + + | + + A + + + + + + + + + + B + + | + + ` + ); + }); + + /********************************************************************************/ + + it('op arg three', () => { + toXmlMatch( + tex2mml('\\op{A}{B}{C}'), + ` + + | + + A + + + + + + + + + + B + + | + + + C + + ` + ); + }); + + /********************************************************************************/ + + it('expectationvalue arg one', () => { + toXmlMatch( + tex2mml('\\expectationvalue{A}'), + ` + + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('expectationvalue arg two', () => { + toXmlMatch( + tex2mml('\\expectationvalue{A}{B}'), + ` + + + + B + + | + + + A + + + | + + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('expectationvalue arg three', () => { + toXmlMatch( + tex2mml('\\expectationvalue{A}{B}{C}'), + ` + + + + B + + | + + + A + + + | + + B + + + + + C + + ` + ); + }); + + /********************************************************************************/ + + it('expval arg one', () => { + toXmlMatch( + tex2mml('\\expval{A}'), + ` + + + + A + + + + ` + ); + }); + + /********************************************************************************/ + + it('expval arg two', () => { + toXmlMatch( + tex2mml('\\expval{A}{B}'), + ` + + + + B + + | + + + A + + + | + + B + + + + ` + ); + }); + + /********************************************************************************/ + + it('expval arg three', () => { + toXmlMatch( + tex2mml('\\expval{A}{B}{C}'), + ` + + + + B + + | + + + A + + + | + + B + + + + + C + + ` + ); + }); + + /********************************************************************************/ + + it('matrixelement arg three', () => { + toXmlMatch( + tex2mml('\\matrixelement{A}{B}{C}'), + ` + + + + A + + | + + + B + + + | + + C + + + + ` + ); + }); + + /********************************************************************************/ + + it('matrixelement arg four', () => { + toXmlMatch( + tex2mml('\\matrixelement{A}{B}{C}{D}'), + ` + + + + A + + | + + + B + + + | + + C + + + + + D + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Matrix Macros Rest', () => { + + /********************************************************************************/ + + it('zeromatrix', () => { + toXmlMatch( + tex2mml('\\pmqty{\\zeromatrix{2}{3}}'), + ` + + ( + + + + 0 + + + 0 + + + 0 + + + + + 0 + + + 0 + + + 0 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('paulimatrix 0', () => { + toXmlMatch( + tex2mml('\\pmqty{\\paulimatrix{0}}'), + ` + + ( + + + + 1 + + + 0 + + + + + 0 + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('paulimatrix 1', () => { + toXmlMatch( + tex2mml('\\pmqty{\\paulimatrix{1}}'), + ` + + ( + + + + 0 + + + 1 + + + + + 1 + + + 0 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('paulimatrix 2', () => { + toXmlMatch( + tex2mml('\\pmqty{\\paulimatrix{2}}'), + ` + + ( + + + + 0 + + + + i + + + + + i + + + 0 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('paulimatrix 3', () => { + toXmlMatch( + tex2mml('\\pmqty{\\paulimatrix{3}}'), + ` + + ( + + + + 1 + + + 0 + + + + + 0 + + + + 1 + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('paulimatrix 4', () => { + toXmlMatch( + tex2mml('\\pmqty{\\paulimatrix{4}}'), + ` + + ( + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('diagonalmatrix', () => { + toXmlMatch( + tex2mml('\\pmqty{\\diagonalmatrix{0,1\\\\2&3}}'), + ` + + ( + + + + + + + 0 + + + + + + + + + + + + 1 + + + + + 2 + + + 3 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('antidiagonalmatrix', () => { + toXmlMatch( + tex2mml('\\pmqty{\\antidiagonalmatrix{0,1\\\\2&3}}'), + ` + + ( + + + + + + + + 0 + + + + + + + + + + + 1 + + + + + 2 + + + 3 + + + + + + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Rest for Completion', () => { + + /********************************************************************************/ + + it('Issue 2831', () => { + toXmlMatch( + tex2mml('\\exp((\\frac{a}{a}a){a})'), + ` + exp + + + ( + ( + + a + a + + a + ) + + a + + ) + + ` + ); + }); + + /********************************************************************************/ + + it('Issue 3000', () => { + toXmlMatch( + tex2mml('\\sin(1\\over2)'), + ` + sin + + + ( + + 1 + 2 + + ) + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Options', () => { + beforeEach(() => setupTex(['base', 'physics'], { physics: { arrowdel: true, italicdiff: true } })); + + /********************************************************************************/ + + it('Arrowdel true', () => { + toXmlMatch( + tex2mml('\\vnabla'), + ` + + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Italicdif true', () => { + toXmlMatch( + tex2mml('\\dd{x}'), + ` + + d + x + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('physics')); diff --git a/testsuite/tests/input/tex/Require.test.ts b/testsuite/tests/input/tex/Require.test.ts new file mode 100644 index 000000000..1e53e06e3 --- /dev/null +++ b/testsuite/tests/input/tex/Require.test.ts @@ -0,0 +1,240 @@ +import { afterAll, beforeEach, describe, test, expect } from '@jest/globals'; +import { + getTokens, + toXmlMatch, + setupTexTypeset, + typeset2mml, + setupComponents, + expectTypesetError +} from '#helpers'; + +import {Configuration} from '#js/input/tex/Configuration.js'; +import {HandlerType, ConfigurationType} from '#js/input/tex/HandlerTypes.js'; +import {CommandMap} from '#js/input/tex/TokenMap.js'; + +declare const MathJax: any; + +setupComponents({ + loader: { + load: ['input/tex-base', '[tex]/require'], + source: { + '[tex]/error': '../../testsuite/lib/error.js' + }, + dependencies: { + '[tex]/upgreek': ['input/tex-base', '[tex]/error'] + } + }, + startup: { + ready() { + // + // Fake the menu, since that isn't added unless there is a window + // + MathJax.startup.extendHandler((handler: any) => { + class myMenuDoc extends handler.documentClass { + menu: any; + constructor(...args: any[]) { + super(...args); + this.menu = { + addRequiredExtensions(_required: any) {} + } + } + } + handler.documentClass = myMenuDoc; + return handler; + }, 20); + MathJax.startup.defaultReady(); + } + } +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +beforeEach(() => setupTexTypeset(['base', 'require'])); + +describe('Require', () => { + + /********************************************************************************/ + + test('Require package', async () => { + toXmlMatch( + await typeset2mml('\\require{bbox} \\bbox[red]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + test('Require with dependencies', async () => { + toXmlMatch( + await typeset2mml('\\require{cancel} \\cancel{x+1}'), + ` + + x + + + 1 + + ` + ); + }); + + /********************************************************************************/ + + test('Require with preprocessors', async () => { + toXmlMatch( + await typeset2mml('\\require{textcomp} \\text{a \\bf b}'), + ` + + + b + + ` + ); + }); + + /********************************************************************************/ + + test('Require with stack items', async () => { + toXmlMatch( + await typeset2mml('\\require{braket} \\bra{a}'), + ` + + + + a + + | + + ` + ); + }); + + /********************************************************************************/ + + test('Require with menu extensions', async () => { + toXmlMatch( + await typeset2mml('\\require{bbm} \\mathbbm{A}'), + ` + + A + + ` + ); + }); + + /********************************************************************************/ + + test('Bad Package name', async () => { + await expectTypesetError('\\require{***}') + .toBe('Argument for \\require is not a valid package name'); + }); + + /********************************************************************************/ + + test('Restricted Package', async () => { + await expectTypesetError('\\require{tagformat}') + .toBe('Extension "[tex]/tagformat" is not allowed to be loaded'); + }); + + /********************************************************************************/ + + test('Dependency error', async () => { + setupTexTypeset(['base', 'require']); + await expectTypesetError('\\require{upgreek}').toBe('Error in Dependency'); + }); + + /********************************************************************************/ + + test('Failed to load error', async () => { + setupTexTypeset(['base', 'require']); + await expectTypesetError('\\require{xyz}').toBe('Extension "xyz" failed to load'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Require Options', () => { + + /********************************************************************************/ + + test('Illegal Prefix', async () => { + setupTexTypeset(['base', 'require'], {require: {prefix: '***'}}); + await expectTypesetError('').toBe('Illegal characters used in \\require prefix'); + }); + + /********************************************************************************/ + + test('Prefix', async () => { + setupTexTypeset(['base', 'require'], {require: {prefix: 'test'}}); + expect(typeset2mml('').then(() => 'OK').catch((e) => e.message)) + .resolves.toBe('OK'); + }); + + /********************************************************************************/ + + test('DefaultAllow with allow', async () => { + setupTexTypeset(['base', 'require'], {require: {defaultAllow: false, allow: {bbox: true}}}); + toXmlMatch( + await typeset2mml('\\require{bbox} \\bbox[red]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + test('Prefixed options', async () => { + setupTexTypeset(['base', 'require'], {require: {defaultAllow: false, allow: {'[tex]/bbox': true}}}); + toXmlMatch( + await typeset2mml('\\require{bbox} \\bbox[red]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + test('RequireLoad with prefix', async () => { + new CommandMap('require-load', { + requireLoad(parser: any) { + MathJax._.input.tex.require.RequireConfiguration.RequireLoad(parser, '[tex]/bbox'); + } + }); + Configuration.create('require-load', { + [ConfigurationType.HANDLER]: { + [HandlerType.MACRO]: ['require-load'] + } + }); + setupTexTypeset(['base', 'require', 'require-load']); + toXmlMatch( + await typeset2mml('\\requireLoad \\bbox[red]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('require')); diff --git a/testsuite/tests/input/tex/SetOptions.test.ts b/testsuite/tests/input/tex/SetOptions.test.ts new file mode 100644 index 000000000..abdf100a5 --- /dev/null +++ b/testsuite/tests/input/tex/SetOptions.test.ts @@ -0,0 +1,338 @@ +import { beforeEach, describe, test } from '@jest/globals'; +import { + toXmlMatch, + setupTex, + setupTexTypeset, + tex2mml, + typeset2mml, + setupComponents, + expectTexError +} from '#helpers'; +import '#js/input/tex/setoptions/SetOptionsConfiguration'; +import '#js/input/tex/ams/AmsConfiguration'; +import '#js/input/tex/units/UnitsConfiguration'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Setoptions', () => { + + beforeEach(() => setupTex(['base', 'ams', 'units', 'setoptions'])); + + /********************************************************************************/ + + test('Set TeX option', () => { + toXmlMatch( + tex2mml('\\setOptions{tagSide=left} a=b\\tag{1}'), + ` + + + + (1) + + + a + = + b + + + + ` + ); + }); + + /********************************************************************************/ + + test('Set invalid option', () => { + expectTexError('\\setOptions{x=y}') + .toBe('Invalid TeX option "x"'); + }); + + /********************************************************************************/ + + test('Set prohibited option', () => { + expectTexError('\\setOptions{tags=all}') + .toBe('Option "tags" is not allowed to be set'); + }); + + /********************************************************************************/ + + test('Set invalid package', () => { + expectTexError('\\setOptions[abc]{x=y}') + .toBe('Not a defined package: abc'); + }); + + /********************************************************************************/ + + test('Set prohibited package', () => { + expectTexError('\\setOptions[setoptions]{setoptions=true}') + .toBe(`Options can't be set for package "setoptions"`); + }); + + /********************************************************************************/ + + test('Set package string option', () => { + toXmlMatch( + tex2mml('\\setOptions[ams]{multlineWidth=50%} \\begin{multline} a \\end{multline}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + test('Set package boolean option', () => { + toXmlMatch( + tex2mml('\\setOptions[units]{loose=true} \\units[1]{kg}'), + ` + 1 +   + + kg + + ` + ); + }); + + /********************************************************************************/ + + test('Set pacjage regexp option', () => { + toXmlMatch( + tex2mml('\\setOptions[ams]{operatornamePattern=/^[a-z0-9]+/} \\operatorname{ab1}'), + ` + ab1 + ` + ); + }); + + /********************************************************************************/ + + test('Set regexp option with flags', () => { + toXmlMatch( + tex2mml('\\setOptions[ams]{operatornamePattern=/^[a-z0-9]+/i} \\operatorname{ab1}'), + ` + ab1 + ` + ); + }); + + /********************************************************************************/ + + test('Set invalid package option', () => { + expectTexError('\\setOptions[ams]{x=y}') + .toBe('Invalid option "x" for package "ams"'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Setoptions options', () => { + + /********************************************************************************/ + + test('allowPackageDefault false',() => { + setupTex(['base', 'ams', 'setoptions'], {setoptions: {allowPackageDefault: false}}); + expectTexError('\\setOptions[ams]{multlineWidth=50%}') + .toBe(`Options can't be set for package "ams"`); + }); + + /********************************************************************************/ + + test('allowPackageDefault false ams true',() => { + setupTex(['base', 'ams', 'setoptions'], { + setoptions: { + allowPackageDefault: false, + allowOptions: {ams: true} + } + }); + toXmlMatch( + tex2mml('\\setOptions[ams]{multlineWidth=50%} \\begin{multline} a \\end{multline}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + test('allowOptionsDefault false',() => { + setupTex(['base', 'ams', 'setoptions'], {setoptions: {allowOptionsDefault: false}}); + expectTexError('\\setOptions[ams]{multlineWidth=50%}') + .toBe('Option "multlineWidth" is not allowed to be set for package ams'); + }); + + /********************************************************************************/ + + test('allowOptionsDefault false ams true',() => { + setupTex(['base', 'ams', 'setoptions'], { + setoptions: { + allowOptionsDefault: false, + allowOptions: {ams: true} + } + }); + expectTexError('\\setOptions[ams]{multlineWidth=50%} \\begin{multline} a \\end{multline}') + .toBe('Option "multlineWidth" is not allowed to be set for package ams'); + }); + + /********************************************************************************/ + + test('allowOptionsDefault false ams multlineWidth true',() => { + setupTex(['base', 'ams', 'setoptions'], { + setoptions: { + allowOptionsDefault: false, + allowOptions: { + ams: {multlineWidth: true} + } + } + }); + toXmlMatch( + tex2mml('\\setOptions[ams]{multlineWidth=50%} \\begin{multline} a \\end{multline}'), + ` + + + + a + + + + ` + ); + expectTexError('\\setOptions[ams]{multlineIndent=50%} \\begin{multline} a \\end{multline}') + .toBe('Option "multlineIndent" is not allowed to be set for package ams'); + }); + + /********************************************************************************/ + + test('filterPackage',() => { + setupTex(['base', 'ams', 'setoptions'], { + setoptions: { + filterPackage: (_parser: any, _extension: string) => false + } + }); + toXmlMatch( + tex2mml('\\setOptions[ams]{multlineWidth=50%} \\begin{multline} a \\end{multline}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + test('filterOption',() => { + setupTex(['base', 'ams', 'setoptions'], { + setoptions: { + filterOption: (_parser: any, _extension: string, _key: string) => false + } + }); + toXmlMatch( + tex2mml('\\setOptions[ams]{multlineWidth=50%} \\begin{multline} a \\end{multline}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + test('filterValue',() => { + setupTex(['base', 'ams', 'setoptions'], { + setoptions: { + filterValue: (_parser: any, _extension: string, _option: string, _value: string) => '25%' + } + }); + toXmlMatch( + tex2mml('\\setOptions[ams]{multlineWidth=50%} \\begin{multline} a \\end{multline}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Setoptions Require', () => { + + setupComponents({ + loader: {load: ['input/tex-base', '[tex]/require']} + }); + + beforeEach(() => setupTexTypeset(['base', 'require', 'setoptions'])); + + /********************************************************************************/ + + test('Require', async () => { + toXmlMatch( + await typeset2mml('\\require{bbox} \\bbox[red]{x}'), + ` + + x + + ` + ); + }); + + /********************************************************************************/ + + test('Require with option', async () => { + toXmlMatch( + await typeset2mml('\\require[ugly=true]{units} \\nicefrac{a}{b}'), + ` + + + a + + + b + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/input/tex/Tag.test.ts b/testsuite/tests/input/tex/Tag.test.ts new file mode 100644 index 000000000..c59313fd3 --- /dev/null +++ b/testsuite/tests/input/tex/Tag.test.ts @@ -0,0 +1,1948 @@ +import { beforeEach, describe, it } from '@jest/globals'; +import { + toXmlMatch, + setupTex, + tex2mml, + setupTexPage, + page2mml, + toXmlArrayMatch, + setupComponents, + expectTexError +} from '#helpers'; +import '#js/input/tex/ams/AmsConfiguration'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('TagAll', () => { + beforeEach(() => setupTex(['ams', 'base'], { tags: 'all' })); + + /********************************************************************************/ + + it('Single Expression', () => { + toXmlMatch( + tex2mml('a'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Align', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('MultLine', () => { + toXmlMatch( + tex2mml('\\begin{multline}a\\\\ b\\\\ c\\end{multline}'), + ` + + + + a + + + + + b + + + + + (1) + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Empty', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{}\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Align', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\notag\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Multline', () => { + toXmlMatch( + tex2mml('\\begin{multline}a\\\\ b\\\\ c\\notag\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Tag', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\notag\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Ref', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{A}'), + ` + + + + (1) + + + a + + + + + 1 + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Unknown', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{B}'), + ` + + + + (1) + + + a + + + + + ??? + + ` + ); + }); + + /********************************************************************************/ + + it('Eqref', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\eqref{A}'), + ` + + + + (1) + + + a + + + + + (1) + + ` + ); + }); + + /********************************************************************************/ + + it('Align Two labels', () => { + toXmlMatch( + tex2mml('\\begin{align}a=b\\label{A}\\\\ c&=d \\label{B}\\end{align}'), + ` + + + + (1) + + + a + = + b + + + + + (2) + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Illegal Tag Error', () => { + expectTexError('\\begin{split}a\\tag{A}\\end{split}') + .toBe('\\tag not allowed in split environment'); + }); + + /********************************************************************************/ + + it('Double Tag Error', () => { + expectTexError('\\begin{align}a\\tag{A}\\tag{B}\\end{align}') + .toBe('Multiple \\tag'); + }); + + /********************************************************************************/ + + it('Double Label Error', () => { + expectTexError('\\begin{align}a\\label{A}\\label{B}\\end{align}') + .toBe('Multiple \\label'); + }); + + /********************************************************************************/ + + it('Duplicate Label Error', () => { + expectTexError('\\begin{align}a\\label{A}\\\\ b\\label{A}\\end{align}') + .toBe("Label 'A' multiply defined"); + }); + + /********************************************************************************/ + + it('Tag Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\end{align}'), + ` + + + + (A) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\\\b\\end{align}'), + ` + + + + (A) + + + a + + + + + (1) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\\\b\\tag{B}\\end{align}'), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\end{align}'), + ` + + + + (A) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\\\b\\label{B}\\end{align}'), + ` + + + + (A) + + + a + + + + + (1) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named Named', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\tag{B}\\label{B}\\end{align}' + ), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{A}'), + ` + + + + (1) + + + a + + + + + 1 + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\end{align}\\ref{A}'), + ` + + + + (A) + + + a + + + + + A + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named Default', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\label{B}\\end{align}\\ref{A}\\ref{B}' + ), + ` + + + + (A) + + + a + + + + + (1) + + + b + + + + + A + + + 1 + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named Named', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\tag{B}\\label{B}\\end{align}\\ref{A}\\ref{B}' + ), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + + A + + + B + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('TagNone', () => { + beforeEach(() => setupTex(['ams', 'base'], { tags: 'none' })); + + /********************************************************************************/ + + it('Single Expression', () => { + toXmlMatch( + tex2mml('a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Simple Tag', () => { + toXmlMatch( + tex2mml('a\\tag{0}'), + ` + + + + (0) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Align', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Split', () => { + toXmlMatch( + tex2mml('\\begin{split}a\\end{split}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('MultLine', () => { + toXmlMatch( + tex2mml('\\begin{multline}a\\\\ b\\\\ c\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Empty', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{}\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Align', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\notag\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Multline', () => { + toXmlMatch( + tex2mml('\\begin{multline}a\\\\ b\\\\ c\\notag\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Tag', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\notag\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Ref', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{A}'), + ` + + + + a + + + + + ??? + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Unknown', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{B}'), + ` + + + + a + + + + + ??? + + ` + ); + }); + + /********************************************************************************/ + + it('Eqref', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\eqref{A}'), + ` + + + + a + + + + + (???) + + ` + ); + }); + + /********************************************************************************/ + + it('Align Two labels', () => { + expectTexError('\\begin{align}a=b\\label{A}\\\\ c&=d \\label{B}\\end{align}') + .toBe('Multiple \\label'); + }); + + /********************************************************************************/ + + it('Illegal Tag Error', () => { + expectTexError('\\begin{split}a\\tag{A}\\end{split}') + .toBe('\\tag not allowed in split environment'); + }); + + /********************************************************************************/ + + it('Double Tag Error', () => { + expectTexError('\\begin{align}a\\tag{A}\\tag{B}\\end{align}') + .toBe('Multiple \\tag'); + }); + + /********************************************************************************/ + + it('Double Label Error', () => { + expectTexError('\\begin{align}a\\label{A}\\label{B}\\end{align}') + .toBe('Multiple \\label'); + }); + + /********************************************************************************/ + + it('Duplicate Label Error', () => { + expectTexError('\\begin{align}a\\label{A}\\\\ b\\label{A}\\end{align}') + .toBe('Multiple \\label'); + }); + + /********************************************************************************/ + + it('Tag Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\end{align}'), + ` + + + + (A) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\\\b\\end{align}'), + ` + + + + (A) + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\\\b\\tag{B}\\end{align}'), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\end{align}'), + ` + + + + (A) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\\\b\\label{B}\\end{align}'), + ` + + + + (A) + + + a + + + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named Named', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\tag{B}\\label{B}\\end{align}' + ), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{A}'), + ` + + + + a + + + + + ??? + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\end{align}\\ref{A}'), + ` + + + + (A) + + + a + + + + + A + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named Default', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\label{B}\\end{align}\\ref{A}\\ref{B}' + ), + ` + + + + (A) + + + a + + + + + b + + + + + A + + + ??? + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named Named', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\tag{B}\\label{B}\\end{align}\\ref{A}\\ref{B}' + ), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + + A + + + B + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('TagAms', () => { + beforeEach(() => setupTex(['ams', 'base'], { tags: 'ams' })); + + /********************************************************************************/ + + it('Single Expression', () => { + toXmlMatch( + tex2mml('a'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + it('Align', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Split', () => { + toXmlMatch( + tex2mml('\\begin{split}a\\end{split}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('MultLine', () => { + toXmlMatch( + tex2mml('\\begin{multline}a\\\\ b\\\\ c\\end{multline}'), + ` + + + + a + + + + + b + + + + + (1) + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Empty', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{}\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Align', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\notag\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Multline', () => { + toXmlMatch( + tex2mml('\\begin{multline}a\\\\ b\\\\ c\\notag\\end{multline}'), + ` + + + + a + + + + + b + + + + + c + + + + ` + ); + }); + + /********************************************************************************/ + + it('Notag Tag', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\notag\\end{align}'), + ` + + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Ref', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{A}'), + ` + + + + (1) + + + a + + + + + 1 + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Unknown', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{B}'), + ` + + + + (1) + + + a + + + + + ??? + + ` + ); + }); + + /********************************************************************************/ + + it('Eqref', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\eqref{A}'), + ` + + + + (1) + + + a + + + + + (1) + + ` + ); + }); + + /********************************************************************************/ + + it('Align Two labels', () => { + toXmlMatch( + tex2mml('\\begin{align}a=b\\label{A}\\\\ c&=d \\label{B}\\end{align}'), + ` + + + + (1) + + + a + = + b + + + + + (2) + + + c + + + + + = + d + + + + + ` + ); + }); + + /********************************************************************************/ + + it('Illegal Tag Error', () => { + expectTexError('\\begin{split}a\\tag{A}\\end{split}') + .toBe('\\tag not allowed in split environment'); + }); + + /********************************************************************************/ + + it('Double Tag Error', () => { + expectTexError('\\begin{align}a\\tag{A}\\tag{B}\\end{align}') + .toBe('Multiple \\tag'); + }); + + /********************************************************************************/ + + it('Double Label Error', () => { + expectTexError('\\begin{align}a\\label{A}\\label{B}\\end{align}') + .toBe('Multiple \\label'); + }); + + /********************************************************************************/ + + it('Duplicate Label Error', () => { + expectTexError('\\begin{align}a\\label{A}\\\\ b\\label{A}\\end{align}') + .toBe('Label \'A\' multiply defined'); + }); + + /********************************************************************************/ + + it('Tag Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\end{align}'), + ` + + + + (A) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\\\b\\end{align}'), + ` + + + + (A) + + + a + + + + + (1) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Tag Named Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\\\b\\tag{B}\\end{align}'), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\end{align}'), + ` + + + + (A) + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\\\b\\label{B}\\end{align}'), + ` + + + + (A) + + + a + + + + + (1) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Label Named Named', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\tag{B}\\label{B}\\end{align}' + ), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Default', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\label{A}\\end{align}\\ref{A}'), + ` + + + + (1) + + + a + + + + + 1 + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named', () => { + toXmlMatch( + tex2mml('\\begin{align}a\\tag{A}\\label{A}\\end{align}\\ref{A}'), + ` + + + + (A) + + + a + + + + + A + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named Default', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\label{B}\\end{align}\\ref{A}\\ref{B}' + ), + ` + + + + (A) + + + a + + + + + (1) + + + b + + + + + A + + + 1 + + ` + ); + }); + + /********************************************************************************/ + + it('Ref Named Named', () => { + toXmlMatch( + tex2mml( + '\\begin{align}a\\tag{A}\\label{A}\\\\b\\tag{B}\\label{B}\\end{align}\\ref{A}\\ref{B}' + ), + ` + + + + (A) + + + a + + + + + (B) + + + b + + + + + A + + + B + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +setupComponents({ + loader: {load: ['input/tex-base', '[tex]/ams']} +}); + +describe('Page References', () => { + beforeEach(() => setupTexPage(['base', 'ams'])); + + it('Forward Reference', async () => { + toXmlArrayMatch( + await page2mml('

$$a=b\\label{eq1}\\tag{1}$$

Refer to \\eqref{eq1}

'), + [ + ` + + + + (1) + + + a + = + b + + + + `, + ` + + (1) + + ` + ] + ); + }); + + it('Forward Reference', async () => { + toXmlArrayMatch( + await page2mml('

Refer to \\eqref{eq1}

$$a=b\\label{eq1}\\tag{1}$$

'), + [ + ` + + (1) + + `, + ` + + + + (1) + + + a + = + b + + + + ` + ] + ); + }); + + it('LabelIds', () => { + setupTex(['base', 'ams'], {useLabelIds: false}); + toXmlMatch( + tex2mml('a\\label{eq1}\\tag{1}'), + ` + + + + (1) + + + a + + + + ` + ); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/input/tex/TagFormat.test.ts b/testsuite/tests/input/tex/TagFormat.test.ts new file mode 100644 index 000000000..fe2ed47bc --- /dev/null +++ b/testsuite/tests/input/tex/TagFormat.test.ts @@ -0,0 +1,162 @@ +import { beforeEach, describe, test } from '@jest/globals'; +import { toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/tagformat/TagFormatConfiguration'; +import '#js/input/tex/ams/AmsConfiguration'; + +beforeEach(() => setupTex(['base', 'ams', 'tagformat'], { + tagformat: { + number: (n: number) => `A${n}`, + tag: (tag: string) => `[${tag}]`, + id: (id: string) => 'my-tag:' + id.replace(/\s/g, '_'), + url: (id: string, base: string) => `[[${base}#${encodeURIComponent(id)}]]` + }, + tags: 'ams' +})); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Tagformat', () => { + + /********************************************************************************/ + + test('Basic tag', () => { + toXmlMatch( + tex2mml('x \\tag{1}'), + ` + + + + [1] + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + test('Text tag', () => { + toXmlMatch( + tex2mml('x \\tag{x}'), + ` + + + + [x] + + + x + + + + ` + ); + }); + + /********************************************************************************/ + + test('Ref', () => { + toXmlMatch( + tex2mml('\\begin{align}x \\label{test}\\tag{x}\\\\ \\ref{test} \\end{align}'), + ` + + + + [x] + + + x + + + + + [A1] + + + + x + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Eqref', () => { + toXmlMatch( + tex2mml('\\begin{align}x \\label{test}\\tag{x}\\\\ \\eqref{test} \\end{align}'), + ` + + + + [x] + + + x + + + + + [A1] + + + + [x] + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Custom ref', () => { + setupTex(['base', 'ams', 'tagformat'], { + tagformat: { + ref: (tag: string) => `**${tag}**` + }, + tags: 'ams' + }); + toXmlMatch( + tex2mml('\\begin{align}x \\label{test}\\tag{x}\\\\ \\eqref{test} \\end{align}'), + ` + + + + (x) + + + x + + + + + (1) + + + + **x** + + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/input/tex/Tex.test.ts b/testsuite/tests/input/tex/Tex.test.ts new file mode 100644 index 000000000..131c4a4ff --- /dev/null +++ b/testsuite/tests/input/tex/Tex.test.ts @@ -0,0 +1,626 @@ +import { beforeEach, describe, test, expect } from '@jest/globals'; +import { + toXmlMatch, + toXmlArrayMatch, + toMathML, + tex2mml, + page2mml, + setupTex, + setupTexPage, + setupComponents, + trapOutput, + trapErrors, + expectTexError +} from '#helpers'; +import '#js/input/tex/ams/AmsConfiguration'; +import '#js/input/tex/newcommand/NewcommandConfiguration'; + +import { TeX } from '#js/input/tex.js'; +import { MmlFactory } from '#js/core/MmlTree/MmlFactory.js'; + +import { Configuration, ConfigurationHandler } from '#js/input/tex/Configuration.js'; +import { HandlerType, ConfigurationType } from '#js/input/tex/HandlerTypes.js'; +import { CommandMap } from '#js/input/tex/TokenMap.js'; +import { Token } from '#js/input/tex/Token.js'; +import { TagsFactory } from '#js/input/tex/Tags.js'; +import TexError from '#js/input/tex/TexError.js'; +import { ParseUtil, KeyValueTypes, KeyValueDef } from '#js/input/tex/ParseUtil.js'; + +/**********************************************************************************/ +/**********************************************************************************/ + +const tex = new TeX(); +tex.setMmlFactory(new MmlFactory()); + +describe('TeX', () => { + test('Reset', () => expect(tex.reset()).toBe(undefined)); +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('NodeFactory', () => { + + test('createText null text', () => { + expect(tex.parseOptions.nodeFactory.create('text', null)).toBe(null) + }); + + test('create null kind', () => { + toXmlMatch( + toMathML(tex.parseOptions.nodeFactory.create('undefined', 'mi')), + `` + ); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('NodeUtil', () => { + + test('inferred propery', () => { + const mrow = tex.parseOptions.nodeFactory.create('node', 'mrow', [], {inferred: true}); + expect(mrow.getProperty('inferred')).toBe(undefined); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Stack', () => { + + new CommandMap('stackMacros', { + showStack: (parser) => {parser.stack.toString()}, + getTop: 'getTop' // coverage for macro defined by name of method in methods object + }, { + getTop: (parser) => { + const top = parser.stack.Top(5); + const mtext = parser.create('token', 'mtext', {}, top === null ? 'yes' : 'no'); + parser.Push(mtext); + }, + }); + + Configuration.create('stackMacros', { + [ConfigurationType.HANDLER]: { + [HandlerType.MACRO]: ['stackMacros'] + } + }); + + beforeEach(() => setupTex(['base', 'stackMacros'])); + + /********************************************************************************/ + + test('toString', () => { + toXmlMatch( + tex2mml('\\showStack'), + `` + ); + }); + + /********************************************************************************/ + + test('getTop', () => { + setupTex(['base', 'stackMacros']); + toXmlMatch( + tex2mml('\\getTop'), + ` + yes + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Token', () => { + + test('token', () => { + const token = new Token('x', 'y', {}); + expect(token.token).toBe('x'); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Tags', () => { + + test('noTag', () => { + expect((tex.parseOptions.tags as any).noTag).toBe(false); + }); + + test('Unknown default', () => { + TagsFactory.setDefault('unknown'); + const message = trapErrors(() => {TagsFactory.create('error')}); + TagsFactory.setDefault('none'); + expect(message).toBe('Unknown tags class'); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('TexError', () => { + + test('Number argument', () => { + const err = new TexError('test', 'Number: %1', 1 as any); + expect(err.message).toBe('Number: 1'); + }); + + test('Braced insertion', () => { + const err = new TexError('test', 'Msg: %{1}, Number: %{2}', 'OK', 2 as any); + expect(err.message).toBe('Msg: OK, Number: 2'); + }); + + test('Plural', () => { + const err = new TexError('test', '%{plural:%1|abc}', 'apple'); + expect(err.message).toBe('%{plural:%1|abc}'); + }); + + test('Percent', () => { + const err = new TexError('test', '10%%'); + expect(err.message).toBe('10%'); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +setupComponents({ + loader: {load: ['input/tex-base']} +}); + +describe('FindTeX', () => { + + setupTexPage(['base']); + + /********************************************************************************/ + + test('display math', async () => { + toXmlArrayMatch( + await page2mml('abc $$ x + 1 $$ def'), + [ + ` + x + + + 1 + ` + ] + ); + }); + + /********************************************************************************/ + + test('environment', async () => { + toXmlArrayMatch( + await page2mml('abc \\begin{equation} x=y \\end{equation} def'), + [ + ` + x + = + y + ` + ] + ); + }); + + /********************************************************************************/ + + test('Nested braces', async () => { + toXmlArrayMatch( + await page2mml('abc $$a + {\\bf b} + c$$ def'), + [ + ` + a + + + + b + + + + c + ` + ] + ); + }); + + /********************************************************************************/ + + test('processEscapes', async () => { + toXmlArrayMatch( + await page2mml('abc \\$ def'), + [ + ` + + $ + + ` + ] + ); + }); + + /********************************************************************************/ + + test('ref undefined', async () => { + toXmlArrayMatch( + await page2mml('abc \\ref{x} def'), + [ + ` + + ??? + + ` + ] + ); + }); + + /********************************************************************************/ + + test('No close delim', () => { + expect(page2mml('abc $$ x + 1')).resolves.toEqual([]); + }); + + /********************************************************************************/ + + test('No close delim', () => { + expect(page2mml('abc \\begin{align} x + 1')).resolves.toEqual([]); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Configuration', () => { + + /********************************************************************************/ + + test('keys', () => { + expect(Array.from(ConfigurationHandler.keys()).length > 0).toBe(true); + }); + + /********************************************************************************/ + + test('init', () => { + const init = () => {}; + const config = Configuration.create('init', { + [ConfigurationType.INIT]: init + }); + expect(config.init).toBe(init); + }); + + /********************************************************************************/ + + test('init null', () => { + expect(ConfigurationHandler.get('base').init).toBe(null); + }); + + /********************************************************************************/ + + test('Package priority', () => { + const order: number[] = []; + Configuration.create('priority 1', { + [ConfigurationType.INIT]: () => {order.push(1)} + }); + Configuration.create('priority 2', { + [ConfigurationType.INIT]: () => {order.push(2)} + }); + setupTex([['priority 1', 1], ['priority 2', 2]]); + expect(order).toEqual([1, 2]); + setupTex([['priority 1', 2], ['priority 2', 1]]); + expect(order).toEqual([1, 2, 2, 1]); + }); + + /********************************************************************************/ + + test('Parser error', () => { + Configuration.create('error', { + [ConfigurationType.PARSER]: 'error' + }); + const message = trapErrors(() => {new TeX({packages: ['base', 'error']})}); + expect(message).toBe("Package 'error' doesn't target the proper parser"); + }); + + /********************************************************************************/ + + test('Package error', () => { + const message = trapOutput('warn', () => new TeX({packages: ['base', 'undefined']})); + expect(message).toBe("MathJax Warning: Package 'undefined' not found. Omitted."); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('MapHandler', () => { + + /********************************************************************************/ + + test('Undefined', () => { + Configuration.create('BadHandler', { + [ConfigurationType.HANDLER]: { + [HandlerType.MACRO]: ['undefindHandler'] + } + }); + const message = trapOutput('log', () => new TeX({packages: ['base', 'BadHandler']})); + expect(message).toBe("TexParser Warning: Configuration 'undefindHandler' not found! Omitted."); + }); + + /********************************************************************************/ + + test('remove', () => { + const fallback = () => {}; + Configuration.create('fallback', { + [ConfigurationType.FALLBACK]: { + [HandlerType.MACRO]: fallback + } + }); + const tex = new TeX({packages: ['fallback']}); + const map = (tex as any).configuration.handlers.get(HandlerType.MACRO); + expect(Array.from((map as any)._fallback).length).toBe(1); + map.remove([], fallback); + expect(Array.from((map as any)._fallback).length).toBe(0); + }); + + /********************************************************************************/ + + test('toString', () => { + const map = (tex as any).configuration.handlers.get(HandlerType.MACRO); + expect(map.toString()) + .toBe('mathchar7, mathchar0mo, mathchar0mi, ucGreek, lcGreek, macros, delimiter'); + }); + + /********************************************************************************/ + + test('retrieve', () => { + const handlers = (tex as any).configuration.handlers; + expect(handlers.retrieve('undefined')).toBe(null); + }); + + /********************************************************************************/ + + test('keys', () => { + const handlers = (tex as any).configuration.handlers; + expect(Array.from(handlers.keys()).sort()).toEqual(Object.values(HandlerType).sort()); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('TexParser', () => { + + /********************************************************************************/ + + test('toString', () => { + let output = ''; + new CommandMap('showParser', { + showparser(parser: any) { + output = parser.toString(); + } + }); + Configuration.create('showParser', { + [ConfigurationType.HANDLER]: { + [HandlerType.MACRO]: ['showParser'] + } + }); + setupTex(['base', 'showParser']); + tex2mml('\\showparser'); + expect(output).toBe( + [ + 'character: digit, letter, special, command', + 'delimiter: delimiter', + 'macro: showParser, mathchar7, mathchar0mo, mathchar0mi, ucGreek, lcGreek, macros, delimiter', + 'environment: environment', + '' + ].join('\n') + ); + }); + + test('GetBrackets nested [', () => { + setupTex(['base', 'ams']); + toXmlMatch( + tex2mml('\\xrightarrow[{[x]}]{a}'), + ` + + + + + [ + x + ] + + + + + a + + + + ` + ); + }); + + test('GetBrackets matchBrakets', () => { + new CommandMap('matchBrackets', { + matchbrackets(parser: any, name: string) { + const arg = parser.GetBrackets(name, '', true); + parser.Push(parser.create('token', 'mtext', {}, arg)); + } + }); + Configuration.create('matchBrackets', { + [ConfigurationType.HANDLER]: { + [HandlerType.MACRO]: ['matchBrackets'] + } + }); + setupTex(['base', 'matchBrackets']); + toXmlMatch( + tex2mml('\\matchbrackets[[x]]'), + ` + [x] + ` + ); + }); + + test('mml', () => { + new CommandMap('mml', { + mml(parser: any) { + parser.mml(); + } + }); + Configuration.create('mml', { + [ConfigurationType.HANDLER]: { + [HandlerType.MACRO]: ['mml'] + } + }); + setupTex(['base', 'mml']); + toXmlMatch( + tex2mml('{\\mml}'), + ` + + ` + ); + }); + + test('Removed delimiter', () => { + setupTex(['base', 'ams', 'newcommand']); + toXmlMatch( + tex2mml('\\let\\vert=x \\begin{vmatrix} a \\end{vmatrix}'), + ` + + + + a + + + + ` + ); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('ParseUtil', () => { + + /********************************************************************************/ + + test('keyValue', () => { + expect(ParseUtil.keyvalOptions('ab')).toEqual({ab: true}); + expect(ParseUtil.keyvalOptions('ab=true')).toEqual({ab: true}); + expect(ParseUtil.keyvalOptions('ab=false')).toEqual({ab: false}); + expect(ParseUtil.keyvalOptions('ab=xyz')).toEqual({ab: 'xyz'}); + expect(ParseUtil.keyvalOptions('ab=')).toEqual({ab: ''}); + expect(ParseUtil.keyvalOptions('{ab=}')).toEqual({ab: ''}); + expect(ParseUtil.keyvalOptions('{{ab=}}')).toEqual({'ab=': true}); + expect(ParseUtil.keyvalOptions('ab=1,cd')).toEqual({'ab': "1", cd: true}); + expect(ParseUtil.keyvalOptions('ab cd=x')).toEqual({'ab cd': 'x'}); + expect(ParseUtil.keyvalOptions('{ab,c=d}=x')).toEqual({'ab,c=d': 'x'}); + expect(ParseUtil.keyvalOptions('ab=\\x')).toEqual({ab: '\\x'}); + expect(ParseUtil.keyvalOptions('ab=\\{')).toEqual({ab: '\\{'}); + expect(ParseUtil.keyvalOptions('ab={a\\{b}')).toEqual({ab: 'a\\{b'}); + expect(ParseUtil.keyvalOptions('ab=\\')).toEqual({ab: '\\'}); + expect(ParseUtil.keyvalOptions('a\\b=c')).toEqual({'a\\b': 'c'}); + }); + + test('keyValue braces', () => { + expect(ParseUtil.keyvalOptions('ab={{{cd} ef}}')).toEqual({ab: '{cd} ef'}); + expect(ParseUtil.keyvalOptions('ab={{{cd} ef}}', null, false, true)).toEqual({ab: '{{cd} ef}'}); + expect(ParseUtil.keyvalOptions('ab={x,y=z}')).toEqual({ab: 'x,y=z'}); + }); + + test('keyValue extra open brace', () => { + const message = trapErrors(() => ParseUtil.keyvalOptions('ab={c{d}')); + expect(message).toBe('Extra open brace or missing close brace'); + }); + + test('keyValue extra close brace', () => { + const message = trapErrors(() => ParseUtil.keyvalOptions('ab=c{d}}')); + expect(message).toBe('Extra close brace or missing open brace'); + }); + + test('keyValue allowed values', () => { + expect(ParseUtil.keyvalOptions('ab', {ab: 1})).toEqual({ab: true}); + expect(ParseUtil.keyvalOptions('ab', {abc: 1})).toEqual({}); + expect(ParseUtil.keyvalOptions('ab', {ab: KeyValueTypes.boolean})).toEqual({ab: true}); + expect(ParseUtil.keyvalOptions('ab=true', {ab: KeyValueTypes.boolean})).toEqual({ab: true}); + expect(ParseUtil.keyvalOptions('ab=1.2', {ab: KeyValueTypes.number})).toEqual({ab: 1.2}); + expect(ParseUtil.keyvalOptions('ab=12', {ab: KeyValueTypes.integer})).toEqual({ab: 12}); + expect(ParseUtil.keyvalOptions('ab=xy', {ab: KeyValueTypes.string})).toEqual({ab: 'xy'}); + expect(ParseUtil.keyvalOptions('ab=x', {ab: KeyValueDef.oneof('x','y')})).toEqual({ab: 'x'}); + expect(ParseUtil.keyvalOptions('ab=y', {ab: KeyValueDef.oneof('x','y')})).toEqual({ab: 'y'}); + expect(ParseUtil.keyvalOptions('ab=2em', {ab: KeyValueTypes.dimen})).toEqual({ab: '2em'}); + }); + + test('keyValue allowed with errors', () => { + function trap(test: string, allow: any) { + return expect(trapErrors(() => ParseUtil.keyvalOptions(test, allow, true))); + } + const error = "Value for key 'ab' is not of the expected type"; + trap('ab', {abc: 1}).toBe('Invalid option: ab'); + trap('ab=x', {ab: KeyValueTypes.boolean}).toBe(error); + trap('ab=x', {ab: KeyValueTypes.number}).toBe(error); + trap('ab=1.2', {ab: KeyValueTypes.integer}).toBe(error); + trap('ab=', {ab: KeyValueTypes.string}).toBe('(no error)'); + trap('ab=z', {ab: KeyValueDef.oneof('x','y')}).toBe(error); + trap('ab=2xy', {ab: KeyValueTypes.dimen}).toBe(error); + trap('ab=2', {ab: KeyValueTypes.dimen}).toBe(error); + }); + + test('fixedFence', () => { + function create(kind: string, options?: any, children?: any[]) { + return tex.mmlFactory.create(kind, options, children); + } + const mrow = create('mrow', {}, [create('mi')]); + const mml = ParseUtil.fixedFence(tex.parseOptions, '(', mrow, ')'); + const kinds = mml.childNodes.map((node) => node.kind); + expect(kinds).toEqual(['MathChoice', 'mi', 'MathChoice']); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('ColumnParser', () => { + + /********************************************************************************/ + + test('Error', () => { + new CommandMap('cError', { + cError(parser: any) { + const array = parser.itemFactory.create('array'); + parser.configuration.columnParser.process(parser, '@{x', array); + } + }); + Configuration.create('cError', { + [ConfigurationType.HANDLER]: { + [HandlerType.MACRO]: ['cError'] + } + }); + setupTex(['base', 'cError']); + expectTexError('\\cError').toBe('Missing close brace'); + }); + +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/input/tex/TexHtml.test.ts b/testsuite/tests/input/tex/TexHtml.test.ts new file mode 100644 index 000000000..f85b974e5 --- /dev/null +++ b/testsuite/tests/input/tex/TexHtml.test.ts @@ -0,0 +1,174 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { + getTokens, + toXmlMatch, + setupTex, + setupTexRender, + tex2mml, + render2mml, + expectTexError +} from '#helpers'; +import '#js/input/tex/texhtml/TexHtmlConfiguration'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Texhtml', () => { + + beforeEach(() => setupTexRender(['base', 'texhtml'], {allowTexHTML: true})); + + /********************************************************************************/ + + test('Html', () => { + toXmlMatch( + render2mml('x + bold + y'), + ` + x + + + bold + + + y + ` + ); + }); + + /********************************************************************************/ + + test('Html multiple', () => { + toXmlMatch( + render2mml('x + bold + italicy'), + ` + x + + + bold + + + italic + y + ` + ); + }); + + /********************************************************************************/ + + test('Html nested', () => { + toXmlMatch( + render2mml('x + bold and html + y'), + ` + x + + +
bold and html
+ + + y +
` + ); + }); + + /********************************************************************************/ + + test('Html empty tag', () => { + toXmlMatch( + render2mml('x + + y'), + ` + x + + + + + y + ` + ); + }); + + /********************************************************************************/ + + test('Html no tag', () => { + toXmlMatch( + render2mml('x < y'), + ` + x + < + y + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Texhtml error', () => { + + beforeEach(() => setupTex(['base', 'texhtml'], {allowTexHTML: true})); + + /********************************************************************************/ + + test('Html missing comment tag', () => { + expectTexError('x + bold + y') + .toBe('Could not find for '); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Texhtml not enabled', () => { + + beforeEach(() => setupTex(['base', 'texhtml'], {allowTexHTML: false})); + + /********************************************************************************/ + + test('Html not allowed', () => { + toXmlMatch( + tex2mml('x + a + y'), + ` + x + + + < + t + e + x + + h + t + m + l + >< + b + > + a + < + + / + + b + >< + + / + + t + e + x + + h + t + m + l + > + + + y + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('texhtml')); diff --git a/testsuite/tests/input/tex/Textcomp.test.ts b/testsuite/tests/input/tex/Textcomp.test.ts new file mode 100644 index 000000000..9dcee65d7 --- /dev/null +++ b/testsuite/tests/input/tex/Textcomp.test.ts @@ -0,0 +1,1328 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/textcomp/TextcompConfiguration'; +import '#js/input/tex/textmacros/TextMacrosConfiguration'; + +beforeEach(() => setupTex(['base', 'textcomp'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Textcomp', () => { + + /********************************************************************************/ + + test('textasciicircum', () => { + toXmlMatch( + tex2mml('\\textasciicircum'), + ` + ^ + ` + ); + }); + + /********************************************************************************/ + + test('textasciitilde', () => { + toXmlMatch( + tex2mml('\\textasciitilde'), + ` + ~ + ` + ); + }); + + /********************************************************************************/ + + test('textasteriskcentered', () => { + toXmlMatch( + tex2mml('\\textasteriskcentered'), + ` + * + ` + ); + }); + + /********************************************************************************/ + + test('textbackslash', () => { + toXmlMatch( + tex2mml('\\textbackslash'), + ` + \\ + ` + ); + }); + + /********************************************************************************/ + + test('textbar', () => { + toXmlMatch( + tex2mml('\\textbar'), + ` + | + ` + ); + }); + + /********************************************************************************/ + + test('textbraceleft', () => { + toXmlMatch( + tex2mml('\\textbraceleft'), + ` + { + ` + ); + }); + + /********************************************************************************/ + + test('textbraceright', () => { + toXmlMatch( + tex2mml('\\textbraceright'), + ` + } + ` + ); + }); + + /********************************************************************************/ + + test('textbullet', () => { + toXmlMatch( + tex2mml('\\textbullet'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textdagger', () => { + toXmlMatch( + tex2mml('\\textdagger'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textdaggerdbl', () => { + toXmlMatch( + tex2mml('\\textdaggerdbl'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textellipsis', () => { + toXmlMatch( + tex2mml('\\textellipsis'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textemdash', () => { + toXmlMatch( + tex2mml('\\textemdash'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textendash', () => { + toXmlMatch( + tex2mml('\\textendash'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textexclamdown', () => { + toXmlMatch( + tex2mml('\\textexclamdown'), + ` + ¡ + ` + ); + }); + + /********************************************************************************/ + + test('textgreater', () => { + toXmlMatch( + tex2mml('\\textgreater'), + ` + > + ` + ); + }); + + /********************************************************************************/ + + test('textless', () => { + toXmlMatch( + tex2mml('\\textless'), + ` + < + ` + ); + }); + + /********************************************************************************/ + + test('textordfeminine', () => { + toXmlMatch( + tex2mml('\\textordfeminine'), + ` + ª + ` + ); + }); + + /********************************************************************************/ + + test('textordmasculine', () => { + toXmlMatch( + tex2mml('\\textordmasculine'), + ` + º + ` + ); + }); + + /********************************************************************************/ + + test('textparagraph', () => { + toXmlMatch( + tex2mml('\\textparagraph'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textperiodcentered', () => { + toXmlMatch( + tex2mml('\\textperiodcentered'), + ` + · + ` + ); + }); + + /********************************************************************************/ + + test('textquestiondown', () => { + toXmlMatch( + tex2mml('\\textquestiondown'), + ` + ¿ + ` + ); + }); + + /********************************************************************************/ + + test('textquotedblleft', () => { + toXmlMatch( + tex2mml('\\textquotedblleft'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textquotedblright', () => { + toXmlMatch( + tex2mml('\\textquotedblright'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textquoteleft', () => { + toXmlMatch( + tex2mml('\\textquoteleft'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textquoteright', () => { + toXmlMatch( + tex2mml('\\textquoteright'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textsection', () => { + toXmlMatch( + tex2mml('\\textsection'), + ` + § + ` + ); + }); + + /********************************************************************************/ + + test('textunderscore', () => { + toXmlMatch( + tex2mml('\\textunderscore'), + ` + _ + ` + ); + }); + + /********************************************************************************/ + + test('textvisiblespace', () => { + toXmlMatch( + tex2mml('\\textvisiblespace'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textacutedbl', () => { + toXmlMatch( + tex2mml('\\textacutedbl'), + ` + ˝ + ` + ); + }); + + /********************************************************************************/ + + test('textasciiacute', () => { + toXmlMatch( + tex2mml('\\textasciiacute'), + ` + ´ + ` + ); + }); + + /********************************************************************************/ + + test('textasciibreve', () => { + toXmlMatch( + tex2mml('\\textasciibreve'), + ` + ˘ + ` + ); + }); + + /********************************************************************************/ + + test('textasciicaron', () => { + toXmlMatch( + tex2mml('\\textasciicaron'), + ` + ˇ + ` + ); + }); + + /********************************************************************************/ + + test('textasciidieresis', () => { + toXmlMatch( + tex2mml('\\textasciidieresis'), + ` + ¨ + ` + ); + }); + + /********************************************************************************/ + + test('textasciimacron', () => { + toXmlMatch( + tex2mml('\\textasciimacron'), + ` + ¯ + ` + ); + }); + + /********************************************************************************/ + + test('textgravedbl', () => { + toXmlMatch( + tex2mml('\\textgravedbl'), + ` + ˵ + ` + ); + }); + + /********************************************************************************/ + + test('texttildelow', () => { + toXmlMatch( + tex2mml('\\texttildelow'), + ` + ˷ + ` + ); + }); + + /********************************************************************************/ + + test('textbaht', () => { + toXmlMatch( + tex2mml('\\textbaht'), + ` + ฿ + ` + ); + }); + + /********************************************************************************/ + + test('textcent', () => { + toXmlMatch( + tex2mml('\\textcent'), + ` + ¢ + ` + ); + }); + + /********************************************************************************/ + + test('textcolonmonetary', () => { + toXmlMatch( + tex2mml('\\textcolonmonetary'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textcurrency', () => { + toXmlMatch( + tex2mml('\\textcurrency'), + ` + ¤ + ` + ); + }); + + /********************************************************************************/ + + test('textdollar', () => { + toXmlMatch( + tex2mml('\\textdollar'), + ` + $ + ` + ); + }); + + /********************************************************************************/ + + test('textdong', () => { + toXmlMatch( + tex2mml('\\textdong'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('texteuro', () => { + toXmlMatch( + tex2mml('\\texteuro'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textflorin', () => { + toXmlMatch( + tex2mml('\\textflorin'), + ` + ƒ + ` + ); + }); + + /********************************************************************************/ + + test('textguarani', () => { + toXmlMatch( + tex2mml('\\textguarani'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textlira', () => { + toXmlMatch( + tex2mml('\\textlira'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textnaira', () => { + toXmlMatch( + tex2mml('\\textnaira'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textpeso', () => { + toXmlMatch( + tex2mml('\\textpeso'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textsterling', () => { + toXmlMatch( + tex2mml('\\textsterling'), + ` + £ + ` + ); + }); + + /********************************************************************************/ + + test('textwon', () => { + toXmlMatch( + tex2mml('\\textwon'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textyen', () => { + toXmlMatch( + tex2mml('\\textyen'), + ` + ¥ + ` + ); + }); + + /********************************************************************************/ + + test('textcircledP', () => { + toXmlMatch( + tex2mml('\\textcircledP'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textcompwordmark', () => { + toXmlMatch( + tex2mml('\\textcompwordmark'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textcopyleft', () => { + toXmlMatch( + tex2mml('\\textcopyleft'), + ` + 🄯 + ` + ); + }); + + /********************************************************************************/ + + test('textcopyright', () => { + toXmlMatch( + tex2mml('\\textcopyright'), + ` + © + ` + ); + }); + + /********************************************************************************/ + + test('textregistered', () => { + toXmlMatch( + tex2mml('\\textregistered'), + ` + ® + ` + ); + }); + + /********************************************************************************/ + + test('textservicemark', () => { + toXmlMatch( + tex2mml('\\textservicemark'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('texttrademark', () => { + toXmlMatch( + tex2mml('\\texttrademark'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textbardbl', () => { + toXmlMatch( + tex2mml('\\textbardbl'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textbigcircle', () => { + toXmlMatch( + tex2mml('\\textbigcircle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textblank', () => { + toXmlMatch( + tex2mml('\\textblank'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textbrokenbar', () => { + toXmlMatch( + tex2mml('\\textbrokenbar'), + ` + ¦ + ` + ); + }); + + /********************************************************************************/ + + test('textdiscount', () => { + toXmlMatch( + tex2mml('\\textdiscount'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textestimated', () => { + toXmlMatch( + tex2mml('\\textestimated'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textinterrobang', () => { + toXmlMatch( + tex2mml('\\textinterrobang'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textinterrobangdown', () => { + toXmlMatch( + tex2mml('\\textinterrobangdown'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textmusicalnote', () => { + toXmlMatch( + tex2mml('\\textmusicalnote'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textnumero', () => { + toXmlMatch( + tex2mml('\\textnumero'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textopenbullet', () => { + toXmlMatch( + tex2mml('\\textopenbullet'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textpertenthousand', () => { + toXmlMatch( + tex2mml('\\textpertenthousand'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textperthousand', () => { + toXmlMatch( + tex2mml('\\textperthousand'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textrecipe', () => { + toXmlMatch( + tex2mml('\\textrecipe'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textreferencemark', () => { + toXmlMatch( + tex2mml('\\textreferencemark'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textlangle', () => { + toXmlMatch( + tex2mml('\\textlangle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textrangle', () => { + toXmlMatch( + tex2mml('\\textrangle'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textlbrackdbl', () => { + toXmlMatch( + tex2mml('\\textlbrackdbl'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textrbrackdbl', () => { + toXmlMatch( + tex2mml('\\textrbrackdbl'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textlquill', () => { + toXmlMatch( + tex2mml('\\textlquill'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textrquill', () => { + toXmlMatch( + tex2mml('\\textrquill'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textcelsius', () => { + toXmlMatch( + tex2mml('\\textcelsius'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textdegree', () => { + toXmlMatch( + tex2mml('\\textdegree'), + ` + ° + ` + ); + }); + + /********************************************************************************/ + + test('textdiv', () => { + toXmlMatch( + tex2mml('\\textdiv'), + ` + ÷ + ` + ); + }); + + /********************************************************************************/ + + test('textdownarrow', () => { + toXmlMatch( + tex2mml('\\textdownarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textfractionsolidus', () => { + toXmlMatch( + tex2mml('\\textfractionsolidus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textleftarrow', () => { + toXmlMatch( + tex2mml('\\textleftarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textlnot', () => { + toXmlMatch( + tex2mml('\\textlnot'), + ` + ¬ + ` + ); + }); + + /********************************************************************************/ + + test('textmho', () => { + toXmlMatch( + tex2mml('\\textmho'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textminus', () => { + toXmlMatch( + tex2mml('\\textminus'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textmu', () => { + toXmlMatch( + tex2mml('\\textmu'), + ` + µ + ` + ); + }); + + /********************************************************************************/ + + test('textohm', () => { + toXmlMatch( + tex2mml('\\textohm'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textonehalf', () => { + toXmlMatch( + tex2mml('\\textonehalf'), + ` + ½ + ` + ); + }); + + /********************************************************************************/ + + test('textonequarter', () => { + toXmlMatch( + tex2mml('\\textonequarter'), + ` + ¼ + ` + ); + }); + + /********************************************************************************/ + + test('textonesuperior', () => { + toXmlMatch( + tex2mml('\\textonesuperior'), + ` + ¹ + ` + ); + }); + + /********************************************************************************/ + + test('textpm', () => { + toXmlMatch( + tex2mml('\\textpm'), + ` + ± + ` + ); + }); + + /********************************************************************************/ + + test('textrightarrow', () => { + toXmlMatch( + tex2mml('\\textrightarrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textsurd', () => { + toXmlMatch( + tex2mml('\\textsurd'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textthreequarters', () => { + toXmlMatch( + tex2mml('\\textthreequarters'), + ` + ¾ + ` + ); + }); + + /********************************************************************************/ + + test('textthreesuperior', () => { + toXmlMatch( + tex2mml('\\textthreesuperior'), + ` + ³ + ` + ); + }); + + /********************************************************************************/ + + test('texttimes', () => { + toXmlMatch( + tex2mml('\\texttimes'), + ` + × + ` + ); + }); + + /********************************************************************************/ + + test('texttwosuperior', () => { + toXmlMatch( + tex2mml('\\texttwosuperior'), + ` + ² + ` + ); + }); + + /********************************************************************************/ + + test('textuparrow', () => { + toXmlMatch( + tex2mml('\\textuparrow'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textborn', () => { + toXmlMatch( + tex2mml('\\textborn'), + ` + * + ` + ); + }); + + /********************************************************************************/ + + test('textdied', () => { + toXmlMatch( + tex2mml('\\textdied'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textdivorced', () => { + toXmlMatch( + tex2mml('\\textdivorced'), + ` + + ` + ); + }); + + /********************************************************************************/ + + test('textmarried', () => { + toXmlMatch( + tex2mml('\\textmarried'), + ` + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Textcompwith Textmacros', () => { + beforeEach(() => setupTex(['base', 'textmacros', 'textcomp'])); + + /********************************************************************************/ + + test('textasciicircum', () => { + toXmlMatch( + tex2mml('\\text{\\textasciicircum}'), + ` + ^ + ` + ); + }); + + /********************************************************************************/ + + test('textcentoldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textcentoldstyle}'), + ` + ¢ + ` + ); + }); + + /********************************************************************************/ + + test('textdollaroldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textdollaroldstyle}'), + ` + $ + ` + ); + }); + + /********************************************************************************/ + + test('textzerooldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textzerooldstyle}'), + ` + 0 + ` + ); + }); + + /********************************************************************************/ + + test('textoneoldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textoneoldstyle}'), + ` + 1 + ` + ); + }); + + /********************************************************************************/ + + test('texttwooldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\texttwooldstyle}'), + ` + 2 + ` + ); + }); + + /********************************************************************************/ + + test('textthreeoldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textthreeoldstyle}'), + ` + 3 + ` + ); + }); + + /********************************************************************************/ + + test('textfouroldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textfouroldstyle}'), + ` + 4 + ` + ); + }); + + /********************************************************************************/ + + test('textfiveoldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textfiveoldstyle}'), + ` + 5 + ` + ); + }); + + /********************************************************************************/ + + test('textsixoldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textsixoldstyle}'), + ` + 6 + ` + ); + }); + + /********************************************************************************/ + + test('textsevenoldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textsevenoldstyle}'), + ` + 7 + ` + ); + }); + + /********************************************************************************/ + + test('texteightoldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\texteightoldstyle}'), + ` + 8 + ` + ); + }); + + /********************************************************************************/ + + test('textnineoldstyle', () => { + toXmlMatch( + tex2mml('\\text{\\textnineoldstyle}'), + ` + 9 + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('textcomp')); diff --git a/testsuite/tests/input/tex/Textmacros.test.ts b/testsuite/tests/input/tex/Textmacros.test.ts new file mode 100644 index 000000000..90dc24801 --- /dev/null +++ b/testsuite/tests/input/tex/Textmacros.test.ts @@ -0,0 +1,1001 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { + getTokens, + toXmlMatch, + setupTex, + setupTexTypeset, + tex2mml, + typeset2mml, + setupComponents, + expectTexError, + expectTypesetError +} from '#helpers'; +import '#js/input/tex/textmacros/TextMacrosConfiguration'; +import '#js/input/tex/newcommand/NewcommandConfiguration'; +import '#js/input/tex/color/ColorConfiguration'; +import '#js/input/tex/html/HtmlConfiguration'; +import '#js/input/tex/unicode/UnicodeConfiguration'; + +import {Configuration} from '#js/input/tex/Configuration.js'; +import {HandlerType, ConfigurationType} from '#js/input/tex/HandlerTypes.js'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Textmacros', () => { + + beforeEach(() => setupTex(['base', 'newcommand', 'color', 'textmacros'])); + + /********************************************************************************/ + + test('Text plain', () => { + toXmlMatch( + tex2mml('\\text{abc}'), + ` + abc + ` + ); + }); + + /********************************************************************************/ + + test('Text macro', () => { + toXmlMatch( + tex2mml('\\text{abc \\large abc}'), + ` + + abc  + abc + + ` + ); + }); + + /********************************************************************************/ + + test('Text unknown macro', () => { + expectTexError('\\text{\\xyz}') + .toBe('Undefined control sequence \\xyz'); + }); + + /********************************************************************************/ + + test('Text substitution macro', () => { + toXmlMatch( + tex2mml('\\def\\x{X} \\text{\\x}'), + ` + X + ` + ); + }); + + /********************************************************************************/ + + test('Text mathmode macro', () => { + expectTexError('\\text{\\frac{1}{2}}') + .toBe('\\frac is only supported in math mode'); + }); + + /********************************************************************************/ + + test('Text internal math', () => { + toXmlMatch( + tex2mml('\\text{a $\\frac{1}{2}$ b}'), + ` + + + + + 1 + 2 + + +  b + + ` + ); + }); + + /********************************************************************************/ + + test('Text internal math complex', () => { + toXmlMatch( + tex2mml('\\text{a $x+y$ b}'), + ` + + + + + x + + + y + + +  b + + ` + ); + }); + + /********************************************************************************/ + + test('Textbf ', () => { + toXmlMatch( + tex2mml('\\def\\x{X} \\textbf{a\\x}'), + ` + aX + ` + ); + }); + + /********************************************************************************/ + + test('Text ref', () => { + toXmlMatch( + tex2mml('\\textbf{a \\ref{a}}'), + ` + + + + ??? + + + ` + ); + }); + + /********************************************************************************/ + + test('HBox size', () => { + toXmlMatch( + tex2mml('\\scriptstyle\\hbox{a}'), + ` + + + a + + + ` + ); + }); + + /********************************************************************************/ + + test('Text color', () => { + toXmlMatch( + tex2mml('\\text{a\\color{red}b}'), + ` + + a + b + + ` + ); + }); + + /********************************************************************************/ + + test('Text color math', () => { + toXmlMatch( + tex2mml('\\text{a\\color{red}b$c$}'), + ` + + a + b + + c + + + ` + ); + }); + + /********************************************************************************/ + + test('Text color math complex', () => { + toXmlMatch( + tex2mml('\\text{a\\color{red}b$c+d$}'), + ` + + a + b + + + c + + + d + + + + ` + ); + }); + + /********************************************************************************/ + + test('Unbalanced Braces', () => { + expectTexError('\\text{a ${$ b }}') + .toBe('Math mode is not properly terminated'); + }); + + /********************************************************************************/ + + test('Unbalanced Braces', () => { + expectTexError('\\text{{a $}$ b }') + .toBe('Extra close brace or missing open brace'); + }); + + /********************************************************************************/ + + test('Unbalanced Braces', () => { + expectTexError('\\let\\x=}\\text{a \\x}') + .toBe('Extra close brace or missing open brace'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Textmacros Specials', () => { + + beforeEach(() => setupTex(['base', 'textmacros'])); + + /********************************************************************************/ + + test('Dollar', () => { + toXmlMatch( + tex2mml('\\text{a$b$}'), + ` + + a + + b + + + ` + ); + }); + + /********************************************************************************/ + + test('Percent', () => { + toXmlMatch( + tex2mml('\\text{a%comment\nb}'), + ` + ab + ` + ); + }); + + /********************************************************************************/ + + test('Hat', () => { + expectTexError('\\text{a^b}').toBe("'^' allowed only in math mode"); + }); + + /********************************************************************************/ + + test('Underscore', () => { + expectTexError('\\text{a_b}').toBe("'_' allowed only in math mode"); + }); + + /********************************************************************************/ + + test('Ampersand', () => { + expectTexError('\\text{a&b}').toBe("Misplaced '&'"); + }); + + /********************************************************************************/ + + test('Hash', () => { + expectTexError('\\text{a#b}').toBe("Misplaced '#'"); + }); + + /********************************************************************************/ + + test('Tilde', () => { + toXmlMatch( + tex2mml('\\text{a~b}'), + ` + a b + ` + ); + }); + + /********************************************************************************/ + + test('Spaces', () => { + toXmlMatch( + tex2mml('\\text{a b\t c\r d\n e\u{00A0}f\\ g}'), + ` + a b c d e f g + ` + ); + }); + + /********************************************************************************/ + + test('Braces', () => { + toXmlMatch( + tex2mml('\\text{a {b} c}'), + ` + + a b +  c + + ` + ); + }); + + /********************************************************************************/ + + test('Quotes', () => { + toXmlMatch( + tex2mml("\\text{a ``b'' `c' d}"), + ` + a “b” ‘c’ d + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Textmacros Macros', () => { + + beforeEach(() => setupTex(['base', 'newcommand', 'color', 'html', 'unicode', 'textmacros'])); + + /********************************************************************************/ + + test('Internal Math', () => { + toXmlMatch( + tex2mml('\\text{a\\(b\\)}'), + ` + + a + + b + + + ` + ); + }); + + /********************************************************************************/ + + test('Quoted Specials', () => { + toXmlMatch( + tex2mml('\\text{a\\$b\\_c\\%d\\{e\\}f\\&g\\#h}'), + ` + a$b_c%d{e}f&g#h + ` + ); + }); + + /********************************************************************************/ + + test('Newline', () => { + toXmlMatch( + tex2mml('\\text{a\\\\b}'), + ` + + a + + + + b + + ` + ); + }); + + /********************************************************************************/ + + test('Accents', () => { + toXmlMatch( + tex2mml("\\text{\\'a\\\u2019a\\`a\\\u2018a\\^a\\\"a\\~a\\=a\\.a\\u a\\v a}"), + ` + + + a + ´ + + + a + ´ + + + a + ${"`"} + + + a + ${"`"} + + + a + ^ + + + a + ¨ + + + a + ~ + + + a + ¯ + + + a + ˙ + + + a + ˘ + + + a + ˇ + + + ` + ); + }); + + /********************************************************************************/ + + test('emph', () => { + toXmlMatch( + tex2mml('\\text{a\\emph{b\\emph{c}}d}'), + ` + + a + + b + c + + d + + ` + ); + }); + + /********************************************************************************/ + + test('rm', () => { + toXmlMatch( + tex2mml('\\text{a{\\rm b}c}'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + test('mit', () => { + toXmlMatch( + tex2mml('\\text{a{\\mit b}c}'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + test('oldstyle', () => { + toXmlMatch( + tex2mml('\\text{0{\\oldstyle 1}2}'), + ` + + 0 + 1 + 2 + + ` + ); + }); + + /********************************************************************************/ + + test('cal', () => { + toXmlMatch( + tex2mml('\\text{a{\\cal B}c}'), + ` + + a + B + c + + ` + ); + }); + + /********************************************************************************/ + + test('it', () => { + toXmlMatch( + tex2mml('\\text{a{\\it b}c}'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + test('bf', () => { + toXmlMatch( + tex2mml('\\text{a{\\bf b}c}'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + test('sf', () => { + toXmlMatch( + tex2mml('\\text{a{\\sf b}c}'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + test('tt', () => { + toXmlMatch( + tex2mml('\\text{a{\\tt b}c}'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + test('frak', () => { + toXmlMatch( + tex2mml('\\text{a{\\frak b}c}'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + test('Bbb', () => { + toXmlMatch( + tex2mml('\\text{a{\\Bbb b}c}'), + ` + + a + b + c + + ` + ); + }); + + /********************************************************************************/ + + test('Sizes small', () => { + toXmlMatch( + tex2mml('\\text{{\\tiny a\\Tiny a \\scriptsize a \\small a\\normalsize a}a}'), + ` + + a + + + a + a + a + + ` + ); + }); + + /********************************************************************************/ + + test('Sizes large', () => { + toXmlMatch( + tex2mml('\\text{a\\large a\\Large a\\LARGE a\\huge a\\Huge a}'), + ` + + a + a + a + a + a + a + + ` + ); + }); + + /********************************************************************************/ + + test('Text fonts', () => { + toXmlMatch( + tex2mml('\\text{\\Bbb a\\textnormal{a}\\textup{a}\\textrm{a}\\textit{a}\\textbf{a}\\textsf{a}\\texttt{a}}'), + ` + + a + a + a + a + a + a + a + a + + ` + ); + }); + + /********************************************************************************/ + + test('Text symbols', () => { + toXmlMatch( + tex2mml('\\text{\\dagger\\ddagger\\S\\AA a\\ldots b\\vdots c}'), + ` + †‡§Åa…b⋮c + ` + ); + }); + + /********************************************************************************/ + + test('Text space macros 1', () => { + toXmlMatch( + tex2mml('\\text{a\\,b\\:c\\>d\\;e\\!f}'), + ` + + a + + b + + c + + d + + e + + f + + ` + ); + }); + + /********************************************************************************/ + + test('Text space macros 2', () => { + toXmlMatch( + tex2mml('\\text{a\\enspace b\\quad c\\qquad d\\thinspace e\\negthinspace f}'), + ` + + a + + b + + c + + d + + e + + f + + ` + ); + }); + + /********************************************************************************/ + + test('Text spacing macros', () => { + toXmlMatch( + tex2mml('\\text{a\\hskip 1emb\\hspace{1em}c\\kern{.1em}d\\mskip{1em}e\\mspace{1em}f\\mkern{.1em}g}'), + ` + + a + + b + + c + + d + + e + + f + + g + + ` + ); + }); + + /********************************************************************************/ + + test('Text rules and spaces', () => { + toXmlMatch( + tex2mml('\\text{\\Rule{1em}{.5em}{.5em}\\Space{1em}{.5em}{0em}\\rule[.25em]{1em}{.5em}}'), + ` + + + + + + + + ` + ); + }); + + /********************************************************************************/ + + test('Color', () => { + toXmlMatch( + tex2mml('\\text{{\\color{red}{x}}\\textcolor{yellow}{A}\\colorbox{green}{x}\\fcolorbox{blue}{orange}{x}}'), + ` + + x + + A + + + x + + + x + + + ` + ); + }); + + /********************************************************************************/ + + test('HTML', () => { + toXmlMatch( + tex2mml('\\text{\\href{tmp.html}{x}\\style{padding:3px}{x}\\class{test}{x}\\data{test=1}{x}\\cssId{test}{x}}'), + ` + + x + x + x + x + x + + ` + ); + }); + + /********************************************************************************/ + + test('Unicode', () => { + toXmlMatch( + tex2mml('\\text{\\unicode{x61}\\U{3333}\\char"65}'), + ` + + a + + e + + ` + ); + }); + + /********************************************************************************/ + + test('Ref and Eqref', () => { + toXmlMatch( + tex2mml('\\text{\\ref{a}\\eqref{b}}'), + ` + + + ??? + + + (???) + + + ` + ); + }); + + /********************************************************************************/ + + test('Underline', () => { + toXmlMatch( + tex2mml('\\text{a \\underline{b c} d}'), + ` + + + + b c + + +  d + + ` + ); + }); + + /********************************************************************************/ + + test('lapping', () => { + toXmlMatch( + tex2mml('\\text{\\rlap{a}-- --\\llap{b}}'), + ` + + + + a + + + -- -- + + + b + + + + ` + ); + }); + + /********************************************************************************/ + + test('Phantoms', () => { + toXmlMatch( + tex2mml('\\text{\\phantom{a}a\\vphantom{a}a\\hphantom{a}a\\smash{a}}'), + ` + + + + a + + + a + + + + a + + + + a + + + + a + + + + a + + + a + + + + ` + ); + }); + + /********************************************************************************/ + + test('mmlToken', () => { + toXmlMatch( + tex2mml('\\text{\\mmlToken{mo}{a}}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Textmacros Autoload', () => { + + setupComponents({ + loader: {load: ['input/tex-base', '[tex]/textmacros', '[tex]/autoload']} + }); + + /********************************************************************************/ + + test('Autoload not present', async () => { + setupTexTypeset(['base', 'textmacros']); + await expectTypesetError('\\text{\\href{tmp.html}{a}}') + .toBe('Undefined control sequence \\href'); + }); + + /********************************************************************************/ + + test('Autoload', async () => { + setupTexTypeset(['base', 'textmacros', 'autoload']) + toXmlMatch( + await typeset2mml('\\text{\\href{tmp.html}{a}}'), + ` + a + ` + ); + }); + + /********************************************************************************/ + + test('No Autoload', async () => { + Configuration.create('no-autoload', { + [ConfigurationType.FALLBACK]: { + [HandlerType.MACRO]: () => {} + } + }); + setupTexTypeset(['base', 'textmacros', 'no-autoload']) + toXmlMatch( + await typeset2mml('\\text{\\href{tmp.html}{a}}'), + ` + + tmp.html + a + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('text-base')); diff --git a/testsuite/tests/input/tex/Unicode.test.ts b/testsuite/tests/input/tex/Unicode.test.ts new file mode 100644 index 000000000..7316c82ab --- /dev/null +++ b/testsuite/tests/input/tex/Unicode.test.ts @@ -0,0 +1,327 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/unicode/UnicodeConfiguration'; + +beforeEach(() => setupTex(['base', 'unicode'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Unicode', () => { + + /********************************************************************************/ + + it('Unicode Dec', () => { + toXmlMatch( + tex2mml('\\unicode{8922}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Hex', () => { + toXmlMatch( + tex2mml('\\unicode{0x22DA}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Dec A', () => { + toXmlMatch( + tex2mml('\\unicode{65}'), + ` + A + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Hex A', () => { + toXmlMatch( + tex2mml('\\unicode{x41}'), + ` + A + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Scale', () => { + toXmlMatch( + tex2mml('\\unicode[.55,0.05]{x22D6}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Scale Font', () => { + toXmlMatch( + tex2mml('\\unicode[.55,0.05][Geramond]{x22D6}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Font', () => { + toXmlMatch( + tex2mml('\\unicode[Garamond]{x22D6}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Combined', () => { + toXmlMatch( + tex2mml('\\mbox{A}\\unicode{65}{B}'), + ` + + A + + A + + B + + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Surrogate Hex', () => { + toXmlMatch( + tex2mml('\\unicode{x1D5A0}'), + ` + 𝖠 + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Surrogate Dec', () => { + toXmlMatch( + tex2mml('\\unicode{120224}'), + ` + 𝖠 + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Blackboard', () => { + toXmlMatch( + tex2mml('\\unicode{x1D538}'), + ` + 𝔸 + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Blackboard Geramond', () => { + toXmlMatch( + tex2mml('\\unicode{x1D538}'), + ` + 𝔸 + ` + ); + }); + + /********************************************************************************/ + +}); + +// Here the order is important! As otherwise bold stays. +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Unicode Complete', () => { + + /********************************************************************************/ + + it('Unicode Caligraphic', () => { + toXmlMatch( + tex2mml('\\mathtt{\\unicode{8922}}'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Bold', () => { + toXmlMatch( + tex2mml('\\mathbf{\\unicode[bold]{8922}}'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + + it('Unicode Italic', () => { + toXmlMatch( + tex2mml('\\mathit{\\unicode[bold]{8922}}'), + ` + + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Unicode others', () => { + + /********************************************************************************/ + + it('Raw Unicode', () => { + toXmlMatch( + tex2mml('\\U{892F}'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Char numerical', () => { + toXmlMatch( + tex2mml('\\char\'777'), + ` + ǿ + ` + ); + }); + + /********************************************************************************/ + + it('Char alpha', () => { + toXmlMatch( + tex2mml('\\char`A'), + ` + A + ` + ) + }); + + /********************************************************************************/ + + it('Char command number', () => { + toXmlMatch( + tex2mml('\\char`\\3'), + ` + 3 + ` + ) + }); + + /********************************************************************************/ + + it('Char Yen', () => { + toXmlMatch( + tex2mml('\\char"A5'), + ` + + ¥ + + ` + ); + }); + + /********************************************************************************/ + + it('Char number', () => { + toXmlMatch( + tex2mml('\\char55'), + ` + 7 + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Unicode Errors', () => { + + /********************************************************************************/ + + it('Unicode BadFont', () => { + expectTexError('\\unicode[arial;]{8922}') + .toBe("Font name for \\unicode can't contain semicolons"); + }); + + /********************************************************************************/ + + it('Unicode BadUnicode', () => { + expectTexError('\\unicode{4A}') + .toBe('Argument to \\unicode must be a number'); + }); + + /********************************************************************************/ + + it('Unicode BadRawUnicode', () => { + expectTexError('\\U{892G}') + .toBe('Argument to \\U must a hexadecimal number with 1 to 6 digits'); + }); + + /********************************************************************************/ + + it('Unicode InvalidAlphanumeric', () => { + expectTexError('\\char`\\nix') + .toBe('Invalid alphanumeric constant for \\char'); + }); + + /********************************************************************************/ + + it('Unicode MissingNumber', () => { + expectTexError('\\char {40}') + .toBe('Missing numeric constant for \\char'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('unicode')); diff --git a/testsuite/tests/input/tex/UnitUtil.test.ts b/testsuite/tests/input/tex/UnitUtil.test.ts new file mode 100644 index 000000000..fbb979df0 --- /dev/null +++ b/testsuite/tests/input/tex/UnitUtil.test.ts @@ -0,0 +1,142 @@ +import { describe, it, expect, beforeEach } from '@jest/globals'; +import { UnitUtil } from '#js/input/tex/UnitUtil.js'; + +/**********************************************************************************/ + +// These methods will be rewritten into non-ParseUtil ones. +function convertLength(unit: string, num: number) { + return UnitUtil.UNIT_CASES.get(unit) * num; +} + +function matchDimension(str: string) { + return UnitUtil.matchDimen(str); +} + +function convertDimension(str: string) { + return UnitUtil.dimen2em(str); +} + +function convertEm(num: number) { + return UnitUtil.em(num); +} + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Length conversion', () => { + it('em', () => expect(convertLength('em', 9)).toBe(9)); + it('ex', () => expect(convertLength('ex', 9)).toBe(3.87)); + it('pt', () => expect(convertLength('pt', 9)).toBe(0.9)); + it('pc', () => expect(convertLength('pc', 9)).toBe(10.799999999999999)); + it('px', () => expect(convertLength('px', 9)).toBe(0.9)); + it('in', () => expect(convertLength('in', 9)).toBe(64.8)); + it('cm', () => expect(convertLength('cm', 9)).toBe(25.511811023622045)); + it('mm', () => expect(convertLength('mm', 9)).toBe(2.5511811023622046)); + it('mu', () => expect(convertLength('mu', 9)).toBe(0.5)); + // Note that we have to pass a function here. + // it('nix', () => expect(() => convertLength('nix', 9)).toThrow(TypeError)); + it('nix', () => expect(convertLength('nix', 9)).toBe(0.9)); +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Em conversion', () => { + it('9', () => expect(convertEm(9)).toBe('9em')); + it('10', () => expect(convertEm(10)).toBe('10em')); + it('1e+25', () => expect(convertEm(1e25)).toBe('1e+25em')); + it('10000', () => expect(convertEm(10000)).toBe('10000em')); + it('0.001', () => expect(convertEm(0.001)).toBe('0.001em')); + it('0.0001', () => expect(convertEm(0.0001)).toBe('0em')); + it('0.0005', () => expect(convertEm(0.0005)).toBe('0em')); + it('0.0006', () => expect(convertEm(0.0006)).toBe('0.001em')); + it('0.0007', () => expect(convertEm(0.0007)).toBe('0.001em')); + it('25.51181102', () => expect(convertEm(25.51181102)).toBe('25.512em')); +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Dimension matching', () => { + it('9', () => expect(matchDimension('9')).toEqual([null, null, 0])); + it('10', () => expect(matchDimension('10')).toEqual([null, null, 0])); + it('9nix', () => expect(matchDimension('9nix')).toEqual([null, null, 0])); + it('10nix', () => expect(matchDimension('10nix')).toEqual([null, null, 0])); + it('empty', () => expect(matchDimension('')).toEqual([null, null, 0])); + it('nix', () => expect(matchDimension('nix')).toEqual([null, null, 0])); + it('9em', () => expect(matchDimension('9em')).toEqual(['9', 'em', 3])); + it('10em', () => expect(matchDimension('10em')).toEqual(['10', 'em', 4])); + it('9ex', () => expect(matchDimension('9ex')).toEqual(['9', 'ex', 3])); + it('10ex', () => expect(matchDimension('10ex')).toEqual(['10', 'ex', 4])); + it('9pt', () => expect(matchDimension('9pt')).toEqual(['9', 'pt', 3])); + it('10pt', () => expect(matchDimension('10pt')).toEqual(['10', 'pt', 4])); + it('9pc', () => expect(matchDimension('9pc')).toEqual(['9', 'pc', 3])); + it('10pc', () => expect(matchDimension('10pc')).toEqual(['10', 'pc', 4])); + it('9px', () => expect(matchDimension('9px')).toEqual(['9', 'px', 3])); + it('10px', () => expect(matchDimension('10px')).toEqual(['10', 'px', 4])); + it('9in', () => expect(matchDimension('9in')).toEqual(['9', 'in', 3])); + it('10in', () => expect(matchDimension('10in')).toEqual(['10', 'in', 4])); + it('9cm', () => expect(matchDimension('9cm')).toEqual(['9', 'cm', 3])); + it('10cm', () => expect(matchDimension('10cm')).toEqual(['10', 'cm', 4])); + it('9mm', () => expect(matchDimension('9mm')).toEqual(['9', 'mm', 3])); + it('10mm', () => expect(matchDimension('10mm')).toEqual(['10', 'mm', 4])); + it('9mu', () => expect(matchDimension('9mu')).toEqual(['0.5', 'em', 3])); + it('10mu', () => expect(matchDimension('10mu')).toEqual(['0.556', 'em', 4])); + it('rest', () => expect(UnitUtil.matchDimen('9em rest', true)).toEqual(['9', 'em', 4])); +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Dimension conversion', () => { + it('9', () => expect(convertDimension('9')).toBe(0.1)); + it('9nix', () => expect(convertDimension('9nix')).toBe(0.1)); + it('empty', () => expect(convertDimension('')).toBe(0.1)); + it('nix', () => expect(convertDimension('nix')).toBe(0.1)); + it('9em', () => expect(convertDimension('9em')).toBe(9)); + it('9ex', () => expect(convertDimension('9ex')).toBe(3.87)); + it('9pt', () => expect(convertDimension('9pt')).toBe(0.9)); + it('9pc', () => expect(convertDimension('9pc')).toBe(10.799999999999999)); + it('9px', () => expect(convertDimension('9px')).toBe(0.9)); + it('9in', () => expect(convertDimension('9in')).toBe(64.8)); + it('9cm', () => expect(convertDimension('9cm')).toBe(25.511811023622045)); + it('9mm', () => expect(convertDimension('9mm')).toBe(2.5511811023622046)); + it('9mu', () => expect(convertDimension('9mu')).toBe(0.5)); +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +// Useful for the IEEE case. +describe('Adds pi unit', () => { + beforeEach(() => UnitUtil.UNIT_CASES.set('pi', 1 / 10)); + it('pi', () => expect(convertLength('pi', 9)).toBe(0.9)); + it('9pi', () => expect(matchDimension('9pi')).toEqual(['9', 'pi', 3])); + it('10pi', () => expect(matchDimension('10pi')).toEqual(['10', 'pi', 4])); + it('9pi', () => expect(convertDimension('9pi')).toBe(0.9)); +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Remove Unit', () => { + it('existing unit', () => { + UnitUtil.UNIT_CASES.set('test', 2); + expect(UnitUtil.UNIT_CASES.delete('test')).toBe(true); + }); + it('non-existing unit', () => { + expect(UnitUtil.UNIT_CASES.delete('test')).toBe(false); + }); +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Trim spaces', () => { + it('removes spaces and tabs', () => expect(UnitUtil.trimSpaces(' \t abc \t ')).toBe('abc')); + it('non-text argument', () => expect(UnitUtil.trimSpaces(null)).toBe(null)); + it('space macro at end', () => expect(UnitUtil.trimSpaces('\\ ')).toBe('\\ ')); +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/input/tex/Units.test.ts b/testsuite/tests/input/tex/Units.test.ts new file mode 100644 index 000000000..2ee049e10 --- /dev/null +++ b/testsuite/tests/input/tex/Units.test.ts @@ -0,0 +1,204 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/units/UnitsConfiguration'; + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Units', () => { + + beforeEach(() => setupTex(['base', 'units'])); + + /********************************************************************************/ + + test('Unit', () => { + toXmlMatch( + tex2mml('\\units{kg}'), + ` + + kg + + ` + ); + }); + + /********************************************************************************/ + + test('Unit squared', () => { + toXmlMatch( + tex2mml('\\units{m^2}'), + ` + + + m + 2 + + + ` + ); + }); + + /********************************************************************************/ + + test('Unit with value', () => { + toXmlMatch( + tex2mml('\\units[2.5]{kg}'), + ` + 2.5 + + + kg + + ` + ); + }); + + /********************************************************************************/ + + test('Unitfrac', () => { + toXmlMatch( + tex2mml('\\unitfrac{m}{s}'), + ` + + + m + + + s + + + ` + ); + }); + + /********************************************************************************/ + + test('Unitfrac with value', () => { + toXmlMatch( + tex2mml('\\unitfrac[9.8]{m}{s^2}'), + ` + 9.8 + + + + m + + + + s + 2 + + + + ` + ); + }); + + /********************************************************************************/ + + test('Nicefrac', () => { + toXmlMatch( + tex2mml('\\nicefrac{1}{2}'), + ` + + + 1 + + + 2 + + + ` + ); + }); + + /********************************************************************************/ + + test('Nicefrac with font', () => { + toXmlMatch( + tex2mml('\\nicefrac[\\mathsf]{1}{2}'), + ` + + + 1 + + + 2 + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Units loose ugly', () => { + + beforeEach(() => setupTex(['base', 'units'], {units: {loose: true, ugly: true}})); + + /********************************************************************************/ + + test('Unit with value', () => { + toXmlMatch( + tex2mml('\\units[5]{kg}'), + ` + 5 +   + + kg + + ` + ); + }); + + /********************************************************************************/ + + test('Unitfrac with value', () => { + toXmlMatch( + tex2mml('\\unitfrac[3]{ft}{min}'), + ` + 3 +   + + + ft + + + min + + + ` + ); + }); + + /********************************************************************************/ + + test('nicefrac', () => { + toXmlMatch( + tex2mml('\\nicefrac{1}{2}'), + ` + + + 1 + + + 2 + + + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('units')); diff --git a/testsuite/tests/input/tex/Upgreek.test.ts b/testsuite/tests/input/tex/Upgreek.test.ts new file mode 100644 index 000000000..6f6767829 --- /dev/null +++ b/testsuite/tests/input/tex/Upgreek.test.ts @@ -0,0 +1,470 @@ +import { afterAll, beforeEach, describe, test } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml } from '#helpers'; +import '#js/input/tex/upgreek/UpgreekConfiguration'; + +beforeEach(() => setupTex(['base', 'upgreek'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Upgreek', () => { + + /********************************************************************************/ + + test('upalpha', () => { + toXmlMatch( + tex2mml('\\upalpha'), + ` + α + ` + ); + }); + + /********************************************************************************/ + + test('upbeta', () => { + toXmlMatch( + tex2mml('\\upbeta'), + ` + β + ` + ); + }); + + /********************************************************************************/ + + test('upgamma', () => { + toXmlMatch( + tex2mml('\\upgamma'), + ` + γ + ` + ); + }); + + /********************************************************************************/ + + test('updelta', () => { + toXmlMatch( + tex2mml('\\updelta'), + ` + δ + ` + ); + }); + + /********************************************************************************/ + + test('upepsilon', () => { + toXmlMatch( + tex2mml('\\upepsilon'), + ` + ϵ + ` + ); + }); + + /********************************************************************************/ + + test('upzeta', () => { + toXmlMatch( + tex2mml('\\upzeta'), + ` + ζ + ` + ); + }); + + /********************************************************************************/ + + test('upeta', () => { + toXmlMatch( + tex2mml('\\upeta'), + ` + η + ` + ); + }); + + /********************************************************************************/ + + test('uptheta', () => { + toXmlMatch( + tex2mml('\\uptheta'), + ` + θ + ` + ); + }); + + /********************************************************************************/ + + test('upiota', () => { + toXmlMatch( + tex2mml('\\upiota'), + ` + ι + ` + ); + }); + + /********************************************************************************/ + + test('upkappa', () => { + toXmlMatch( + tex2mml('\\upkappa'), + ` + κ + ` + ); + }); + + /********************************************************************************/ + + test('uplambda', () => { + toXmlMatch( + tex2mml('\\uplambda'), + ` + λ + ` + ); + }); + + /********************************************************************************/ + + test('upmu', () => { + toXmlMatch( + tex2mml('\\upmu'), + ` + μ + ` + ); + }); + + /********************************************************************************/ + + test('upnu', () => { + toXmlMatch( + tex2mml('\\upnu'), + ` + ν + ` + ); + }); + + /********************************************************************************/ + + test('upxi', () => { + toXmlMatch( + tex2mml('\\upxi'), + ` + ξ + ` + ); + }); + + /********************************************************************************/ + + test('upomicron', () => { + toXmlMatch( + tex2mml('\\upomicron'), + ` + ο + ` + ); + }); + + /********************************************************************************/ + + test('uppi', () => { + toXmlMatch( + tex2mml('\\uppi'), + ` + π + ` + ); + }); + + /********************************************************************************/ + + test('uprho', () => { + toXmlMatch( + tex2mml('\\uprho'), + ` + ρ + ` + ); + }); + + /********************************************************************************/ + + test('upsigma', () => { + toXmlMatch( + tex2mml('\\upsigma'), + ` + σ + ` + ); + }); + + /********************************************************************************/ + + test('uptau', () => { + toXmlMatch( + tex2mml('\\uptau'), + ` + τ + ` + ); + }); + + /********************************************************************************/ + + test('upupsilon', () => { + toXmlMatch( + tex2mml('\\upupsilon'), + ` + υ + ` + ); + }); + + /********************************************************************************/ + + test('upphi', () => { + toXmlMatch( + tex2mml('\\upphi'), + ` + ϕ + ` + ); + }); + + /********************************************************************************/ + + test('upchi', () => { + toXmlMatch( + tex2mml('\\upchi'), + ` + χ + ` + ); + }); + + /********************************************************************************/ + + test('uppsi', () => { + toXmlMatch( + tex2mml('\\uppsi'), + ` + ψ + ` + ); + }); + + /********************************************************************************/ + + test('upomega', () => { + toXmlMatch( + tex2mml('\\upomega'), + ` + ω + ` + ); + }); + + /********************************************************************************/ + + test('upvarepsilon', () => { + toXmlMatch( + tex2mml('\\upvarepsilon'), + ` + ε + ` + ); + }); + + /********************************************************************************/ + + test('upvartheta', () => { + toXmlMatch( + tex2mml('\\upvartheta'), + ` + ϑ + ` + ); + }); + + /********************************************************************************/ + + test('upvarpi', () => { + toXmlMatch( + tex2mml('\\upvarpi'), + ` + ϖ + ` + ); + }); + + /********************************************************************************/ + + test('upvarrho', () => { + toXmlMatch( + tex2mml('\\upvarrho'), + ` + ϱ + ` + ); + }); + + /********************************************************************************/ + + test('upvarsigma', () => { + toXmlMatch( + tex2mml('\\upvarsigma'), + ` + ς + ` + ); + }); + + /********************************************************************************/ + + test('upvarphi', () => { + toXmlMatch( + tex2mml('\\upvarphi'), + ` + φ + ` + ); + }); + + /********************************************************************************/ + + test('Upgamma', () => { + toXmlMatch( + tex2mml('\\Upgamma'), + ` + Γ + ` + ); + }); + + /********************************************************************************/ + + test('Updelta', () => { + toXmlMatch( + tex2mml('\\Updelta'), + ` + Δ + ` + ); + }); + + /********************************************************************************/ + + test('Uptheta', () => { + toXmlMatch( + tex2mml('\\Uptheta'), + ` + Θ + ` + ); + }); + + /********************************************************************************/ + + test('Uplambda', () => { + toXmlMatch( + tex2mml('\\Uplambda'), + ` + Λ + ` + ); + }); + + /********************************************************************************/ + + test('Upxi', () => { + toXmlMatch( + tex2mml('\\Upxi'), + ` + Ξ + ` + ); + }); + + /********************************************************************************/ + + test('Uppi', () => { + toXmlMatch( + tex2mml('\\Uppi'), + ` + Π + ` + ); + }); + + /********************************************************************************/ + + test('Upsigma', () => { + toXmlMatch( + tex2mml('\\Upsigma'), + ` + Σ + ` + ); + }); + + /********************************************************************************/ + + test('Upupsilon', () => { + toXmlMatch( + tex2mml('\\Upupsilon'), + ` + Υ + ` + ); + }); + + /********************************************************************************/ + + test('Upphi', () => { + toXmlMatch( + tex2mml('\\Upphi'), + ` + Φ + ` + ); + }); + + /********************************************************************************/ + + test('Uppsi', () => { + toXmlMatch( + tex2mml('\\Uppsi'), + ` + Ψ + ` + ); + }); + + /********************************************************************************/ + + test('Upomega', () => { + toXmlMatch( + tex2mml('\\Upomega'), + ` + Ω + ` + ); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('upgreek')); diff --git a/testsuite/tests/input/tex/Verb.test.ts b/testsuite/tests/input/tex/Verb.test.ts new file mode 100644 index 000000000..5a14a2021 --- /dev/null +++ b/testsuite/tests/input/tex/Verb.test.ts @@ -0,0 +1,87 @@ +import { afterAll, beforeEach, describe, it } from '@jest/globals'; +import { getTokens, toXmlMatch, setupTex, tex2mml, expectTexError } from '#helpers'; +import '#js/input/tex/verb/VerbConfiguration'; + +beforeEach(() => setupTex(['base', 'verb'])); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('Verb', () => { + + /********************************************************************************/ + + it('Verb Plus ', () => { + toXmlMatch( + tex2mml('\\verb+{a}+'), + ` + {a} + ` + ); + }); + + /********************************************************************************/ + + it('Verb Plus Empty', () => { + toXmlMatch( + tex2mml('\\verb ++'), + ` + + ` + ); + }); + + /********************************************************************************/ + + it('Verb Plus Space', () => { + toXmlMatch( + tex2mml('\\verb + +'), + ` +   + ` + ); + }); + + /********************************************************************************/ + + it('Verb Minus', () => { + toXmlMatch( + tex2mml('\\verb -{a}-'), + ` + {a} + ` + ); + }); + + /********************************************************************************/ + + it('Verb Minus Double', () => { + toXmlMatch( + tex2mml('\\verb -{a--'), + ` + {a + + ` + ); + }); + + /********************************************************************************/ + + it('Verb Error', () => { + expectTexError('\\verb{a}').toBe('Can\'t find closing delimiter for \\verb'); + }); + + /********************************************************************************/ + + it('Verb Missing Arg', () => { + expectTexError('\\verb').toBe('Missing argument for \\verb'); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +afterAll(() => getTokens('verb')); diff --git a/testsuite/tests/util/AsyncLoad.test.ts b/testsuite/tests/util/AsyncLoad.test.ts new file mode 100644 index 000000000..9e3fe19a3 --- /dev/null +++ b/testsuite/tests/util/AsyncLoad.test.ts @@ -0,0 +1,39 @@ +import { describe, test, expect } from '@jest/globals'; +import {asyncLoad} from '#js/util/AsyncLoad.js'; +import {mathjax} from '#js/mathjax.js'; + +describe('asyncLoad()', () => { + + test('asyncLoad()', async () => { + // + // Throws error if not set in mathjax + // + expect(asyncLoad('x.js').then(() => false).catch(() => true)).resolves.toBe(true); + + // + // mathjax.asyncLoad returns value + // + mathjax.asyncLoad = (_name: string) => 'success'; + await expect(asyncLoad('x.js')).resolves.toBe('success'); + + // + // mathjax.asyncLoad throws error + // + mathjax.asyncLoad = (_name: string) => {throw 'fail'}; + await expect(asyncLoad('x.js')).rejects.toBe('fail'); + + // + // mathjax.asyncLoad returns promise + // + mathjax.asyncLoad = (_name: string) => Promise.resolve().then(() => 'success'); + await expect(asyncLoad('x.js')).resolves.toBe('success'); + + // + // mathjax.asyncLoad returns promise that rejects + // + mathjax.asyncLoad = (_name: string) => Promise.reject().catch(() => {throw 'fail'}); + await expect(asyncLoad('x.js')).rejects.toBe('fail'); + + }); + +}); diff --git a/testsuite/tests/util/BBox.test.ts b/testsuite/tests/util/BBox.test.ts new file mode 100644 index 000000000..686649eb0 --- /dev/null +++ b/testsuite/tests/util/BBox.test.ts @@ -0,0 +1,130 @@ +import { describe, test, expect } from '@jest/globals'; +import {BBox} from '#js/util/BBox.js'; +import {BIGDIMEN} from '#js/util/lengths.js'; + +describe('BBox object', () => { + + test('BBox creation', () => { + expect(BBox.zero()).toEqual(expect.objectContaining({w: 0, h: 0, d: 0})); + expect(BBox.empty()).toEqual(expect.objectContaining({w: 0, h: -BIGDIMEN, d: -BIGDIMEN})); + expect(new BBox({w: 1, h: 2, d: 0})).toEqual({ + w: 1, h: 2, d: 0, + L: 0, R: 0, + ic: 0, oc: 0, sk: 0, dx: 0, + scale: 1, rscale: 1, + pwidth: '' + }); + expect(new BBox({w: 1})).toEqual(expect.objectContaining({w: 1, h: -BIGDIMEN, d: -BIGDIMEN})); + }); + + test('empty()', () => { + expect(BBox.zero().empty()).toEqual(expect.objectContaining({w: 0, h: -BIGDIMEN, d: -BIGDIMEN})); + }); + + test('clean()', () => { + const bbox = BBox.empty(); + bbox.w = -BIGDIMEN; + bbox.clean(); + expect(bbox).toEqual(expect.objectContaining({w: 0, h: 0, d: 0})); + }); + + test('rescale()', () => { + const bbox = new BBox({w: 1, h: 2, d: 3}); + bbox.rescale(2); + expect(bbox).toEqual(expect.objectContaining({w: 2, h: 4, d: 6})); + bbox.rescale(0); + expect(bbox).toEqual(BBox.zero()); + }); + + test('copy()', () => { + const bbox = Object.assign(new BBox({w: 1, h: 2, d: 3}), { + L: 4, R: 5, + ic: 6, oc: 7, sk: 8, dx: 9, + scale: 10, rscale: 11, + pwidth: '10%' + }); + const copy = bbox.copy(); + expect(copy).toEqual(bbox); + expect(copy).not.toBe(bbox); + }); + + test('updateFrom()', () => { + const bbox1 = Object.assign(new BBox({w: 1, h: 2, d: 3}), { + L: 4, R: 5, + ic: 6, oc: 7, sk: 8, dx: 9, + scale: 10, rscale: 11, + pwidth: '' + }); + bbox1.updateFrom(BBox.empty()); + expect(bbox1).toEqual({ + w: 0, h: -BIGDIMEN, d: -BIGDIMEN, + L: 4, R: 5, + ic: 6, oc: 7, sk: 8, dx: 9, + scale: 10, rscale: 11, + pwidth: '' + }); + bbox1.pwidth = '100%'; + const bbox2 = BBox.zero(); + bbox2.updateFrom(bbox1); + expect(bbox2).toEqual({ + w: 0, h: -BIGDIMEN, d: -BIGDIMEN, + L: 0, R: 0, + ic: 0, oc: 0, sk: 0, dx: 0, + scale: 1, rscale: 1, + pwidth: '100%' + }); + }); + + test('combine()', () => { + let bbox = BBox.empty(); + const cbox = new BBox({w: 1, h: 2, d: 3}); + bbox.combine(cbox); + expect(bbox).toEqual(expect.objectContaining({w: 1, h: 2, d: 3})); + + // + // Check that a scaled bbox is placed properly + // + cbox.rscale = 2; + bbox.combine(cbox); + expect(bbox).toEqual(expect.objectContaining({w: 2, h: 4, d: 6})); + + // + // Check x and y positioning + // + bbox = BBox.empty(); + cbox.L = 2; + cbox.R = 1; + cbox.rscale = .5; + bbox.combine(cbox, 1, 2); + expect(bbox).toEqual(expect.objectContaining({w: 3, h: 3, d: -.5})); + + // + // Check box that doesn't change current bbox + // + cbox.rscale = .01; + bbox.combine(cbox, 1, 1); + expect(bbox).toEqual(expect.objectContaining({w: 3, h: 3, d: -.5})); + }); + + test('append()', () => { + let bbox = BBox.empty(); + const cbox = new BBox({w: 1, h: 2, d: 3}); + bbox.append(cbox); + expect(bbox).toEqual(expect.objectContaining({w: 1, h: 2, d: 3})); + + // + // Check that a scaled bbox is placed properly + // + cbox.rscale = 2; + bbox.append(cbox); + expect(bbox).toEqual(expect.objectContaining({w: 3, h: 4, d: 6})); + + // + // Check that h and d don't change + // + cbox.rscale = 1; + bbox.append(cbox); + expect(bbox).toEqual(expect.objectContaining({w: 4, h: 4, d: 6})); + }); + +}); diff --git a/testsuite/tests/util/BitField.test.ts b/testsuite/tests/util/BitField.test.ts new file mode 100644 index 000000000..25a6f8694 --- /dev/null +++ b/testsuite/tests/util/BitField.test.ts @@ -0,0 +1,66 @@ +import { describe, test, expect } from '@jest/globals'; +import {BitField, BitFieldClass} from '#js/util/BitField.js'; + +const MAXBIT = (BitField as any).MAXBIT; + +const bitClass = BitFieldClass('a', 'b'); +bitClass.allocate('c'); + +describe('BitField object', () => { + + test('Allocating bits', () => { + expect(bitClass.has('a')).toBe(true); + expect(bitClass.has('b')).toBe(true); + expect(bitClass.has('c')).toBe(true); + expect(() => bitClass.allocate('a')).toThrow('Bit already allocated for a'); + for (let i = 1 << 3; i !== MAXBIT; i = i << 1) { + bitClass.allocate('x' + i); + } + expect(() => bitClass.allocate('y')).toThrow('Maximum number of bits already allocated'); + }); + + test('set/clear/isSet/reset', () => { + const bits = new bitClass(); + // + // Bit is initially false + // + expect(bits.isSet('a')).toBe(false); + expect(bits.isSet('b')).toBe(false); + // + // Check that it sets + // + bits.set('a'); + expect(bits.isSet('a')).toBe(true); + expect(bits.isSet('b')).toBe(false); + // + // Check that setting again is still set + // + bits.set('a') + expect(bits.isSet('a')).toBe(true); + // + // Check that it clears + // + bits.clear('a'); + expect(bits.isSet('a')).toBe(false); + // + // Check that it stays clear + // + bits.clear('a'); + expect(bits.isSet('a')).toBe(false); + // + // Check that reset clears all bits + // + bits.set('a'); + bits.set('b'); + expect(bits.isSet('a')).toBe(true); + expect(bits.isSet('b')).toBe(true); + bits.reset(); + expect(bits.isSet('a')).toBe(false); + expect(bits.isSet('b')).toBe(false); + // + // Invalid name throws error + // + expect(() => bits.isSet('A')).toThrow('Unknown bit-field name: A'); + }); + +}); diff --git a/testsuite/tests/util/Context-android.test.ts b/testsuite/tests/util/Context-android.test.ts new file mode 100644 index 000000000..4b9c88db1 --- /dev/null +++ b/testsuite/tests/util/Context-android.test.ts @@ -0,0 +1,14 @@ +import { describe, test, expect } from '@jest/globals'; + +const window = {document: {}, navigator: {userAgent: 'Android', appVersion: ''}}; +(global as any).window = window; + +describe('context object', () => { + + test('context', async () => { + let {context, hasWindow} = await import("#js/util/context.js"); + expect(context).toEqual({window: window, document: window.document, os: 'Unix'}); + expect(hasWindow).toBe(true); + }); + +}); diff --git a/testsuite/tests/util/Context-browser.test.ts b/testsuite/tests/util/Context-browser.test.ts new file mode 100644 index 000000000..cb5d959cf --- /dev/null +++ b/testsuite/tests/util/Context-browser.test.ts @@ -0,0 +1,14 @@ +import { describe, test, expect } from '@jest/globals'; + +const window = {document: {}, navigator: {appVersion: 'Linux'}}; +(global as any).window = window; + +describe('context object', () => { + + test('context', async () => { + let {context, hasWindow} = await import("#js/util/context.js"); + expect(context).toEqual({window: window, document: window.document, os: 'Unix'}); + expect(hasWindow).toBe(true); + }); + +}); diff --git a/testsuite/tests/util/Context-node.test.ts b/testsuite/tests/util/Context-node.test.ts new file mode 100644 index 000000000..8df0b38fe --- /dev/null +++ b/testsuite/tests/util/Context-node.test.ts @@ -0,0 +1,11 @@ +import { describe, test, expect } from '@jest/globals'; +import { context, hasWindow } from '#js/util/context.js'; + +describe('context object', () => { + + test('context', () => { + expect(context).toEqual({window: null, document: null, os: 'unknown'}); + expect(hasWindow).toBe(false); + }); + +}); diff --git a/testsuite/tests/util/Entities.test.ts b/testsuite/tests/util/Entities.test.ts new file mode 100644 index 000000000..b06b5227c --- /dev/null +++ b/testsuite/tests/util/Entities.test.ts @@ -0,0 +1,21 @@ +import { describe, test, expect } from '@jest/globals'; +import * as Entities from '#js/util/Entities.js'; +import {handleRetriesFor} from '#js/util/Retries.js'; +import '#js/util/asyncLoad/esm.js'; + +describe('Entities translation', () => { + + test('translate()', async () => { + expect(Entities.translate('a')).toBe('a'); + expect(Entities.translate('a')).toBe('a'); + expect(Entities.translate('&')).toBe('&'); + await expect(handleRetriesFor(() => Entities.translate('&xyz;'))).resolves.toBe('&xyz;'); // no such entity + await expect(handleRetriesFor(() => Entities.translate('≈'))).resolves.toBe('\u2248'); // load a.js + await expect(handleRetriesFor(() => Entities.translate('ℬ'))).resolves.toBe('\u212C'); // load scr.js + Entities.remove('approx'); + expect(Entities.translate('≈')).toBe('≈'); // undefined entities remain unchanged + Entities.options.loadMissingEntities = false; + expect(Entities.translate('⋀')).toBe('⋀'); // don't load b.js + }); + +}); diff --git a/testsuite/tests/util/FunctionList.test.ts b/testsuite/tests/util/FunctionList.test.ts new file mode 100644 index 000000000..901cb8d1b --- /dev/null +++ b/testsuite/tests/util/FunctionList.test.ts @@ -0,0 +1,157 @@ +import { describe, test, expect } from '@jest/globals'; +import {FunctionList, AnyFunction} from '#js/util/FunctionList.js'; + +// +// Set up a function list with 6 functions that captures output +// +function LIST(): [FunctionList, string[]] { + const output = [] as string[]; + const list = new FunctionList(); + for (const i of [5, 0, 2, 1, 6, 3, 4]) {list.add(FN(i, output), i)} + return [list, output]; +} + +// +// A function that buffers the value of its parameters plus i +// unless the parameter is false or fail, which do special actions, +// or if the second is 'p', when we return a promise with a delay. +// +function FN(i: number, output: string[] = []) { + return function (x?: string, y?: string) { + if (x === 'false' && i === 3) return false; + if (x === 'fail' && i === 3) throw new Error('fail'); + output.push(x === undefined ? String(i) : y == null ? x + i : x + y + i); + if (x === 'delay' && i === 3) { + return new Promise((ok, fail) => { + setTimeout(() => {y === 'fail' ? fail('Failed!') : ok()}, 10); + }); + } + return true; + }; +} + +describe('FunctionList functionality', () => { + test('Empty list is empty array', () => { + expect(Array.from(new FunctionList())).toEqual([]); + }); + + test('Adding one item', () => { + const list = new FunctionList(); + const fn = FN(0); + const item = list.add(fn); + expect(Array.from(list)).toEqual([{item: item, priority: 5}]); + expect(item).toBe(fn); + }); + + test('Adding a list of items', () => { + const fns = [(_: any) => {}, [(_: any) => {}, 1]] as [AnyFunction, [AnyFunction, number]]; + const list = new FunctionList(fns); + expect(Array.from(list)).toEqual([ + {item: fns[1][0], priority: 1}, + {item: fns[0], priority: 5}, + ]); + }); + + test('Removing one item', () => { + const list = new FunctionList(); + const fn = list.add(FN(0)); + const item = list.remove(fn); + expect(Array.from(list)).toEqual([]); + expect(item).toBe(list); + }); + + test('Executing list', () => { + const output = [] as string[]; + const list = new FunctionList(); + list.add(FN(0, output)); + expect(list.execute()).toBe(true); + expect(output).toEqual(["0"]); + }); + + test('Sorting of list', () => { + const [list, output] = LIST(); + expect(list.execute()).toBe(true); + expect(output).toEqual(['0', '1', '2', '3', '4', '5', '6']); + }); + + test('Passing one parameter', () => { + const [list, output] = LIST(); + expect(list.execute('x')).toBe(true); + expect(output).toEqual(['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6']); + }); + + test('Passing multiple parameters', () => { + const [list, output] = LIST(); + expect(list.execute('x', 'y')).toBe(true); + expect(output).toEqual(['xy0', 'xy1', 'xy2', 'xy3', 'xy4', 'xy5', 'xy6']); + }); + + test('Function returning false', () => { + const [list, output] = LIST(); + expect(list.execute('false')).toBe(false); + expect(output).toEqual(['false0', 'false1', 'false2']); + }); + + test('asyncExecute() returns promise', () => { + const list = new FunctionList(); + expect(list.asyncExecute() instanceof Promise).toBe(true); + }); + + test('asyncExecute() runs', () => { + const [list, output] = LIST(); + list.asyncExecute().then((result: boolean) => { + expect(result).toBe(true); + expect(output).toEqual(['0', '1', '2', '3', '4', '5', '6']); + }); + }); + + test('Passing parameter to asyncExecute()', () => { + const [list, output] = LIST(); + list.asyncExecute('x').then((result: boolean) => { + expect(result).toBe(true); + expect(output).toEqual(['x0', 'x1', 'x2', 'x3', 'x4', 'x5', 'x6']); + }); + }); + + test('Passing multiple parameters to asyncExecute()', () => { + const [list, output] = LIST(); + list.asyncExecute('x', 'y').then((result: boolean) => { + expect(result).toBe(true); + expect(output).toEqual(['xy0', 'xy1', 'xy2', 'xy3', 'xy4', 'xy5', 'xy6']); + }); + }); + + test('Function returning false in asyncExecute()', () => { + const [list, output] = LIST(); + list.asyncExecute('false').then((result: boolean) => { + expect(result).toBe(false); + expect(output).toEqual(['false0', 'false1', 'false2']); + }); + }); + + test('Function error in asyncExecute()', () => { + const [list, output] = LIST(); + expect.assertions(2); + list.asyncExecute('fail').catch((err: Error) => { + expect(output).toEqual(['fail0', 'fail1', 'fail2']); + expect(err.message).toBe("fail"); + }); + }); + + test('Delay in asyncExecute()', () => { + const [list, output] = LIST(); + list.asyncExecute('delay', '').then((result: boolean) => { + expect(result).toBe(true); + expect(output).toEqual(['delay0', 'delay1', 'delay2', 'delay3', 'delay4', 'delay5', 'delay6']); + }); + }); + + test('Failed promise in asyncExecute()', () => { + const [list, output] = LIST(); + list.asyncExecute('delay', 'fail').catch((result: string) => { + expect(output).toEqual(['delayfail0', 'delayfail1', 'delayfail2', 'delayfail3']); + expect(result).toBe("Failed!"); + }); + }); + +}); diff --git a/testsuite/tests/util/LinkedList.test.ts b/testsuite/tests/util/LinkedList.test.ts new file mode 100644 index 000000000..be0b01b77 --- /dev/null +++ b/testsuite/tests/util/LinkedList.test.ts @@ -0,0 +1,149 @@ +import { describe, test, expect } from '@jest/globals'; +import {LinkedList} from '#js/util/LinkedList.js'; + +function inReverse(a: number, b: number) {return a > b} + +describe('LinkedList functionality', () => { + test('Empty list is empty array', () => { + const list = new LinkedList(); + expect(Array.from(list)).toEqual([]); + }); + + test('Adding one item', () => { + const list = new LinkedList(); + const item = list.push('x'); + expect(Array.from(list)).toEqual(['x']); + expect(item).toBe(list); + }); + + test('Removing an item from list of 1 item', () => { + const list = new LinkedList('x'); + const item = list.pop(); + expect(Array.from(list)).toEqual([]); + expect(item).toBe('x'); + }); + + test('Removing from empty list', () => { + const list = new LinkedList(); + const item1 = list.pop(); + expect(Array.from(list)).toEqual([]); + expect(item1).toBe(null); + const item2 = list.shift(); + expect(Array.from(list)).toEqual([]); + expect(item2).toBe(null); + }); + + test('Removing items', () => { + expect(Array.from(new LinkedList(1, 2, 3, 4).remove())).toEqual([1, 2, 3, 4]); // remove nothing + expect(Array.from(new LinkedList(1, 2, 3, 4).remove(1))).toEqual([2, 3, 4]); // at start + expect(Array.from(new LinkedList(1, 2, 3, 4).remove(4))).toEqual([1, 2, 3]); // at end + expect(Array.from(new LinkedList(1, 2, 3, 4).remove(2))).toEqual([1, 3, 4]); // in midle + expect(Array.from(new LinkedList(1, 2, 3, 4).remove(1, 3, 4))).toEqual([2]); // multiple items removed + expect(Array.from(new LinkedList(1, 2, 3, 4).remove(6))).toEqual([1, 2, 3, 4]); // item not in list + expect(Array.from(new LinkedList(1, 2, 3, 4).remove(2, 6))).toEqual([1, 3, 4]); // some items not in list + expect(Array.from(new LinkedList(1, 2, 3, 4).remove(1, 2, 3, 4))).toEqual([]); // all items removed + }); + + test('Adding nothing', () => { + expect(Array.from(new LinkedList().push())).toEqual([]); + expect(Array.from(new LinkedList().unshift())).toEqual([]); + expect(Array.from(new LinkedList(1, 2).push())).toEqual([1, 2]); + expect(Array.from(new LinkedList(1, 2).unshift())).toEqual([1, 2]); + }); + + test('unshift to empty array', () => { + const list = new LinkedList(); + expect(Array.from(list.unshift('x'))).toEqual(['x']); + const item = list.shift(); + expect(Array.from(list)).toEqual([]); + expect(item).toBe('x'); + }); + + test('Pushing several items', () => { + const list = new LinkedList(); + list.push(2, 3, 4); + expect(Array.from(list)).toEqual([2, 3, 4]); + list.push(5, 6); + expect(Array.from(list)).toEqual([2, 3, 4, 5, 6]); + const item = list.unshift(0, 1); + expect(Array.from(list)).toEqual([0, 1, 2, 3, 4, 5, 6]); + expect(item).toBe(list); + }); + + test('Iterator', () => { + const list = new LinkedList(0, 1, 2, 3, 4, 5, 6); + let j = 0; + for (const item of list) { + if (item === j) j++; else break; + } + expect(j).toBe(7); + }); + + test('Reversed iterator', () => { + const list = new LinkedList(0, 1, 2, 3, 4, 5, 6); + let j = 6; + for (const item of list.reversed()) { + if (item === j) j--; else break; + } + expect(j).toBe(-1); + }); + + test('Removing items by shift', () => { + const list = new LinkedList(0, 1, 2, 3); + expect(list.shift()).toBe(0); + expect(Array.from(list)).toEqual([1, 2, 3]); + expect(list.pop()).toBe(3); + expect(Array.from(list)).toEqual([1, 2]); + }); + + test('Clearing of list', () => { + const list = new LinkedList(1, 2, 3); + expect(Array.from(list.clear())).toEqual([]); + expect(list.clear()).toBe(list); // clear() returns list + }); + + test('Sorting of list', () => { + const list = new LinkedList(); + expect(list.sort()).toBe(list); // sort() returns list + expect(Array.from(list.sort())).toEqual([]); // empty list + expect(Array.from(new LinkedList(5, 1, 3, 6, 4, 0, 2).sort())).toEqual([0, 1, 2, 3, 4, 5, 6]); + expect(Array.from(new LinkedList(5, 1, 3, 6, 4, 0, 2).sort(inReverse))).toEqual([6, 5, 4, 3, 2, 1, 0]); + }); + + test('Inserting item in sorted list', () => { + const list = new LinkedList(); + expect(list.insert(3)).toBe(list); // insert() returns list + expect(Array.from(new LinkedList().insert(3))).toEqual([3]); // with empty list + expect(Array.from(new LinkedList(5, 3, 4, 1).sort().insert(0))).toEqual([0, 1, 3, 4, 5]); // at start + expect(Array.from(new LinkedList(5, 3, 4, 1).sort().insert(6))).toEqual([1, 3, 4, 5, 6]); // at end + expect(Array.from(new LinkedList(5, 3, 4, 1).sort().insert(2))).toEqual([1, 2, 3, 4, 5]); // in middle + }); + + test('Inserting with sort function', () => { + expect(Array.from(new LinkedList().insert(3, inReverse))).toEqual([3]); // with empty list + expect(Array.from(new LinkedList(3, 2, 1).insert(4, inReverse))).toEqual([4, 3, 2, 1]); // at start + expect(Array.from(new LinkedList(3, 2, 1).insert(0, inReverse))).toEqual([3, 2, 1, 0]); // at end + expect(Array.from(new LinkedList(4, 3, 1).insert(2, inReverse))).toEqual([4, 3, 2, 1]); // in middle + }); + + test('Merging of lists', () => { + const list = new LinkedList(1, 3); + expect(list.merge(new LinkedList(2, 4))).toBe(list); // merge() return list + expect(Array.from(new LinkedList().merge(new LinkedList()))).toEqual([]); // with two empty lists + expect(Array.from(new LinkedList().merge(new LinkedList(1, 3, 5)))).toEqual([1, 3, 5]); // with 1st list empty + expect(Array.from(new LinkedList(1, 3, 5).merge(new LinkedList()))).toEqual([1, 3, 5]); // with 2nd list empty + expect(Array.from(new LinkedList(1, 3, 4, 7, 8, 9).merge(new LinkedList(2, 5, 6, 10, 11)))) + .toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); // intermized lists + expect(Array.from(new LinkedList(1, 3, 4).merge(new LinkedList(1, 2, 4, 5)))) + .toEqual([1, 1, 2, 3, 4, 4, 5]); // merge with repeats + expect(Array.from(new LinkedList(1, 2, 3, 4).merge(new LinkedList(5, 6, 7, 8)))) + .toEqual([1, 2, 3, 4, 5, 6, 7, 8]); // at end + expect(Array.from(new LinkedList(5, 6, 7, 8).merge(new LinkedList(1, 2, 3, 4)))) + .toEqual([1, 2, 3, 4, 5, 6, 7, 8]); // at start + expect(Array.from(new LinkedList(1, 2, 7, 8).merge(new LinkedList(3, 4, 5, 6)))) + .toEqual([1, 2, 3, 4, 5, 6, 7, 8]); // in the middle + expect(Array.from(new LinkedList(9, 8, 7, 4, 3, 1).merge(new LinkedList(11, 10, 6, 5, 2, 0), inReverse))) + .toEqual([11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]); // with sort function + }); + +}); diff --git a/testsuite/tests/util/Options.test.ts b/testsuite/tests/util/Options.test.ts new file mode 100644 index 000000000..57016ecd5 --- /dev/null +++ b/testsuite/tests/util/Options.test.ts @@ -0,0 +1,340 @@ +import { describe, test, expect } from '@jest/globals'; +import * as Options from '#js/util/Options.js'; + +const SYMB = Symbol('symbol'); +const OPTIONS = Options.OPTIONS +const optionError = OPTIONS.optionError; + +describe('Options utility', () => { + + test('keys()', () => { + expect(Options.keys({a: 1, [Symbol.iterator]: 2})).toEqual(['a', Symbol.iterator]); + expect(Options.keys(null)).toEqual([]); + expect(Options.keys({})).toEqual([]); + }); + + test('copy()', () => { + // + // Copy() copies deeply + // + const orig: any = { + a: 1, + b: {x: 'x'}, + c: {y: 'y'}, + d: [1, {z: 'z'}, {w: 'w'}], + e: [1], + [SYMB]: 1 + }; + let copy = Options.copy(orig); + expect(copy).toEqual(orig); + + // + // Changing original doesn't change copy + // + orig.a = 2; + orig.b.x = 'xx'; + orig.c = {yy: 'yy'}; + orig.d[0] = 2; + orig.d[1].z = 'zz'; + orig.d[2] = {ww: 'ww'}; + orig.e = [2]; + orig.f = 2; + orig[SYMB] = 2; + expect(copy).toEqual({ + a: 1, + b: {x: 'x'}, + c: {y: 'y'}, + d: [1, {z: 'z'}, {w: 'w'}], + e: [1], + [SYMB]: 1 + }); + + // + // Copy() copies symbols + // + expect((copy as any)[SYMB]).toBe(1); + + // + // Copy() copies getter and setter + // + copy = Options.copy({ + _a: 1, + get a() {return this._a}, + set a(x) {this._a = x} + }); + expect(copy.a).toBe(1); + copy.a = 2; + expect(copy._a).toBe(2); + + // + // Copy() handle empty objects + // + expect(Options.copy({})).toEqual({}); + }); + + test('insert()', () => { + let warnings = [] as string[]; + OPTIONS.optionError = (_msg: string, key: string) => {warnings.push(key)}; + + const options = {a: 1, b: {x: 'x', y: [0]}, c: [1, 2, 3]}; + let copy = Options.insert({}, options, false); + expect(copy).toEqual(options); + expect(warnings).toEqual([]); + + // + // Error on unknown keys + // + copy = Options.insert({}, options); + expect(copy).toEqual({}); + expect(warnings).toEqual(['a', 'b', 'c']); // invalid keys + warnings = []; + copy = Options.insert({a: 2, b: {}, c: [4]}, options, true); + expect(copy).toEqual({a: 1, b: {}, c: [1, 2, 3]}); + expect(warnings).toEqual(['x', 'y']); // invalid keys + warnings = []; + copy = Options.insert({}, {[SYMB]: 1}); + expect(copy).toEqual({}); + expect(warnings).toEqual(['Symbol(symbol)']); + warnings = []; + + // + // insert() adds to objects and replaces other values + // + copy = Options.insert({a: 2, b: {}, c: [4]}, options, false); + expect(copy).toEqual(options); + + // + // insert() merges objects + // + copy = Options.insert({a: {}, b: 2}, {a: {x: 'x'}}, false); + expect(copy).toEqual({a: {x: 'x'}, b: 2}); + + // + // insert() merges into functions + // + copy = Options.insert({a: function () {}}, {a: {x: 'x'}}, false); + expect(copy.a.x).toBe('x'); + + // + // insert() changes object type + // + copy = Options.insert({a: {x: 'x'}}, {a: 1}, false); + expect(copy).toEqual({a: 1}); + + // + // insert() replaces arrays + // + copy = Options.insert({a: [1, 2]}, {a: [3, 4]}, false); + expect(copy).toEqual({a: [3, 4]}); + + // + // insert() appends to arrays with APPEND key + // + copy = Options.insert({a: [1, 2]}, {a: {[Options.APPEND]:[3, 4]}}, false); + expect(copy).toEqual({a: [1, 2, 3, 4]}); + + // + // insert() removes from arrays with REMOVE key + // + copy = Options.insert({a: [1, 2, 3, 4]}, {a: {[Options.REMOVE]:[1, 3]}}, false); + expect(copy).toEqual({a: [2, 4]}); + + // + // insert() adds and removes from arrays + // + copy = Options.insert({a: [1, 2, 3, 4]}, {a: {[Options.REMOVE]:[1, 3], [Options.APPEND]: [3, 5]}}, false); + expect(copy).toEqual({a: [2, 4, 3, 5]}); + + // + // insert() handles empty objects + // + copy = Options.insert({a: 1}, {}); + expect(copy).toEqual({a: 1}); + expect(warnings).toEqual([]); + + OPTIONS.optionError = optionError; + }); + + test('expandable()', () => { + let warnings = [] as string[]; + OPTIONS.optionError = (_msg: string, key: string) => {warnings.push(key)}; + + // + // No error for unknonw keys in expandables + // + const options = {a: Options.expandable({x: 1})}; + let copy = Options.userOptions(options, {a: {y: 2}}); + expect(copy).toEqual({a: {x: 1, y: 2}}); + expect(warnings).toEqual([]); + + OPTIONS.optionError = optionError; + + // + // Expandable copies as expandable + // + copy = Options.copy(Options.expandable({x: 1})); + expect(copy instanceof Options.Expandable).toBe(true); + expect(copy).toEqual({x:1}); + }); + + test('defaultOptions()', () => { + let warnings = 0; + OPTIONS.optionError = () => {warnings++}; + + const copy = Options.defaultOptions({}, {a: 1}, {b: 2}); + expect(copy).toEqual({a: 1, b: 2}); + expect(warnings).toBe(0); + + OPTIONS.optionError = optionError; + }); + + test('userOptions()', () => { + let warnings = [] as string[]; + OPTIONS.optionError = (_msg: string, key: string) => {warnings.push(key)}; + + // + // userOptions() warns about invalid options + // + let copy = Options.userOptions({}, {a: 1}, {b: 2}); + expect(copy).toEqual({}); + expect(warnings).toEqual(['a', 'b']); + warnings = []; + + // + // userOptions() warns about invalid secondary options + // + copy = Options.userOptions({a: 'x'}, {a: 1}, {b: 2}); + expect(copy).toEqual({a: 1}); + expect(warnings).toEqual(['b']); + warnings = []; + + // + // userOptions() merges multiple options + // + copy = Options.userOptions({a: 'x', b: 'y'}, {a: 1}, {b: 2}); + expect(copy).toEqual({a: 1, b: 2}); + expect(warnings).toEqual([]); + + OPTIONS.optionError = optionError; + }); + + test('selectOptions()', () => { + // + // selectOptions() finds existing keys and skips others + // + const options = {a: 1, b: 2, c: 3, d: 4}; + let copy = Options.selectOptions(options, 'a', 'c', 'x', 'y'); + expect(copy).toEqual({a: 1, c: 3}); + + // + // selectOptions() handles empty list + // + copy = Options.selectOptions({}, 'x', 'y'); + expect(copy).toEqual({}); + + // + // selectOptions() handles empty list of keys + // + copy = Options.selectOptions(options); + expect(copy).toEqual({}); + }); + + test('selectOptionsFromKeys()', () => { + // + // selectOptionsFromKeys() finds existing keys and skips others + // + const options = {a: 1, b: 2, c: 3, d: 4}; + let copy = Options.selectOptionsFromKeys(options, {a: true, c: true, x: true, y: true}); + expect(copy).toEqual({a: 1, c: 3}); + // + // selectOptionsFromKeys() handles empty source list + // + copy = Options.selectOptionsFromKeys({}, options); + expect(copy).toEqual({}); + // + // selectOptionsFromKeys() handles empty key list; + // + copy = Options.selectOptionsFromKeys(options, {}); + expect(copy).toEqual({}); + }); + + test('separateOptions()', () => { + // + // separateOptions() works with one set + // + const options = {a: 1, b: 2, c: 3, d: 4, e: 5}; + let result = Options.separateOptions(options, {a: true, c: true}); + expect(result).toEqual([{b: 2, d: 4, e: 5}, {a: 1, c: 3}]); + + // + // separateOptions() works with two sets + // + result = Options.separateOptions(options, {a: true, c: true}, {d: true}); + expect(result).toEqual([{b: 2, e: 5}, {a: 1, c: 3}, {d: 4}]); + + // + // separateOptions() works with no sets + // + result = Options.separateOptions(options); + expect(result).toEqual([options]); + + // + // separateOptions() works with unknown keys + // + result = Options.separateOptions(options, {a: true, c: true, x: true}); + expect(result).toEqual([{b: 2, d: 4, e: 5}, {a: 1, c: 3}]); + + // + // separateOptions() works with empty options + // + result = Options.separateOptions({}, {a: true}); + expect(result).toEqual([{}, {}]); + + // + // separateOptions() works with no options + // + result = Options.separateOptions(null, {a: true}); + expect(result).toEqual([{}, {}]); + }); + + test('OPTIONS settings', () => { + let copy: Options.OptionList; + + // + // Fatal throws an error + // + OPTIONS.invalidOption = 'fatal'; + try { + copy = Options.userOptions({}, {a: 1}); + } catch(err) { + expect(err.message).toBe('Invalid option "a" (no default value).'); + } + expect(copy).toEqual(undefined); + + // + // Warn does not throw an error + // + const warn = console.warn; + console.warn = () => {} + OPTIONS.invalidOption = 'warn'; + try { + copy = Options.userOptions({}, {a: 1}); + } catch(err) {} + expect(copy).toEqual({}); + console.warn = warn; + + }); + + test('makeArray()', () => { + expect(Options.makeArray([1, 2])).toEqual([1, 2]); + expect(Options.makeArray(1)).toEqual([1]); + }); + + test('lookup()', () => { + const options = {a: 1, b: 'x'}; + expect(Options.lookup('a', options)).toBe(1); + expect(Options.lookup('c', options, 'default')).toBe('default'); + expect(Options.lookup('c', options)).toBe(null); + }); + +}); diff --git a/testsuite/tests/util/PrioritizedList.test.ts b/testsuite/tests/util/PrioritizedList.test.ts new file mode 100644 index 000000000..f3a6f7bc1 --- /dev/null +++ b/testsuite/tests/util/PrioritizedList.test.ts @@ -0,0 +1,70 @@ +import { describe, test, expect } from '@jest/globals'; +import {PrioritizedList} from '#js/util/PrioritizedList.js'; + +// +// Turn the item list into a list of just that data +// +function ARRAY(list: PrioritizedList) { + let array = []; + for (const {item} of list) array.push(item); + return array; +} + +describe('PrioritizedList functionality', () => { + test('Empty list is empty array', () => { + expect(ARRAY(new PrioritizedList())).toEqual([]); + }); + + test('Adding one item', () => { + const list = new PrioritizedList(); + const item = list.add(0); + expect(Array.from(list)).toHaveLength(1); + expect(Array.from(list)).toEqual([{item: 0, priority: 5}]); + expect(item).toBe(0); + }); + + test('Removing one item', () => { + const list = new PrioritizedList(); + list.add(0); + const item = list.remove(0); + expect(Array.from(list)).toEqual([]); + expect(item).toBe(list); + }); + + test('Sorting of list', () => { + const list = new PrioritizedList(); + for (const i of [5, 0, 2, 1, 6, 3, 4]) {list.add(i, i)} + expect(ARRAY(list)).toEqual([0, 1, 2, 3, 4, 5, 6]); + }); + + test('Iterator', () => { + const list = new PrioritizedList(); + for (const i of [5, 0, 2, 1, 6, 3, 4]) {list.add(i, i)} + let j = 0; + for (const item of list) { + if (item.item === j) j++; else break; + } + expect(j).toBe(7); + }); + + test('Removing from longer list', () => { + const list = new PrioritizedList(); + for (const i of [5, 0, 2, 1, 6, 3, 4]) {list.add(i, i)} + list.remove(3); // remove from middle + expect(ARRAY(list)).toEqual([0, 1, 2, 4, 5, 6]); + list.remove(0); // remove first + expect(ARRAY(list)).toEqual([1, 2, 4, 5, 6]); + list.remove(6); // remove last + expect(ARRAY(list)).toEqual([1, 2, 4, 5]); + }); + + test('Adding with same priority', () => { + const list = new PrioritizedList(); + list.add(3); + list.add(1,1); + list.add(4); + list.add(2,1); + expect(ARRAY(list)).toEqual([1, 2, 3, 4]); + }); + +}); diff --git a/testsuite/tests/util/Retries.test.ts b/testsuite/tests/util/Retries.test.ts new file mode 100644 index 000000000..45d3e4fb0 --- /dev/null +++ b/testsuite/tests/util/Retries.test.ts @@ -0,0 +1,148 @@ +import { describe, test, expect } from '@jest/globals'; +import {handleRetriesFor, retryAfter} from '#js/util/Retries.js'; +import {MathJax as MJX, MathJaxObject} from '#js/components/global.js'; + +/** + * Add the legacy MathJax.CallBack for teting v2-style restarts + */ +type MathJaxGlobal = MathJaxObject & { + Callback: { + After(code: Function): void, + mock(): Function + } +}; +const MathJax: MathJaxGlobal = Object.assign(MJX, { + Callback: { + After(code: () => void) { + setTimeout(code, 1); + }, + mock() {return Object.assign(() => {}, {isCallback: true})} + } +}); + +/**********************************************************************************/ +/**********************************************************************************/ + +describe('handleRetriesFor() and retryAfter()', () => { + + /********************************************************************************/ + + test('handleRetriesFor() then/catch getting called', () => { + expect(handleRetriesFor(() => 'success')).resolves.toBe('success'); + expect(handleRetriesFor(() => {throw Error('failed')})).rejects.toThrow('failed'); + }); + + /********************************************************************************/ + + test('handleRetriesFor().then called after 3 retries', () => { + let n = 0; + handleRetriesFor(() => { + if (++n < 3) { + let p = new Promise((ok, _fail) => { + setTimeout(() => ok(), 1); + }); + retryAfter(p); + } + return 'success'; + }).then((result: string) => { + expect(result).toBe('success'); + expect(n).toBe(3); + }); + }); + + /********************************************************************************/ + + test('handleRetriesFor().catch called for fail on 3rd retry', () => { + let n = 0; + handleRetriesFor(() => { + if (++n < 3) { + let p = new Promise((ok, fail) => { + setTimeout(() => n < 2 ? ok() : fail('fail'), 1); + }); + retryAfter(p); + } + return 'success'; + }).catch((result: string) => { + expect(result).toBe('fail'); + expect(n).toBe(2); + }); + }); + + /********************************************************************************/ + + test('handleRetriesFor().catch called for error on 3rd retry', () => { + let n = 0; + handleRetriesFor(() => { + if (++n < 3) { + let p = new Promise((ok, _fail) => { + setTimeout(() => ok(), 1); + }); + retryAfter(p); + } + throw Error('fail'); + }).catch((err: Error) => { + expect(err.message).toBe('fail'); + expect(n).toBe(3); + }); + }); + + /********************************************************************************/ + + test('v2 retry', () => { + let n = 0; + handleRetriesFor(() => { + if (++n < 3) { + throw Object.assign(new Error('restart'), { + restart: MathJax.Callback.mock() // mark this error as a v2 restart + }); + } + return 'success'; + }).then((result: string) => { + expect(result).toBe('success'); + expect(n).toBe(3); + }); + }); + + /********************************************************************************/ + + test('handleRetriedFor() async success', () => { + expect(handleRetriesFor(async () => { + const wait = new Promise((ok, _fail) => setTimeout(() => ok('success'), 1)); + return (await wait); + })).resolves.toBe('success'); + }); + + /********************************************************************************/ + + test('handleRetriedFor() async fails', () => { + expect(handleRetriesFor(async () => { + const wait = new Promise((_ok, fail) => setTimeout(() => fail('fail'), 1)); + return (await wait); + })).rejects.toBe('fail'); + }); + + /********************************************************************************/ + + test('handleRetriedFor() async with retry', () => { + let n = 0; + handleRetriesFor(async () => { + if (++n < 3) { + await new Promise((ok, _fail) => setTimeout(ok, 1)); + let p = new Promise((ok, _fail) => { + setTimeout(() => ok(), 1); + }); + retryAfter(p); + } + return 'success'; + }).then((result: string) => { + expect(result).toBe('success'); + expect(n).toBe(3); + }); + }); + + /********************************************************************************/ + +}); + +/**********************************************************************************/ +/**********************************************************************************/ diff --git a/testsuite/tests/util/StyleJson.test.ts b/testsuite/tests/util/StyleJson.test.ts new file mode 100644 index 000000000..84a013515 --- /dev/null +++ b/testsuite/tests/util/StyleJson.test.ts @@ -0,0 +1,39 @@ +import { describe, test, expect } from '@jest/globals'; +import {StyleJsonSheet} from '#js/util/StyleJson.js'; + +describe('StyleJsonSheet object', () => { + + test('CssStyle creation', () => { + expect(new StyleJsonSheet().cssText).toBe(''); + expect(new StyleJsonSheet({'.mjx': {padding: '0px'}}).cssText).toBe('.mjx {\n padding: 0px;\n}'); + expect(new StyleJsonSheet({ + '.mjx': { + padding: '0px', + 'font-size': '150%' + }, + p: { + 'font-weight': 'bold' + } + }).cssText).toBe([ + '.mjx {', + ' padding: 0px;', + ' font-size: 150%;', + '}', + '', + 'p {', + ' font-weight: bold;', + '}' + ].join('\n')); + }); + + test('Add/remove styles', () => { + const styles = new StyleJsonSheet(); + styles.addStyles({p: {'font-weight': 'bold'}, h1: {'font-size': '150%'}, 'h2': {}}); + expect(styles.cssText).toBe('p {\n font-weight: bold;\n}\n\nh1 {\n font-size: 150%;\n}\n\nh2 {\n\n}'); + styles.removeStyles('h1', 'h2'); + expect(styles.cssText).toBe('p {\n font-weight: bold;\n}'); + styles.clear(); + expect(styles.cssText).toBe(''); + }); + +}); diff --git a/testsuite/tests/util/Styles.test.ts b/testsuite/tests/util/Styles.test.ts new file mode 100644 index 000000000..1e80abaea --- /dev/null +++ b/testsuite/tests/util/Styles.test.ts @@ -0,0 +1,359 @@ +import { describe, test, expect } from '@jest/globals'; +import {Styles, StyleList} from '#js/util/Styles.js'; + +function cssTest(css: string, list: StyleList, text: string = css + ';') { + const styles = new Styles(css); + expect(styles.styleList).toEqual(list); + expect(styles.cssText).toBe(text); +} + +function cssFontTest(css: string, list: StyleList) { + const test = Array.from(Object.keys(list)).map((k) => `${k}: ${list[k]};`).join(' '); + return cssTest(css, list, test); +} + +describe('CssStyles object', () => { + + test('Styles parsing', () => { + cssTest('', {}, ''); // emtpy list + cssTest('font-size: 150%', {'font-size': '150%'}); // one style + cssTest('abc-def: 0', {'abc-def': '0'}); // unknown style is retained + cssTest('a: 0; b: 1px', {a: '0', b: '1px'}); // multiple styles + cssTest('a: 0; /*b: 1px*/ c: bold', {a: '0', c: 'bold'}, 'a: 0; c: bold;'); // comments + cssTest(' a : \n 0 ; b\n : 1px \n ', {a: '0', b: '1px'}, 'a: 0; b: 1px;'); // extra spaces + cssTest('abc: ; xyz: 0', {xyz: '0'}, 'xyz: 0;'); // missing value + cssTest('abc xyz: 1px', {}, ''); // malformed CSS string + + cssTest(`abc: xy 'pqr`, {abc: `xy 'pqr'`}, `abc: xy 'pqr';`); // append missing ' + cssTest(`abc: xy "pqr`, {abc: `xy "pqr"`}, `abc: xy "pqr";`); // append missing " + cssTest(`abc: xy '\\'pqr`, {abc: `xy '\\'pqr'`}, `abc: xy '\\'pqr';`); // handle quoted ' + cssTest(`abc: xy "\\"pqr`, {abc: `xy "\\"pqr"`}, `abc: xy "\\"pqr";`); // handle quoted " + cssTest(`abc: ';'`, {abc: `';'`}); // handle quoted ; + cssTest(`abc: ';`, {abc: `';'`}, `abc: ';';`); // and missing ' + + cssTest('\nabc\n:\n xyz \n; \n def \n : \n pqr\n ; \n ', { + abc: 'xyz', + def: 'pqr' + }, 'abc: xyz; def: pqr;'); + cssTest(`abc: \n xy \n 'pqr\n`, {abc: `xy 'pqr '`}, `abc: xy 'pqr ';`); + + // + // Remove unquoted ; and beyond + // + const styles = new Styles(); + styles.set('abc', 'xy ; z'); + expect(styles.styleList).toEqual({abc: 'xy'}); + expect(styles.cssText).toBe('abc: xy;'); + }); + + test('padding', () => { + cssTest('padding: 3px', { + 'padding': '3px', + 'padding-bottom': '3px', + 'padding-left': '3px', + 'padding-right': '3px', + 'padding-top': '3px' + }); + cssTest('padding: 3px; padding-right: 1px', { + 'padding': '3px 1px 3px 3px', + 'padding-bottom': '3px', + 'padding-left': '3px', + 'padding-right': '1px', + 'padding-top': '3px' + }, 'padding: 3px 1px 3px 3px;'); + cssTest('padding-top: 0; padding-right: 1px; padding-bottom: 0; padding-left: 1px', { + 'padding': '0 1px', + 'padding-bottom': '0', + 'padding-left': '1px', + 'padding-right': '1px', + 'padding-top': '0' + }, 'padding: 0 1px;'); + cssTest('padding-top: 0; padding-right: 1px; padding-bottom: 2px; padding-left: 1px', { + 'padding': '0 1px 2px', + 'padding-bottom': '2px', + 'padding-left': '1px', + 'padding-right': '1px', + 'padding-top': '0' + }, 'padding: 0 1px 2px;'); + cssTest('padding-top: 0; padding-right: 0; padding-bottom: 0; padding-left: 0', { + 'padding': '0', + 'padding-bottom': '0', + 'padding-left': '0', + 'padding-right': '0', + 'padding-top': '0' + }, 'padding: 0;'); + cssTest('padding:', {}, ''); + }); + + test('border', () => { + cssTest('border: 3px solid red', { + 'border': '3px solid red', + 'border-top': '3px solid red', + 'border-top-color': 'red', + 'border-top-style': 'solid', + 'border-top-width': '3px', + 'border-right': '3px solid red', + 'border-right-color': 'red', + 'border-right-style': 'solid', + 'border-right-width': '3px', + 'border-bottom': '3px solid red', + 'border-bottom-color': 'red', + 'border-bottom-style': 'solid', + 'border-bottom-width': '3px', + 'border-left': '3px solid red', + 'border-left-color': 'red', + 'border-left-style': 'solid', + 'border-left-width': '3px' + }); + cssTest('border: 3px solid red; border-top: inset blue 2px', { + 'border-top': 'inset blue 2px', + 'border-top-color': 'blue', + 'border-top-style': 'inset', + 'border-top-width': '2px', + 'border-right': '3px solid red', + 'border-right-color': 'red', + 'border-right-style': 'solid', + 'border-right-width': '3px', + 'border-bottom': '3px solid red', + 'border-bottom-color': 'red', + 'border-bottom-style': 'solid', + 'border-bottom-width': '3px', + 'border-left': '3px solid red', + 'border-left-color': 'red', + 'border-left-style': 'solid', + 'border-left-width': '3px' + }, [ + 'border-top: inset blue 2px; border-right: 3px solid red;', + 'border-bottom: 3px solid red; border-left: 3px solid red;' + ].join(' ')); + cssTest('border: 3px solid red; border-top-color: blue', { + 'border-top': '3px solid blue', + 'border-top-color': 'blue', + 'border-top-style': 'solid', + 'border-top-width': '3px', + 'border-right': '3px solid red', + 'border-right-color': 'red', + 'border-right-style': 'solid', + 'border-right-width': '3px', + 'border-bottom': '3px solid red', + 'border-bottom-color': 'red', + 'border-bottom-style': 'solid', + 'border-bottom-width': '3px', + 'border-left': '3px solid red', + 'border-left-color': 'red', + 'border-left-style': 'solid', + 'border-left-width': '3px' + }, [ + 'border-top: 3px solid blue; border-right: 3px solid red;', + 'border-bottom: 3px solid red; border-left: 3px solid red;' + ].join(' ')); + cssTest('border-top: 3px solid red; border-top-color: blue', { + 'border-top': '3px solid blue', + 'border-top-color': 'blue', + 'border-top-style': 'solid', + 'border-top-width': '3px', + }, 'border-top: 3px solid blue;'); + cssTest('border-top: 3px solid red; border-top-style: groove', { + 'border-top': '3px groove red', + 'border-top-color': 'red', + 'border-top-style': 'groove', + 'border-top-width': '3px', + }, 'border-top: 3px groove red;'); + cssTest('border-top: 3px solid red; border-top-width: 2px', { + 'border-top': '2px solid red', + 'border-top-color': 'red', + 'border-top-style': 'solid', + 'border-top-width': '2px', + }, 'border-top: 2px solid red;'); + cssTest('border: 3px solid', { + 'border': '3px solid', + 'border-bottom': '3px solid', + 'border-bottom-style': 'solid', + 'border-bottom-width': '3px', + 'border-left': '3px solid', + 'border-left-style': 'solid', + 'border-left-width': '3px', + 'border-right': '3px solid', + 'border-right-style': 'solid', + 'border-right-width': '3px', + 'border-top': '3px solid', + 'border-top-style': 'solid', + 'border-top-width': '3px', + }); + cssTest('border: 3px blue', { + 'border': '3px blue', + 'border-bottom': '3px blue', + 'border-bottom-color': 'blue', + 'border-bottom-width': '3px', + 'border-left': '3px blue', + 'border-left-color': 'blue', + 'border-left-width': '3px', + 'border-right': '3px blue', + 'border-right-color': 'blue', + 'border-right-width': '3px', + 'border-top': '3px blue', + 'border-top-color': 'blue', + 'border-top-width': '3px', + }); + cssTest('border: solid blue', { + 'border': 'solid blue', + 'border-bottom': 'solid blue', + 'border-bottom-color': 'blue', + 'border-bottom-style': 'solid', + 'border-left': 'solid blue', + 'border-left-color': 'blue', + 'border-left-style': 'solid', + 'border-right': 'solid blue', + 'border-right-color': 'blue', + 'border-right-style': 'solid', + 'border-top': 'solid blue', + 'border-top-color': 'blue', + 'border-top-style': 'solid', + }); + cssTest('border-top: red; border-right: red; border-bottom: red; border-left: red', { + 'border': 'red', + 'border-bottom': 'red', + 'border-bottom-color': 'red', + 'border-left': 'red', + 'border-left-color': 'red', + 'border-right': 'red', + 'border-right-color': 'red', + 'border-top': 'red', + 'border-top-color': 'red', + }, 'border: red;'); + cssTest('border: 3px solid red; border-width: 2px', { + 'border': '2px solid red', + 'border-bottom': '2px solid red', + 'border-bottom-color': 'red', + 'border-bottom-style': 'solid', + 'border-bottom-width': '2px', + 'border-left': '2px solid red', + 'border-left-color': 'red', + 'border-left-style': 'solid', + 'border-left-width': '2px', + 'border-right': '2px solid red', + 'border-right-color': 'red', + 'border-right-style': 'solid', + 'border-right-width': '2px', + 'border-top': '2px solid red', + 'border-top-color': 'red', + 'border-top-style': 'solid', + 'border-top-width': '2px', + }, 'border: 2px solid red;'); + cssTest('border: red; border-left-color:', { + 'border-bottom': 'red', + 'border-bottom-color': 'red', + 'border-right': 'red', + 'border-right-color': 'red', + 'border-top': 'red', + 'border-top-color': 'red', + }, 'border-top: red; border-right: red; border-bottom: red;'); + cssTest('border-radius: 3px', { + 'border-radius': '3px', + }); + cssTest('background: red; background-clip: none', { + 'background': 'red', + 'background-clip': 'none', + }); + }); + + test('font', () => { + cssFontTest('font-family: arial', {'font-family': 'arial'}); + cssFontTest('font-size: 120%', {'font-size': '120%'}); + cssFontTest('font-style: italic', {'font-style': 'italic'}); + cssFontTest('font-weight: bold', {'font-weight': 'bold'}); + cssFontTest('font: arial 120%', { + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial 120%', { + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: 120% arial', { + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial small', { + 'font-size': 'small', + 'font-family': 'arial' + }); + cssFontTest('font: arial 16px', { + 'font-size': '16px', + 'font-family': 'arial' + }); + cssFontTest('font: arial bold 120%', { + 'font-weight': 'bold', + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial lighter 120%', { + 'font-weight': 'lighter', + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial italic 120%', { + 'font-style': 'italic', + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial bold italic 120%', { + 'font-style': 'italic', + 'font-weight': 'bold', + 'font-size': '120%', + 'font-family': 'arial', + }); + cssFontTest('font: arial full-width 120%', { + 'font-variant': 'full-width', + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial full-width simplified 120%', { + 'font-variant': 'full-width simplified', + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial condensed 120%', { + 'font-stretch': 'condensed', + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial semi-condensed 120%', { + 'font-stretch': 'semi-condensed', + 'font-size': '120%', + 'font-family': 'arial' + }); + cssFontTest('font: arial small/.75', { + 'line-height': '.75', + 'font-size': 'small', + 'font-family': 'arial' + }); + cssFontTest('font: arial small/12px', { + 'line-height': '12px', + 'font-size': 'small', + 'font-family': 'arial' + }); + cssFontTest('font: arial small/75%', { + 'line-height': '75%', + 'font-size': 'small', + 'font-family': 'arial' + }); + cssFontTest('font: arial bold 120%; font-style: italic', { + 'font-weight': 'bold', + 'font-size': '120%', + 'font-family': 'arial', + 'font-style': 'italic' + }); + }); + + test('get()', () => { + const styles = new Styles('padding: 0; padding-left: 1px'); + expect(styles.get('padding')).toBe('0 0 0 1px'); + expect(styles.get('padding-top')).toBe('0'); + expect(styles.get('padding-right')).toBe('0'); + expect(styles.get('padding-bottom')).toBe('0'); + expect(styles.get('padding-left')).toBe('1px'); + expect(styles.get('border')).toBe(''); + }); + +}); diff --git a/testsuite/tests/util/asyncLoad/dirname.cjs b/testsuite/tests/util/asyncLoad/dirname.cjs new file mode 100644 index 000000000..ad99475b4 --- /dev/null +++ b/testsuite/tests/util/asyncLoad/dirname.cjs @@ -0,0 +1,3 @@ +const path = require('path'); + +module.exports.dirname = path.resolve(__dirname, path.join('..', '..', '..', '..', 'mjs', 'util', 'asyncLoad')); diff --git a/testsuite/tests/util/asyncLoad/dirname.mjs b/testsuite/tests/util/asyncLoad/dirname.mjs new file mode 100644 index 000000000..7d3b7205f --- /dev/null +++ b/testsuite/tests/util/asyncLoad/dirname.mjs @@ -0,0 +1,3 @@ +import {dirname} from './dirname.cjs'; + +global.__dirname = dirname; diff --git a/testsuite/tests/util/asyncLoad/esm.test.ts b/testsuite/tests/util/asyncLoad/esm.test.ts new file mode 100644 index 000000000..c29bcea23 --- /dev/null +++ b/testsuite/tests/util/asyncLoad/esm.test.ts @@ -0,0 +1,41 @@ +import { describe, test, expect } from '@jest/globals'; +import {mathjax} from '#js/mathjax.js'; +import {asyncLoad} from '#js/util/AsyncLoad.js'; +import {setBaseURL} from '#js/util/asyncLoad/esm.js'; +import * as path from 'path'; + +const root = path.resolve('..', 'mjs'); +const lib = path.resolve('lib'); + +describe('asyncLoad() for esm', () => { + + test('asyncLoad()', async () => { + const cjsFile = path.join('..', 'testsuite', 'lib', 'AsyncLoad.child.cjs'); + const mjsFile = path.join('..', 'testsuite', 'lib', 'AsyncLoad.child.mjs'); + const relUnknown = path.join('..', 'testsuite', 'lib', 'AsyncLoad.unknown.cjs'); + const absFile = path.join(root, cjsFile); + const absUnknown = path.join(root, relUnknown); + + await expect(asyncLoad(cjsFile)).resolves.toEqual({loaded: true}); // relative file found + await expect(asyncLoad(relUnknown).catch(() => true)).resolves.toBe(true); // relative file not found + await expect(asyncLoad(absFile)).resolves.toEqual({loaded: true}); // absolute file found + await expect(asyncLoad(absUnknown).catch(() => true)).resolves.toBe(true); // absolute file not found + + await expect(asyncLoad('#js/components/version.js') // load using package exports + .then((result: any) => result.VERSION)).resolves.toBe(mathjax.version); + await expect(asyncLoad('@mathjax/src/js/components/version.js') // load from module + .then((result: any) => result.VERSION)).resolves.toBe(mathjax.version); + + await expect(asyncLoad(mjsFile).then((result: any) => result.loaded)).resolves.toBe(true); // mjs file loads + expect(mathjax.asyncIsSynchronous).toBe(false); // esm.js is asynchronous + }); + + test('setBaseURL() for esm', async () => { + setBaseURL(lib); + const relFile = './AsyncLoad.child.cjs'; + const relUnknown = './AsyncLoad.unknown.cjs'; + await expect(asyncLoad(relFile)).resolves.toEqual({loaded: true}); // relative file found + await expect(asyncLoad(relUnknown).catch(() => true)).resolves.toBe(true); // relative file not found + }); + +}); diff --git a/testsuite/tests/util/asyncLoad/node.test.ts b/testsuite/tests/util/asyncLoad/node.test.ts new file mode 100644 index 000000000..3d7a6c080 --- /dev/null +++ b/testsuite/tests/util/asyncLoad/node.test.ts @@ -0,0 +1,43 @@ +import { describe, test, expect } from '@jest/globals'; +import './dirname.mjs'; +import '#source/../require.mjs'; +import {mathjax} from '#js/mathjax.js'; +import {asyncLoad} from '#js/util/AsyncLoad.js'; +import {setBaseURL} from '#js/util/asyncLoad/node.js'; +import * as path from 'path'; + +const root = path.dirname(path.dirname(__dirname)); +const lib = path.resolve('lib'); + +describe('asyncLoad() for node', () => { + + test('asyncLoad()', async () => { + const cjsFile = path.join('..', 'testsuite', 'lib', 'AsyncLoad.child.cjs'); + const mjsFile = path.join('..', 'testsuite', 'lib', 'AsyncLoad.child.mjs'); + const relUnknown = path.join('..', 'testsuite', 'lib', 'AsyncLoad.unknown.cjs'); + const absFile = path.join(root, cjsFile); + const absUnknown = path.join(root, relUnknown); + + await expect(asyncLoad(cjsFile)).resolves.toEqual({loaded: true}); // relative file found + await expect(asyncLoad(relUnknown).catch(() => true)).resolves.toBe(true); // relative file not found + await expect(asyncLoad(absFile)).resolves.toEqual({loaded: true}); // absolute file found + await expect(asyncLoad(absUnknown).catch(() => true)).resolves.toBe(true); // absolute file not found + + await expect(asyncLoad('#js/../cjs/components/version.js') // load using package exports + .then((result: any) => result.VERSION)).resolves.toBe(mathjax.version); + await expect(asyncLoad('@mathjax/src/js/components/version.js') // load from module + .then((result: any) => result.VERSION)).resolves.toBe(mathjax.version); + + await expect(asyncLoad(mjsFile).catch(() => true)).resolves.toBe(true); // mjs file fails + expect(mathjax.asyncIsSynchronous).toBe(true); // node.js is synchronous + }); + + test('setBaseURL() for node', async () => { + setBaseURL(lib); + const relFile = './AsyncLoad.child.cjs'; + const relUnknown = './AsyncLoad.unknown.cjs'; + await expect(asyncLoad(relFile)).resolves.toEqual({loaded: true}); // relative file found + await expect(asyncLoad(relUnknown).catch(() => true)).resolves.toBe(true); // relative file not found + }); + +}); diff --git a/testsuite/tests/util/asyncLoad/system.cjs b/testsuite/tests/util/asyncLoad/system.cjs new file mode 100644 index 000000000..dc89d8baf --- /dev/null +++ b/testsuite/tests/util/asyncLoad/system.cjs @@ -0,0 +1,11 @@ +const path = require('path'); + +/** + * Fake SystemJS, which is hard to run within jest + */ +System = { + import(name, root) { + return import(new URL(name, root).href); + } +} + diff --git a/testsuite/tests/util/asyncLoad/system.test.ts b/testsuite/tests/util/asyncLoad/system.test.ts new file mode 100644 index 000000000..b97626b7b --- /dev/null +++ b/testsuite/tests/util/asyncLoad/system.test.ts @@ -0,0 +1,43 @@ +import { describe, test, expect } from '@jest/globals'; +import './dirname.mjs'; +import './system.cjs'; +import {mathjax} from '#js/mathjax.js'; +import {asyncLoad} from '#js/util/AsyncLoad.js'; +import {setBaseURL} from '#js/util/asyncLoad/system.js'; +import * as path from 'path'; + +const root = path.resolve('..', 'mjs'); +const lib = path.resolve('lib'); + +describe('asyncLoad() for node', () => { + + test('asyncLoad()', async () => { + const cjsFile = path.join('..', 'testsuite', 'lib', 'AsyncLoad.child.cjs'); + const mjsFile = path.join('..', 'testsuite', 'lib', 'AsyncLoad.child.mjs'); + const relUnknown = path.join('..', 'testsuite', 'lib', 'AsyncLoad.unknown.cjs'); + const absFile = path.join(root, cjsFile); + const absUnknown = path.join(root, relUnknown); + + await expect(asyncLoad(cjsFile)).resolves.toEqual({loaded: true}); // relative file found + await expect(asyncLoad(relUnknown).catch(() => true)).resolves.toBe(true); // relative file not found + await expect(asyncLoad(absFile)).resolves.toEqual({loaded: true}); // absolute file found + await expect(asyncLoad(absUnknown).catch(() => true)).resolves.toBe(true); // absolute file not found + + await expect(asyncLoad('#js/components/version.js') // can't load using package exports + .catch(() => true)).resolves.toBe(true); + await expect(asyncLoad('mathjax-full/js/components/version.js') // can't load from module + .catch(() => true)).resolves.toBe(true); + + await expect(asyncLoad(mjsFile).then((result: any) => result.loaded)).resolves.toBe(true); // mjs file loads + expect(mathjax.asyncIsSynchronous).toBe(false); // system.js is asynchronous + }); + + test('setBaseURL() for node', async () => { + setBaseURL(lib); + const relFile = './AsyncLoad.child.cjs'; + const relUnknown = './AsyncLoad.unknown.cjs'; + await expect(asyncLoad(relFile)).resolves.toEqual({loaded: true}); // relative file found + await expect(asyncLoad(relUnknown).catch(() => true)).resolves.toBe(true); // relative file not found + }); + +}); diff --git a/testsuite/tests/util/length.test.ts b/testsuite/tests/util/length.test.ts new file mode 100644 index 000000000..5bbd6e796 --- /dev/null +++ b/testsuite/tests/util/length.test.ts @@ -0,0 +1,79 @@ +import { describe, it, expect } from '@jest/globals'; +import * as Length from '#js/util/lengths.js'; + +function convertLengthDim(str: string | number) { + return Length.length2em(str); +} + +describe('Dimension conversion from length', () => { + it('9', () => expect(convertLengthDim('9')).toBe(0)); + it('9nix', () => expect(convertLengthDim('9nix')).toBe(0)); + it('empty', () => expect(convertLengthDim('')).toBe(0)); + it('nix', () => expect(convertLengthDim('nix')).toBe(0)); + it('9em', () => expect(convertLengthDim('9em')).toBe(9)); + it('9ex', () => expect(convertLengthDim('9ex')).toBe(3.879)); + it('9pt', () => expect(convertLengthDim('9pt')).toBe(0.9)); + it('9pc', () => expect(convertLengthDim('9pc')).toBe(10.799999999999999)); + it('9px', () => expect(convertLengthDim('9px')).toBe(0.5625)); + it('9in', () => expect(convertLengthDim('9in')).toBe(54)); + it('9cm', () => expect(convertLengthDim('9cm')).toBe(21.259842519685037)); + it('9mm', () => expect(convertLengthDim('9mm')).toBe(2.125984251968504)); + it('9mu', () => expect(convertLengthDim('9mu')).toBe(0.5)); + it('9%', () => expect(convertLengthDim('9%')).toBe(0)); + it('number 9', () => expect(convertLengthDim(9)).toBe(0)); + it('thinmathspace', () => expect(convertLengthDim('thinmathspace')).toBe(3/18)); + it('em', () => expect(convertLengthDim('em')).toBe(1)); +}); + +describe('Dimension conversion with default', () => { + it('9', () => expect(Length.length2em('9', 100)).toBe(900)); + it('empty', () => expect(Length.length2em('', 100)).toBe(100)); + it('nix', () => expect(Length.length2em('nix', 100)).toBe(100)); + it('9nix', () => expect(Length.length2em('9nix', 100)).toBe(900)); + it('9%', () => expect(Length.length2em('9%', 100)).toBe(9)); + it('number 9', () => expect(Length.length2em(9, 100)).toBe(900)); +}); + +describe('Dimension conversion with scale', () => { + it('9px', () => expect(Length.length2em('9px', 0, 2)).toBe(0.5625 / 2)); + it('9in', () => expect(Length.length2em('9in', 0, 2)).toBe(54 / 2)); + it('9cm', () => expect(Length.length2em('9cm', 0, 2)).toBe(21.259842519685037 / 2)); + it('9mm', () => expect(Length.length2em('9mm', 0, 2)).toBe(2.125984251968504 / 2)); +}); + +describe('Dimension conversion with scale', () => { + it('9px', () => expect(Length.length2em('9px', 0, 1, 8)).toBe(0.5625 * 2)); + it('9in', () => expect(Length.length2em('9in', 0, 1, 8)).toBe(54 * 2)); + it('9cm', () => expect(Length.length2em('9cm', 0, 1, 8)).toBe(21.259842519685037 * 2)); + it('9mm', () => expect(Length.length2em('9mm', 0, 1, 8)).toBe(2.125984251968504 * 2)); +}); + +describe('percent()', () => { + it('.75', () => expect(Length.percent(.75)).toBe('75%')); + it('1.75', () => expect(Length.percent(1.75)).toBe('175%')); + it('.754321', () => expect(Length.percent(.754321)).toBe('75.4%')); + it('1.754321', () => expect(Length.percent(1.754321)).toBe('175.4%')); + it('1', () => expect(Length.percent(1)).toBe('100%')); +}); + +describe('em()', () => { + it('.75', () => expect(Length.em(.75)).toBe('0.75em')); + it('1.75', () => expect(Length.em(1.75)).toBe('1.75em')); + it('.754321', () => expect(Length.em(.754321)).toBe('0.754em')); + it('1.754321', () => expect(Length.em(1.754321)).toBe('1.754em')); + it('1', () => expect(Length.em(1)).toBe('1em')); + it('0', () => expect(Length.em(0)).toBe('0')); + it('0.0001', () => expect(Length.em(0.0001)).toBe('0')); +}); + +describe('px()', () => { + it('.75', () => expect(Length.px(.75)).toBe('12px')); + it('1.75', () => expect(Length.px(1.75)).toBe('28px')); + it('.754321', () => expect(Length.px(.754321)).toBe('12.1px')); + it('1.754321', () => expect(Length.px(1.754321)).toBe('28.1px')); + it('1', () => expect(Length.px(1)).toBe('16px')); + it('0', () => expect(Length.px(0)).toBe('0')); + it('0.001', () => expect(Length.px(0.001)).toBe('0')); + it('min=1', () => expect(Length.px(0.001, 1)).toBe('1px')); + it('em=8', () => expect(Length.px(1, 1, 8)).toBe('8px')); +}); diff --git a/testsuite/tests/util/numeric.test.ts b/testsuite/tests/util/numeric.test.ts new file mode 100644 index 000000000..45cfd3949 --- /dev/null +++ b/testsuite/tests/util/numeric.test.ts @@ -0,0 +1,16 @@ +import { describe, test, expect } from '@jest/globals'; +import * as numeric from '#js/util/numeric.js'; + +describe('numeric functions', () => { + + test('sum', () => { + expect(numeric.sum([1, 2, 3, 4, 5])).toBe(15); + expect(numeric.sum([])).toBe(0); + }); + + test('max', () => { + expect(numeric.max([5, 2, 10, 3, 50, -5])).toBe(50); + expect(numeric.max([])).toBe(0); + }); + +}); diff --git a/testsuite/tests/util/string.test.ts b/testsuite/tests/util/string.test.ts new file mode 100644 index 000000000..eff65512e --- /dev/null +++ b/testsuite/tests/util/string.test.ts @@ -0,0 +1,67 @@ +import { describe, test, expect } from '@jest/globals'; +import * as string from '#js/util/string.js'; + +describe('string functions', () => { + + test('sortLength()', () => { + expect(['a', '', 'aaa', 'aa'].sort(string.sortLength)).toEqual(['aaa', 'aa', 'a', '']); + expect(['a', '', 'aaa', 'a', 'aa'].sort(string.sortLength)).toEqual(['aaa', 'aa', 'a', 'a', '']); + expect(['a', 'ccc', '', 'aaa', 'bb', 'aa', 'bbb'].sort(string.sortLength)).toEqual( + ['aaa', 'bbb', 'ccc', 'aa', 'bb', 'a', ''] + ); + expect(['a'].sort(string.sortLength)).toEqual(['a']); + expect([].sort(string.sortLength)).toEqual([]); + }); + + test('quotePattern()', () => { + expect(string.quotePattern('[({.*+?^$-|:\\})]')).toBe('\\[\\(\\{\\.\\*\\+\\?\\^\\$\\-\\|\\:\\\\\\}\\)\\]'); + }); + + test('unicodeChars()', () => { + expect(string.unicodeChars('aA\u00AA\u2212\uFFFD\u{1D410}')).toEqual([0x61, 0x41, 0xAA, 0x2212, 0xFFFD, 0x1D410]); + expect(string.unicodeChars('')).toEqual([]); + }); + + test('uncideString()', () => { + expect(string.unicodeString([0x61, 0x41, 0xAA, 0x2212, 0xFFFD, 0x1D410])).toBe('aA\u00AA\u2212\uFFFD\u{1D410}'); + expect(string.unicodeString([])).toBe(''); + }); + + test('isPercent()', () => { + expect(string.isPercent('10%')).toBe(true); + expect(string.isPercent('10 % ')).toBe(true); + expect(string.isPercent('10%10')).toBe(false); + }); + + test('split()', () => { + expect(string.split('a bbb cc')).toEqual(['a', 'bbb', 'cc']); + expect(string.split(' a bbb cc ')).toEqual(['a', 'bbb', 'cc']); + expect(string.split('abc')).toEqual(['abc']); + expect(string.split('')).toEqual(['']); + }); + + test('replaceUnicode()', () => { + expect(string.replaceUnicode(String.raw`\U0061`)).toBe('a'); + expect(string.replaceUnicode(String.raw`a \U0062`)).toBe('a b'); + expect(string.replaceUnicode(String.raw`\U{61}`)).toBe('a'); + expect(string.replaceUnicode(String.raw`\U006D`)).toBe('m'); + expect(string.replaceUnicode(String.raw`\U006d`)).toBe('m'); + expect(string.replaceUnicode(String.raw`\U{6D}`)).toBe('m'); + expect(string.replaceUnicode(String.raw`\U{6d}`)).toBe('m'); + expect(string.replaceUnicode(String.raw`\U{6d}\U{6d}`)).toBe('mm'); + expect(string.replaceUnicode(String.raw`a \U{62} c`)).toBe('a b c'); + expect(string.replaceUnicode(String.raw`\\U{61}`)).toBe(String.raw`\U{61}`); + expect(string.replaceUnicode(String.raw`\\\U{61}`)).toBe(String.raw`\a`); + expect(string.replaceUnicode(String.raw`\\\\U{61}`)).toBe(String.raw`\\U{61}`); + expect(string.replaceUnicode(String.raw`\\\\\U{61}`)).toBe(String.raw`\\a`); + expect(string.replaceUnicode(String.raw`x\\U{61}`)).toBe(String.raw`x\U{61}`); + expect(string.replaceUnicode(String.raw`x\\\U{61}`)).toBe(String.raw`x\a`); + expect(string.replaceUnicode(String.raw`x\\\\U{61}`)).toBe(String.raw`x\\U{61}`); + expect(string.replaceUnicode(String.raw`x\\\\\U{61}`)).toBe(String.raw`x\\a`); + }); + + test('toEntity()', () => { + expect(string.toEntity('\u200B')).toBe('​'); + }); + +}); diff --git a/testsuite/tsconfig.json b/testsuite/tsconfig.json new file mode 100644 index 000000000..a77db3003 --- /dev/null +++ b/testsuite/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../tsconfig/mjs.json", + "compilerOptions": { + "rootDir": ".", + "outDir": "./js", + "module": "nodenext", + "moduleResolution": "nodenext", + "paths": { + "#js/*": ["../mjs/*"], + "#source/*": ["../components/mjs/*"], + "#src/*": ["./src/*"], + "#helpers": ["./js/src/index.js"] + }, + "isolatedModules": true, + "lib": ["DOM", "es2022"] + }, + "include": ["./tests/**/*.ts", "./src/*.ts"] +} diff --git a/ts/a11y/assistive-mml.ts b/ts/a11y/assistive-mml.ts index 349cfe4c9..4a4ada224 100644 --- a/ts/a11y/assistive-mml.ts +++ b/ts/a11y/assistive-mml.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2019-2022 The MathJax Consortium + * Copyright (c) 2019-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +16,31 @@ */ /** - * @fileoverview Mixin that adds hidden MathML to the output + * @file Mixin that adds hidden MathML to the output * * @author dpvc@mathjax.org (Davide Cervone) */ -import {Handler} from '../core/Handler.js'; -import {MathDocument, AbstractMathDocument, MathDocumentConstructor} from '../core/MathDocument.js'; -import {MathItem, AbstractMathItem, STATE, newState} from '../core/MathItem.js'; -import {MmlNode} from '../core/MmlTree/MmlNode.js'; -import {SerializedMmlVisitor} from '../core/MmlTree/SerializedMmlVisitor.js'; -import {OptionList, expandable} from '../util/Options.js'; -import {StyleList} from '../util/StyleList.js'; +import { Handler } from '../core/Handler.js'; +import { + MathDocument, + AbstractMathDocument, + MathDocumentConstructor, +} from '../core/MathDocument.js'; +import { + MathItem, + AbstractMathItem, + STATE, + newState, +} from '../core/MathItem.js'; +import { MmlNode } from '../core/MmlTree/MmlNode.js'; +import { SerializedMmlVisitor } from '../core/MmlTree/SerializedMmlVisitor.js'; +import { OptionList, expandable } from '../util/Options.js'; +import { StyleJson } from '../util/StyleJson.js'; /*==========================================================================*/ export class LimitedMmlVisitor extends SerializedMmlVisitor { - /** * @override */ @@ -42,13 +50,12 @@ export class LimitedMmlVisitor extends SerializedMmlVisitor { */ return super.getAttributes(node).replace(/ ?id=".*?"/, ''); } - } /** * Generic constructor for Mixins */ -export type Constructor = new(...args: any[]) => T; +export type Constructor = new (...args: any[]) => T; /*==========================================================================*/ @@ -76,54 +83,70 @@ export interface AssistiveMmlMathItem extends MathItem { * The mixin for adding assistive MathML to MathItems * * @param {B} BaseMathItem The MathItem class to be extended - * @return {AssistiveMathItem} The augmented MathItem class + * @returns {AssistiveMmlMathItem} The augmented MathItem class * * @template N The HTMLElement node class * @template T The Text node class * @template D The Document class * @template B The MathItem class to extend */ -export function AssistiveMmlMathItemMixin>>( - BaseMathItem: B -): Constructor> & B { - +export function AssistiveMmlMathItemMixin< + N, + T, + D, + B extends Constructor>, +>(BaseMathItem: B): Constructor> & B { return class extends BaseMathItem { - /** * @param {MathDocument} document The MathDocument for the MathItem * @param {boolean} force True to force assistive MathML evenif enableAssistiveMml is false */ - public assistiveMml(document: AssistiveMmlMathDocument, force: boolean = false) { + public assistiveMml( + document: AssistiveMmlMathDocument, + force: boolean = false + ) { if (this.state() >= STATE.ASSISTIVEMML) return; if (!this.isEscaped && (document.options.enableAssistiveMml || force)) { const adaptor = document.adaptor; // // Get the serialized MathML // - const mml = document.toMML(this.root).replace(/\n */g, '').replace(//g, ''); + const mml = document + .toMML(this.root) + .replace(/\n */g, '') + .replace(//g, ''); // // Parse is as HTML and retrieve the element // - const mmlNodes = adaptor.firstChild(adaptor.body(adaptor.parse(mml, 'text/html'))); + const mmlNodes = adaptor.firstChild( + adaptor.body(adaptor.parse(mml, 'text/html')) + ); // // Create a container for the hidden MathML // - const node = adaptor.node('mjx-assistive-mml', { - unselectable: 'on', display: (this.display ? 'block' : 'inline') - }, [mmlNodes]); + const node = adaptor.node( + 'mjx-assistive-mml', + { + unselectable: 'on', + display: this.display ? 'block' : 'inline', + }, + [mmlNodes] + ); // // Hide the typeset math from assistive technology and append the MathML that is visually // hidden from other users // - adaptor.setAttribute(adaptor.firstChild(this.typesetRoot) as N, 'aria-hidden', 'true'); + adaptor.setAttribute( + adaptor.firstChild(this.typesetRoot) as N, + 'aria-hidden', + 'true' + ); adaptor.setStyle(this.typesetRoot, 'position', 'relative'); adaptor.append(this.typesetRoot, node); } this.state(STATE.ASSISTIVEMML); } - }; - } /*==========================================================================*/ @@ -135,41 +158,42 @@ export function AssistiveMmlMathItemMixin extends AbstractMathDocument { - +export interface AssistiveMmlMathDocument + extends AbstractMathDocument { /** * @param {MmlNode} node The node to be serializes - * @return {string} The serialization of the node + * @returns {string} The serialization of the node */ toMML: (node: MmlNode) => string; /** * Add assistive MathML to the MathItems in the MathDocument * - * @return {AssistiveMmlMathDocument} The MathDocument (so calls can be chained) + * @returns {AssistiveMmlMathDocument} The MathDocument (so calls can be chained) */ assistiveMml(): AssistiveMmlMathDocument; - } /** * The mixin for adding assistive MathML to MathDocuments * * @param {B} BaseDocument The MathDocument class to be extended - * @return {AssistiveMmlMathDocument} The Assistive MathML MathDocument class + * @returns {AssistiveMmlMathDocument} The Assistive MathML MathDocument class * * @template N The HTMLElement node class * @template T The Text node class * @template D The Document class * @template B The MathDocument class to extend */ -export function AssistiveMmlMathDocumentMixin>>( +export function AssistiveMmlMathDocumentMixin< + N, + T, + D, + B extends MathDocumentConstructor>, +>( BaseDocument: B ): MathDocumentConstructor> & B { - return class BaseClass extends BaseDocument { - /** * @override */ @@ -178,23 +202,28 @@ B extends MathDocumentConstructor>>( enableAssistiveMml: true, renderActions: expandable({ ...BaseDocument.OPTIONS.renderActions, - assistiveMml: [STATE.ASSISTIVEMML] - }) + assistiveMml: [STATE.ASSISTIVEMML], + }), }; /** * styles needed for the hidden MathML */ - public static assistiveStyles: StyleList = { + public static assistiveStyles: StyleJson = { 'mjx-assistive-mml': { position: 'absolute !important', - top: '0px', left: '0px', + top: '0px', + left: '0px', + bottom: '0px', + right: '0px', clip: 'rect(1px, 1px, 1px, 1px)', + 'clip-path': 'polygon(0 0, 0 1px, 1px 1px, 1px 0)', padding: '1px 0px 0px 0px !important', border: '0px !important', display: 'block !important', width: 'auto !important', overflow: 'hidden !important', + 'text-indent': '0px ! important', /* * Don't allow the assistive MathML to become part of the selection */ @@ -203,11 +232,11 @@ B extends MathDocumentConstructor>>( '-khtml-user-select': 'none', '-moz-user-select': 'none', '-ms-user-select': 'none', - 'user-select': 'none' + 'user-select': 'none', }, 'mjx-assistive-mml[display="block"]': { - width: '100% !important' - } + width: '100% !important', + }, }; /** @@ -219,20 +248,22 @@ B extends MathDocumentConstructor>>( * Augment the MathItem class used for this MathDocument, and create the serialization visitor. * * @override - * @constructor + * @class */ constructor(...args: any[]) { super(...args); - const CLASS = (this.constructor as typeof BaseClass); + const CLASS = this.constructor as typeof BaseClass; const ProcessBits = CLASS.ProcessBits; if (!ProcessBits.has('assistive-mml')) { ProcessBits.allocate('assistive-mml'); } this.visitor = new LimitedMmlVisitor(this.mmlFactory); - this.options.MathItem = - AssistiveMmlMathItemMixin>>( - this.options.MathItem - ); + this.options.MathItem = AssistiveMmlMathItemMixin< + N, + T, + D, + Constructor> + >(this.options.MathItem); if ('addStyles' in this) { (this as any).addStyles(CLASS.assistiveStyles); } @@ -240,7 +271,7 @@ B extends MathDocumentConstructor>>( /** * @param {MmlNode} node The node to be serializes - * @return {string} The serialization of the node + * @returns {string} The serialization of the node */ public toMML(node: MmlNode): string { return this.visitor.visitTree(node); @@ -248,8 +279,10 @@ B extends MathDocumentConstructor>>( /** * Add assistive MathML to the MathItems in this MathDocument + * + * @returns {AssistiveMmlMathDocument} The assistive mml document. */ - public assistiveMml() { + public assistiveMml(): AssistiveMmlMathDocument { if (!this.processed.isSet('assistive-mml')) { for (const math of this.math) { (math as AssistiveMmlMathItem).assistiveMml(this); @@ -269,9 +302,7 @@ B extends MathDocumentConstructor>>( } return this; } - }; - } /*==========================================================================*/ @@ -280,16 +311,20 @@ B extends MathDocumentConstructor>>( * Add assitive MathML support a Handler instance * * @param {Handler} handler The Handler instance to enhance - * @return {Handler} The handler that was modified (for purposes of chainging extensions) + * @returns {Handler} The handler that was modified (for purposes of chainging extensions) * * @template N The HTMLElement node class * @template T The Text node class * @template D The Document class */ -export function AssistiveMmlHandler(handler: Handler): Handler { - handler.documentClass = - AssistiveMmlMathDocumentMixin>>( - handler.documentClass - ); +export function AssistiveMmlHandler( + handler: Handler +): Handler { + handler.documentClass = AssistiveMmlMathDocumentMixin< + N, + T, + D, + MathDocumentConstructor> + >(handler.documentClass); return handler; } diff --git a/ts/a11y/complexity.ts b/ts/a11y/complexity.ts index 7635a0e33..7103ad9f2 100644 --- a/ts/a11y/complexity.ts +++ b/ts/a11y/complexity.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,32 +16,41 @@ */ /** - * @fileoverview Mixin that computes complexity of the internal MathML + * @file Mixin that computes complexity of the internal MathML * and optionally marks collapsible items * * @author dpvc@mathjax.org (Davide Cervone) */ -import {Handler} from '../core/Handler.js'; -import {MathDocumentConstructor} from '../core/MathDocument.js'; -import {STATE, newState} from '../core/MathItem.js'; -import {MathML} from '../input/mathml.js'; -import {MmlNode} from '../core/MmlTree/MmlNode.js'; -import {EnrichHandler, EnrichedMathItem, EnrichedMathDocument} from './semantic-enrich.js'; -import {ComplexityVisitor} from './complexity/visitor.js'; -import {OptionList, selectOptionsFromKeys, expandable} from '../util/Options.js'; +import { Handler } from '../core/Handler.js'; +import { MathDocumentConstructor } from '../core/MathDocument.js'; +import { STATE, newState } from '../core/MathItem.js'; +import { MathML } from '../input/mathml.js'; +import { + EnrichHandler, + EnrichedMathItem, + EnrichedMathDocument, +} from './semantic-enrich.js'; +import { ComplexityVisitor } from './complexity/visitor.js'; +import { + OptionList, + selectOptionsFromKeys, + expandable, +} from '../util/Options.js'; /** * Generic constructor for Mixins */ -export type Constructor = new(...args: any[]) => T; +export type Constructor = new (...args: any[]) => T; /** * Shorthands for constructors */ export type EMItemC = Constructor>; export type CMItemC = Constructor>; -export type EMDocC = MathDocumentConstructor>; +export type EMDocC = MathDocumentConstructor< + EnrichedMathDocument +>; export type CMDocC = Constructor>; /*==========================================================================*/ @@ -59,47 +68,56 @@ newState('COMPLEXITY', 40); * @template D The Document class */ export interface ComplexityMathItem extends EnrichedMathItem { + /** + * The starting collapse ID for this expression + */ + initialID: number; /** * @param {ComplexityMathDocument} document The MathDocument for the MathItem * @param {boolean} force True to force the computation even if enableComplexity is false */ complexity(document: ComplexityMathDocument, force?: boolean): void; - } /** * The mixin for adding complexity to MathItems * * @param {B} BaseMathItem The MathItem class to be extended - * @param {function(MmlNode): void} computeComplexity Method of complexity computation. - * @return {ComplexityMathItem} The complexity MathItem class + * @param {(math: ComplexityMathItem) => void} computeComplexity Method of complexity computation. + * @returns {ComplexityMathItem} The complexity MathItem class * * @template N The HTMLElement node class * @template T The Text node class * @template D The Document class * @template B The MathItem class to extend */ -export function ComplexityMathItemMixin>(BaseMathItem: B, computeComplexity: (node: MmlNode) => void): CMItemC & B { - +export function ComplexityMathItemMixin>( + BaseMathItem: B, + computeComplexity: (math: ComplexityMathItem) => void +): CMItemC & B { return class extends BaseMathItem { + /** + * The starting collapse ID for this expression + */ + public initialID: number = null; /** * @param {ComplexityMathDocument} document The MathDocument for the MathItem * @param {boolean} force True to force the computation even if enableComplexity is false */ - public complexity(document: ComplexityMathDocument, force: boolean = false) { + public complexity( + document: ComplexityMathDocument, + force: boolean = false + ) { if (this.state() >= STATE.COMPLEXITY) return; if (!this.isEscaped && (document.options.enableComplexity || force)) { this.enrich(document, true); - computeComplexity(this.root); + computeComplexity(this); } this.state(STATE.COMPLEXITY); } - }; - } /*==========================================================================*/ @@ -111,11 +129,12 @@ EMItemC>(BaseMathItem: B, computeComplexity: (node: MmlNode) => void): * @template T The Text node class * @template D The Document class */ -export interface ComplexityMathDocument extends EnrichedMathDocument { +export interface ComplexityMathDocument + extends EnrichedMathDocument { /** * Perform complexity computations on the MathItems in the MathDocument * - * @return {ComplexityMathDocument} The MathDocument (so calls can be chained) + * @returns {ComplexityMathDocument} The MathDocument (so calls can be chained) */ complexity(): ComplexityMathDocument; } @@ -124,18 +143,17 @@ export interface ComplexityMathDocument extends EnrichedMathDocument>(BaseDocument: B): CMDocC & B { - +export function ComplexityMathDocumentMixin>( + BaseDocument: B +): CMDocC & B { return class extends BaseDocument { - /** * The options for this type of document */ @@ -146,8 +164,8 @@ EMDocC>(BaseDocument: B): CMDocC & B { ComplexityVisitor: ComplexityVisitor, renderActions: expandable({ ...BaseDocument.OPTIONS.renderActions, - complexity: [STATE.COMPLEXITY] - }) + complexity: [STATE.COMPLEXITY], + }), }; /** @@ -159,7 +177,7 @@ EMDocC>(BaseDocument: B): CMDocC & B { * Extend the MathItem class used for this MathDocument * * @override - * @constructor + * @class */ constructor(...args: any[]) { super(...args); @@ -167,19 +185,34 @@ EMDocC>(BaseDocument: B): CMDocC & B { if (!ProcessBits.has('complexity')) { ProcessBits.allocate('complexity'); } - const visitorOptions = selectOptionsFromKeys(this.options, this.options.ComplexityVisitor.OPTIONS); - this.complexityVisitor = new this.options.ComplexityVisitor(this.mmlFactory, visitorOptions); - const computeComplexity = ((node: MmlNode) => this.complexityVisitor.visitTree(node)); - this.options.MathItem = - ComplexityMathItemMixin>( - this.options.MathItem, computeComplexity + const visitorOptions = selectOptionsFromKeys( + this.options, + this.options.ComplexityVisitor.OPTIONS + ); + this.complexityVisitor = new this.options.ComplexityVisitor( + this.mmlFactory, + visitorOptions + ); + const computeComplexity = (math: ComplexityMathItem) => { + math.initialID = this.complexityVisitor.visitTree( + math.root, + math.initialID ); + }; + this.options.MathItem = ComplexityMathItemMixin< + N, + T, + D, + EMItemC + >(this.options.MathItem, computeComplexity); } /** * Compute the complexity the MathItems in this MathDocument + * + * @returns {ComplexityMathDocument} The object for chaining. */ - public complexity() { + public complexity(): ComplexityMathDocument { if (!this.processed.isSet('complexity')) { if (this.options.enableComplexity) { for (const math of this.math) { @@ -201,9 +234,7 @@ EMDocC>(BaseDocument: B): CMDocC & B { } return this; } - }; - } /*==========================================================================*/ @@ -213,7 +244,7 @@ EMDocC>(BaseDocument: B): CMDocC & B { * * @param {Handler} handler The Handler instance to enhance * @param {MathML} MmlJax The MathML input jax to use for reading the enriched MathML - * @return {Handler} The handler that was modified (for purposes of chainging extensions) + * @returns {Handler} The handler that was modified (for purposes of chainging extensions) * * @template N The HTMLElement node class * @template T The Text node class @@ -226,6 +257,8 @@ export function ComplexityHandler( if (!handler.documentClass.prototype.enrich && MmlJax) { handler = EnrichHandler(handler, MmlJax); } - handler.documentClass = ComplexityMathDocumentMixin>(handler.documentClass as any); + handler.documentClass = ComplexityMathDocumentMixin>( + handler.documentClass as any + ); return handler; } diff --git a/ts/a11y/complexity/collapse.ts b/ts/a11y/complexity/collapse.ts index c9befe58c..f20db9065 100644 --- a/ts/a11y/complexity/collapse.ts +++ b/ts/a11y/complexity/collapse.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,17 @@ */ /** - * @fileoverview Implements a class that marks complex items for collapsing + * @file Implements a class that marks complex items for collapsing * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MmlNode, AbstractMmlTokenNode, TextNode} from '../../core/MmlTree/MmlNode.js'; -import {ComplexityVisitor} from './visitor.js'; +import { + MmlNode, + AbstractMmlTokenNode, + TextNode, +} from '../../core/MmlTree/MmlNode.js'; +import { ComplexityVisitor } from './visitor.js'; /*==========================================================================*/ @@ -41,479 +45,611 @@ export type CollapseFunctionMap = Map; * * @template T The type of the indexed item */ -export type TypeRole = {[type: string]: T | {[role: string]: T}}; +export type TypeRole = { [type: string]: T | { [role: string]: T } }; /** * The class for determining of a subtree can be collapsed */ export class Collapse { - - /** - * A constant to use to indicate no collapsing - */ - public static NOCOLLAPSE: number = 10000000; // really big complexity - - /** - * The complexity object containing this one - */ - public complexity: ComplexityVisitor; - - /** - * The cutt-off complexity values for when a structure - * of the given type should collapse - */ - public cutoff: TypeRole = { - identifier: 3, - number: 3, - text: 10, - infixop: 15, - relseq: 15, - multirel: 15, - fenced: 18, - bigop: 20, - integral: 20, - fraction: 12, - sqrt: 9, - root: 12, - vector: 15, - matrix: 15, - cases: 15, - superscript: 9, - subscript: 9, - subsup: 9, - punctuated: { - endpunct: Collapse.NOCOLLAPSE, - startpunct: Collapse.NOCOLLAPSE, - value: 12 + /** + * A constant to use to indicate no collapsing + */ + public static NOCOLLAPSE: number = 10000000; // really big complexity + + /** + * The complexity object containing this one + */ + public complexity: ComplexityVisitor; + + /** + * The cutt-off complexity values for when a structure + * of the given type should collapse + */ + public cutoff: TypeRole = { + identifier: 3, + number: 3, + text: 10, + infixop: 15, + relseq: 15, + multirel: 15, + fenced: 18, + bigop: 20, + integral: 20, + fraction: 12, + sqrt: 9, + root: 12, + vector: 15, + matrix: 15, + cases: 15, + superscript: 9, + subscript: 9, + subsup: 9, + punctuated: { + endpunct: Collapse.NOCOLLAPSE, + startpunct: Collapse.NOCOLLAPSE, + value: 12, + }, + }; + + /** + * These are the characters to use for the various collapsed elements + * (if an object, then semantic-role is used to get the character + * from the object) + */ + public marker: TypeRole = { + identifier: 'x', + number: '#', + text: '...', + appl: { + 'limit function': 'lim', + value: 'f()', + }, + fraction: '/', + sqrt: '\u221A', + root: '\u221A', + superscript: '\u25FD\u02D9', + subscript: '\u25FD.', + subsup: '\u25FD:', + vector: { + binomial: '(:)', + determinant: '|:|', + value: '\u27E8:\u27E9', + }, + matrix: { + squarematrix: '[::]', + rowvector: '\u27E8\u22EF\u27E9', + columnvector: '\u27E8\u22EE\u27E9', + determinant: '|::|', + value: '(::)', + }, + cases: '{:', + infixop: { + addition: '+', + subtraction: '\u2212', + multiplication: '\u22C5', + implicit: '\u22C5', + value: '+', + }, + punctuated: { + text: '...', + value: ',', + }, + }; + + /** + * The type-to-function mapping for semantic types + * + * @param {MmlNode} node The current node + * @param {number} complexity The current complexity + * @returns {number} The newly computed complexity + */ + public collapse: CollapseFunctionMap = new Map([ + // + // For fenced elements, if the contents are collapsed, + // collapse the fence instead. + // + [ + 'fenced', + (node, complexity) => { + complexity = this.uncollapseChild(complexity, node, 1); + if ( + complexity > (this.cutoff.fenced as number) && + node.attributes.get('data-semantic-role') === 'leftright' + ) { + complexity = this.recordCollapse( + node, + complexity, + this.getText(node.childNodes[0]) + + this.getText(node.childNodes[node.childNodes.length - 1]) + ); } - }; - - /** - * These are the characters to use for the various collapsed elements - * (if an object, then semantic-role is used to get the character - * from the object) - */ - public marker: TypeRole = { - identifier: 'x', - number: '#', - text: '...', - appl: { - 'limit function': 'lim', - value: 'f()' - }, - fraction: '/', - sqrt: '\u221A', - root: '\u221A', - superscript: '\u25FD\u02D9', - subscript: '\u25FD.', - subsup: '\u25FD:', - vector: { - binomial: '(:)', - determinant: '|:|', - value: '\u27E8:\u27E9' - }, - matrix: { - squarematrix: '[::]', - rowvector: '\u27E8\u22EF\u27E9', - columnvector: '\u27E8\u22EE\u27E9', - determinant: '|::|', - value: '(::)' - }, - cases: '{:', - infixop: { - addition: '+', - subtraction: '\u2212', - multiplication: '\u22C5', - implicit: '\u22C5', - value: '+' - }, - punctuated: { - text: '...', - value: ',' + return complexity; + }, + ], + + // + // Collapse function applications if the argument is collapsed + // (FIXME: Handle role="limit function" a bit better?) + // + [ + 'appl', + (node, complexity) => { + if (this.canUncollapse(node, 2, 2)) { + complexity = this.complexity.visitNode(node, false); + const marker = this.marker.appl as { [name: string]: string }; + const text = + marker[node.attributes.get('data-semantic-role') as string] || + marker.value; + complexity = this.recordCollapse(node, complexity, text); } - }; - - /** - * The type-to-function mapping for semantic types - */ - public collapse: CollapseFunctionMap = new Map([ - - // - // For fenced elements, if the contents are collapsed, - // collapse the fence instead. - // - ['fenced', (node, complexity) => { - complexity = this.uncollapseChild(complexity, node, 1); - if (complexity > this.cutoff.fenced && node.attributes.get('data-semantic-role') === 'leftright') { - complexity = this.recordCollapse( - node, complexity, - this.getText(node.childNodes[0] as MmlNode) + - this.getText(node.childNodes[node.childNodes.length - 1] as MmlNode) - ); - } - return complexity; - }], - - // - // Collapse function applications if the argument is collapsed - // (FIXME: Handle role="limit function" a bit better?) - // - ['appl', (node, complexity) => { - if (this.canUncollapse(node, 2, 2)) { - complexity = this.complexity.visitNode(node, false); - const marker = this.marker.appl as {[name: string]: string}; - const text = marker[node.attributes.get('data-semantic-role') as string] || marker.value; - complexity = this.recordCollapse(node, complexity, text); - } - return complexity; - }], - - // - // For sqrt elements, if the contents are collapsed, - // collapse the sqrt instead. - // - ['sqrt', (node, complexity) => { - complexity = this.uncollapseChild(complexity, node, 0); - if (complexity > this.cutoff.sqrt) { - complexity = this.recordCollapse(node, complexity, this.marker.sqrt as string); - } - return complexity; - }], - ['root', (node, complexity) => { - complexity = this.uncollapseChild(complexity, node, 0, 2); - if (complexity > this.cutoff.sqrt) { - complexity = this.recordCollapse(node, complexity, this.marker.sqrt as string); - } - return complexity; - }], - - // - // For enclose, include enclosure in collapse - // - ['enclose', (node, complexity) => { - if (this.splitAttribute(node, 'children').length === 1) { - const child = this.canUncollapse(node, 1); - if (child) { - const marker = child.getProperty('collapse-marker') as string; - this.unrecordCollapse(child); - complexity = this.recordCollapse(node, this.complexity.visitNode(node, false), marker); - } - } - return complexity; - }], - - // - // For bigops, get the character to use from the largeop at its core. - // - ['bigop', (node, complexity) => { - if (complexity > this.cutoff.bigop || !node.isKind('mo')) { - const id = this.splitAttribute(node, 'content').pop(); - const op = this.findChildText(node, id); - complexity = this.recordCollapse(node, complexity, op); - } - return complexity; - }], - ['integral', (node, complexity) => { - if (complexity > this.cutoff.integral || !node.isKind('mo')) { - const id = this.splitAttribute(node, 'content').pop(); - const op = this.findChildText(node, id); - complexity = this.recordCollapse(node, complexity, op); - } - return complexity; - }], - - // - // For relseq and multirel, use proper symbol - // - ['relseq', (node, complexity) => { - if (complexity > this.cutoff.relseq) { - const id = this.splitAttribute(node, 'content')[0]; - const text = this.findChildText(node, id); - complexity = this.recordCollapse(node, complexity, text); - } - return complexity; - }], - ['multirel', (node, complexity) => { - if (complexity > this.cutoff.relseq) { - const id = this.splitAttribute(node, 'content')[0]; - const text = this.findChildText(node, id) + '\u22EF'; - complexity = this.recordCollapse(node, complexity, text); - } - return complexity; - }], - - // - // Include super- and subscripts into a collapsed base - // - ['superscript', (node, complexity) => { - complexity = this.uncollapseChild(complexity, node, 0, 2); - if (complexity > this.cutoff.superscript) { - complexity = this.recordCollapse(node, complexity, this.marker.superscript as string); - } - return complexity; - }], - ['subscript', (node, complexity) => { - complexity = this.uncollapseChild(complexity, node, 0, 2); - if (complexity > this.cutoff.subscript) { - complexity = this.recordCollapse(node, complexity, this.marker.subscript as string); - } - return complexity; - }], - ['subsup', (node, complexity) => { - complexity = this.uncollapseChild(complexity, node, 0, 3); - if (complexity > this.cutoff.subsup) { - complexity = this.recordCollapse(node, complexity, this.marker.subsup as string); - } - return complexity; - }] - - ] as [string, CollapseFunction][]); - - /** - * The highest id number used for mactions so far - */ - private idCount = 0; - - /** - * @param {ComplexityVisitor} visitor The visitor for computing complexities - */ - constructor(visitor: ComplexityVisitor) { - this.complexity = visitor; - } - - /** - * Check if a node should be collapsible and insert the - * maction node to handle that. Return the updated - * complexity. - * - * @param {MmlNode} node The node to check - * @param {number} complexity The current complexity of the node - * @return {number} The revised complexity - */ - public check(node: MmlNode, complexity: number): number { - const type = node.attributes.get('data-semantic-type') as string; - if (this.collapse.has(type)) { - return this.collapse.get(type).call(this, node, complexity); + return complexity; + }, + ], + + // + // For sqrt elements, if the contents are collapsed, + // collapse the sqrt instead. + // + [ + 'sqrt', + (node, complexity) => { + complexity = this.uncollapseChild(complexity, node, 0); + if (complexity > (this.cutoff.sqrt as number)) { + node.setProperty('collapse-variant', true); + complexity = this.recordCollapse( + node, + complexity, + this.marker.sqrt as string + ); } - if (this.cutoff.hasOwnProperty(type)) { - return this.defaultCheck(node, complexity, type); + return complexity; + }, + ], + [ + 'root', + (node, complexity) => { + complexity = this.uncollapseChild(complexity, node, 0, 2); + if (complexity > (this.cutoff.sqrt as number)) { + node.setProperty('collapse-variant', true); + complexity = this.recordCollapse( + node, + complexity, + this.marker.sqrt as string + ); } return complexity; - } - - /** - * Check if the complexity exceeds the cutoff value for the type - * - * @param {MmlNode} node The node to check - * @param {number} complexity The current complexity of the node - * @param {string} type The semantic type of the node - * @return {number} The revised complexity - */ - protected defaultCheck(node: MmlNode, complexity: number, type: string): number { - const role = node.attributes.get('data-semantic-role') as string; - const check = this.cutoff[type]; - const cutoff = (typeof check === 'number' ? check : check[role] || check.value); - if (complexity > cutoff) { - const marker = this.marker[type] || '??'; - const text = (typeof marker === 'string' ? marker : marker[role] || marker.value); - complexity = this.recordCollapse(node, complexity, text); + }, + ], + + // + // For enclose, include enclosure in collapse + // + [ + 'enclose', + (node, complexity) => { + if (this.splitAttribute(node, 'children').length === 1) { + const child = this.canUncollapse(node, 1); + if (child) { + const marker = child.getProperty('collapse-marker') as string; + this.unrecordCollapse(child); + complexity = this.recordCollapse( + node, + this.complexity.visitNode(node, false), + marker + ); + } } return complexity; - } - - /** - * @param {MmlNode} node The node to check - * @param {number} complexity The current complexity of the node - * @param {string} text The text to use for the collapsed node - * @return {number} The revised complexity for the collapsed node - */ - protected recordCollapse(node: MmlNode, complexity: number, text: string): number { - text = '\u25C2' + text + '\u25B8'; - node.setProperty('collapse-marker', text); - node.setProperty('collapse-complexity', complexity); - return text.length * this.complexity.complexity.text; - } - - /** - * Remove collapse markers (to move them to a parent node) - * - * @param {MmlNode} node The node to uncollapse - */ - protected unrecordCollapse(node: MmlNode) { - const complexity = node.getProperty('collapse-complexity'); - if (complexity != null) { - node.attributes.set('data-semantic-complexity', complexity); - node.removeProperty('collapse-complexity'); - node.removeProperty('collapse-marker'); + }, + ], + + // + // For bigops, get the character to use from the largeop at its core. + // + [ + 'bigop', + (node, complexity) => { + if (complexity > (this.cutoff.bigop as number) || !node.isKind('mo')) { + const id = this.splitAttribute(node, 'content').pop(); + const op = this.findChildText(node, id); + complexity = this.recordCollapse(node, complexity, op); } - } - - /** - * @param {MmlNode} node The node to check if its child is collapsible - * @param {number} n The position of the child node to check - * @param {number=} m The number of children node must have - * @return {MmlNode|null} The child node that was collapsed (or null) - */ - protected canUncollapse(node: MmlNode, n: number, m: number = 1): MmlNode | null { - if (this.splitAttribute(node, 'children').length === m) { - const mml = (node.childNodes.length === 1 && - (node.childNodes[0] as MmlNode).isInferred ? node.childNodes[0] as MmlNode : node); - if (mml && mml.childNodes[n]) { - const child = mml.childNodes[n] as MmlNode; - if (child.getProperty('collapse-marker')) { - return child; - } - } + return complexity; + }, + ], + [ + 'integral', + (node, complexity) => { + if ( + complexity > (this.cutoff.integral as number) || + !node.isKind('mo') + ) { + const id = this.splitAttribute(node, 'content').pop(); + const op = this.findChildText(node, id); + complexity = this.recordCollapse(node, complexity, op); } - return null; - } - - /** - * @param {number} complexity The current complexity - * @param {MmlNode} node The node to check - * @param {number} n The position of the child node to check - * @param {number=} m The number of children the node must have - * @return {number} The updated complexity - */ - protected uncollapseChild(complexity: number, node: MmlNode, n: number, m: number = 1): number { - const child = this.canUncollapse(node, n, m); - if (child) { - this.unrecordCollapse(child); - if (child.parent !== node) { - child.parent.attributes.set('data-semantic-complexity', undefined); - } - complexity = this.complexity.visitNode(node, false) as number; + return complexity; + }, + ], + + // + // For relseq and multirel, use proper symbol + // + [ + 'relseq', + (node, complexity) => { + if (complexity > (this.cutoff.relseq as number)) { + const id = this.splitAttribute(node, 'content')[0]; + const text = this.findChildText(node, id); + complexity = this.recordCollapse(node, complexity, text); + } + return complexity; + }, + ], + [ + 'multirel', + (node, complexity) => { + if (complexity > (this.cutoff.relseq as number)) { + const id = this.splitAttribute(node, 'content')[0]; + const text = this.findChildText(node, id) + '\u22EF'; + complexity = this.recordCollapse(node, complexity, text); } return complexity; + }, + ], + + // + // Include super- and subscripts into a collapsed base + // + [ + 'superscript', + (node, complexity) => { + complexity = this.uncollapseChild(complexity, node, 0, 2); + if (complexity > (this.cutoff.superscript as number)) { + complexity = this.recordCollapse( + node, + complexity, + this.marker.superscript as string + ); + } + return complexity; + }, + ], + [ + 'subscript', + (node, complexity) => { + complexity = this.uncollapseChild(complexity, node, 0, 2); + if (complexity > (this.cutoff.subscript as number)) { + complexity = this.recordCollapse( + node, + complexity, + this.marker.subscript as string + ); + } + return complexity; + }, + ], + [ + 'subsup', + (node, complexity) => { + complexity = this.uncollapseChild(complexity, node, 0, 3); + if (complexity > (this.cutoff.subsup as number)) { + complexity = this.recordCollapse( + node, + complexity, + this.marker.subsup as string + ); + } + return complexity; + }, + ], + ] as [string, CollapseFunction][]); + + /** + * The highest id number used for mactions so far + */ + private idCount = 0; + + /** + * @param {ComplexityVisitor} visitor The visitor for computing complexities + */ + constructor(visitor: ComplexityVisitor) { + this.complexity = visitor; + } + + /** + * Check if a node should be collapsible and insert the + * maction node to handle that. Return the updated + * complexity. + * + * @param {MmlNode} node The node to check + * @param {number} complexity The current complexity of the node + * @returns {number} The revised complexity + */ + public check(node: MmlNode, complexity: number): number { + const type = node.attributes.get('data-semantic-type') as string; + if (this.collapse.has(type)) { + return this.collapse.get(type).call(this, node, complexity); } - - /** - * @param {MmlNode} node The node whose attribute is to be split - * @param {string} id The name of the data-semantic attribute to split - * @return {string[]} Array of ids in the attribute split at commas - */ - protected splitAttribute(node: MmlNode, id: string): string[] { - return (node.attributes.get('data-semantic-' + id) as string || '').split(/,/); + if (Object.hasOwn(this.cutoff, type)) { + return this.defaultCheck(node, complexity, type); } - - /** - * @param {MmlNode} node The node whose text content is needed - * @return{string} The text of the node (and its children), combined - */ - protected getText(node: MmlNode): string { - if (node.isToken) return (node as AbstractMmlTokenNode).getText(); - return node.childNodes.map((n: MmlNode) => this.getText(n)).join(''); + return complexity; + } + + /** + * Check if the complexity exceeds the cutoff value for the type + * + * @param {MmlNode} node The node to check + * @param {number} complexity The current complexity of the node + * @param {string} type The semantic type of the node + * @returns {number} The revised complexity + */ + protected defaultCheck( + node: MmlNode, + complexity: number, + type: string + ): number { + const role = node.attributes.get('data-semantic-role') as string; + const check = this.cutoff[type]; + const cutoff = + typeof check === 'number' ? check : check[role] || check.value; + if (complexity > cutoff) { + const marker = this.marker[type] || '??'; + const text = + typeof marker === 'string' ? marker : marker[role] || marker.value; + complexity = this.recordCollapse(node, complexity, text); } - - /** - * @param {MmlNode} node The node whose child text is needed - * @param {string} id The (semantic) id of the child needed - * @return {string} The text of the specified child node - */ - protected findChildText(node: MmlNode, id: string): string { - const child = this.findChild(node, id); - return this.getText(child.coreMO() || child); + return complexity; + } + + /** + * @param {MmlNode} node The node to check + * @param {number} complexity The current complexity of the node + * @param {string} text The text to use for the collapsed node + * @returns {number} The revised complexity for the collapsed node + */ + protected recordCollapse( + node: MmlNode, + complexity: number, + text: string + ): number { + text = '\u25C2' + text + '\u25B8'; + node.setProperty('collapse-marker', text); + node.setProperty('collapse-complexity', complexity); + return text.length * this.complexity.complexity.text; + } + + /** + * Remove collapse markers (to move them to a parent node) + * + * @param {MmlNode} node The node to uncollapse + */ + protected unrecordCollapse(node: MmlNode) { + const complexity = node.getProperty('collapse-complexity'); + if (complexity != null) { + node.attributes.set('data-semantic-complexity', complexity); + node.removeProperty('collapse-complexity'); + node.removeProperty('collapse-marker'); } - - /** - * @param {MmlNode} node The node whose child is to be located - * @param {string} id The (semantic) id of the child to be found - * @return {MmlNode|null} The child node (or null if not found) - */ - protected findChild(node: MmlNode, id: string): MmlNode | null { - if (!node || node.attributes.get('data-semantic-id') === id) return node; - if (!node.isToken) { - for (const mml of node.childNodes) { - const child = this.findChild(mml as MmlNode, id); - if (child) return child; - } + } + + /** + * @param {MmlNode} node The node to check if its child is collapsible + * @param {number} n The position of the child node to check + * @param {number=} m The number of children node must have + * @returns {MmlNode|null} The child node that was collapsed (or null) + */ + protected canUncollapse( + node: MmlNode, + n: number, + m: number = 1 + ): MmlNode | null { + if (this.splitAttribute(node, 'children').length === m) { + const mml = + node.childNodes.length === 1 && node.childNodes[0].isInferred + ? node.childNodes[0] + : node; + if (mml && mml.childNodes[n]) { + const child = mml.childNodes[n]; + if (child.getProperty('collapse-marker')) { + return child; } - return null; + } } - - /** - * Add maction nodes to the nodes in the tree that can collapse - * - * @paramn {MmlNode} node The root of the tree to check - */ - public makeCollapse(node: MmlNode) { - const nodes: MmlNode[] = []; - node.walkTree((child: MmlNode) => { - if (child.getProperty('collapse-marker')) { - nodes.push(child); - } - }); - this.makeActions(nodes); + return null; + } + + /** + * @param {number} complexity The current complexity + * @param {MmlNode} node The node to check + * @param {number} n The position of the child node to check + * @param {number=} m The number of children the node must have + * @returns {number} The updated complexity + */ + protected uncollapseChild( + complexity: number, + node: MmlNode, + n: number, + m: number = 1 + ): number { + const child = this.canUncollapse(node, n, m); + if (child) { + this.unrecordCollapse(child); + if (child.parent !== node) { + child.parent.attributes.set('data-semantic-complexity', undefined); + } + complexity = this.complexity.visitNode(node, false) as number; } - - /** - * @param {MmlNode[]} nodes The list of nodes to replace by maction nodes - */ - public makeActions(nodes: MmlNode[]) { - for (const node of nodes) { - this.makeAction(node); - } + return complexity; + } + + /** + * @param {MmlNode} node The node whose attribute is to be split + * @param {string} id The name of the data-semantic attribute to split + * @returns {string[]} Array of ids in the attribute split at commas + */ + protected splitAttribute(node: MmlNode, id: string): string[] { + return ((node.attributes.get('data-semantic-' + id) as string) || '').split( + /,/ + ); + } + + /** + * @param {MmlNode} node The node whose text content is needed + * @returns {string} The text of the node (and its children), combined + */ + protected getText(node: MmlNode): string { + if (node.isToken) return (node as AbstractMmlTokenNode).getText(); + return node.childNodes.map((n: MmlNode) => this.getText(n)).join(''); + } + + /** + * @param {MmlNode} node The node whose child text is needed + * @param {string} id The (semantic) id of the child needed + * @returns {string} The text of the specified child node + */ + protected findChildText(node: MmlNode, id: string): string { + const child = this.findChild(node, id); + return this.getText(child.coreMO() || child); + } + + /** + * @param {MmlNode} node The node whose child is to be located + * @param {string} id The (semantic) id of the child to be found + * @returns {MmlNode|null} The child node (or null if not found) + */ + protected findChild(node: MmlNode, id: string): MmlNode | null { + if (!node || node.attributes.get('data-semantic-id') === id) return node; + if (!node.isToken) { + for (const mml of node.childNodes) { + const child = this.findChild(mml, id); + if (child) return child; + } } - - /** - * @return {string} A unique id string. - */ - private makeId(): string { - return 'mjx-collapse-' + this.idCount++; + return null; + } + + /** + * Add maction nodes to the nodes in the tree that can collapse + * + * @param {MmlNode} node The root of the tree to check + * @param {number|null} id The initial id to use + * @returns {number} The initial id used + */ + public makeCollapse(node: MmlNode, id: number | null): number { + let oldCount = null; + if (id === null) { + id = this.idCount; + } else { + oldCount = this.idCount; + this.idCount = id; } - - /** - * @param {MmlNode} node The node to make collapsible by replacing with an maction - */ - public makeAction(node: MmlNode) { - if (node.isKind('math')) { - node = this.addMrow(node); - } - const factory = this.complexity.factory; - const marker = node.getProperty('collapse-marker') as string; - const parent = node.parent; - let maction = factory.create('maction', { - actiontype: 'toggle', - selection: 2, - 'data-collapsible': true, - id: this.makeId(), - 'data-semantic-complexity': node.attributes.get('data-semantic-complexity') - }, [ - factory.create('mtext', {mathcolor: 'blue'}, [ - (factory.create('text') as TextNode).setText(marker) - ]) - ]); - maction.inheritAttributesFrom(node); - node.attributes.set('data-semantic-complexity', node.getProperty('collapse-complexity')); - node.removeProperty('collapse-marker'); - node.removeProperty('collapse-complexity'); - parent.replaceChild(maction, node); - maction.appendChild(node); + const nodes: MmlNode[] = []; + node.walkTree((child: MmlNode) => { + if (child.getProperty('collapse-marker')) { + nodes.push(child); + } + }); + this.makeActions(nodes); + if (oldCount !== null) { + this.idCount = oldCount; } - - /** - * If the node is to be collapsible, add an mrow to it instead so that we can wrap it - * in an maction (can't put one around the node). - * - * @param {MmlNode} node The math node to create an mrow for - * @return {MmlNode} The newly created mrow - */ - public addMrow(node: MmlNode): MmlNode { - const mrow = this.complexity.factory.create('mrow', null, node.childNodes[0].childNodes as MmlNode[]); - node.childNodes[0].setChildren([mrow]); - - const attributes = node.attributes.getAllAttributes(); - for (const name of Object.keys(attributes)) { - if (name.substr(0, 14) === 'data-semantic-') { - mrow.attributes.set(name, attributes[name]); - delete attributes[name]; - } - } - - mrow.setProperty('collapse-marker', node.getProperty('collapse-marker')); - mrow.setProperty('collapse-complexity', node.getProperty('collapse-complexity')); - node.removeProperty('collapse-marker'); - node.removeProperty('collapse-complexity'); - return mrow; + return id; + } + + /** + * @param {MmlNode[]} nodes The list of nodes to replace by maction nodes + */ + public makeActions(nodes: MmlNode[]) { + for (const node of nodes) { + this.makeAction(node); + } + } + + /** + * @returns {string} A unique id string. + */ + private makeId(): string { + return 'mjx-collapse-' + this.idCount++; + } + + /** + * @param {MmlNode} node The node to make collapsible by replacing with an maction + */ + public makeAction(node: MmlNode) { + if (node.isKind('math')) { + node = this.addMrow(node); } + const factory = this.complexity.factory; + const marker = node.getProperty('collapse-marker') as string; + const parent = node.parent; + const variant = node.getProperty('collapse-variant') + ? { mathvariant: '-tex-variant' } + : {}; + const maction = factory.create( + 'maction', + { + actiontype: 'toggle', + selection: 2, + 'data-collapsible': true, + id: this.makeId(), + 'data-semantic-complexity': node.attributes.get( + 'data-semantic-complexity' + ), + }, + [ + factory.create('mtext', { mathcolor: 'blue', ...variant }, [ + (factory.create('text') as TextNode).setText(marker), + ]), + ] + ); + maction.inheritAttributesFrom(node); + node.attributes.set( + 'data-semantic-complexity', + node.getProperty('collapse-complexity') + ); + node.removeProperty('collapse-marker'); + node.removeProperty('collapse-complexity'); + parent.replaceChild(maction, node); + maction.appendChild(node); + } + + /** + * If the node is to be collapsible, add an mrow to it instead so that we can wrap it + * in an maction (can't put one around the node). + * + * @param {MmlNode} node The math node to create an mrow for + * @returns {MmlNode} The newly created mrow + */ + public addMrow(node: MmlNode): MmlNode { + const mrow = this.complexity.factory.create( + 'mrow', + null, + node.childNodes[0].childNodes + ); + node.childNodes[0].setChildren([mrow]); + + const attributes = node.attributes.getAllAttributes(); + for (const name of Object.keys(attributes)) { + if ( + name.substring(0, 14) === 'data-semantic-' || + name.substring(0, 12) === 'data-speech-' || + name.substring(0, 5) === 'aria-' || + name === 'role' + ) { + mrow.attributes.set(name, attributes[name]); + delete attributes[name]; + } + } + + mrow.setProperty('collapse-marker', node.getProperty('collapse-marker')); + mrow.setProperty( + 'collapse-complexity', + node.getProperty('collapse-complexity') + ); + node.removeProperty('collapse-marker'); + node.removeProperty('collapse-complexity'); + return mrow; + } } diff --git a/ts/a11y/complexity/visitor.ts b/ts/a11y/complexity/visitor.ts index 1e755fdd1..500af1b11 100644 --- a/ts/a11y/complexity/visitor.ts +++ b/ts/a11y/complexity/visitor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,28 @@ */ /** - * @fileoverview Implements a class that computes complexities for enriched math + * @file Implements a class that computes complexities for enriched math * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MmlNode, AbstractMmlTokenNode} from '../../core/MmlTree/MmlNode.js'; -import {MmlMroot} from '../../core/MmlTree/MmlNodes/mroot.js'; -import {MmlMaction} from '../../core/MmlTree/MmlNodes/maction.js'; -import {MmlMsubsup, MmlMsub, MmlMsup} from '../../core/MmlTree/MmlNodes/msubsup.js'; -import {MmlMunderover, MmlMunder, MmlMover} from '../../core/MmlTree/MmlNodes/munderover.js'; -import {MmlVisitor} from '../../core/MmlTree/MmlVisitor.js'; -import {MmlFactory} from '../../core/MmlTree/MmlFactory.js'; -import {Collapse} from './collapse.js'; -import {OptionList, userOptions, defaultOptions} from '../../util/Options.js'; +import { MmlNode, AbstractMmlTokenNode } from '../../core/MmlTree/MmlNode.js'; +import { MmlMroot } from '../../core/MmlTree/MmlNodes/mroot.js'; +import { MmlMaction } from '../../core/MmlTree/MmlNodes/maction.js'; +import { + MmlMsubsup, + MmlMsub, + MmlMsup, +} from '../../core/MmlTree/MmlNodes/msubsup.js'; +import { + MmlMunderover, + MmlMunder, + MmlMover, +} from '../../core/MmlTree/MmlNodes/munderover.js'; +import { MmlVisitor } from '../../core/MmlTree/MmlVisitor.js'; +import { MmlFactory } from '../../core/MmlTree/MmlFactory.js'; +import { Collapse } from './collapse.js'; +import { OptionList, userOptions, defaultOptions } from '../../util/Options.js'; /*==========================================================================*/ @@ -37,345 +45,381 @@ import {OptionList, userOptions, defaultOptions} from '../../util/Options.js'; * A visitor pattern that computes complexities within the MathML tree */ export class ComplexityVisitor extends MmlVisitor { - - /** - * The options for handling collapsing - */ - public static OPTIONS: OptionList = { - identifyCollapsible: true, // mark elements that should be collapsed - makeCollapsible: true, // insert maction to allow collapsing - Collapse: Collapse // the Collapse class to use - }; - - /** - * Values used to compute complexities - */ - public complexity: {[name: string]: number} = { - text: .5, // each character of a token element adds this to complexity - token: .5, // each token element gets this additional complexity - child: 1, // child nodes add this to their parent node's complexity - - script: .8, // script elements reduce their complexity by this factor - sqrt: 2, // sqrt adds this extra complexity - subsup: 2, // sub-sup adds this extra complexity - underover: 2, // under-over adds this extra complexity - fraction: 2, // fractions add this extra complexity - enclose: 2, // menclose adds this extra complexity - action: 2, // maction adds this extra complexity - phantom: 0, // mphantom makes complexity 0? - xml: 2, // Can't really measure complexity of annotation-xml, so punt - glyph: 2 // Can't really measure complexity of mglyph, to punt - }; - - /** - * The object used to handle collapsable content - */ - public collapse: Collapse; - - /** - * The MmlFactory for this visitor - */ - public factory: MmlFactory; - - /** - * The options for this visitor - */ - public options: OptionList; - - /** - * @override - */ - constructor(factory: MmlFactory, options: OptionList) { - super(factory); - let CLASS = this.constructor as typeof ComplexityVisitor; - this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options); - this.collapse = new this.options.Collapse(this); - this.factory = factory; - } - - /*==========================================================================*/ - - /** - * @override - */ - public visitTree(node: MmlNode) { - super.visitTree(node, true); - if (this.options.makeCollapsible) { - this.collapse.makeCollapse(node); - } - } - - /** - * @override - */ - public visitNode(node: MmlNode, save: boolean) { - if (node.attributes.get('data-semantic-complexity')) return; - return super.visitNode(node, save); - } - - /** - * For token nodes, use the content length, otherwise, add up the child complexities - * - * @override - */ - public visitDefault(node: MmlNode, save: boolean) { - let complexity; - if (node.isToken) { - const text = (node as AbstractMmlTokenNode).getText(); - complexity = this.complexity.text * text.length + this.complexity.token; - } else { - complexity = this.childrenComplexity(node); - } - return this.setComplexity(node, complexity, save); - } - - /** - * For a fraction, add the complexities of the children and scale by script factor, then - * add the fraction amount - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMfracNode(node: MmlNode, save: boolean) { - const complexity = this.childrenComplexity(node) * this.complexity.script + this.complexity.fraction; - return this.setComplexity(node, complexity, save); - } - - /** - * For square roots, use the child complexity plus the sqrt complexity - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMsqrtNode(node: MmlNode, save: boolean) { - const complexity = this.childrenComplexity(node) + this.complexity.sqrt; - return this.setComplexity(node, complexity, save); - } - - /** - * For roots, do the sqrt root computation and remove a bit for the root - * (since it is counted in the children sum but is smaller) - * - * @param {MmlMroot} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMrootNode(node: MmlMroot, save: boolean) { - const complexity = this.childrenComplexity(node) + this.complexity.sqrt - - (1 - this.complexity.script) * this.getComplexity(node.childNodes[1]); - return this.setComplexity(node, complexity, save); - } - - /** - * Phantom complexity is 0 - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMphantomNode(node: MmlNode, save: boolean) { - return this.setComplexity(node, this.complexity.phantom, save); - } - - /** - * For ms, add the complexity of the quotes to that of the content, and use the - * length of that times the text factor as the complexity - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMsNode(node: MmlNode, save: boolean) { - const text = node.attributes.get('lquote') - + (node as AbstractMmlTokenNode).getText() - + node.attributes.get('rquote'); - const complexity = text.length * this.complexity.text; - return this.setComplexity(node, complexity, save); - } - - /** - * For supscripts and superscripts use the maximum of the script complexities, - * multiply by the script factor, and add the base complexity. Add the child - * complexity for each child, and the subsup complexity. - * - * @param {MmlMsubsup} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMsubsupNode(node: MmlMsubsup, save: boolean) { - super.visitDefault(node, true); - const sub = node.childNodes[node.sub]; - const sup = node.childNodes[node.sup]; - const base = node.childNodes[node.base]; - let complexity = Math.max( - sub ? this.getComplexity(sub) : 0, - sup ? this.getComplexity(sup) : 0 - ) * this.complexity.script; - complexity += this.complexity.child * ((sub ? 1 : 0) + (sup ? 1 : 0)); - complexity += (base ? this.getComplexity(base) + this.complexity.child : 0); - complexity += this.complexity.subsup; - return this.setComplexity(node, complexity, save); - } - /** - * @param {MmlMsub} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMsubNode(node: MmlMsub, save: boolean) { - return this.visitMsubsupNode(node, save); - } - /** - * @param {MmlMsup} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMsupNode(node: MmlMsup, save: boolean) { - return this.visitMsubsupNode(node, save); - } - - /** - * For under/over, get the maximum of the complexities of the under and over - * elements times the script factor, and that the maximum of that with the - * base complexity. Add child complexity for all children, and add the - * underover amount. - * - * @param {MmlMunderover} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMunderoverNode(node: MmlMunderover, save: boolean) { - super.visitDefault(node, true); - const under = node.childNodes[node.under]; - const over = node.childNodes[node.over]; - const base = node.childNodes[node.base]; - let complexity = Math.max( - under ? this.getComplexity(under) : 0, - over ? this.getComplexity(over) : 0, - ) * this.complexity.script; - if (base) { - complexity = Math.max(this.getComplexity(base), complexity); - } - complexity += this.complexity.child * ((under ? 1 : 0) + (over ? 1 : 0) + (base ? 1 : 0)); - complexity += this.complexity.underover; - return this.setComplexity(node, complexity, save); + /** + * The options for handling collapsing + */ + /* prettier-ignore */ + public static OPTIONS: OptionList = { + identifyCollapsible: true, // mark elements that should be collapsed + makeCollapsible: true, // insert maction to allow collapsing + Collapse: Collapse // the Collapse class to use + }; + + /** + * Values used to compute complexities + */ + /* prettier-ignore */ + public complexity: {[name: string]: number} = { + text: .5, // each character of a token element adds this to complexity + token: .5, // each token element gets this additional complexity + child: 1, // child nodes add this to their parent node's complexity + + script: .8, // script elements reduce their complexity by this factor + sqrt: 2, // sqrt adds this extra complexity + subsup: 2, // sub-sup adds this extra complexity + underover: 2, // under-over adds this extra complexity + fraction: 2, // fractions add this extra complexity + enclose: 2, // menclose adds this extra complexity + action: 2, // maction adds this extra complexity + phantom: 0, // mphantom makes complexity 0? + xml: 2, // Can't really measure complexity of annotation-xml, so punt + glyph: 2 // Can't really measure complexity of mglyph, to punt + }; + + /** + * The object used to handle collapsable content + */ + public collapse: Collapse; + + /** + * The MmlFactory for this visitor + */ + public factory: MmlFactory; + + /** + * The options for this visitor + */ + public options: OptionList; + + /** + * @override + */ + constructor(factory: MmlFactory, options: OptionList) { + super(factory); + const CLASS = this.constructor as typeof ComplexityVisitor; + this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options); + this.collapse = new this.options.Collapse(this); + this.factory = factory; + } + + /*==========================================================================*/ + + /** + * @override + */ + public visitTree(node: MmlNode, id: number) { + super.visitTree(node, true); + if (this.options.makeCollapsible) { + id = this.collapse.makeCollapse(node, id); } - /** - * @param {MmlMunder} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMunderNode(node: MmlMunder, save: boolean) { - return this.visitMunderoverNode(node, save); + return id; + } + + /** + * @override + */ + public visitNode(node: MmlNode, save: boolean) { + if (node.attributes.get('data-semantic-complexity')) return; + return super.visitNode(node, save); + } + + /** + * For token nodes, use the content length, otherwise, add up the child complexities + * + * @override + */ + public visitDefault(node: MmlNode, save: boolean) { + let complexity; + if (node.isToken) { + const text = (node as AbstractMmlTokenNode).getText(); + complexity = this.complexity.text * text.length + this.complexity.token; + } else { + complexity = this.childrenComplexity(node); } - /** - * @param {MmlMover} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMoverNode(node: MmlMover, save: boolean) { - return this.visitMunderoverNode(node, save); + return this.setComplexity(node, complexity, save); + } + + /** + * For a fraction, add the complexities of the children and scale by script factor, then + * add the fraction amount + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMfracNode(node: MmlNode, save: boolean): number { + const complexity = + this.childrenComplexity(node) * this.complexity.script + + this.complexity.fraction; + return this.setComplexity(node, complexity, save); + } + + /** + * For square roots, use the child complexity plus the sqrt complexity + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMsqrtNode(node: MmlNode, save: boolean): number { + const complexity = this.childrenComplexity(node) + this.complexity.sqrt; + return this.setComplexity(node, complexity, save); + } + + /** + * For roots, do the sqrt root computation and remove a bit for the root + * (since it is counted in the children sum but is smaller) + * + * @param {MmlMroot} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMrootNode(node: MmlMroot, save: boolean): number { + const complexity = + this.childrenComplexity(node) + + this.complexity.sqrt - + (1 - this.complexity.script) * this.getComplexity(node.childNodes[1]); + return this.setComplexity(node, complexity, save); + } + + /** + * Phantom complexity is 0 + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMphantomNode(node: MmlNode, save: boolean): number { + return this.setComplexity(node, this.complexity.phantom, save); + } + + /** + * For ms, add the complexity of the quotes to that of the content, and use the + * length of that times the text factor as the complexity + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMsNode(node: MmlNode, save: boolean): number { + const text = + node.attributes.get('lquote') + + (node as AbstractMmlTokenNode).getText() + + node.attributes.get('rquote'); + const complexity = text.length * this.complexity.text; + return this.setComplexity(node, complexity, save); + } + + /** + * For supscripts and superscripts use the maximum of the script complexities, + * multiply by the script factor, and add the base complexity. Add the child + * complexity for each child, and the subsup complexity. + * + * @param {MmlMsubsup} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMsubsupNode(node: MmlMsubsup, save: boolean): number { + super.visitDefault(node, true); + const sub = node.childNodes[node.sub]; + const sup = node.childNodes[node.sup]; + const base = node.childNodes[node.base]; + let complexity = + Math.max( + sub ? this.getComplexity(sub) : 0, + sup ? this.getComplexity(sup) : 0 + ) * this.complexity.script; + complexity += this.complexity.child * ((sub ? 1 : 0) + (sup ? 1 : 0)); + complexity += base ? this.getComplexity(base) + this.complexity.child : 0; + complexity += this.complexity.subsup; + return this.setComplexity(node, complexity, save); + } + /** + * @param {MmlMsub} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMsubNode(node: MmlMsub, save: boolean): number { + return this.visitMsubsupNode(node, save); + } + /** + * @param {MmlMsup} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMsupNode(node: MmlMsup, save: boolean): number { + return this.visitMsubsupNode(node, save); + } + + /** + * For under/over, get the maximum of the complexities of the under and over + * elements times the script factor, and that the maximum of that with the + * base complexity. Add child complexity for all children, and add the + * underover amount. + * + * @param {MmlMunderover} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMunderoverNode(node: MmlMunderover, save: boolean): number { + super.visitDefault(node, true); + const under = node.childNodes[node.under]; + const over = node.childNodes[node.over]; + const base = node.childNodes[node.base]; + let complexity = + Math.max( + under ? this.getComplexity(under) : 0, + over ? this.getComplexity(over) : 0 + ) * this.complexity.script; + if (base) { + complexity = Math.max(this.getComplexity(base), complexity); } - - /** - * For enclose, use sum of child complexities plus some for the enclose - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMencloseNode(node: MmlNode, save: boolean) { - const complexity = this.childrenComplexity(node) + this.complexity.enclose; - return this.setComplexity(node, complexity, save); + complexity += + this.complexity.child * + ((under ? 1 : 0) + (over ? 1 : 0) + (base ? 1 : 0)); + complexity += this.complexity.underover; + return this.setComplexity(node, complexity, save); + } + /** + * @param {MmlMunder} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMunderNode(node: MmlMunder, save: boolean): number { + return this.visitMunderoverNode(node, save); + } + /** + * @param {MmlMover} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMoverNode(node: MmlMover, save: boolean): number { + return this.visitMunderoverNode(node, save); + } + + /** + * For enclose, use sum of child complexities plus some for the enclose + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMencloseNode(node: MmlNode, save: boolean): number { + const complexity = this.childrenComplexity(node) + this.complexity.enclose; + return this.setComplexity(node, complexity, save); + } + + /** + * For actions, use the complexity of the selected child + * + * @param {MmlMaction} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMactionNode(node: MmlMaction, save: boolean): number { + this.childrenComplexity(node); + const complexity = this.getComplexity(node.selected); + return this.setComplexity(node, complexity, save); + } + + /** + * For semantics, get the complexity from the first child + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitMsemanticsNode(node: MmlNode, save: boolean): number { + const child = node.childNodes[0]; + let complexity = 0; + if (child) { + this.visitNode(child, true); + complexity = this.getComplexity(child); } - - /** - * For actions, use the complexity of the selected child - * - * @param {MmlMaction} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMactionNode(node: MmlMaction, save: boolean) { - this.childrenComplexity(node); - const complexity = this.getComplexity(node.selected); - return this.setComplexity(node, complexity, save); + return this.setComplexity(node, complexity, save); + } + + /** + * Can't really measure annotations, so just use a specific value + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitAnnotationNode(node: MmlNode, save: boolean): number { + return this.setComplexity(node, this.complexity.xml, save); + } + + /** + * Can't really measure annotations, so just use a specific value + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node + */ + protected visitAnnotation_xmlNode(node: MmlNode, save: boolean): number { + return this.setComplexity(node, this.complexity.xml, save); + } + + /** + * Can't really measure mglyph complexity, so just use a specific value + * + * @param {MmlNode} node The node whose complixity is being computed + * @param {boolean} save True if the complexity is to be saved or just returned + * @returns {number} The complexity of the node (if collapsable, then the collapsed complexity) + */ + protected visitMglyphNode(node: MmlNode, save: boolean): number { + return this.setComplexity(node, this.complexity.glyph, save); + } + + /*==========================================================================*/ + + /** + * @param {MmlNode} node The node whose complixity is needed + * @returns {number} The complexity of the node (if collapsable, then the collapsed complexity) + */ + public getComplexity(node: MmlNode): number { + const collapsed = node.getProperty('collapsedComplexity'); + return ( + collapsed != null + ? collapsed + : node.attributes.get('data-semantic-complexity') + ) as number; + } + + /** + * @param {MmlNode} node The node whose complixity is being set + * @param {number} complexity The complexity for the node + * @param {boolean} save True if complexity is to be set or just reported + * @returns {number} The complexity of the node + */ + protected setComplexity( + node: MmlNode, + complexity: number, + save: boolean + ): number { + if (save) { + if (this.options.identifyCollapsible) { + complexity = this.collapse.check(node, complexity); + } + node.attributes.set('data-semantic-complexity', complexity); } - - /** - * For semantics, get the complexity from the first child - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMsemanticsNode(node: MmlNode, save: boolean) { - const child = node.childNodes[0] as MmlNode; - let complexity = 0; - if (child) { - this.visitNode(child, true); - complexity = this.getComplexity(child); - } - return this.setComplexity(node, complexity, save); + return complexity; + } + + /** + * @param {MmlNode} node The node whose children complexities are to be added + * @returns {number} The sum of the complexities, plus child complexity for each one + */ + protected childrenComplexity(node: MmlNode): number { + super.visitDefault(node, true); + let complexity = 0; + for (const child of node.childNodes) { + complexity += this.getComplexity(child); } - - /** - * Can't really measure annotations, so just use a specific value - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitAnnotationNode(node: MmlNode, save: boolean) { - return this.setComplexity(node, this.complexity.xml, save); + if (node.childNodes.length > 1) { + complexity += node.childNodes.length * this.complexity.child; } - - /** - * Can't really measure annotations, so just use a specific value - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitAnnotation_xmlNode(node: MmlNode, save: boolean) { - return this.setComplexity(node, this.complexity.xml, save); - } - - /** - * Can't really measure mglyph complexity, so just use a specific value - * - * @param {MmlNode} node The node whose complixity is being computed - * @param {boolean} save True if the complexity is to be saved or just returned - */ - protected visitMglyphNode(node: MmlNode, save: boolean) { - return this.setComplexity(node, this.complexity.glyph, save); - } - - /*==========================================================================*/ - - /** - * @param {MmlNode} node The node whose complixity is needed - * @return {number} The complexity fof the node (if collapsable, then the collapsed complexity) - */ - public getComplexity(node: MmlNode): number { - const collapsed = node.getProperty('collapsedComplexity'); - return (collapsed != null ? collapsed : node.attributes.get('data-semantic-complexity')) as number; - } - - /** - * @param {MmlNode} node The node whose complixity is being set - * @param {complexity} number The complexity for the node - * @param {boolean} save True if complexity is to be set or just reported - */ - protected setComplexity(node: MmlNode, complexity: number, save: boolean) { - if (save) { - if (this.options.identifyCollapsible) { - complexity = this.collapse.check(node, complexity); - } - node.attributes.set('data-semantic-complexity', complexity); - } - return complexity; - } - - /** - * @param {MmlNode} node The node whose children complexities are to be added - * @return {number} The sum of the complexities, plus child complexity for each one - */ - protected childrenComplexity(node: MmlNode): number { - super.visitDefault(node, true); - let complexity = 0; - for (const child of node.childNodes) { - complexity += this.getComplexity(child as MmlNode); - } - if (node.childNodes.length > 1) { - complexity += node.childNodes.length * this.complexity.child; - } - return complexity; - } - + return complexity; + } } diff --git a/ts/a11y/explorer.ts b/ts/a11y/explorer.ts index b170edb0b..7964807c0 100644 --- a/ts/a11y/explorer.ts +++ b/ts/a11y/explorer.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,55 +16,79 @@ */ /** - * @fileoverview Mixin that implements the Explorer + * @file Mixin that implements the Explorer * * @author dpvc@mathjax.org (Davide Cervone) */ -import {Handler} from '../core/Handler.js'; -import {MmlNode} from '../core/MmlTree/MmlNode.js'; -import {MathML} from '../input/mathml.js'; -import {STATE, newState} from '../core/MathItem.js'; -import {EnrichedMathItem, EnrichedMathDocument, EnrichHandler} from './semantic-enrich.js'; -import {MathDocumentConstructor} from '../core/MathDocument.js'; -import {OptionList, expandable} from '../util/Options.js'; -import {SerializedMmlVisitor} from '../core/MmlTree/SerializedMmlVisitor.js'; -import {MJContextMenu} from '../ui/menu/MJContextMenu.js'; +import { Handler } from '../core/Handler.js'; +import { MmlNode } from '../core/MmlTree/MmlNode.js'; +import { MathML } from '../input/mathml.js'; +import { STATE, newState } from '../core/MathItem.js'; +import { SpeechMathItem, SpeechMathDocument, SpeechHandler } from './speech.js'; +import { MathDocumentConstructor } from '../core/MathDocument.js'; +import { OptionList, expandable } from '../util/Options.js'; +import { SerializedMmlVisitor } from '../core/MmlTree/SerializedMmlVisitor.js'; +import { hasWindow } from '../util/context.js'; +import { StyleJson } from '../util/StyleJson.js'; +import { context } from '../util/context.js'; -import {Explorer} from './explorer/Explorer.js'; -import * as ke from './explorer/KeyExplorer.js'; -import * as me from './explorer/MouseExplorer.js'; -import {TreeColorer, FlameColorer} from './explorer/TreeExplorer.js'; -import {LiveRegion, ToolTip, HoverRegion} from './explorer/Region.js'; +import { ExplorerPool, RegionPool } from './explorer/ExplorerPool.js'; -import {Submenu} from 'mj-context-menu/js/item_submenu.js'; +import * as Sre from './sre.js'; -import Sre from './sre.js'; +const isUnix = context.os === 'Unix'; /** * Generic constructor for Mixins */ -export type Constructor = new(...args: any[]) => T; +export type Constructor = new (...args: any[]) => T; /** * Shorthands for types with HTMLElement, Text, and Document instead of generics */ export type HANDLER = Handler; -export type HTMLDOCUMENT = EnrichedMathDocument; -export type HTMLMATHITEM = EnrichedMathItem; +export type HTMLDOCUMENT = SpeechMathDocument & { + menu?: any; +}; +export type HTMLMATHITEM = SpeechMathItem; export type MATHML = MathML; /*==========================================================================*/ /** - * Add STATE value for having the Explorer added (after TYPESET and before INSERTED or CONTEXT_MENU) + * Add STATE value for having the Explorer added (after INSERTED and before CONTEXT_MENU) */ -newState('EXPLORER', 160); +newState('EXPLORER', STATE.INSERTED + 30); /** * The properties added to MathItem for the Explorer */ export interface ExplorerMathItem extends HTMLMATHITEM { + /** + * The value to use for the aria role for mjx-speech elements + */ + ariaRole: string; + + /** + * The aria-roleDescription to use for the math + */ + roleDescription: string; + + /** + * The string to use for when there is no description; + */ + none: string; + + /** + * The Explorer objects for this math item + */ + explorers: ExplorerPool; + + /** + * Semantic id of the rerendered element that should regain the focus. + */ + refocus: string; /** * @param {HTMLDocument} document The document where the Explorer is being added @@ -73,9 +97,15 @@ export interface ExplorerMathItem extends HTMLMATHITEM { explorable(document: HTMLDOCUMENT, force?: boolean): void; /** - * @param {HTMLDocument} document The document where the Explorer is being added + * @param {ExplorerMathDocument} document The explorer document being used + * @returns {HTMLElement} The temporary focus element, if any + */ + setTemporaryFocus(document: ExplorerMathDocument): HTMLElement; + + /** + * @param {HTMLElement} focus The temporary focus element, if any */ - attachExplorers(document: HTMLDOCUMENT): void; + clearTemporaryFocus(focus: HTMLElement): void; } /** @@ -91,33 +121,73 @@ export function ExplorerMathItemMixin>( BaseMathItem: B, toMathML: (node: MmlNode) => string ): Constructor & B { + return class BaseClass extends BaseMathItem { + /** + * The value to use for the aria role for mjx-speech elements + */ + protected static ariaRole: string = isUnix ? 'tree' : 'application'; - return class extends BaseMathItem { + /** + * The aria-roleDescription to use for the math + */ + protected static roleDescription: string = 'math'; /** - * The Explorer objects for this math item + * Decription to use when set to none + * (private-use-1 is not spoken by any screen reader tested) */ - protected explorers: {[key: string]: Explorer} = {}; + protected static none: string = '\u0091'; + + public get ariaRole() { + return (this.constructor as typeof BaseClass).ariaRole; + } + + public get roleDescription() { + const CLASS = this.constructor as typeof BaseClass; + return CLASS.roleDescription === 'none' + ? CLASS.none + : CLASS.roleDescription; + } + + public get none() { + return (this.constructor as typeof BaseClass).none; + } /** - * The currently attached explorers + * @override */ - protected attached: string[] = []; + public explorers: ExplorerPool; /** - * True when a rerendered element should restart these explorers + * @override */ - protected restart: string[] = []; + public refocus: string = null; /** - * True when a rerendered element should regain the focus + * @override */ - protected refocus: boolean = false; + public attachSpeech(document: ExplorerMathDocument) { + super.attachSpeech(document); + this.outputData.speechPromise + ?.then(() => this.explorers.speech.attachSpeech()) + ?.then(() => { + if (this.explorers?.speech) { + this.explorers.speech.restarted = this.refocus; + } + this.refocus = null; + if (this.explorers) { + this.explorers.restart(); + } + }); + } /** - * Save explorer id during rerendering. + * @override */ - protected savedId: string = null; + public detachSpeech(document: ExplorerMathDocument) { + super.detachSpeech(document); + this.explorers.speech.detachSpeech(); + } /** * Add the explorer to the output for this math item @@ -130,97 +200,106 @@ export function ExplorerMathItemMixin>( if (!this.isEscaped && (document.options.enableExplorer || force)) { const node = this.typesetRoot; const mml = toMathML(this.root); - if (this.savedId) { - this.typesetRoot.setAttribute('sre-explorer-id', this.savedId); - this.savedId = null; + if (!this.explorers) { + this.explorers = new ExplorerPool(); } - // Init explorers: - this.explorers = initExplorers(document, node, mml); - this.attachExplorers(document); + this.explorers.init(document, node, mml, this); } this.state(STATE.EXPLORER); } /** - * Attaches the explorers that are currently meant to be active given - * the document options. Detaches all others. - * @param {ExplorerMathDocument} document The current document. + * @override */ - public attachExplorers(document: ExplorerMathDocument) { - this.attached = []; - let keyExplorers = []; - for (let key of Object.keys(this.explorers)) { - let explorer = this.explorers[key]; - if (explorer instanceof ke.AbstractKeyExplorer) { - explorer.AddEvents(); - explorer.stoppable = false; - keyExplorers.unshift(explorer); - } - if (document.options.a11y[key]) { - explorer.Attach(); - this.attached.push(key); - } else { - explorer.Detach(); - } - } - // Ensure that the last currently attached key explorer stops propagating - // key events. - for (let explorer of keyExplorers) { - if (explorer.attached) { - explorer.stoppable = true; - break; + public state(state: number = null, restore: boolean = false) { + if (state < STATE.EXPLORER && this.explorers) { + for (const explorer of Object.values(this.explorers.explorers)) { + if (explorer.active) { + explorer.Stop(); + } } } + return super.state(state, restore); } /** * @override */ - public rerender(document: ExplorerMathDocument, start: number = STATE.RERENDER) { - this.savedId = this.typesetRoot.getAttribute('sre-explorer-id'); - this.refocus = (window.document.activeElement === this.typesetRoot); - for (let key of this.attached) { - let explorer = this.explorers[key]; - if (explorer.active) { - this.restart.push(key); - explorer.Stop(); - } - } + public rerender( + document: ExplorerMathDocument, + start: number = STATE.RERENDER + ) { + const focus = this.setTemporaryFocus(document); super.rerender(document, start); + this.clearTemporaryFocus(focus); } /** - * @override + * Focuses a temporary element during rerendering + * + * @param {ExplorerMathDocument} document The explorer document to use + * @returns {HTMLElement} The temporary focus element, if any */ - public updateDocument(document: ExplorerMathDocument) { - super.updateDocument(document); - this.refocus && this.typesetRoot.focus(); - this.restart.forEach(x => this.explorers[x].Start()); - this.restart = []; - this.refocus = false; + public setTemporaryFocus(document: ExplorerMathDocument): HTMLElement { + let focus = null; + if (this.explorers) { + const speech = this.explorers.speech; + focus = speech?.attached ? document.tmpFocus : null; + if (focus) { + this.refocus = speech.semanticFocus() ?? null; + const adaptor = document.adaptor; + adaptor.append(adaptor.body(), focus); + } + this.explorers.reattach(); + focus?.focus(); + } + return focus; } + /** + * Removes the temporary element after rerendering + * + * @param {HTMLElement} focus The temporary focus element, if any + */ + public clearTemporaryFocus(focus: HTMLElement) { + if (focus) { + const promise = this.outputData.speechPromise ?? Promise.resolve(); + promise.then(() => setTimeout(() => focus.remove(), 100)); + } + } }; - } /** * The functions added to MathDocument for the Explorer */ export interface ExplorerMathDocument extends HTMLDOCUMENT { + /** + * The info icon for the selected expression + */ + infoIcon: HTMLElement; + + /** + * An element ot use for temporary focus during rerendering + */ + tmpFocus: HTMLElement; /** * The objects needed for the explorer */ - explorerRegions: ExplorerRegions; + explorerRegions: RegionPool; + + /** + * The MathItem with the active KeyExplorer, if any + */ + activeItem: ExplorerMathItem; /** * Add the Explorer to the MathItems in the MathDocument * - * @returns {MathDocument} The MathDocument (so calls can be chained) + * @returns {HTMLDocument} The MathDocument (so calls can be chained) */ explorable(): HTMLDOCUMENT; - } /** @@ -228,32 +307,33 @@ export interface ExplorerMathDocument extends HTMLDOCUMENT { * * @param {B} BaseDocument The MathDocument class to be extended * @returns {ExplorerMathDocument} The extended MathDocument class + * + * @template B The MathItem class to extend */ -export function ExplorerMathDocumentMixin>( - BaseDocument: B -): MathDocumentConstructor & B { - - return class extends BaseDocument { - +export function ExplorerMathDocumentMixin< + B extends MathDocumentConstructor, +>(BaseDocument: B): MathDocumentConstructor & B { + return class BaseClass extends BaseDocument { /** * @override */ + /* prettier-ignore */ public static OPTIONS: OptionList = { ...BaseDocument.OPTIONS, - enableExplorer: true, + enableExplorer: hasWindow, // only activate in interactive contexts renderActions: expandable({ ...BaseDocument.OPTIONS.renderActions, explorable: [STATE.EXPLORER] }), sre: expandable({ ...BaseDocument.OPTIONS.sre, - speech: 'shallow', // overrides option in EnrichedMathDocument + speech: 'none', // None as speech is explicitly computed }), a11y: { + ...BaseDocument.OPTIONS.a11y, align: 'top', // placement of magnified expression backgroundColor: 'Blue', // color for background of selected sub-expression backgroundOpacity: 20, // opacity for background of selected sub-expression - braille: false, // switch on Braille output flame: false, // color collapsible sub-expressions foregroundColor: 'Black', // color to use for text of selected sub-expression foregroundOpacity: 100, // opacity for text of selected sub-expression @@ -266,24 +346,177 @@ export function ExplorerMathDocumentMixin mjx-help': { + display: 'none', + position: 'absolute', + top: '-.33em', + right: '-.5em', + width: '.6em', + height: '.6em', + cursor: 'pointer', + }, + 'mjx-container[display="true"] > mjx-help': { + right: 0, + }, + 'mjx-help > svg': { + stroke: 'black', + width: '100%', + height: '100%', + }, + 'mjx-help > svg > circle': { + 'stroke-width': '1.5px', + cx: '9px', + cy: '9px', + r: '9px', + fill: 'white', + }, + 'mjx-help > svg > circle:nth-child(2)': { + fill: 'rgba(0, 0, 255, 0.2)', + r: '7px', + }, + 'mjx-help > svg > line': { + 'stroke-width': '2.5px', + 'stroke-linecap': 'round', + }, + 'mjx-help:hover > svg > circle:nth-child(2)': { + fill: 'white', + }, + 'mjx-container.mjx-explorer-active > mjx-help': { + display: 'inline-flex', + 'align-items': 'center', + }, + + 'mjx-help-sizer': { + position: 'fixed', + width: '40%', + 'max-width': '30em', + top: '3em', + left: '50%', + }, + 'mjx-help-dialog': { + position: 'absolute', + width: '200%', + left: '-100%', + border: '3px outset', + 'border-radius': '15px', + color: 'black', + 'background-color': '#DDDDDD', + 'z-index': '301', + 'text-align': 'right', + 'font-style': 'normal', + 'text-indent': 0, + 'text-transform': 'none', + 'line-height': 'normal', + 'letter-spacing': 'normal', + 'word-spacing': 'normal', + 'word-wrap': 'normal', + float: 'none', + 'box-shadow': '0px 10px 20px #808080', + outline: 'none', + }, + 'mjx-help-dialog > h1': { + 'font-size': '24px', + 'text-align': 'center', + margin: '.5em 0', + }, + 'mjx-help-dialog > div': { + margin: '0 1em', + padding: '3px', + overflow: 'auto', + height: '20em', + border: '2px inset black', + 'background-color': 'white', + 'text-align': 'left', + }, + 'mjx-help-dialog > input': { + margin: '.5em 2em', + }, + 'mjx-help-dialog kbd': { + display: 'inline-block', + padding: '3px 5px', + 'font-size': '11px', + 'line-height': '10px', + color: '#444d56', + 'vertical-align': 'middle', + 'background-color': '#fafbfc', + border: 'solid 1.5px #c6cbd1', + 'border-bottom-color': '#959da5', + 'border-radius': '3px', + 'box-shadow': 'inset -.5px -1px 0 #959da5', + }, + 'mjx-help-dialog ul': { + 'list-style-type': 'none', + }, + 'mjx-help-dialog li': { + 'margin-bottom': '.5em', + }, + 'mjx-help-background': { + position: 'fixed', + top: 0, + left: 0, + right: 0, + bottom: 0, + }, + }; + + /** + * The info icon for the selected expression + */ + public infoIcon: HTMLElement; + + /** + * An element ot use for temporary focus during rerendering + */ + public tmpFocus: HTMLElement; + /** * The objects needed for the explorer */ - public explorerRegions: ExplorerRegions; + public explorerRegions: RegionPool = null; + + /** + * The MathItem with the active KeyExplorer, if any + */ + public activeItem: ExplorerMathItem = null; /** * Extend the MathItem class used for this MathDocument * and create the visitor and explorer objects needed for the explorer * * @override - * @constructor + * @class */ constructor(...args: any[]) { super(...args); @@ -292,16 +525,59 @@ export function ExplorerMathDocumentMixin visitor.visitTree(node)); - this.options.MathItem = ExplorerMathItemMixin(this.options.MathItem, toMathML); - // TODO: set backward compatibility options here. - this.explorerRegions = initExplorerRegions(this); + const toMathML = (node: MmlNode) => visitor.visitTree(node); + const options = this.options; + if (!options.a11y.speechRules) { + options.a11y.speechRules = `${options.sre.domain}-${options.sre.style}`; + } + const mathItem = (options.MathItem = ExplorerMathItemMixin( + options.MathItem, + toMathML + )); + mathItem.roleDescription = options.roleDescription; + this.explorerRegions = new RegionPool(this); + if ('addStyles' in this) { + (this as any).addStyles( + (this.constructor as typeof BaseClass).speechStyles + ); + } + const adaptor = this.adaptor; + const SVGNS = 'http://www.w3.org/2000/svg'; + this.infoIcon = adaptor.node('mjx-help', {}, [ + adaptor.node( + 'svg', + { viewBox: '0 0 18 18', xmlns: SVGNS, 'aria-hidden': 'true' }, + [ + adaptor.node('circle', { stroke: 'none' }, [], SVGNS), + adaptor.node('circle', {}, [], SVGNS), + adaptor.node('line', { x1: 9, y1: 9, x2: 9, y2: 13 }, [], SVGNS), + adaptor.node('line', { x1: 9, y1: 5.5, x2: 9, y2: 5.5 }, [], SVGNS), + ], + SVGNS + ), + ]); + this.tmpFocus = this.adaptor.node('mjx-focus', { + tabIndex: 0, + style: { + outline: 'none', + display: 'block', + position: 'absolute', + top: 0, + left: '-10px', + width: '1px', + height: '1px', + overflow: 'hidden', + }, + role: mathItem.ariaRole, + 'aria-label': mathItem.none, + 'aria-roledescription': mathItem.none, + }); } /** * Add the Explorer to the MathItems in this MathDocument * - * @return {ExplorerMathDocument} The MathDocument (so calls can be chained) + * @returns {ExplorerMathDocument} The MathDocument (so calls can be chained) */ public explorable(): ExplorerMathDocument { if (!this.processed.isSet('explorer')) { @@ -315,6 +591,17 @@ export function ExplorerMathDocumentMixin Explorer; - -/** - * Generation methods for all MathJax explorers available via option settings. - */ -let allExplorers: {[options: string]: ExplorerInit} = { - speech: (doc: ExplorerMathDocument, node: HTMLElement, ...rest: any[]) => { - let explorer = ke.SpeechExplorer.create( - doc, doc.explorerRegions.speechRegion, node, ...rest) as ke.SpeechExplorer; - explorer.speechGenerator.setOptions({ - locale: doc.options.sre.locale, domain: doc.options.sre.domain, - style: doc.options.sre.style, modality: 'speech'}); - // This weeds out the case of providing a non-existent locale option. - let locale = explorer.speechGenerator.getOptions().locale; - if (locale !== Sre.engineSetup().locale) { - doc.options.sre.locale = Sre.engineSetup().locale; - explorer.speechGenerator.setOptions({locale: doc.options.sre.locale}); - } - explorer.showRegion = 'subtitles'; - return explorer; - }, - braille: (doc: ExplorerMathDocument, node: HTMLElement, ...rest: any[]) => { - let explorer = ke.SpeechExplorer.create( - doc, doc.explorerRegions.brailleRegion, node, ...rest) as ke.SpeechExplorer; - explorer.speechGenerator.setOptions({locale: 'nemeth', domain: 'default', - style: 'default', modality: 'braille'}); - explorer.showRegion = 'viewBraille'; - return explorer; - }, - keyMagnifier: (doc: ExplorerMathDocument, node: HTMLElement, ...rest: any[]) => - ke.Magnifier.create(doc, doc.explorerRegions.magnifier, node, ...rest), - mouseMagnifier: (doc: ExplorerMathDocument, node: HTMLElement, ..._rest: any[]) => - me.ContentHoverer.create(doc, doc.explorerRegions.magnifier, node, - (x: HTMLElement) => x.hasAttribute('data-semantic-type'), - (x: HTMLElement) => x), - hover: (doc: ExplorerMathDocument, node: HTMLElement, ..._rest: any[]) => - me.FlameHoverer.create(doc, null, node), - infoType: (doc: ExplorerMathDocument, node: HTMLElement, ..._rest: any[]) => - me.ValueHoverer.create(doc, doc.explorerRegions.tooltip1, node, - (x: HTMLElement) => x.hasAttribute('data-semantic-type'), - (x: HTMLElement) => x.getAttribute('data-semantic-type')), - infoRole: (doc: ExplorerMathDocument, node: HTMLElement, ..._rest: any[]) => - me.ValueHoverer.create(doc, doc.explorerRegions.tooltip2, node, - (x: HTMLElement) => x.hasAttribute('data-semantic-role'), - (x: HTMLElement) => x.getAttribute('data-semantic-role')), - infoPrefix: (doc: ExplorerMathDocument, node: HTMLElement, ..._rest: any[]) => - me.ValueHoverer.create(doc, doc.explorerRegions.tooltip3, node, - (x: HTMLElement) => x.hasAttribute('data-semantic-prefix'), - (x: HTMLElement) => x.getAttribute('data-semantic-prefix')), - flame: (doc: ExplorerMathDocument, node: HTMLElement, ..._rest: any[]) => - FlameColorer.create(doc, null, node), - treeColoring: (doc: ExplorerMathDocument, node: HTMLElement, ...rest: any[]) => - TreeColorer.create(doc, null, node, ...rest) -}; - - -/** - * Initialises explorers for a document. - * @param {ExplorerMathDocument} document The target document. - * @param {HTMLElement} node The node explorers will be attached to. - * @param {string} mml The corresponding Mathml node as a string. - * @return {Explorer[]} A list of initialised explorers. - */ -function initExplorers(document: ExplorerMathDocument, node: HTMLElement, mml: string): {[key: string]: Explorer} { - let explorers: {[key: string]: Explorer} = {}; - for (let key of Object.keys(allExplorers)) { - explorers[key] = allExplorers[key](document, node, mml); - } - return explorers; -} - - /* Context Menu Interactions */ /** * Sets a list of a11y options for a given document. + * * @param {HTMLDOCUMENT} document The current document. * @param {{[key: string]: any}} options Association list for a11y option value pairs. */ -export function setA11yOptions(document: HTMLDOCUMENT, options: {[key: string]: any}) { - let sreOptions = Sre.engineSetup() as {[name: string]: string}; - for (let key in options) { +export function setA11yOptions( + document: HTMLDOCUMENT, + options: { [key: string]: any } +) { + // TODO (volker): This needs to be replace by the engine feature vector. + // Minus rule sets etc. Breaking change in SRE. + const sreOptions = Sre.engineSetup() as { [name: string]: string }; + for (const key in options) { if (document.options.a11y[key] !== undefined) { setA11yOption(document, key, options[key]); - if (key === 'locale') { - document.options.sre[key] = options[key]; - } - continue; - } - if (sreOptions[key] !== undefined) { + } else if (sreOptions[key] !== undefined) { document.options.sre[key] = options[key]; } } + if (options.roleDescription) { + document.options.MathItem.roleDescription = options.roleDescription; + } // Reinit explorers - for (let item of document.math) { - (item as ExplorerMathItem).attachExplorers(document as ExplorerMathDocument); + for (const item of document.math) { + (item as ExplorerMathItem)?.explorers?.attach(); } } - /** * Sets a single a11y option for a menu name. + * * @param {HTMLDOCUMENT} document The current document. * @param {string} option The option name in the menu. * @param {string|boolean} value The new value. */ -export function setA11yOption(document: HTMLDOCUMENT, option: string, value: string | boolean) { +export function setA11yOption( + document: HTMLDOCUMENT, + option: string, + value: string | boolean +) { switch (option) { - case 'magnification': - switch (value) { - case 'None': - document.options.a11y.magnification = value; - document.options.a11y.keyMagnifier = false; - document.options.a11y.mouseMagnifier = false; - break; - case 'Keyboard': - document.options.a11y.magnification = value; - document.options.a11y.keyMagnifier = true; - document.options.a11y.mouseMagnifier = false; - break; - case 'Mouse': - document.options.a11y.magnification = value; - document.options.a11y.keyMagnifier = false; - document.options.a11y.mouseMagnifier = true; + case 'speechRules': { + const [domain, style] = (value as string).split('-'); + document.options.sre.domain = domain; + document.options.sre.style = style; break; } - break; - case 'highlight': - switch (value) { - case 'None': - document.options.a11y.highlight = value; - document.options.a11y.hover = false; - document.options.a11y.flame = false; + case 'magnification': + switch (value) { + case 'None': + document.options.a11y.magnification = value; + document.options.a11y.keyMagnifier = false; + document.options.a11y.mouseMagnifier = false; + break; + case 'Keyboard': + document.options.a11y.magnification = value; + document.options.a11y.keyMagnifier = true; + document.options.a11y.mouseMagnifier = false; + break; + case 'Mouse': + document.options.a11y.magnification = value; + document.options.a11y.keyMagnifier = false; + document.options.a11y.mouseMagnifier = true; + break; + } break; - case 'Hover': - document.options.a11y.highlight = value; - document.options.a11y.hover = true; - document.options.a11y.flame = false; + case 'highlight': + switch (value) { + case 'None': + document.options.a11y.highlight = value; + document.options.a11y.hover = false; + document.options.a11y.flame = false; + break; + case 'Hover': + document.options.a11y.highlight = value; + document.options.a11y.hover = true; + document.options.a11y.flame = false; + break; + case 'Flame': + document.options.a11y.highlight = value; + document.options.a11y.hover = false; + document.options.a11y.flame = true; + break; + } break; - case 'Flame': - document.options.a11y.highlight = value; - document.options.a11y.hover = false; - document.options.a11y.flame = true; + case 'locale': + document.options.sre.locale = value; break; - } - break; - default: - document.options.a11y[option] = value; + default: + document.options.a11y[option] = value; } } - -/** - * Values for the ClearSpeak preference variables. - */ -let csPrefsSetting: {[pref: string]: string} = {}; - -/** - * Generator of all variables for the Clearspeak Preference settings. - * @param {MJContextMenu} menu The current context menu. - * @param {string[]} prefs The preferences. - */ -let csPrefsVariables = function(menu: MJContextMenu, prefs: string[]) { - let srVariable = menu.pool.lookup('speechRules'); - for (let pref of prefs) { - if (csPrefsSetting[pref]) continue; - menu.factory.get('variable')(menu.factory, { - name: 'csprf_' + pref, - setter: (value: string) => { - csPrefsSetting[pref] = value; - srVariable.setValue( - 'clearspeak-' + - Sre.clearspeakPreferences.addPreference( - Sre.clearspeakStyle(), pref, value) - ); - }, - getter: () => { return csPrefsSetting[pref] || 'Auto'; } - }, menu.pool); - } -}; - -/** - * Generate the selection box for the Clearspeak Preferences. - * @param {MJContextMenu} menu The current context menu. - * @param {string} locale The current locale. - */ -let csSelectionBox = function(menu: MJContextMenu, locale: string) { - let prefs = Sre.clearspeakPreferences.getLocalePreferences(); - let props = prefs[locale]; - if (!props) { - let csEntry = menu.findID('Accessibility', 'Speech', 'Clearspeak'); - if (csEntry) { - csEntry.disable(); - } - return null; - } - csPrefsVariables(menu, Object.keys(props)); - let items = []; - for (const prop of Object.getOwnPropertyNames(props)) { - items.push({ - 'title': prop, - 'values': props[prop].map(x => x.replace(RegExp('^' + prop + '_'), '')), - 'variable': 'csprf_' + prop - }); - } - let sb = menu.factory.get('selectionBox')(menu.factory, { - 'title': 'Clearspeak Preferences', - 'signature': '', - 'order': 'alphabetic', - 'grid': 'square', - 'selections': items - }, menu); - return {'type': 'command', - 'id': 'ClearspeakPreferences', - 'content': 'Select Preferences', - 'action': () => sb.post(0, 0)}; -}; - -/** - * Creates dynamic clearspeak menu. - * @param {MJContextMenu} menu The context menu. - * @param {Submenu} sub The submenu to attach. - */ -let csMenu = function(menu: MJContextMenu, sub: Submenu) { - let locale = menu.pool.lookup('locale').getValue() as string; - const box = csSelectionBox(menu, locale); - let items: Object[] = []; - try { - items = Sre.clearspeakPreferences.smartPreferences( - menu.mathItem, locale); - } catch (e) { - console.log(e); - } - if (box) { - items.splice(2, 0, box); - } - return menu.factory.get('subMenu')(menu.factory, { - items: items, - id: 'Clearspeak' - }, sub); -}; - -MJContextMenu.DynamicSubmenus.set('Clearspeak', csMenu); - -/** - * Creates dynamic locale menu. - * @param {MJContextMenu} menu The context menu. - * @param {Submenu} sub The submenu to attach. - */ -let language = function(menu: MJContextMenu, sub: Submenu) { - let radios: {type: string, id: string, - content: string, variable: string}[] = []; - for (let lang of Sre.locales.keys()) { - if (lang === 'nemeth') continue; - radios.push({type: 'radio', id: lang, - content: Sre.locales.get(lang) || lang, variable: 'locale'}); - } - radios.sort((x, y) => x.content.localeCompare(y.content, 'en')); - return menu.factory.get('subMenu')(menu.factory, { - items: radios, id: 'Language'}, sub); -}; - -MJContextMenu.DynamicSubmenus.set('A11yLanguage', language); diff --git a/ts/a11y/explorer/Explorer.ts b/ts/a11y/explorer/Explorer.ts index d94833364..8aa7254ce 100644 --- a/ts/a11y/explorer/Explorer.ts +++ b/ts/a11y/explorer/Explorer.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,35 +15,44 @@ * limitations under the License. */ - /** - * @fileoverview Explorers for A11Y purposes. + * @file Explorers for A11Y purposes. * * @author v.sorge@mathjax.org (Volker Sorge) */ +import { A11yDocument, Region } from './Region.js'; +import { Highlighter } from './Highlighter.js'; -import {A11yDocument, Region} from './Region.js'; -import Sre from '../sre.js'; +import type { ExplorerPool } from './ExplorerPool.js'; /** * A11y explorers. + * * @interface */ export interface Explorer { - /** * Flag indicating if the explorer is active. + * * @type {boolean} */ active: boolean; /** * Flag indicating if event bubbling is stopped. + * * @type {boolean} */ stoppable: boolean; + /** + * The pool the explorer belongs to. + * + * @type {ExplorerPool} + */ + pool: ExplorerPool; + /** * Attaches navigator and its event handlers to a node. */ @@ -64,7 +73,6 @@ export interface Explorer { */ Stop(): void; - /** * Adds the events of the explorer to the node's event listener. */ @@ -77,14 +85,13 @@ export interface Explorer { /** * Update the explorer after state changes. + * * @param {boolean=} force Forces the update in any case. (E.g., even if * explorer is inactive.) */ Update(force?: boolean): void; - } - /** * Abstract class implementing the very basic explorer functionality. * @@ -92,13 +99,12 @@ export interface Explorer { * to their node. This class provides the create method and is consequently not * declared abstract. * - * @constructor + * @class * @implements {Explorer} * * @template T The type that is consumed by the Region of this explorer. */ export class AbstractExplorer implements Explorer { - /** * @override */ @@ -106,24 +112,28 @@ export class AbstractExplorer implements Explorer { /** * Named events and their functions. - * @type {[string, function(x: Event)][]} + * + * @type {[string, (x: Event) => void][]} */ protected events: [string, (x: Event) => void][] = []; /** - * The Sre highlighter associated with the walker. - * @type {Sre.highlighter} + * @returns {Highlighter} The Sre highlighter associated with the walker. */ - protected highlighter: Sre.highlighter = this.getHighlighter(); + protected get highlighter(): Highlighter { + return this.pool.highlighter; + } /** * Flag if explorer is active. + * * @type {boolean} */ private _active: boolean = false; /** * Stops event bubbling. + * * @param {Event} event The event that is stopped. */ protected static stopEvent(event: Event) { @@ -142,47 +152,51 @@ export class AbstractExplorer implements Explorer { /** * Creator pattern for explorers. + * * @param {A11yDocument} document The current document. + * @param {ExplorerPool} pool The explorer pool. * @param {Region} region A region to display results. * @param {HTMLElement} node The node on which the explorer works. - * @param {any[]} ...rest Remaining information. - * @return {Explorer} An object of the particular explorer class. + * @param {any[]} rest Remaining information. + * @returns {Explorer} An object of the particular explorer class. * * @template T */ public static create( document: A11yDocument, + pool: ExplorerPool, region: Region, - node: HTMLElement, ...rest: any[] + node: HTMLElement, + ...rest: any[] ): Explorer { - let explorer = new this(document, region, node, ...rest); + const explorer = new this(document, pool, region, node, ...rest); return explorer; } /** - * @constructor + * @class * @param {A11yDocument} document The current document. + * @param {ExplorerPool} pool The explorer pool. * @param {Region} region A region to display results. * @param {HTMLElement} node The node on which the explorer works. - * @param {any[]} ...rest Remaining information. + * @param {any[]} _rest Remaining information. */ protected constructor( public document: A11yDocument, - protected region: Region, - protected node: HTMLElement, ..._rest: any[] - ) { - } - + public pool: ExplorerPool, + public region: Region, + protected node: HTMLElement, + ..._rest: any[] + ) {} /** - * @return {[string, (x: Event) => void][]} The events associated with this + * @returns {[string, (x: Event) => void][]} The events associated with this * explorer. */ protected Events(): [string, (x: Event) => void][] { return this.events; } - /** * @override */ @@ -215,7 +229,6 @@ export class AbstractExplorer implements Explorer { * @override */ public Start() { - this.highlighter = this.getHighlighter(); this.active = true; } @@ -234,7 +247,7 @@ export class AbstractExplorer implements Explorer { * @override */ public AddEvents() { - for (let [eventkind, eventfunc] of this.events) { + for (const [eventkind, eventfunc] of this.events) { this.node.addEventListener(eventkind, eventfunc); } } @@ -243,7 +256,7 @@ export class AbstractExplorer implements Explorer { * @override */ public RemoveEvents() { - for (let [eventkind, eventfunc] of this.events) { + for (const [eventkind, eventfunc] of this.events) { this.node.removeEventListener(eventkind, eventfunc); } } @@ -251,26 +264,11 @@ export class AbstractExplorer implements Explorer { /** * @override */ - // @ts-ignore: unused variable - public Update(force: boolean = false): void {} - - - /** - * @return {Sre.Highlighter} A highlighter for the explorer. - */ - protected getHighlighter(): Sre.highlighter { - let opts = this.document.options.a11y; - let foreground = {color: opts.foregroundColor.toLowerCase(), - alpha: opts.foregroundOpacity / 100}; - let background = {color: opts.backgroundColor.toLowerCase(), - alpha: opts.backgroundOpacity / 100}; - return Sre.getHighlighter( - background, foreground, - {renderer: this.document.outputJax.name, browser: 'v3'}); - } + public Update(_force: boolean = false): void {} /** * Stops the events of this explorer from bubbling. + * * @param {Event} event The event to stop. */ protected stopEvent(event: Event) { @@ -278,5 +276,4 @@ export class AbstractExplorer implements Explorer { AbstractExplorer.stopEvent(event); } } - } diff --git a/ts/a11y/explorer/ExplorerPool.ts b/ts/a11y/explorer/ExplorerPool.ts new file mode 100644 index 000000000..f497f1575 --- /dev/null +++ b/ts/a11y/explorer/ExplorerPool.ts @@ -0,0 +1,430 @@ +/************************************************************* + * + * COPYRIGHT (c) 2022-2024 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Class for handling all explorers on a single Math Item. + * + * @author v.sorge@mathjax.org (Volker Sorge) + */ + +import { LiveRegion, SpeechRegion, ToolTip, HoverRegion } from './Region.js'; +import type { ExplorerMathDocument, ExplorerMathItem } from '../explorer.js'; + +import { Explorer } from './Explorer.js'; +import { SpeechExplorer } from './KeyExplorer.js'; +import * as me from './MouseExplorer.js'; +import { TreeColorer, FlameColorer } from './TreeExplorer.js'; + +import { Highlighter, getHighlighter } from './Highlighter.js'; +// import * as Sre from '../sre.js'; + +/** + * The regions objects needed for the explorers. + */ +export class RegionPool { + /** + * The speech region. + */ + public speechRegion: SpeechRegion = new SpeechRegion(this.document); + + /** + * The Braille region. + */ + public brailleRegion: LiveRegion = new LiveRegion(this.document); + + /** + * Hover region for all magnifiers. + */ + public magnifier: HoverRegion = new HoverRegion(this.document); + + /** + * A tooltip region. + */ + public tooltip1: ToolTip = new ToolTip(this.document); + + /** + * A tooltip region. + */ + public tooltip2: ToolTip = new ToolTip(this.document); + + /** + * A tooltip region. + */ + public tooltip3: ToolTip = new ToolTip(this.document); + + /** + * @param {ExplorerMathDocument} document The document the handler belongs to. + */ + constructor(public document: ExplorerMathDocument) {} +} + +/** + * Type of explorer initialization methods. + * + * @type {(doc: ExplorerMathDocument, + * pool: ExplorerPool, + * node: HTMLElement, + * ...rest: any[] + * ) => Explorer} + */ +type ExplorerInit = ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ...rest: any[] +) => Explorer; + +/** + * Generation methods for all MathJax explorers available via option settings. + */ +const allExplorers: { [options: string]: ExplorerInit } = { + speech: ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ...rest: any[] + ) => { + const explorer = SpeechExplorer.create( + doc, + pool, + doc.explorerRegions.speechRegion, + node, + doc.explorerRegions.brailleRegion, + doc.explorerRegions.magnifier, + rest[0], + rest[1] + ) as SpeechExplorer; + explorer.sound = true; + return explorer; + }, + mouseMagnifier: ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ..._rest: any[] + ) => + me.ContentHoverer.create( + doc, + pool, + doc.explorerRegions.magnifier, + node, + (x: HTMLElement) => x.hasAttribute('data-semantic-type'), + (x: HTMLElement) => x + ), + hover: ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ..._rest: any[] + ) => me.FlameHoverer.create(doc, pool, null, node), + infoType: ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ..._rest: any[] + ) => + me.ValueHoverer.create( + doc, + pool, + doc.explorerRegions.tooltip1, + node, + (x: HTMLElement) => x.hasAttribute('data-semantic-type'), + (x: HTMLElement) => x.getAttribute('data-semantic-type') + ), + infoRole: ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ..._rest: any[] + ) => + me.ValueHoverer.create( + doc, + pool, + doc.explorerRegions.tooltip2, + node, + (x: HTMLElement) => x.hasAttribute('data-semantic-role'), + (x: HTMLElement) => x.getAttribute('data-semantic-role') + ), + infoPrefix: ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ..._rest: any[] + ) => + me.ValueHoverer.create( + doc, + pool, + doc.explorerRegions.tooltip3, + node, + (x: HTMLElement) => x.hasAttribute?.('data-semantic-prefix-none'), + (x: HTMLElement) => x.getAttribute?.('data-semantic-prefix-none') + ), + flame: ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ..._rest: any[] + ) => FlameColorer.create(doc, pool, null, node), + treeColoring: ( + doc: ExplorerMathDocument, + pool: ExplorerPool, + node: HTMLElement, + ...rest: any[] + ) => TreeColorer.create(doc, pool, null, node, ...rest), +}; + +/** + * Class to bundle and handle all explorers on a Math item. This in particular + * means that all explorer share the same highlighter, meaning that there is no + * uncontrolled interaction between highlighting of different explorers. + */ +export class ExplorerPool { + /** + * A highlighter that is used to mark nodes during auto voicing. + */ + public secondaryHighlighter: Highlighter; + + /** + * The explorer dictionary. + */ + public explorers: { [key: string]: Explorer } = {}; + + /** + * The currently attached explorers + */ + protected attached: string[] = []; + + /** + * The target document. + */ + protected document: ExplorerMathDocument; + + /** + * The node explorers will be attached to. + */ + protected node: HTMLElement; + + /** + * The corresponding Mathml node as a string. + */ + protected mml: string; + + /** + * The primary highlighter shared by all explorers. + */ + private _highlighter: Highlighter; + + /** + * The name of the current output jax. + */ + private _renderer: string; + + /** + * All explorers that need to be restarted on a rerendered element. + */ + private _restart: string[] = []; + + /** + * @returns {Highlighter} The primary highlighter shared by all explorers. + */ + public get highlighter(): Highlighter { + if (this._renderer !== this.document.outputJax.name) { + this._renderer = this.document.outputJax.name; + this.setPrimaryHighlighter(); + return this._highlighter; + } + const [foreground, background] = this.colorOptions(); + this._highlighter.setColor(background, foreground); + return this._highlighter; + } + + /** + * @param {ExplorerMathDocument} document The target document. + * @param {HTMLElement} node The node explorers will be attached to. + * @param {string} mml The corresponding Mathml node as a string. + * @param {ExplorerMathItem} item The current math item. + */ + public init( + document: ExplorerMathDocument, + node: HTMLElement, + mml: string, + item: ExplorerMathItem + ) { + this.document = document; + this.mml = mml; + this.node = node; + this.setPrimaryHighlighter(); + for (const key of Object.keys(allExplorers)) { + this.explorers[key] = allExplorers[key]( + this.document, + this, + this.node, + this.mml, + item + ); + } + this.setSecondaryHighlighter(); + this.attach(); + } + + /** + * A11y options keys associated with the speech explorer. + */ + private speechExplorerKeys = ['speech', 'braille', 'keyMagnifier']; + + /** + * Attaches the explorers that are currently meant to be active given + * the document options. Detaches all others. + */ + public attach() { + this.attached = []; + const keyExplorers = []; + const a11y = this.document.options.a11y; + for (const [key, explorer] of Object.entries(this.explorers)) { + if (explorer instanceof SpeechExplorer) { + explorer.stoppable = false; + keyExplorers.unshift(explorer); + if ( + this.speechExplorerKeys.some( + (exKey) => this.document.options.a11y[exKey] + ) + ) { + explorer.Attach(); + this.attached.push(key); + } else { + explorer.Detach(); + } + continue; + } + if ( + a11y[key] || + (key === 'speech' && (a11y.braille || a11y.keyMagnifier)) + ) { + explorer.Attach(); + this.attached.push(key); + } else { + explorer.Detach(); + } + } + // Ensure that the last currently attached key explorer stops propagating + // key events. + for (const explorer of keyExplorers) { + if (explorer.attached) { + explorer.stoppable = true; + break; + } + } + } + + /** + * Computes the explorers that need to be reattached after a MathItem is + * rerendered. + */ + public reattach() { + for (const key of this.attached) { + const explorer = this.explorers[key]; + if (explorer.active) { + this._restart.push(key); + explorer.Stop(); + } + } + } + + /** + * Restarts explorers after a MathItem is rerendered. + */ + public restart() { + this._restart.forEach((x) => { + this.explorers[x].Start(); + }); + this._restart = []; + } + + /** + * A highlighter for the explorer. + */ + protected setPrimaryHighlighter() { + const [foreground, background] = this.colorOptions(); + this._highlighter = getHighlighter( + background, + foreground, + this.document.outputJax.name + ); + } + + /** + * Sets the secondary highlighter for marking nodes during autovoicing. + */ + protected setSecondaryHighlighter() { + this.secondaryHighlighter = getHighlighter( + { color: 'red' }, + { color: 'black' }, + this.document.outputJax.name + ); + (this.speech.region as SpeechRegion).highlighter = + this.secondaryHighlighter; + } + + /** + * Highlights a set of DOM nodes. + * + * @param {HTMLElement[]} nodes The array of HTML nodes to be highlighted. + */ + public highlight(nodes: HTMLElement[]) { + this.highlighter.highlight(nodes); + } + + /** + * Unhighlights the currently highlighted DOM nodes. + */ + public unhighlight() { + this.secondaryHighlighter.unhighlight(); + this.highlighter.unhighlight(); + } + + /** + * Convenience method to return the speech explorer of the pool with the + * correct type. + * + * @returns {SpeechExplorer} The speech explorer. + */ + public get speech(): SpeechExplorer { + return this.explorers['speech'] as SpeechExplorer; + } + + /** + * Retrieves color assignment for the document options. + * + * @returns {[ { color: string; alpha: number }, { color: string; alpha: + * number } ]} Color assignments for fore and background colors. + */ + private colorOptions(): [ + { color: string; alpha: number }, + { color: string; alpha: number }, + ] { + const opts = this.document.options.a11y; + const foreground = { + color: opts.foregroundColor.toLowerCase(), + alpha: opts.foregroundOpacity / 100, + }; + const background = { + color: opts.backgroundColor.toLowerCase(), + alpha: opts.backgroundOpacity / 100, + }; + return [foreground, background]; + } +} diff --git a/ts/a11y/explorer/Highlighter.ts b/ts/a11y/explorer/Highlighter.ts new file mode 100644 index 000000000..7f520914c --- /dev/null +++ b/ts/a11y/explorer/Highlighter.ts @@ -0,0 +1,486 @@ +// +// Copyright 2025 Volker Sorge +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/** + * @file Highlighter for exploring nodes. + * @author v.sorge@mathjax.org (Volker Sorge) + */ + +interface NamedColor { + color: string; + alpha?: number; +} + +interface ChannelColor { + red: number; + green: number; + blue: number; + alpha?: number; +} + +const namedColors: { [key: string]: ChannelColor } = { + red: { red: 255, green: 0, blue: 0 }, + green: { red: 0, green: 255, blue: 0 }, + blue: { red: 0, green: 0, blue: 255 }, + yellow: { red: 255, green: 255, blue: 0 }, + cyan: { red: 0, green: 255, blue: 255 }, + magenta: { red: 255, green: 0, blue: 255 }, + white: { red: 255, green: 255, blue: 255 }, + black: { red: 0, green: 0, blue: 0 }, +}; + +/** + * Turns a named color into a channel color. + * + * @param {NamedColor} color The definition. + * @param {NamedColor} deflt The default color name if the named color does not exist. + * @returns {string} The channel color. + */ +function getColorString(color: NamedColor, deflt: NamedColor): string { + const channel = namedColors[color.color] || namedColors[deflt.color]; + channel.alpha = color.alpha ?? deflt.alpha; + return rgba(channel); +} + +/** + * RGBa string version of the channel color. + * + * @param {ChannelColor} color The channel color. + * @returns {string} The color in RGBa format. + */ +function rgba(color: ChannelColor): string { + return `rgba(${color.red},${color.green},${color.blue},${color.alpha ?? 1})`; +} + +/** + * The default background color if a none existing color is provided. + */ +const DEFAULT_BACKGROUND: NamedColor = { color: 'blue', alpha: 1 }; + +/** + * The default color if a none existing color is provided. + */ +const DEFAULT_FOREGROUND: NamedColor = { color: 'black', alpha: 1 }; + +export interface Highlighter { + /** + * Sets highlighting on a node. + * + * @param {HTMLElement} nodes The nodes to highlight. + */ + highlight(nodes: HTMLElement[]): void; + + /** + * Unhighlights the last nodes that were highlighted. + */ + unhighlight(): void; + + /** + * Sets highlighting on all maction-like sub nodes of the given node. + * + * @param {HTMLElement} node The node to highlight. + */ + highlightAll(node: HTMLElement): void; + + /** + * Unhighlights all currently highlighted nodes. + */ + unhighlightAll(): void; + + /** + * Predicate to check if a node is an maction node. + * + * @param {Element} node A DOM node. + * @returns {boolean} True if the node is an maction node. + */ + isMactionNode(node: Element): boolean; + + /** + * @returns {string} The foreground color as rgba string. + */ + get foreground(): string; + + /** + * @returns {string} The background color as rgba string. + */ + get background(): string; + + /** + * Sets of the color the highlighter is using. + * + * @param {NamedColor} background The new background color to use. + * @param {NamedColor} foreground The new foreground color to use. + */ + setColor(background: NamedColor, foreground: NamedColor): void; +} + +/** + * Highlight information consisting of node, fore and background color. + */ +interface Highlight { + node: HTMLElement; + background?: string; + foreground?: string; +} + +let counter = 0; + +abstract class AbstractHighlighter implements Highlighter { + /** + * This counter creates a unique highlighter name. This is important in case + * we have more than a single highlighter on a node, e.g., during auto voicing + * with synchronised highlighting. + */ + public counter = counter++; + + /** + * The Attribute for marking highlighted nodes. + */ + protected ATTR = 'sre-highlight-' + this.counter.toString(); + + /** + * The foreground color. + */ + private _foreground: string; + + /** + * The background color. + */ + private _background: string; + + /** + * The maction name/class for a highlighter. + */ + protected mactionName = ''; + + /** + * List of currently highlighted nodes and their original background color. + */ + private currentHighlights: Highlight[][] = []; + + /** + * Highlights a single node. + * + * @param node The node to be highlighted. + * @returns The old node information. + */ + protected abstract highlightNode(node: HTMLElement): Highlight; + + /** + * Unhighlights a single node. + * + * @param highlight The highlight info for the node to be unhighlighted. + */ + protected abstract unhighlightNode(highlight: Highlight): void; + + /** + * @override + */ + public highlight(nodes: HTMLElement[]) { + this.currentHighlights.push( + nodes.map((node) => { + const info = this.highlightNode(node); + this.setHighlighted(node); + return info; + }) + ); + } + + /** + * @override + */ + public highlightAll(node: HTMLElement) { + const mactions = this.getMactionNodes(node); + for (let i = 0, maction; (maction = mactions[i]); i++) { + this.highlight([maction]); + } + } + + /** + * @override + */ + public unhighlight() { + const nodes = this.currentHighlights.pop(); + if (!nodes) { + return; + } + nodes.forEach((highlight: Highlight) => { + if (this.isHighlighted(highlight.node)) { + this.unhighlightNode(highlight); + this.unsetHighlighted(highlight.node); + } + }); + } + + /** + * @override + */ + public unhighlightAll() { + while (this.currentHighlights.length > 0) { + this.unhighlight(); + } + } + + /** + * @override + */ + public setColor(background: NamedColor, foreground: NamedColor) { + this._foreground = getColorString(foreground, DEFAULT_FOREGROUND); + this._background = getColorString(background, DEFAULT_BACKGROUND); + } + + /** + * @override + */ + public get foreground(): string { + return this._foreground; + } + + /** + * @override + */ + public get background(): string { + return this._background; + } + + /** + * Returns the maction sub nodes of a given node. + * + * @param {HTMLElement} node The root node. + * @returns {HTMLElement[]} The list of maction sub nodes. + */ + public getMactionNodes(node: HTMLElement): HTMLElement[] { + return Array.from( + node.getElementsByClassName(this.mactionName) + ) as HTMLElement[]; + } + + /** + * @override + */ + public isMactionNode(node: Element): boolean { + const className = node.className || node.getAttribute('class'); + return className ? !!className.match(new RegExp(this.mactionName)) : false; + } + + /** + * Check if a node is already highlighted. + * + * @param {HTMLElement} node The node. + * @returns {boolean} True if already highlighted. + */ + public isHighlighted(node: HTMLElement): boolean { + return node.hasAttribute(this.ATTR); + } + + /** + * Sets the indicator attribute that node is already highlighted. + * + * @param {HTMLElement} node The node. + */ + public setHighlighted(node: HTMLElement) { + node.setAttribute(this.ATTR, 'true'); + } + + /** + * Removes the indicator attribute that node is already highlighted. + * + * @param {HTMLElement} node The node. + */ + public unsetHighlighted(node: HTMLElement) { + node.removeAttribute(this.ATTR); + } +} + +class SvgHighlighter extends AbstractHighlighter { + /** + * @override + */ + constructor() { + super(); + this.mactionName = 'maction'; + } + + /** + * @override + */ + public highlightNode(node: HTMLElement) { + let info: Highlight; + if (this.isHighlighted(node)) { + info = { + node: node, + background: this.background, + foreground: this.foreground, + }; + return info; + } + if (node.tagName === 'svg' || node.tagName === 'MJX-CONTAINER') { + info = { + node: node, + background: node.style.backgroundColor, + foreground: node.style.color, + }; + node.style.backgroundColor = this.background; + node.style.color = this.foreground; + return info; + } + // This is a hack for v4. + // TODO: v4 Change + // const rect = (document ?? DomUtil).createElementNS( + const rect = document.createElementNS('http://www.w3.org/2000/svg', 'rect'); + rect.setAttribute( + 'sre-highlighter-added', // Mark highlighting rect. + 'true' + ); + const padding = 40; + const bbox: SVGRect = (node as any as SVGGraphicsElement).getBBox(); + rect.setAttribute('x', (bbox.x - padding).toString()); + rect.setAttribute('y', (bbox.y - padding).toString()); + rect.setAttribute('width', (bbox.width + 2 * padding).toString()); + rect.setAttribute('height', (bbox.height + 2 * padding).toString()); + const transform = node.getAttribute('transform'); + if (transform) { + rect.setAttribute('transform', transform); + } + rect.setAttribute('fill', this.background); + node.setAttribute(this.ATTR, 'true'); + node.parentNode.insertBefore(rect, node); + info = { node: node, foreground: node.getAttribute('fill') }; + if (node.nodeName !== 'rect') { + // We currently do not change foreground of collapsed nodes. + node.setAttribute('fill', this.foreground); + } + return info; + } + + /** + * @override + */ + public setHighlighted(node: HTMLElement) { + if (node.tagName === 'svg') { + super.setHighlighted(node); + } + } + + /** + * @override + */ + public unhighlightNode(info: Highlight) { + const previous = info.node.previousSibling as HTMLElement; + if (previous && previous.hasAttribute('sre-highlighter-added')) { + info.foreground + ? info.node.setAttribute('fill', info.foreground) + : info.node.removeAttribute('fill'); + info.node.parentNode.removeChild(previous); + return; + } + info.node.style.backgroundColor = info.background; + info.node.style.color = info.foreground; + } + + /** + * @override + */ + public isMactionNode(node: HTMLElement) { + return node.getAttribute('data-mml-node') === this.mactionName; + } + + /** + * @override + */ + public getMactionNodes(node: HTMLElement) { + return Array.from( + node.querySelectorAll(`[data-mml-node="${this.mactionName}"]`) + ) as HTMLElement[]; + } +} + +class ChtmlHighlighter extends AbstractHighlighter { + /** + * @override + */ + constructor() { + super(); + this.mactionName = 'mjx-maction'; + } + + /** + * @override + */ + public highlightNode(node: HTMLElement) { + const info = { + node: node, + background: node.style.backgroundColor, + foreground: node.style.color, + }; + if (!this.isHighlighted(node)) { + node.style.backgroundColor = this.background; + node.style.color = this.foreground; + } + return info; + } + + /** + * @override + */ + public unhighlightNode(info: Highlight) { + info.node.style.backgroundColor = info.background; + info.node.style.color = info.foreground; + } + + /** + * @override + */ + public isMactionNode(node: HTMLElement) { + return node.tagName?.toUpperCase() === this.mactionName.toUpperCase(); + } + + /** + * @override + */ + public getMactionNodes(node: HTMLElement) { + return Array.from( + node.getElementsByTagName(this.mactionName) + ) as HTMLElement[]; + } +} + +/** + * Highlighter factory that returns the highlighter that goes with the current + * Mathjax renderer. + * + * @param {NamedColor} back A background color specification. + * @param {NamedColor} fore A foreground color specification. + * @param {string} renderer The renderer name. + * @returns {Highlighter} A new highlighter. + */ +export function getHighlighter( + back: NamedColor, + fore: NamedColor, + renderer: string +): Highlighter { + const highlighter = new highlighterMapping[renderer](); + highlighter.setColor(back, fore); + return highlighter; +} + +/** + * Mapping renderer names to highlighter constructor. + */ +const highlighterMapping: { [key: string]: new () => Highlighter } = { + SVG: SvgHighlighter, + CHTML: ChtmlHighlighter, + generic: ChtmlHighlighter, +}; diff --git a/ts/a11y/explorer/KeyExplorer.ts b/ts/a11y/explorer/KeyExplorer.ts index 3d42e2b3e..943def94d 100644 --- a/ts/a11y/explorer/KeyExplorer.ts +++ b/ts/a11y/explorer/KeyExplorer.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,446 +15,1719 @@ * limitations under the License. */ - /** - * @fileoverview Explorers based on keyboard events. + * @file Explorers based on keyboard events. * * @author v.sorge@mathjax.org (Volker Sorge) */ - -import {A11yDocument, Region} from './Region.js'; -import {Explorer, AbstractExplorer} from './Explorer.js'; -import Sre from '../sre.js'; - +import { HoverRegion, SpeechRegion, LiveRegion } from './Region.js'; +import { STATE } from '../../core/MathItem.js'; +import type { ExplorerMathItem, ExplorerMathDocument } from '../explorer.js'; +import { Explorer, AbstractExplorer } from './Explorer.js'; +import { ExplorerPool } from './ExplorerPool.js'; +import { MmlNode } from '../../core/MmlTree/MmlNode.js'; +import { honk, SemAttr } from '../speech/SpeechUtil.js'; +import { GeneratorPool } from '../speech/GeneratorPool.js'; +import { context } from '../../util/context.js'; /** * Interface for keyboard explorers. Adds the necessary keyboard events. + * * @interface - * @extends {Explorer} + * @augments {Explorer} */ export interface KeyExplorer extends Explorer { - /** * Function to be executed on key down. + * * @param {KeyboardEvent} event The keyboard event. */ KeyDown(event: KeyboardEvent): void; /** * Function to be executed on focus in. + * * @param {KeyboardEvent} event The keyboard event. */ FocusIn(event: FocusEvent): void; /** * Function to be executed on focus out. + * * @param {KeyboardEvent} event The keyboard event. */ FocusOut(event: FocusEvent): void; + /** + * A method that is executed if no move is executed. + */ + NoMove(): void; +} + +/**********************************************************************/ + +/** + * Type of function that implements a key press action + */ +type keyMapping = ( + explorer: SpeechExplorer, + event: KeyboardEvent +) => boolean | void; + +/** + * Selectors for walking. + */ +const nav = '[data-speech-node]'; + +/** + * Predicate to check if element is a MJX container. + * + * @param {HTMLElement} el The HTML element. + * @returns {boolean} True if the element is an mjx-container. + */ +export function isContainer(el: HTMLElement): boolean { + return el.matches('mjx-container'); +} + +/** + * Test if an event has any modifier keys + * + * @param {MouseEvent|KeyboardEvent} event The event to check + * @param {boolean} shift True if shift is to be included in check + * @returns {boolean} True if shift, ctrl, alt, or meta key is pressed + */ +export function hasModifiers( + event: MouseEvent | KeyboardEvent, + shift: boolean = true +): boolean { + return ( + (event.shiftKey && shift) || event.metaKey || event.altKey || event.ctrlKey + ); +} + +/**********************************************************************/ + +/** + * Creates a customized help dialog + * + * @param {string} title The title to use for the message + * @param {string} select Additional ways to select the typeset math + * @returns {string} The customized message + */ +function helpMessage(title: string, select: string): string { + return ` +

Exploring expressions ${title}

+ +

The mathematics on this page is being rendered by MathJax, which +generates both the text spoken by screen readers, as well as the +visual layout for sighted users.

+ +

Expressions typeset by MathJax can be explored interactively, and +are focusable. You can use the Tab key to move to a typeset +expression${select}. Initially, the expression will be read in full, +but you can use the following keys to explore the expression +further:

+ +

    + +
  • Down Arrow moves one level deeper into the expression to +allow you to explore the current subexpression term by term.
  • + +
  • Up Arrow moves back up a level within the expression.
  • + +
  • Right Arrow moves to the next term in the current +subexpression.
  • + +
  • Left Arrow moves to the next term in the current +subexpression.
  • + +
  • Shift+Arrow moves to a neighboring cell within a table. + +
  • 0-9+0-9 jumps to a cell by its index in the table, where 0 = 10. + +
  • Home takes you to the top of the expression.
  • + +
  • Enter or Return clicks a link or activates an active +subexpression.
  • + +
  • Space opens the MathJax contextual menu where you can view +or copy the source format of the expression, or modify MathJax's +settings.
  • + +
  • Escape exits the expression explorer.
  • + +
  • x gives a summary of the current subexpression.
  • + +
  • z gives the full text of a collapsed expression.
  • + +
  • d gives the current depth within the expression.
  • + +
  • s starts or stops auto-voicing with synchronized highlighting.
  • + +
  • v marks the current position in the expression.
  • + +
  • p cycles through the marked positions in the expression.
  • + +
  • u clears all marked positions and returns to the starting position.
  • + +
  • > cycles through the available speech rule sets +(MathSpeak, ClearSpeak).
  • + +
  • < cycles through the verbosity levels for the current +rule set.
  • + +
  • h produces this help listing.
  • +
+ +

The MathJax contextual menu allows you to enable or disable speech +or Braille generation for mathematical expressions, the language to +use for the spoken mathematics, and other features of MathJax. In +particular, the Explorer submenu allows you to specify how the +mathematics should be identified in the page (e.g., by saying "math" +when the expression is spoken), and whether or not to include a +message about the letter "h" bringing up this dialog box.

+ +

The contextual menu also provides options for viewing or copying a +MathML version of the expression or its original source format, +creating an SVG version of the expression, and viewing various other +information.

+ +

For more help, see the MathJax accessibility documentation.

+`; } +/** + * Help for the different OS versions + */ +const helpData: Map = new Map([ + [ + 'MacOS', + [ + 'on MacOS and iOS using VoiceOver', + ', or the VoiceOver arrow keys to select an expression', + ], + ], + [ + 'Windows', + [ + 'in Windows using NVDA or JAWS', + `. The screen reader should enter focus or forms mode automatically +when the expression gets the browser focus, but if not, you can toggle +focus mode using NVDA+space in NVDA; for JAWS, Enter should start +forms mode while Numpad Plus leaves it. Also note that you can use +the NVDA or JAWS key plus the arrow keys to explore the expression +even in browse mode, and you can use NVDA+shift+arrow keys to +navigate out of an expression that has the focus in NVDA`, + ], + ], + [ + 'Unix', + [ + 'in Unix using Orca', + `, and Orca should enter focus mode automatically. If not, use the +Orca+a key to toggle focus mode on or off. Also note that you can use +Orca+arrow keys to explore expressions even in browse mode`, + ], + ], + ['unknown', ['with a Screen Reader.', '']], +]); + +/**********************************************************************/ +/**********************************************************************/ /** - * @constructor - * @extends {AbstractExplorer} + * @class + * @augments {AbstractExplorer} * * @template T The type that is consumed by the Region of this explorer. */ -export abstract class AbstractKeyExplorer extends AbstractExplorer implements KeyExplorer { +export class SpeechExplorer + extends AbstractExplorer + implements KeyExplorer +{ + /* + * The explorer key mapping + */ + protected static keyMap: Map = new Map([ + ['Tab', [() => true]], + ['Escape', [(explorer) => explorer.escapeKey()]], + ['Enter', [(explorer, event) => explorer.enterKey(event)]], + ['Home', [(explorer) => explorer.homeKey()]], + [ + 'ArrowDown', + [(explorer, event) => explorer.moveDown(event.shiftKey), true], + ], + ['ArrowUp', [(explorer, event) => explorer.moveUp(event.shiftKey), true]], + [ + 'ArrowLeft', + [(explorer, event) => explorer.moveLeft(event.shiftKey), true], + ], + [ + 'ArrowRight', + [(explorer, event) => explorer.moveRight(event.shiftKey), true], + ], + [' ', [(explorer) => explorer.spaceKey()]], + ['h', [(explorer) => explorer.hKey()]], + ['>', [(explorer) => explorer.nextRules(), false]], + ['<', [(explorer) => explorer.nextStyle(), false]], + ['x', [(explorer) => explorer.summary(), false]], + ['z', [(explorer) => explorer.details(), false]], + ['d', [(explorer) => explorer.depth(), false]], + ['v', [(explorer) => explorer.addMark(), false]], + ['p', [(explorer) => explorer.prevMark(), false]], + ['u', [(explorer) => explorer.clearMarks(), false]], + ['s', [(explorer) => explorer.autoVoice(), false]], + ...[...'0123456789'].map((n) => [ + n, + [(explorer: SpeechExplorer) => explorer.numberKey(parseInt(n)), false], + ]), + ] as [string, [keyMapping, boolean?]][]); /** - * Flag indicating if the explorer is attached to an object. + * Switches on or off the use of sound on this explorer. */ - public attached: boolean = false; + public sound: boolean = false; + + /** + * Convenience getter for generator pool of the item. + * + * @returns {GeneratorPool} The item's generator pool. + */ + private get generators(): GeneratorPool { + return this.item?.generatorPool; + } + + /** + * Shorthand for the item's speech ARIA role + * + * @returns {string} The role + */ + protected get role(): string { + return this.item.ariaRole; + } + + /** + * Shorthand for the item's ARIA role description + * + * @returns {string} The role description + */ + protected get description(): string { + return this.item.roleDescription; + } + + /** + * Shorthand for the item's "none" indicator + * + * @returns {string} The string to use for no description + */ + protected get none(): string { + return this.item.none; + } + + /** + * The currently focused element. + */ + protected current: HTMLElement = null; + + /** + * The clicked node from a mousedown event + */ + protected clicked: HTMLElement = null; + + /** + * Node to focus on when restarted + */ + public refocus: HTMLElement = null; + + /** + * True when we are refocusing on the speech node + */ + protected focusSpeech: boolean = false; + + /** + * Selector string for re-focusing after re-rendering + */ + public restarted: string = null; + + /** + * The transient speech node + */ + protected speech: HTMLElement = null; + + /** + * Set to 'd' when depth is showing, 'x' when summary, '' when speech. + */ + protected speechType: string = ''; /** - * The attached Sre walker. - * @type {Walker} + * The speech node when the top-level node has no role */ - protected walker: Sre.walker; + protected img: HTMLElement = null; + /** + * True when explorer is attached to a node + */ + public attached: boolean = false; + + /** + * Treu if events of the explorer are attached. + */ private eventsAttached: boolean = false; /** - * @override + * The array of saved positions. */ - protected events: [string, (x: Event) => void][] = - super.Events().concat( - [['keydown', this.KeyDown.bind(this)], - ['focusin', this.FocusIn.bind(this)], - ['focusout', this.FocusOut.bind(this)]]); + protected marks: HTMLElement[] = []; /** - * The original tabindex value before explorer was attached. - * @type {boolean} + * The index of the current position in the array. + */ + protected currentMark: number = -1; + + /** + * The last explored position from previously exploring this + * expression. + */ + protected lastMark: HTMLElement = null; + + /** + * First index of cell to jump to + */ + protected pendingIndex: number[] = []; + + /** + * The possible types for a "table" cell + */ + protected cellTypes: string[] = ['cell', 'line']; + + /********************************************************************/ + /* + * The event handlers */ - private oldIndex: number = null; /** * @override */ - public abstract KeyDown(event: KeyboardEvent): void; + protected events: [string, (x: Event) => void][] = super.Events().concat([ + ['focusin', this.FocusIn.bind(this)], + ['focusout', this.FocusOut.bind(this)], + ['keydown', this.KeyDown.bind(this)], + ['mousedown', this.MouseDown.bind(this)], + ['click', this.Click.bind(this)], + ['dblclick', this.DblClick.bind(this)], + ]); /** * @override */ public FocusIn(_event: FocusEvent) { + if (this.item.outputData.nofocus) { + // + // we are refocusing after a menu or dialog box has closed + // + this.item.outputData.nofocus = false; + return; + } + if (!this.clicked) { + this.Start(); + } + this.clicked = null; } /** * @override */ public FocusOut(_event: FocusEvent) { - this.Stop(); + if (this.current && !this.focusSpeech) { + this.setCurrent(null); + this.Stop(); + if (!document.hasFocus()) { + this.focusTop(); + } + } } /** * @override */ - public Update(force: boolean = false) { - if (!this.active && !force) return; - this.highlighter.unhighlight(); - let nodes = this.walker.getFocus(true).getNodes(); - if (!nodes.length) { - this.walker.refocus(); - nodes = this.walker.getFocus().getNodes(); + public KeyDown(event: KeyboardEvent) { + this.pendingIndex.shift(); + this.region.cancelVoice(); + // + if (hasModifiers(event, false)) return; + // + // Get the key action, if there is one and perform it + // + const CLASS = this.constructor as typeof SpeechExplorer; + const key = event.key.length === 1 ? event.key.toLowerCase() : event.key; + const [action, value] = CLASS.keyMap.get(key) || []; + const result = action + ? value === undefined || this.active + ? action(this, event) + : value + : this.undefinedKey(event); + // + // If result is true, propagate event, + // Otherwise stop the event, and if false, play the honk sound + // + if (result) return; + this.stopEvent(event); + if (result === false && this.sound) { + this.NoMove(); } - this.highlighter.highlight(nodes as HTMLElement[]); } /** - * @override + * Handle clicks that perform selections, and keep track of clicked node + * so that the focusin event will know something was clicked. + * + * @param {MouseEvent} event The mouse down event */ - public Attach() { - super.Attach(); - this.attached = true; - this.oldIndex = this.node.tabIndex; - this.node.tabIndex = 1; - this.node.setAttribute('role', 'application'); + private MouseDown(event: MouseEvent) { + this.pendingIndex = []; + this.region.cancelVoice(); + // + if (hasModifiers(event) || event.buttons === 2) { + this.item.outputData.nofocus = true; + return; + } + // + // Get the speech element that was clicked + // + const clicked = this.findClicked( + event.target as HTMLElement, + event.x, + event.y + ); + // + // If it is the info icon, top the event and let the click handler process it + // + if (clicked === this.document.infoIcon) { + this.stopEvent(event); + return; + } + // + // Remove any selection ranges and + // If the target is the highlight rectangle, refocus on the clicked element + // otherwise record the click for the focusin handler + // + document.getSelection()?.removeAllRanges(); + if ((event.target as HTMLElement).getAttribute('sre-highlighter-added')) { + this.refocus = clicked; + } else { + this.clicked = clicked; + } } /** - * @override + * Handle a click event + * + * @param {MouseEvent} event The mouse click event */ - public AddEvents() { - if (!this.eventsAttached) { - super.AddEvents(); - this.eventsAttached = true; + public Click(event: MouseEvent) { + // + // If we are extending a click region, focus out + // + if ( + hasModifiers(event) || + event.buttons === 2 || + document.getSelection().type === 'Range' + ) { + this.FocusOut(null); + return; + } + // + // Get the speech element that was clicked + // + const clicked = this.findClicked( + event.target as HTMLElement, + event.x, + event.y + ); + // + // If it was the info icon, open the help dialog + // + if (clicked === this.document.infoIcon) { + this.stopEvent(event); + this.help(); + return; + } + // + // If the node contains the clicked element, + // don't propagate the event + // focus on the clicked element when focusin occurs + // start the explorer if this isn't a link + // + if (!clicked || this.node.contains(clicked)) { + this.stopEvent(event); + this.refocus = clicked; + if (!this.triggerLinkMouse()) { + this.Start(); + } } } /** - * @override + * Handle a double-click event (focus full expression) + * + * @param {MouseEvent} event The mouse click event */ - public Detach() { - if (this.active) { - this.node.tabIndex = this.oldIndex; - this.oldIndex = null; - this.node.removeAttribute('role'); + public DblClick(event: MouseEvent) { + const direction = (document.getSelection() as any).direction ?? 'none'; + if (hasModifiers(event) || event.buttons === 2 || direction !== 'none') { + this.FocusOut(null); + } else { + this.stopEvent(event); + this.refocus = this.rootNode(); + this.Start(); } - this.attached = false; + } + + /********************************************************************/ + /* + * The Key action functions + */ + + /** + * The space key opens the menu, so it propagates, but we retain the + * current focus to refocus it when the menu closes. + * + * @returns {boolean} Don't cancel the event + */ + protected spaceKey(): boolean { + this.refocus = this.current; + return true; } /** - * @override + * Open the help dialog, and refocus when it closes. */ - public Stop() { + protected hKey() { + this.refocus = this.current; + this.help(); + } + + /** + * Stop exploring and focus the top element + * + * @returns {boolean} Don't cancel the event + */ + protected escapeKey(): boolean { + this.Stop(); + this.focusTop(); + return true; + } + + /** + * Process Enter key events + * + * @param {KeyboardEvent} event The event for the enter key + * @returns {void | boolean} False means play the honk sound + */ + protected enterKey(event: KeyboardEvent): void | boolean { if (this.active) { - this.highlighter.unhighlight(); - this.walker.deactivate(); + if (this.triggerLinkKeyboard(event)) { + this.Stop(); + } else { + const expandable = this.actionable(this.current); + if (!expandable) { + return false; + } + this.refocus = expandable; + expandable.dispatchEvent(new Event('click')); + } + } else { + this.Start(); } - super.Stop(); } -} + /** + * Select top-level of expression + */ + protected homeKey() { + this.setCurrent(this.rootNode()); + } + /** + * Move to deeper level in the expression + * + * @param {boolean} shift True if shift is pressed + * @returns {boolean | void} False if no node, void otherwise + */ + protected moveDown(shift: boolean): boolean | void { + return shift + ? this.moveToNeighborCell(1, 0) + : this.moveTo(this.firstNode(this.current)); + } -/** - * Explorer that pushes speech to live region. - * @constructor - * @extends {AbstractKeyExplorer} - */ -export class SpeechExplorer extends AbstractKeyExplorer { + /** + * Move to higher level in expression + * + * @param {boolean} shift True if shift is pressed + * @returns {boolean | void} False if no node, void otherwise + */ + protected moveUp(shift: boolean): boolean | void { + return shift + ? this.moveToNeighborCell(-1, 0) + : this.moveTo(this.getParent(this.current)); + } - private static updatePromise = Promise.resolve(); + /** + * Move to next term in the expression + * + * @param {boolean} shift True if shift is pressed + * @returns {boolean | void} False if no node, void otherwise + */ + protected moveRight(shift: boolean): boolean | void { + return shift + ? this.moveToNeighborCell(0, 1) + : this.moveTo(this.nextSibling(this.current)); + } /** - * The Sre speech generator associated with the walker. - * @type {SpeechGenerator} + * Move to previous term in the expression + * + * @param {boolean} shift True if shift is pressed + * @returns {boolean | void} False if no node, void otherwise */ - public speechGenerator: Sre.speechGenerator; + protected moveLeft(shift: boolean): boolean | void { + return shift + ? this.moveToNeighborCell(0, -1) + : this.moveTo(this.prevSibling(this.current)); + } /** - * The name of the option used to control when this is being shown - * @type {string} + * Move to a specified node, unless it is null + * + * @param {HTMLElement} node The node to move it + * @returns {boolean | void} False if no node, void otherwise */ - public showRegion: string = 'subtitles'; + protected moveTo(node: HTMLElement): void | boolean { + if (!node) return false; + this.setCurrent(node); + } - private init: boolean = false; + /** + * Move to an adjacent table cell + * + * @param {number} di Change in row number + * @param {number} dj Change in column number + * @returns {boolean | void} False if no such cell, void otherwise + */ + protected moveToNeighborCell(di: number, dj: number): boolean | void { + const cell = this.tableCell(this.current); + if (!cell) return false; + const [i, j] = this.cellPosition(cell); + if (i == null) return false; + const move = this.cellAt(this.cellTable(cell), i + di, j + dj); + if (!move) return false; + this.setCurrent(move); + } /** - * Flag in case the start method is triggered before the walker is fully - * initialised. I.e., we have to wait for Sre. Then region is re-shown if - * necessary, as otherwise it leads to incorrect stacking. - * @type {boolean} + * Determine if an event that is not otherwise mapped should be + * allowed to propagate. + * + * @param {KeyboardEvent} event The event to check + * @returns {boolean} True if not active or the event has a modifier */ - private restarted: boolean = false; + protected undefinedKey(event: KeyboardEvent): boolean { + return !this.active || hasModifiers(event); + } /** - * @constructor - * @extends {AbstractKeyExplorer} + * Mark a location so we can return to it later */ - constructor(public document: A11yDocument, - protected region: Region, - protected node: HTMLElement, - private mml: string) { - super(document, region, node); - this.initWalker(); + protected addMark() { + if (this.current === this.marks[this.marks.length - 1]) { + this.setCurrent(this.current); + } else { + this.currentMark = this.marks.length - 1; + this.marks.push(this.current); + this.speak('Position marked'); + } } + /** + * Return to a previous location (loop through them). + * If no saved marks, go to the last previous position, + * or if not, the top level. + */ + protected prevMark() { + if (this.currentMark < 0) { + if (this.marks.length === 0) { + this.setCurrent(this.lastMark || this.rootNode()); + return; + } + this.currentMark = this.marks.length - 1; + } + const current = this.currentMark; + this.setCurrent(this.marks[current]); + this.currentMark = current - 1; + } /** - * @override + * Clear all saved positions and return to the last explored position. */ - public Start() { - if (!this.attached) return; - let options = this.getOptions(); - if (!this.init) { - this.init = true; - SpeechExplorer.updatePromise = SpeechExplorer.updatePromise.then(async () => { - return Sre.sreReady() - .then(() => Sre.setupEngine({locale: options.locale})) - .then(() => { - // Important that both are in the same block so speech explorers - // are restarted sequentially. - this.Speech(this.walker); - this.Start(); - }); - }) - .catch((error: Error) => console.log(error.message)); - return; + protected clearMarks() { + this.marks = []; + this.currentMark = -1; + this.prevMark(); + } + + /** + * Toggle auto voicing. + */ + protected autoVoice() { + const value = !this.document.options.a11y.voicing; + if (this.document.menu) { + this.document.menu.menu.pool.lookup('voicing').setValue(value); + } else { + this.document.options.a11y.voicing = value; } - super.Start(); - this.speechGenerator = Sre.getSpeechGenerator('Direct'); - this.speechGenerator.setOptions(options); - this.walker = Sre.getWalker( - 'table', this.node, this.speechGenerator, this.highlighter, this.mml); - this.walker.activate(); this.Update(); - if (this.document.options.a11y[this.showRegion]) { - SpeechExplorer.updatePromise.then( - () => this.region.Show(this.node, this.highlighter)); + } + + /** + * Get index for cell to jump to. + * + * @param {number} n The number key that was pressed + * @returns {boolean|void} False if not in a table or no such cell to jump to. + */ + protected numberKey(n: number): boolean | void { + if (!this.tableCell(this.current)) return false; + if (n === 0) { + n = 10; + } + if (this.pendingIndex.length) { + const table = this.cellTable(this.tableCell(this.current)); + const cell = this.cellAt(table, this.pendingIndex[0] - 1, n - 1); + this.pendingIndex = []; + this.speak(String(n)); + if (!cell) return false; + setTimeout(() => this.setCurrent(cell), 500); + } else { + this.pendingIndex = [null, n]; + this.speak(`Jump to row ${n} and column`); } - this.restarted = true; } + /** + * Computes the nesting depth announcement for the currently focused sub + * expression. + */ + public depth() { + if (this.speechType === 'd') { + this.setCurrent(this.current); + return; + } + this.speechType = 'd'; + const parts = [ + [ + this.node.getAttribute('data-semantic-level') ?? 'Level', + this.current.getAttribute('aria-level') ?? '0', + ] + .join(' ') + .trim(), + ]; + const action = this.actionable(this.current); + if (action) { + parts.unshift( + this.node.getAttribute( + action.getAttribute('toggle') === '1' + ? 'data-semantic-expandable' + : 'data-semantic-collapsible' + ) ?? '' + ); + } + this.speak(parts.join(' '), this.current.getAttribute(SemAttr.BRAILLE)); + } /** - * @override + * Computes the summary for this expression. */ - public Update(force: boolean = false) { - super.Update(force); - let options = this.speechGenerator.getOptions(); - // This is a necessary in case speech options have changed via keypress - // during walking. - if (options.modality === 'speech') { - this.document.options.sre.domain = options.domain; - this.document.options.sre.style = options.style; - this.document.options.a11y.speechRules = - options.domain + '-' + options.style; - } - SpeechExplorer.updatePromise = SpeechExplorer.updatePromise.then(async () => { - return Sre.sreReady() - .then(() => Sre.setupEngine({modality: options.modality, - locale: options.locale})) - .then(() => this.region.Update(this.walker.speech())); - }); + public summary() { + if (this.speechType === 'x') { + this.setCurrent(this.current); + return; + } + this.speechType = 'x'; + const summary = this.current.getAttribute(SemAttr.SUMMARY); + this.speak( + summary, + this.current.getAttribute(SemAttr.BRAILLE), + this.SsmlAttributes(this.current, SemAttr.SUMMARY_SSML) + ); + } + + /** + * Cycles to next speech rule set if possible and recomputes the speech for + * the expression. + */ + public nextRules() { + this.node.removeAttribute('data-speech-attached'); + this.restartAfter(this.generators.nextRules(this.item)); } + /** + * Cycles to next speech style or preference if possible and recomputes the + * speech for the expression. + */ + public nextStyle() { + this.node.removeAttribute('data-speech-attached'); + this.restartAfter(this.generators.nextStyle(this.current, this.item)); + } /** - * Computes the speech for the current expression once Sre is ready. - * @param {Walker} walker The sre walker. + * Speak the expanded version of a collapsed expression. */ - public Speech(walker: Sre.walker) { - SpeechExplorer.updatePromise.then(() => { - walker.speech(); - this.node.setAttribute('hasspeech', 'true'); - this.Update(); - if (this.restarted && this.document.options.a11y[this.showRegion]) { - this.region.Show(this.node, this.highlighter); + public details() { + // + // If the current node is not collapsible and collapsed, just speak it + // + const action = this.actionable(this.current); + if ( + !action || + !action.getAttribute('data-collapsible') || + action.getAttribute('toggle') !== '1' || + this.speechType === 'z' + ) { + this.setCurrent(this.current); + return; + } + this.speechType = 'z'; + // + // Otherwise, look for the current node in the MathML tree + // + const id = this.nodeId(this.current); + let current: MmlNode; + this.item.root.walkTree((node) => { + if (node.attributes.get('data-semantic-id') === id) { + current = node; } }); + // + // Create a new MathML string from the subtree + // + let mml = this.item.toMathML(current, this.item); + if (!current.isKind('math')) { + mml = `${mml}`; + } + mml = mml.replace( + / (?:data-semantic-|aria-|data-speech-|data-latex).*?=".*?"/g, + '' + ); + // + // Get the speech for the new subtree and speak it. + // + this.item + .speechFor(mml) + .then(([speech, braille]) => this.speak(speech, braille)); } - /** - * @override + * Displays the help dialog. */ - public KeyDown(event: KeyboardEvent) { - const code = event.keyCode; - this.walker.modifier = event.shiftKey; - if (code === 27) { - this.Stop(); + protected help() { + const adaptor = this.document.adaptor; + const helpBackground = adaptor.node('mjx-help-background'); + const close = (event: Event) => { + helpBackground.remove(); + this.node.focus(); this.stopEvent(event); - return; + }; + helpBackground.addEventListener('click', close); + const helpSizer = adaptor.node('mjx-help-sizer', {}, [ + adaptor.node( + 'mjx-help-dialog', + { tabindex: 0, role: 'dialog', 'aria-labeledby': 'mjx-help-label' }, + [ + adaptor.node('h1', { id: 'mjx-help-label' }, [ + adaptor.text('MathJax Expression Explorer Help'), + ]), + adaptor.node('div'), + adaptor.node('input', { type: 'button', value: 'Close' }), + ] + ), + ]); + helpBackground.append(helpSizer); + const help = helpSizer.firstChild as HTMLElement; + help.addEventListener('click', (event) => this.stopEvent(event)); + help.lastChild.addEventListener('click', close); + help.addEventListener('keydown', (event: KeyboardEvent) => { + if (event.code === 'Escape') { + close(event); + } + }); + const [title, select] = helpData.get(context.os); + (help.childNodes[1] as HTMLElement).innerHTML = helpMessage(title, select); + document.body.append(helpBackground); + help.focus(); + } + + /********************************************************************/ + /* + * Methods to handle the currently selected node and its speech + */ + + /** + * Set the currently selected node and speak its label, if requested. + * + * @param {HTMLElement} node The node that should become current + * @param {boolean} addDescription True if the speech node should get a description + */ + protected setCurrent(node: HTMLElement, addDescription: boolean = false) { + this.speechType = ''; + if (!document.hasFocus()) { + this.refocus = this.current; } - if (this.active) { - this.Move(code); - if (this.triggerLink(code)) return; - this.stopEvent(event); - return; + // + // Let AT know we are making changes + // + this.node.setAttribute('aria-busy', 'true'); + // + // If there is a current selection + // clear it and remove the associated speech + // if we aren't setting a new selection + // (i.e., we are focusing out) + // + if (this.current) { + for (const part of this.getSplitNodes(this.current)) { + part.classList.remove('mjx-selected'); + } + this.pool.unhighlight(); + if (this.document.options.a11y.tabSelects === 'last') { + this.refocus = this.current; + } + if (!node) { + this.lastMark = this.current; + this.removeSpeech(); + } + this.current = null; } - if (code === 32 && event.shiftKey || code === 13) { - this.Start(); - this.stopEvent(event); + // + // If there is a current node + // Select it and add its speech, if requested + // + this.current = node; + this.currentMark = -1; + if (this.current) { + const parts = this.getSplitNodes(this.current); + for (const part of parts) { + part.classList.add('mjx-selected'); + } + this.pool.highlight(parts); + this.addSpeech(node, addDescription); } + // + // Done making changes + // + this.node.removeAttribute('aria-busy'); } /** - * Programmatically triggers a link if the focused node contains one. - * @param {number} code The keycode of the last key pressed. + * Get all nodes with the same semantic id (multiple nodes if there are line breaks). + * + * @param {HTMLElement} node The node to check if it is split + * @returns {HTMLElement[]} All the nodes for the given id */ - protected triggerLink(code: number) { - if (code !== 13) { - return false; + protected getSplitNodes(node: HTMLElement): HTMLElement[] { + const id = this.nodeId(node); + if (!id) { + return [node]; } - let node = this.walker.getFocus().getNodes()?.[0]; - let focus = node?. - getAttribute('data-semantic-postfix')?. - match(/(^| )link($| )/); - if (focus) { - node.parentNode.dispatchEvent(new MouseEvent('click')); - return true; + return Array.from(this.node.querySelectorAll(`[data-semantic-id="${id}"]`)); + } + + /** + * Remove the top-level speech node and create + * a temporary one for the given node. + * + * @param {HTMLElement} node The node to be spoken + * @param {boolean} describe True if the description should be added + */ + protected addSpeech(node: HTMLElement, describe: boolean) { + this.img?.remove(); + let speech = [ + node.getAttribute(SemAttr.PREFIX), + node.getAttribute(SemAttr.SPEECH), + node.getAttribute(SemAttr.POSTFIX), + ] + .join(' ') + .trim(); + if (describe) { + let description = + this.description === this.none ? '' : ', ' + this.description; + if (this.document.options.a11y.help) { + description += ', press h for help'; + } + speech += description; } - return false; + this.speak( + speech, + node.getAttribute(SemAttr.BRAILLE), + this.SsmlAttributes(node, SemAttr.SPEECH_SSML) + ); + this.node.setAttribute('tabindex', '-1'); } /** - * @override + * If there is a speech node, remove it + * and put back the top-level node, if needed. + */ + protected removeSpeech() { + if (this.speech) { + this.speech.remove(); + this.speech = null; + if (this.img) { + this.node.append(this.img); + } + this.node.setAttribute('tabindex', '0'); + } + } + + /** + * Create a new speech node and sets its needed attributes, + * then add it to the container and focus it. If there is + * and old speech node, remove it after a delay (the delay + * is needed for Orca on Linux). + * + * @param {string} speech The string to speak + * @param {string} braille The braille string + * @param {string[]} ssml The SSML attributes to add + * @param {string} description The description to add to the speech */ - public Move(key: number) { - this.walker.move(key); + public speak( + speech: string, + braille: string = '', + ssml: string[] = null, + description: string = this.none + ) { + const oldspeech = this.speech; + this.speech = document.createElement('mjx-speech'); + this.speech.setAttribute('role', this.role); + this.speech.setAttribute('aria-label', speech); + this.speech.setAttribute(SemAttr.SPEECH, speech); + if (ssml) { + this.speech.setAttribute(SemAttr.PREFIX_SSML, ssml[0] || ''); + this.speech.setAttribute(SemAttr.SPEECH_SSML, ssml[1] || ''); + this.speech.setAttribute(SemAttr.POSTFIX_SSML, ssml[2] || ''); + } + if (braille) { + this.speech.setAttribute('aria-braillelabel', braille); + } + this.speech.setAttribute('aria-roledescription', description); + this.speech.setAttribute('tabindex', '0'); + this.node.append(this.speech); + this.focusSpeech = true; + this.speech.focus(); + this.focusSpeech = false; this.Update(); + if (oldspeech) { + setTimeout(() => oldspeech.remove(), 100); + } } /** - * Initialises the Sre walker. + * Set up the MathItem output to handle the speech exploration */ - private initWalker() { - this.speechGenerator = Sre.getSpeechGenerator('Tree'); - let dummy = Sre.getWalker( - 'dummy', this.node, this.speechGenerator, this.highlighter, this.mml); - this.walker = dummy; + public attachSpeech() { + const item = this.item; + const container = this.node; + if (!container.hasAttribute('has-speech')) { + for (const child of Array.from(container.childNodes) as HTMLElement[]) { + child.setAttribute('aria-hidden', 'true'); // hide the content + } + container.setAttribute('has-speech', 'true'); + } + const description = item.roleDescription; + const speech = + (container.getAttribute(SemAttr.SPEECH) || '') + + (description ? ', ' + description : ''); + this.img?.remove(); + this.img = this.document.adaptor.node('mjx-speech', { + 'aria-label': speech, + role: 'img', + 'aria-roledescription': item.none, + }); + container.appendChild(this.img); } /** - * Retrieves the speech options to sync with document options. - * @return {{[key: string]: string}} The options settings for the speech - * generator. + * Undo any changes from attachSpeech() */ - private getOptions(): {[key: string]: string} { - let options = this.speechGenerator.getOptions(); - let sreOptions = this.document.options.sre; - if (options.modality === 'speech' && - (options.locale !== sreOptions.locale || - options.domain !== sreOptions.domain || - options.style !== sreOptions.style)) { - options.domain = sreOptions.domain; - options.style = sreOptions.style; - options.locale = sreOptions.locale; - this.walker.update(options); + public detachSpeech() { + const container = this.node; + this.img?.remove(); + container.removeAttribute('has-speech'); + for (const child of Array.from(container.childNodes) as HTMLElement[]) { + child.removeAttribute('aria-hidden'); } - return options; } -} + /** + * Set focus on the current node + */ + public focus() { + this.node.focus(); + } + /********************************************************************/ + /* + * Utility functions + */ -/** - * Explorer that magnifies what is currently explored. Uses a hover region. - * @constructor - * @extends {AbstractKeyExplorer} - */ -export class Magnifier extends AbstractKeyExplorer { + /** + * @param {HTMLElement} node The node whose ID we want + * @returns {string} The node's semantic ID + */ + protected nodeId(node: HTMLElement): string { + return node.getAttribute('data-semantic-id'); + } /** - * @constructor - * @extends {AbstractKeyExplorer} + * @param {HTMLElement} node The node whose parent ID we want + * @returns {string} The node's parent's semantic ID */ - constructor(public document: A11yDocument, - protected region: Region, - protected node: HTMLElement, - private mml: string) { - super(document, region, node); - this.walker = Sre.getWalker( - 'table', this.node, Sre.getSpeechGenerator('Dummy'), - this.highlighter, this.mml); + protected parentId(node: HTMLElement): string { + return node.getAttribute('data-semantic-parent'); } /** - * @override + * @param {string} id The semantic ID of the node we want + * @returns {HTMLElement} The HTML node with that id + */ + protected getNode(id: string): HTMLElement { + return id ? this.node.querySelector(`[data-semantic-id="${id}"]`) : null; + } + + /** + * @param {HTMLElement} node The HTML node whose parent is to be found + * @returns {HTMLElement} The HTML node of the parent node + */ + protected getParent(node: HTMLElement): HTMLElement { + return this.getNode(this.parentId(node)); + } + + /** + * @param {HTMLElement} node The node whose child array we want + * @returns {string[]} The array of semantic IDs of its children + */ + protected childArray(node: HTMLElement): string[] { + return node ? node.getAttribute('data-semantic-children').split(/,/) : []; + } + + /** + * @param {HTMLElement} node The node to check for being a cell node + * @returns {boolean} True if the node is a cell node + */ + protected isCell(node: HTMLElement): boolean { + return ( + !!node && this.cellTypes.includes(node.getAttribute('data-semantic-type')) + ); + } + + /** + * @param {HTMLElement} node The node to check for being a row node + * @returns {boolean} True if the node is a row node + */ + protected isRow(node: HTMLElement): boolean { + return !!node && node.getAttribute('data-semantic-type') === 'row'; + } + + /** + * @param {HTMLElement} node A node that may be in a table cell + * @returns {HTMLElement} The HTML node for the table cell containing it, or null */ - public Update(force: boolean = false) { - super.Update(force); - this.showFocus(); + protected tableCell(node: HTMLElement): HTMLElement { + while (node && node !== this.node) { + if (this.isCell(node)) { + return node; + } + node = node.parentNode as HTMLElement; + } + return null; + } + + /** + * @param {HTMLElement} cell An HTML node that is a cell of a table + * @returns {HTMLElement} The HTML node for semantic table element containing the cell + */ + protected cellTable(cell: HTMLElement): HTMLElement { + const row = this.getParent(cell); + return this.isRow(row) ? this.getParent(row) : row; + } + + /** + * @param {HTMLElement} cell The HTML node for a semantic table cell + * @returns {[number, number]} The row and column numbers for the cell in its table (0-based) + */ + protected cellPosition(cell: HTMLElement): [number, number] { + const row = this.getParent(cell); + const j = this.childArray(row).indexOf(this.nodeId(cell)); + if (!this.isRow(row)) { + return [j, 1]; + } + const table = this.getParent(row); + const i = this.childArray(table).indexOf(this.nodeId(row)); + return [i, j]; + } + + /** + * @param {HTMLElement} table An HTML node for a semantic table element + * @param {number} i The row number of the desired cell in the table + * @param {number} j The column numnber of the desired cell in the table + * @returns {HTMLElement} The HTML element for the (i,j)-th cell of the table + */ + protected cellAt(table: HTMLElement, i: number, j: number): HTMLElement { + const row = this.getNode(this.childArray(table)[i]); + if (!this.isRow(row)) { + return j === 1 ? row : null; + } + const cell = this.getNode(this.childArray(row)[j]); + return cell; + } + + /** + * Get an element's first speech child. This is computed by going through the + * owns list until the first speech element is found. + * + * @param {HTMLElement} node The parent element to get a child from + * @returns {HTMLElement} The first speech child of the node + */ + protected firstNode(node: HTMLElement): HTMLElement { + const owns = node.getAttribute('data-semantic-owns'); + if (!owns) { + return node.querySelector(nav) as HTMLElement; + } + const ownsList = owns.split(/ /); + for (const id of ownsList) { + const node = this.getNode(id); + if (node?.hasAttribute('data-speech-node')) { + return node; + } + } + return node.querySelector(nav) as HTMLElement; } + /** + * Get the element's semantic root node. We compute this from the root id + * given in the semantic structure. The semantic structure is an sexp either + * of the form `0` or `(0 1 (2 ...) ...)`. We can safely assume that the root + * node contains the speech for the entire structure. + * + * If for some reason the semantic structure is not available, we return the + * first speech node found in the expression. + * + * @returns {HTMLElement} The semantic root or first speech node. + */ + protected rootNode(): HTMLElement { + const base = this.node.querySelector('[data-semantic-structure]'); + if (!base) { + return this.node.querySelector(nav) as HTMLElement; + } + const id = base + .getAttribute('data-semantic-structure') + .split(/ /)[0] + .replace('(', ''); + return this.getNode(id); + } + + /** + * Navigate one step to the right on the same level. + * + * @param {HTMLElement} node The current element. + * @returns {HTMLElement} The next element. + */ + protected nextSibling(node: HTMLElement): HTMLElement { + const id = this.parentId(node); + if (!id) return null; + const owns = this.getNode(id) + .getAttribute('data-semantic-owns') + ?.split(/ /); + if (!owns) return null; + let i = owns.indexOf(this.nodeId(node)); + let next; + do { + next = this.getNode(owns[++i]); + } while (next && !next.hasAttribute('data-speech-node')); + return next; + } + + /** + * Navigate one step to the left on the same level. + * + * @param {HTMLElement} node The current element. + * @returns {HTMLElement} The next element. + */ + protected prevSibling(node: HTMLElement): HTMLElement { + const id = this.parentId(node); + if (!id) return null; + const owns = this.getNode(id) + .getAttribute('data-semantic-owns') + ?.split(/ /); + if (!owns) return null; + let i = owns.indexOf(this.nodeId(node)); + let prev; + do { + prev = this.getNode(owns[--i]); + } while (prev && !prev.hasAttribute('data-speech-node')); + return prev; + } + + /** + * Find the speech node that was clicked, if any + * + * @param {HTMLElement} node The target node that was clicked + * @param {number} x The x-coordinate of the click + * @param {number} y The y-coordinate of the click + * @returns {HTMLElement} The clicked node or null + */ + protected findClicked(node: HTMLElement, x: number, y: number): HTMLElement { + // + // Check if the click is on the info icon and return that if it is. + // + const icon = this.document.infoIcon; + if (icon === node || icon.contains(node)) { + return icon; + } + // + // For CHTML, get the closest navigable parent element. + // + if (this.node.getAttribute('jax') !== 'SVG') { + return node.closest(nav) as HTMLElement; + } + // + // For SVG, look through the tree to find the element whose bounding box + // contains the click (x,y) position. + // + let found = null; + let clicked = this.node; + while (clicked) { + if (clicked.matches(nav)) { + found = clicked; // could be this node, but check if a child is clicked + } + const nodes = Array.from(clicked.childNodes) as HTMLElement[]; + clicked = null; + for (const child of nodes) { + if ( + child !== this.speech && + child !== this.img && + child.tagName.toLowerCase() !== 'rect' + ) { + const { left, right, top, bottom } = child.getBoundingClientRect(); + if (left <= x && x <= right && top <= y && y <= bottom) { + clicked = child; + break; + } + } + } + } + return found; + } + + /** + * Focus the container node without activating it (e.g., when Escape is pressed) + */ + protected focusTop() { + this.focusSpeech = true; + this.node.focus(); + this.focusSpeech = false; + } + + /** + * Get the SSML attribute array + * + * @param {HTMLElement} node The node whose SSML attributes are to be obtained + * @param {SemAttr} center The name of the SSML attribute between pre and postfix + * @returns {string[]} The prefix/speech or summary/postfix array + */ + protected SsmlAttributes(node: HTMLElement, center: SemAttr): string[] { + return [ + node.getAttribute(SemAttr.PREFIX_SSML), + node.getAttribute(center), + node.getAttribute(SemAttr.POSTFIX_SSML), + ]; + } + + /** + * Restarts the explorer after a promise resolves (e.g., for an maction rerender) + * + * @param {Promise} promise The promise to restart after + */ + protected async restartAfter(promise: Promise) { + await promise; + this.attachSpeech(); + const current = this.current; + this.current = null; + this.pool.unhighlight(); + this.setCurrent(current); + } + + /********************************************************************/ + /* + * Base class overrides + */ + + /** + * @param {ExplorerMathDocument} document The accessible math document. + * @param {ExplorerPool} pool The explorer pool. + * @param {SpeechRegion} region The speech region for the explorer. + * @param {HTMLElement} node The node the explorer is assigned to. + * @param {LiveRegion} brailleRegion The braille region. + * @param {HoverRegion} magnifyRegion The magnification region. + * @param {MmlNode} _mml The internal math node. + * @param {ExplorerMathItem} item The math item. + * @class + * @augments {AbstractExplorer} + */ + constructor( + public document: ExplorerMathDocument, + public pool: ExplorerPool, + public region: SpeechRegion, + protected node: HTMLElement, + public brailleRegion: LiveRegion, + public magnifyRegion: HoverRegion, + _mml: MmlNode, + public item: ExplorerMathItem + ) { + super(document, pool, null, node); + } + + /** + * Determine the node that should be made active when we start + * (the refocus, current, or restarted node, if any otherwise null) + * + * @returns {HTMLElement} The node to be made the current node + */ + protected findStartNode(): HTMLElement { + let node = this.refocus || this.current; + if (!node && this.restarted) { + node = this.node.querySelector(this.restarted); + } + this.refocus = this.restarted = null; + return node; + } /** * @override */ - public Start() { + public async Start() { + // + // If we aren't attached or already active, return + // + if (!this.attached || this.active) return; + this.document.activeItem = this.item; + // + // If there is no speech, request the speech and wait for it + // + if (this.item.state() < STATE.ATTACHSPEECH) { + this.item.attachSpeech(this.document); + await this.generators.promise; + } + // + // If we are respnding to a focusin on the speech node, we are done + // + if (this.focusSpeech) return; + // + // Mark the node as active (for CSS that turns on the info icon) + // and add the info icon. + // + this.node.classList.add('mjx-explorer-active'); + this.node.append(this.document.infoIcon); + // + // Get the node to make current, and determine if we need to add a + // speech node (or just use the top-level node), then set the + // current node (which creates the speech) and start the explorer. + // + const node = this.findStartNode(); + this.setCurrent(node || this.rootNode(), !node); super.Start(); - if (!this.attached) return; - this.region.Show(this.node, this.highlighter); - this.walker.activate(); + // + // Show any needed regions + // + const options = this.document.options; + const a11y = options.a11y; + if (a11y.subtitles && a11y.speech && options.enableSpeech) { + this.region.Show(this.node, this.highlighter); + } + if (a11y.viewBraille && a11y.braille && options.enableBraille) { + this.brailleRegion.Show(this.node, this.highlighter); + } + if (a11y.keyMagnifier) { + this.magnifyRegion.Show(this.current, this.highlighter); + } this.Update(); } + /** + * @override + */ + public Stop() { + if (this.active) { + const description = this.description; + if (this.node.getAttribute('aria-roledescription') !== description) { + this.node.setAttribute('aria-roledescription', description); + } + this.node.classList.remove('mjx-explorer-active'); + this.document.infoIcon.remove(); + this.pool.unhighlight(); + this.magnifyRegion.Hide(); + this.region.Hide(); + this.brailleRegion.Hide(); + } + super.Stop(); + } /** - * Shows the nodes that are currently focused. + * @override */ - private showFocus() { - let node = this.walker.getFocus().getNodes()[0] as HTMLElement; - this.region.Show(node, this.highlighter); + public Update() { + if (!this.active) return; + this.region.node = this.node; + this.generators.updateRegions( + this.speech || this.node, + this.region, + this.brailleRegion + ); + this.magnifyRegion.Update(this.current); } + /** + * @override + */ + public Attach() { + if (this.attached) return; + super.Attach(); + this.node.setAttribute('tabindex', '0'); + this.attached = true; + } /** * @override */ - public Move(key: number) { - let result = this.walker.move(key); - if (result) { - this.Update(); + public Detach() { + super.RemoveEvents(); + this.node.removeAttribute('role'); + this.node.removeAttribute('aria-roledescription'); + this.node.removeAttribute('aria-label'); + this.img?.remove(); + if (this.active) { + this.node.setAttribute('tabindex', '0'); } + this.attached = false; } + /** + * @override + */ + public NoMove() { + honk(); + } /** * @override */ - public KeyDown(event: KeyboardEvent) { - const code = event.keyCode; - this.walker.modifier = event.shiftKey; - if (code === 27) { - this.Stop(); - this.stopEvent(event); - return; + public AddEvents() { + if (!this.eventsAttached) { + super.AddEvents(); + this.eventsAttached = true; } - if (this.active && code !== 13) { - this.Move(code); - this.stopEvent(event); - return; + } + + /********************************************************************/ + /* + * Actions and links + */ + + /** + * Checks if a node is actionable, i.e., corresponds to an maction. + * + * @param {HTMLElement} node The (rendered) node under consideration. + * @returns {HTMLElement} The node corresponding to an maction element. + */ + private actionable(node: HTMLElement): HTMLElement { + const parent = node?.parentNode as HTMLElement; + return parent && this.highlighter.isMactionNode(parent) ? parent : null; + } + + /** + * Programmatically triggers a link if the focused node contains one. + * + * @param {KeyboardEvent} event The keyboard event for the last keydown event. + * @returns {boolean} True if link was successfully triggered. + */ + protected triggerLinkKeyboard(event: KeyboardEvent): boolean { + if (!this.current) { + if (event.target instanceof HTMLAnchorElement) { + event.target.dispatchEvent(new MouseEvent('click')); + return true; + } + return false; } - if (code === 32 && event.shiftKey || code === 13) { - this.Start(); - this.stopEvent(event); + return this.triggerLink(this.current); + } + + /** + * Executiving the trigger the link action. + * + * @param {HTMLElement} node The node with the link. + * @returns {boolean} True if link was successfully triggered. + */ + protected triggerLink(node: HTMLElement): boolean { + const focus = node + ?.getAttribute('data-semantic-postfix') + ?.match(/(^| )link($| )/); + if (focus) { + while (node && node !== this.node) { + if (node instanceof HTMLAnchorElement) { + node.dispatchEvent(new MouseEvent('click')); + setTimeout(() => this.FocusOut(null), 50); + return true; + } + node = node.parentNode as HTMLElement; + } } + return false; } + /** + * Programmatically triggers a link if the clicked mouse event contains one. + * + * @returns {boolean} True if link was successfully triggered. + */ + protected triggerLinkMouse(): boolean { + let node = this.refocus; + while (node && node !== this.node) { + if (this.triggerLink(node)) { + return true; + } + node = node.parentNode as HTMLElement; + } + return false; + } + + /** + * @returns {string} The semantic id of the node that is currently focused. + */ + public semanticFocus(): string { + const focus = []; + let name = 'data-semantic-id'; + let node = this.current || this.refocus || this.node; + const action = this.actionable(node); + if (action) { + name = action.hasAttribute('data-maction-id') ? 'data-maction-id' : 'id'; + node = action; + focus.push(nav); + } + const attr = node.getAttribute(name); + if (attr) { + focus.unshift(`[${name}="${attr}"]`); + } + return focus.join(' '); + } } diff --git a/ts/a11y/explorer/MouseExplorer.ts b/ts/a11y/explorer/MouseExplorer.ts index 715723ef3..056b4b7a5 100644 --- a/ts/a11y/explorer/MouseExplorer.ts +++ b/ts/a11y/explorer/MouseExplorer.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,57 +15,56 @@ * limitations under the License. */ - /** - * @fileoverview Explorers based on mouse events. + * @file Explorers based on mouse events. * * @author v.sorge@mathjax.org (Volker Sorge) */ - -import {A11yDocument, DummyRegion, Region} from './Region.js'; -import {Explorer, AbstractExplorer} from './Explorer.js'; +import { A11yDocument, DummyRegion, Region } from './Region.js'; +import { Explorer, AbstractExplorer } from './Explorer.js'; +import { ExplorerPool } from './ExplorerPool.js'; import '../sre.js'; - /** * Interface for mouse explorers. Adds the necessary mouse events. + * * @interface - * @extends {Explorer} + * @augments {Explorer} */ export interface MouseExplorer extends Explorer { - /** * Function to be executed on mouse over. + * * @param {MouseEvent} event The mouse event. */ MouseOver(event: MouseEvent): void; /** * Function to be executed on mouse out. + * * @param {MouseEvent} event The mouse event. */ MouseOut(event: MouseEvent): void; - } - /** - * @constructor - * @extends {AbstractExplorer} + * @class + * @augments {AbstractExplorer} * * @template T The type that is consumed by the Region of this explorer. */ -export abstract class AbstractMouseExplorer extends AbstractExplorer implements MouseExplorer { - +export abstract class AbstractMouseExplorer + extends AbstractExplorer + implements MouseExplorer +{ /** * @override */ - protected events: [string, (x: Event) => void][] = - super.Events().concat([ - ['mouseover', this.MouseOver.bind(this)], - ['mouseout', this.MouseOut.bind(this)] - ]); + protected events: [string, (x: Event) => void][] = super.Events().concat([ + ['mouseover', this.MouseOver.bind(this)], + ['mouseout', this.MouseOut.bind(this)], + ]); /** * @override @@ -74,75 +73,63 @@ export abstract class AbstractMouseExplorer extends AbstractExplorer imple this.Start(); } - /** * @override */ public MouseOut(_event: MouseEvent) { this.Stop(); } - } - /** * Exploration via hovering. - * @constructor - * @extends {AbstractMouseExplorer} + * + * @class + * @augments {AbstractMouseExplorer} + * + * @template T */ export abstract class Hoverer extends AbstractMouseExplorer { - - /** - * Remember the last position to avoid flickering. - * @type {[number, number]} - */ - protected coord: [number, number]; - /** - * @constructor - * @extends {AbstractMouseExplorer} + * @class + * @augments {AbstractMouseExplorer} * * @param {A11yDocument} document The current document. + * @param {ExplorerPool} pool The explorer pool. * @param {Region} region A region to display results. * @param {HTMLElement} node The node on which the explorer works. * @param {(node: HTMLElement) => boolean} nodeQuery Predicate on nodes that * will fire the hoverer. * @param {(node: HTMLElement) => T} nodeAccess Accessor to extract node value * that is passed to the region. - * - * @template T */ - protected constructor(public document: A11yDocument, - protected region: Region, - protected node: HTMLElement, - protected nodeQuery: (node: HTMLElement) => boolean, - protected nodeAccess: (node: HTMLElement) => T) { - super(document, region, node); + protected constructor( + public document: A11yDocument, + public pool: ExplorerPool, + public region: Region, + protected node: HTMLElement, + protected nodeQuery: (node: HTMLElement) => boolean, + protected nodeAccess: (node: HTMLElement) => T + ) { + super(document, pool, region, node); } - /** * @override */ public MouseOut(event: MouseEvent) { - if (event.clientX === this.coord[0] && - event.clientY === this.coord[1]) { - return; - } this.highlighter.unhighlight(); this.region.Hide(); super.MouseOut(event); } - /** * @override */ public MouseOver(event: MouseEvent) { super.MouseOver(event); - let target = event.target as HTMLElement; - this.coord = [event.clientX, event.clientY]; - let [node, kind] = this.getNode(target); + const target = event.target as HTMLElement; + const [node, kind] = this.getNode(target); if (!node) { return; } @@ -152,7 +139,6 @@ export abstract class Hoverer extends AbstractMouseExplorer { this.region.Show(node, this.highlighter); } - /** * Retrieves the closest node on which the node query fires. Thereby closest * is defined as: @@ -161,10 +147,10 @@ export abstract class Hoverer extends AbstractMouseExplorer { * 3. Otherwise fails. * * @param {HTMLElement} node The node on which the mouse event fired. - * @return {[HTMLElement, T]} Node and output pair if successful. + * @returns {[HTMLElement, T]} Node and output pair if successful. */ public getNode(node: HTMLElement): [HTMLElement, T] { - let original = node; + const original = node; while (node && node !== this.node) { if (this.nodeQuery(node)) { return [node, this.nodeAccess(node)]; @@ -176,49 +162,55 @@ export abstract class Hoverer extends AbstractMouseExplorer { if (this.nodeQuery(node)) { return [node, this.nodeAccess(node)]; } - let child = node.childNodes[0] as HTMLElement; - node = (child && child.tagName === 'defs') ? // This is for SVG. - node.childNodes[1] as HTMLElement : child; + const child = node.childNodes[0] as HTMLElement; + node = + child && child.tagName === 'defs' // This is for SVG. + ? (node.childNodes[1] as HTMLElement) + : child; } return [null, null]; } - } - /** * Hoverer that displays information on nodes (e.g., as tooltips). - * @constructor - * @extends {Hoverer} + * + * @class + * @augments {Hoverer} */ -export class ValueHoverer extends Hoverer { } - +export class ValueHoverer extends Hoverer {} /** * Hoverer that displays node content (e.g., for magnification). - * @constructor - * @extends {Hoverer} + * + * @class + * @augments {Hoverer} */ -export class ContentHoverer extends Hoverer { } - +export class ContentHoverer extends Hoverer {} /** * Highlights maction nodes on hovering. - * @constructor - * @extends {Hoverer} + * + * @class + * @augments {Hoverer} */ export class FlameHoverer extends Hoverer { - /** * @override */ protected constructor( public document: A11yDocument, + public pool: ExplorerPool, _ignore: any, - protected node: HTMLElement) { - super(document, new DummyRegion(document), node, - x => this.highlighter.isMactionNode(x), - () => {}); + protected node: HTMLElement + ) { + super( + document, + pool, + new DummyRegion(document), + node, + (x) => this.highlighter.isMactionNode(x), + () => {} + ); } - } diff --git a/ts/a11y/explorer/Region.ts b/ts/a11y/explorer/Region.ts index e34fb1dba..109a42d2b 100644 --- a/ts/a11y/explorer/Region.ts +++ b/ts/a11y/explorer/Region.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,22 +15,20 @@ * limitations under the License. */ - /** - * @fileoverview Regions for A11y purposes. + * @file Regions for A11y purposes. * * @author v.sorge@mathjax.org (Volker Sorge) */ - -import {MathDocument} from '../../core/MathDocument.js'; -import {CssStyles} from '../../util/StyleList.js'; -import Sre from '../sre.js'; +import { MathDocument } from '../../core/MathDocument.js'; +import { StyleJsonSheet } from '../../util/StyleJson.js'; +import { Highlighter, getHighlighter } from './Highlighter.js'; +import { SsmlElement, buildSpeech } from '../speech/SpeechUtil.js'; export type A11yDocument = MathDocument; export interface Region { - /** * Adds a style sheet for the live region to the document. */ @@ -43,10 +41,11 @@ export interface Region { /** * Shows the live region in the document. + * * @param {HTMLElement} node - * @param {Sre.highlighter} highlighter + * @param {Highlighter} highlighter */ - Show(node: HTMLElement, highlighter: Sre.highlighter): void; + Show(node: HTMLElement, highlighter: Highlighter): void; /** * Takes the element out of the document flow. @@ -60,61 +59,64 @@ export interface Region { /** * Updates the content of the region. + * * @template T */ Update(content: T): void; - } export abstract class AbstractRegion implements Region { - /** * CSS Classname of the element. - * @type {String} + * + * @type {string} */ protected static className: string; /** * True if the style has already been added to the document. + * * @type {boolean} */ protected static styleAdded: boolean = false; /** * The CSS style that needs to be added for this type of region. - * @type {CssStyles} + * + * @type {StyleJsonSheet} */ - protected static style: CssStyles; + protected static style: StyleJsonSheet; /** * The outer div node. + * * @type {HTMLElement} */ - protected div: HTMLElement; + public div: HTMLElement; /** * The inner node. + * * @type {HTMLElement} */ protected inner: HTMLElement; /** * The actual class name to refer to static elements of a class. + * * @type {typeof AbstractRegion} */ protected CLASS: typeof AbstractRegion; /** - * @constructor + * @class * @param {A11yDocument} document The document the live region is added to. */ constructor(public document: A11yDocument) { this.CLASS = this.constructor as typeof AbstractRegion; this.AddStyles(); - this.AddElement(); } - /** * @override */ @@ -123,77 +125,76 @@ export abstract class AbstractRegion implements Region { return; } // TODO: should that be added to document.documentStyleSheet()? - let node = this.document.adaptor.node('style'); + const node = this.document.adaptor.node('style'); node.innerHTML = this.CLASS.style.cssText; - this.document.adaptor.head(this.document.adaptor.document). - appendChild(node); + this.document.adaptor + .head(this.document.adaptor.document) + .appendChild(node); this.CLASS.styleAdded = true; } - /** * @override */ public AddElement() { - let element = this.document.adaptor.node('div'); + if (this.div) return; + const element = this.document.adaptor.node('div'); element.classList.add(this.CLASS.className); - element.style.backgroundColor = 'white'; this.div = element; this.inner = this.document.adaptor.node('div'); this.div.appendChild(this.inner); - this.document.adaptor. - body(this.document.adaptor.document). - appendChild(this.div); - + this.document.adaptor + .body(this.document.adaptor.document) + .appendChild(this.div); } - /** * @override */ - public Show(node: HTMLElement, highlighter: Sre.highlighter) { + public Show(node: HTMLElement, highlighter: Highlighter) { + this.AddElement(); this.position(node); this.highlight(highlighter); this.div.classList.add(this.CLASS.className + '_Show'); } - /** * Computes the position where to place the element wrt. to the given node. + * * @param {HTMLElement} node The reference node. */ protected abstract position(node: HTMLElement): void; - /** * Highlights the region. - * @param {Sre.highlighter} highlighter The Sre highlighter. + * + * @param {Highlighter} highlighter The Sre highlighter. */ - protected abstract highlight(highlighter: Sre.highlighter): void; - + protected abstract highlight(highlighter: Highlighter): void; /** * @override */ public Hide() { - this.div.classList.remove(this.CLASS.className + '_Show'); + if (!this.div) return; + this.div.parentNode.removeChild(this.div); + this.div = null; + this.inner = null; } - /** * @override */ public abstract Clear(): void; - /** * @override */ public abstract Update(content: T): void; - /** * Auxiliary position method that stacks shown regions of the same type. + * * @param {HTMLElement} node The reference node. */ protected stackRegions(node: HTMLElement) { @@ -201,25 +202,30 @@ export abstract class AbstractRegion implements Region { const rect = node.getBoundingClientRect(); let baseBottom = 0; let baseLeft = Number.POSITIVE_INFINITY; - let regions = this.document.adaptor.document.getElementsByClassName( - this.CLASS.className + '_Show'); + const regions = this.document.adaptor.document.getElementsByClassName( + this.CLASS.className + '_Show' + ); // Get all the shown regions (one is this element!) and append at bottom. - for (let i = 0, region; region = regions[i]; i++) { + for (let i = 0, region; (region = regions[i]); i++) { if (region !== this.div) { - baseBottom = Math.max(region.getBoundingClientRect().bottom, baseBottom); + baseBottom = Math.max( + region.getBoundingClientRect().bottom, + baseBottom + ); baseLeft = Math.min(region.getBoundingClientRect().left, baseLeft); } } - const bot = (baseBottom ? baseBottom : rect.bottom + 10) + window.pageYOffset; - const left = (baseLeft < Number.POSITIVE_INFINITY ? baseLeft : rect.left) + window.pageXOffset; + + const bot = (baseBottom ? baseBottom : rect.bottom + 10) + window.scrollY; + const left = + (baseLeft < Number.POSITIVE_INFINITY ? baseLeft : rect.left) + + window.scrollX; this.div.style.top = bot + 'px'; this.div.style.left = left + 'px'; } - } export class DummyRegion extends AbstractRegion { - /** * @override */ @@ -258,28 +264,31 @@ export class DummyRegion extends AbstractRegion { /** * @override */ - public highlight(_highlighter: Sre.highlighter) {} + public highlight(_highlighter: Highlighter) {} } - export class StringRegion extends AbstractRegion { - /** * @override */ public Clear(): void { + if (!this.div) return; this.Update(''); this.inner.style.top = ''; this.inner.style.backgroundColor = ''; } - /** * @override */ public Update(speech: string) { - this.inner.textContent = ''; - this.inner.textContent = speech; + if (speech) { + this.AddElement(); + } + if (this.inner) { + this.inner.textContent = ''; + this.inner.textContent = speech || '\u00a0'; + } } /** @@ -289,21 +298,17 @@ export class StringRegion extends AbstractRegion { this.stackRegions(node); } - /** * @override */ - protected highlight(highlighter: Sre.highlighter) { - const color = highlighter.colorString(); - this.inner.style.backgroundColor = color.background; - this.inner.style.color = color.foreground; + protected highlight(highlighter: Highlighter) { + if (!this.div) return; + this.inner.style.backgroundColor = highlighter.background; + this.inner.style.color = highlighter.foreground; } - } - export class ToolTip extends StringRegion { - /** * @override */ @@ -312,25 +317,28 @@ export class ToolTip extends StringRegion { /** * @override */ - protected static style: CssStyles = - new CssStyles({ - ['.' + ToolTip.className]: { - position: 'absolute', display: 'inline-block', - height: '1px', width: '1px' - }, - ['.' + ToolTip.className + '_Show']: { - width: 'auto', height: 'auto', opacity: 1, 'text-align': 'center', - 'border-radius': '6px', padding: '0px 0px', - 'border-bottom': '1px dotted black', position: 'absolute', - 'z-index': 202 - } - }); - + protected static style: StyleJsonSheet = new StyleJsonSheet({ + ['.' + ToolTip.className]: { + width: 'auto', + height: 'auto', + opacity: 1, + 'text-align': 'center', + 'border-radius': '4px', + padding: 0, + 'border-bottom': '1px dotted black', + position: 'absolute', + display: 'inline-block', + 'background-color': 'white', + 'z-index': 202, + }, + ['.' + ToolTip.className + ' > div']: { + 'border-radius': 'inherit', + padding: '0 2px', + }, + }); } - export class LiveRegion extends StringRegion { - /** * @override */ @@ -339,69 +347,244 @@ export class LiveRegion extends StringRegion { /** * @override */ - protected static style: CssStyles = - new CssStyles({ - ['.' + LiveRegion.className]: { - position: 'absolute', top: '0', height: '1px', width: '1px', - padding: '1px', overflow: 'hidden' - }, - ['.' + LiveRegion.className + '_Show']: { - top: '0', position: 'absolute', width: 'auto', height: 'auto', - padding: '0px 0px', opacity: 1, 'z-index': '202', - left: 0, right: 0, 'margin': '0 auto', - 'background-color': 'rgba(0, 0, 255, 0.2)', 'box-shadow': '0px 10px 20px #888', - border: '2px solid #CCCCCC' - } - }); - + protected static style: StyleJsonSheet = new StyleJsonSheet({ + ['.' + LiveRegion.className]: { + position: 'absolute', + top: 0, + display: 'none', + width: 'auto', + height: 'auto', + padding: 0, + opacity: 1, + 'z-index': '202', + left: 0, + right: 0, + margin: '0 auto', + 'background-color': 'white', + 'box-shadow': '0px 5px 20px #888', + border: '2px solid #CCCCCC', + }, + ['.' + LiveRegion.className + '_Show']: { + display: 'block', + }, + }); +} +/** + * Region class that enables auto voicing of content via SSML markup. + */ +export class SpeechRegion extends LiveRegion { /** - * @constructor - * @param {A11yDocument} document The document the live region is added to. + * Flag to activate auto voicing. */ - constructor(public document: A11yDocument) { - super(document); - this.div.setAttribute('aria-live', 'assertive'); - } + public active: boolean = false; -} + /** + * The math expression that is currently explored. Other regions do not need + * this node as the explorer administers both node and region, while only + * pushing output into the region. But in the case autovoicing the speech + * regions needs to mark elements in the node directly. + */ + public node: Element = null; + /** + * Flag to indicate if a node is marked as being spoken. + */ + private clear: boolean = false; -// Region that overlays the current element. -export class HoverRegion extends AbstractRegion { + /** + * The highlighter to use. + */ + public highlighter: Highlighter = getHighlighter( + { color: 'red' }, + { color: 'black' }, + this.document.outputJax.name + ); /** * @override */ - protected static className = 'MJX_HoverRegion'; + public Show(node: HTMLElement, highlighter: Highlighter) { + super.Update('\u00a0'); // Ensures region shown and cannot be overwritten. + this.node = node; + super.Show(node, highlighter); + } + + /** + * Have we already requested voices from the browser? + */ + private voiceRequest: boolean = false; + + /** + * Has the auto voicing been cancelled? + */ + private voiceCancelled: boolean = false; /** * @override */ - protected static style: CssStyles = - new CssStyles({ - ['.' + HoverRegion.className]: { - position: 'absolute', height: '1px', width: '1px', - padding: '1px', overflow: 'hidden' - }, - ['.' + HoverRegion.className + '_Show']: { - position: 'absolute', width: 'max-content', height: 'auto', - padding: '0px 0px', opacity: 1, 'z-index': '202', 'margin': '0 auto', - 'background-color': 'rgba(0, 0, 255, 0.2)', - 'box-shadow': '0px 10px 20px #888', border: '2px solid #CCCCCC' - } + public Update(speech: string) { + // TODO (Volker): Make sure we use speech and ssml! + if (this.voiceRequest) { + this.makeVoice(speech); + return; + } + speechSynthesis.onvoiceschanged = (() => (this.voiceRequest = true)).bind( + this + ); + const promise = new Promise((resolve) => { + setTimeout(() => { + if (this.voiceRequest) { + resolve(true); + } else { + // This case is to make FF and Safari work. + setTimeout(() => { + this.voiceRequest = true; + resolve(true); + }, 100); + } + }, 100); }); + promise.then(() => this.makeVoice(speech)); + } + private makeVoice(speech: string) { + this.active = + this.document.options.a11y.voicing && + !!speechSynthesis.getVoices().length; + speechSynthesis.cancel(); + this.clear = true; + const [text, ssml] = buildSpeech( + speech, + this.document.options.sre.locale, + this.document.options.sre.rate + ); + super.Update(text); + if (this.active && text) { + this.makeUtterances(ssml, this.document.options.sre.locale); + } + } /** - * @constructor - * @param {A11yDocument} document The document the live region is added to. + * Generates the utterance chain. + * + * @param {SsmlElement[]} ssml The list of ssml annotations. + * @param {string} locale The locale to use. + */ + protected makeUtterances(ssml: SsmlElement[], locale: string) { + this.voiceCancelled = false; + let utterance = null; + for (const utter of ssml) { + if (utter.mark) { + if (!utterance) { + // First utterance, call with init = true. + this.highlightNode(utter.mark, true); + continue; + } + utterance.addEventListener('end', (_event: Event) => { + if (!this.voiceCancelled) { + this.highlightNode(utter.mark); + } + }); + continue; + } + if (utter.pause) { + const time = parseInt(utter.pause.match(/^[0-9]+/)[0]); + if (isNaN(time) || !utterance) { + continue; + } + // TODO: Ensure pausing does not advance the highlighting. + utterance.addEventListener('end', (_event: Event) => { + speechSynthesis.pause(); + setTimeout(() => { + speechSynthesis.resume(); + }, time); + }); + continue; + } + utterance = new SpeechSynthesisUtterance(utter.text); + if (utter.rate) { + utterance.rate = utter.rate; + } + if (utter.pitch) { + utterance.pitch = utter.pitch; + } + utterance.lang = locale; + speechSynthesis.speak(utterance); + } + if (utterance) { + utterance.addEventListener('end', (_event: Event) => { + this.highlighter.unhighlight(); + }); + } + } + + /** + * @override */ - constructor(public document: A11yDocument) { - super(document); - this.inner.style.lineHeight = '0'; + public Hide() { + this.cancelVoice(); + super.Hide(); + } + + /** + * Cancel the auto-voicing + */ + public cancelVoice() { + this.voiceCancelled = true; + speechSynthesis.cancel(); + this.highlighter.unhighlight(); } + /** + * Highlighting the node that is being marked in the SSML. + * + * @param {string} id The id of the node to highlight. + * @param {boolean} init Flag to indicate the very first utterance where there + * is no need for unhighlighting. + */ + private highlightNode(id: string, init: boolean = false) { + this.highlighter.unhighlight(); + const nodes = Array.from( + this.node.querySelectorAll(`[data-semantic-id="${id}"]`) + ); + if (!this.clear || init) { + this.highlighter.highlight(nodes as HTMLElement[]); + } + this.clear = false; + } +} + +// Region that overlays the current element. +export class HoverRegion extends AbstractRegion { + /** + * @override + */ + protected static className = 'MJX_HoverRegion'; + + /** + * @override + */ + protected static style: StyleJsonSheet = new StyleJsonSheet({ + ['.' + HoverRegion.className]: { + display: 'block', + position: 'absolute', + width: 'max-content', + height: 'auto', + padding: 0, + opacity: 1, + 'z-index': '202', + margin: '0 auto', + 'background-color': 'white', + 'line-height': 0, + 'box-shadow': '0px 10px 20px #888', + border: '2px solid #CCCCCC', + }, + ['.' + HoverRegion.className + ' > div']: { + overflow: 'hidden', + }, + }); + /** * Sets the position of the region with respect to align parameter. There are * three options: top, bottom and center. Center is the default. @@ -411,25 +594,26 @@ export class HoverRegion extends AbstractRegion { protected position(node: HTMLElement) { const nodeRect = node.getBoundingClientRect(); const divRect = this.div.getBoundingClientRect(); - const xCenter = nodeRect.left + (nodeRect.width / 2); - let left = xCenter - (divRect.width / 2); - left = (left < 0) ? 0 : left; - left = left + window.pageXOffset; + const xCenter = nodeRect.left + nodeRect.width / 2; + let left = xCenter - divRect.width / 2; + left = left < 0 ? 0 : left; + left = left + window.scrollX; let top; switch (this.document.options.a11y.align) { - case 'top': - top = nodeRect.top - divRect.height - 10 ; - break; - case 'bottom': - top = nodeRect.bottom + 10; - break; - case 'center': - default: - const yCenter = nodeRect.top + (nodeRect.height / 2); - top = yCenter - (divRect.height / 2); + case 'top': + top = nodeRect.top - divRect.height - 10; + break; + case 'bottom': + top = nodeRect.bottom + 10; + break; + case 'center': + default: { + const yCenter = nodeRect.top + nodeRect.height / 2; + top = yCenter - divRect.height / 2; + } } - top = top + window.pageYOffset; - top = (top < 0) ? 0 : top; + top = top + window.scrollY; + top = top < 0 ? 0 : top; this.div.style.top = top + 'px'; this.div.style.left = left + 'px'; } @@ -437,21 +621,24 @@ export class HoverRegion extends AbstractRegion { /** * @override */ - protected highlight(highlighter: Sre.highlighter) { + protected highlight(highlighter: Highlighter) { + if (!this.div) return; // TODO Do this with styles to avoid the interaction of SVG/CHTML. - if (this.inner.firstChild && - !(this.inner.firstChild as HTMLElement).hasAttribute('sre-highlight')) { + if ( + this.inner.firstChild && + !(this.inner.firstChild as HTMLElement).hasAttribute('sre-highlight') + ) { return; } - const color = highlighter.colorString(); - this.inner.style.backgroundColor = color.background; - this.inner.style.color = color.foreground; + this.inner.style.backgroundColor = highlighter.background; + this.inner.style.color = highlighter.foreground; } /** * @override */ - public Show(node: HTMLElement, highlighter: Sre.highlighter) { + public Show(node: HTMLElement, highlighter: Highlighter) { + this.AddElement(); this.div.style.fontSize = this.document.options.a11y.magnify; this.Update(node); super.Show(node, highlighter); @@ -461,6 +648,7 @@ export class HoverRegion extends AbstractRegion { * @override */ public Clear() { + if (!this.div) return; this.inner.textContent = ''; this.inner.style.top = ''; this.inner.style.backgroundColor = ''; @@ -470,18 +658,26 @@ export class HoverRegion extends AbstractRegion { * @override */ public Update(node: HTMLElement) { + if (!this.div) return; this.Clear(); - let mjx = this.cloneNode(node); + const mjx = this.cloneNode(node); + const selected = mjx.querySelector('[data-mjx-clone]') as HTMLElement; + this.inner.style.backgroundColor = node.style.backgroundColor; + selected.style.backgroundColor = ''; + selected.classList.remove('mjx-selected'); this.inner.appendChild(mjx); + this.position(node); } /** * Clones the node to put into the hover region. + * * @param {HTMLElement} node The original node. - * @return {HTMLElement} The cloned node. + * @returns {HTMLElement} The cloned node. */ private cloneNode(node: HTMLElement): HTMLElement { let mjx = node.cloneNode(true) as HTMLElement; + mjx.setAttribute('data-mjx-clone', 'true'); if (mjx.nodeName !== 'MJX-CONTAINER') { // remove element spacing (could be done in CSS) if (mjx.nodeName !== 'g') { @@ -498,22 +694,28 @@ export class HoverRegion extends AbstractRegion { // SVG specific // if (mjx.nodeName === 'svg') { - (mjx.firstChild as HTMLElement).setAttribute('transform', 'matrix(1 0 0 -1 0 0)'); + (mjx.firstChild as HTMLElement).setAttribute( + 'transform', + 'matrix(1 0 0 -1 0 0)' + ); const W = parseFloat(mjx.getAttribute('viewBox').split(/ /)[2]); const w = parseFloat(mjx.getAttribute('width')); - const {x, y, width, height} = (node as any).getBBox(); - mjx.setAttribute('viewBox', [x, -(y + height), width, height].join(' ')); + const { x, y, width, height } = (node as any).getBBox(); + mjx.setAttribute( + 'viewBox', + [x, -(y + height), width, height].join(' ') + ); mjx.removeAttribute('style'); - mjx.setAttribute('width', (w / W * width) + 'ex'); - mjx.setAttribute('height', (w / W * height) + 'ex'); + mjx.setAttribute('width', (w / W) * width + 'ex'); + mjx.setAttribute('height', (w / W) * height + 'ex'); container.setAttribute('sre-highlight', 'false'); } } - mjx = container.cloneNode(false).appendChild(mjx).parentNode as HTMLElement; + mjx = container.cloneNode(false).appendChild(mjx) + .parentNode as HTMLElement; // remove displayed math margins (could be done in CSS) mjx.style.margin = '0'; } return mjx; } - } diff --git a/ts/a11y/explorer/TreeExplorer.ts b/ts/a11y/explorer/TreeExplorer.ts index aa6838156..94915de8e 100644 --- a/ts/a11y/explorer/TreeExplorer.ts +++ b/ts/a11y/explorer/TreeExplorer.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,34 +15,29 @@ * limitations under the License. */ - /** - * @fileoverview Tree Explorers allow to switch on effects on the entire + * @file Tree Explorers allow to switch on effects on the entire * expression tree. * * @author v.sorge@mathjax.org (Volker Sorge) */ - -import {A11yDocument, Region} from './Region.js'; -import {Explorer, AbstractExplorer} from './Explorer.js'; -import Sre from '../sre.js'; - -export interface TreeExplorer extends Explorer { - -} - +import { A11yDocument, Region } from './Region.js'; +import { AbstractExplorer } from './Explorer.js'; +import { ExplorerPool } from './ExplorerPool.js'; export class AbstractTreeExplorer extends AbstractExplorer { - /** * @override */ - protected constructor(public document: A11yDocument, - protected region: Region, - protected node: HTMLElement, - protected mml: HTMLElement) { - super(document, null, node); + protected constructor( + public document: A11yDocument, + public pool: ExplorerPool, + public region: Region, + protected node: HTMLElement, + protected mml: HTMLElement + ) { + super(document, pool, null, node); } /** @@ -50,7 +45,6 @@ export class AbstractTreeExplorer extends AbstractExplorer { */ public readonly stoppable = false; - /** * @override */ @@ -66,12 +60,9 @@ export class AbstractTreeExplorer extends AbstractExplorer { this.Stop(); super.Detach(); } - } - export class FlameColorer extends AbstractTreeExplorer { - /** * @override */ @@ -90,11 +81,16 @@ export class FlameColorer extends AbstractTreeExplorer { } this.active = false; } - } - export class TreeColorer extends AbstractTreeExplorer { + /** + * Contrast value. + */ + public contrast: ContrastPicker = new ContrastPicker(); + + private leaves: HTMLElement[] = []; + private modality: string = 'data-semantic-foreground'; /** * @override @@ -102,13 +98,12 @@ export class TreeColorer extends AbstractTreeExplorer { public Start() { if (this.active) return; this.active = true; - let generator = Sre.getSpeechGenerator('Color'); if (!this.node.hasAttribute('hasforegroundcolor')) { - generator.generateSpeech(this.node, this.mml); + this.colorLeaves(); this.node.setAttribute('hasforegroundcolor', 'true'); } // TODO: Make this cleaner in Sre. - (this.highlighter as any).colorizeAll(this.node); + this.leaves.forEach((leaf) => this.colorize(leaf)); } /** @@ -116,9 +111,118 @@ export class TreeColorer extends AbstractTreeExplorer { */ public Stop() { if (this.active) { - (this.highlighter as any).uncolorizeAll(this.node); + this.leaves.forEach((leaf) => this.uncolorize(leaf)); } this.active = false; } + /** + * Colors the leave nodes of the expression. + */ + private colorLeaves() { + this.leaves = Array.from( + this.node.querySelectorAll( + '[data-semantic-id]:not([data-semantic-children])' + ) + ); + for (const leaf of this.leaves) { + leaf.setAttribute(this.modality, this.contrast.generate()); + this.contrast.increment(); + } + } + + /** + * Tree colors a single node. + * + * @param {HTMLElement} node The node. + */ + public colorize(node: HTMLElement) { + if (node.hasAttribute(this.modality)) { + node.setAttribute(this.modality + '-old', node.style.color); + node.style.color = node.getAttribute(this.modality); + } + } + + /** + * Removes tree coloring from a single node. + * + * @param {HTMLElement} node The node. + */ + public uncolorize(node: HTMLElement) { + const fore = this.modality + '-old'; + if (node.hasAttribute(fore)) { + node.style.color = node.getAttribute(fore); + } + } +} + +export class ContrastPicker { + /** + * Hue value. + */ + public hue = 10; + + /** + * Saturation value. + */ + public sat = 100; + + /** + * Light value. + */ + public light = 50; + + /** + * Increment step. Prime closest to 50. + */ + public incr = 53; + + /** + * Generates the current color as rgb color in hex code. + * + * @returns {string} The rgb color attribute. + */ + public generate(): string { + return ContrastPicker.hsl2rgb(this.hue, this.sat, this.light); + } + + /** + * Increments the hue value of the current color. + */ + public increment() { + this.hue = (this.hue + this.incr) % 360; + } + + /** + * Transforms a HSL triple into an rgb value triple. + * + * @param {number} h The hue. + * @param {number} s The saturation. + * @param {number} l The luminosity. + * @returns {string} The string with rgb value triple with values in [0, 255]. + */ + public static hsl2rgb(h: number, s: number, l: number): string { + s = s > 1 ? s / 100 : s; + l = l > 1 ? l / 100 : l; + const c = (1 - Math.abs(2 * l - 1)) * s; + const x = c * (1 - Math.abs(((h / 60) % 2) - 1)); + const m = l - c / 2; + let r = 0, + g = 0, + b = 0; + if (0 <= h && h < 60) { + [r, g, b] = [c, x, 0]; + } else if (60 <= h && h < 120) { + [r, g, b] = [x, c, 0]; + } else if (120 <= h && h < 180) { + [r, g, b] = [0, c, x]; + } else if (180 <= h && h < 240) { + [r, g, b] = [0, x, c]; + } else if (240 <= h && h < 300) { + [r, g, b] = [x, 0, c]; + } else if (300 <= h && h < 360) { + [r, g, b] = [c, 0, x]; + } + return `rgb(${(r + m) * 255}, ${(g + m) * 255}, ${(b + m) * 255})`; + } } diff --git a/ts/a11y/semantic-enrich.ts b/ts/a11y/semantic-enrich.ts index 48bb6086a..61c776f3f 100644 --- a/ts/a11y/semantic-enrich.ts +++ b/ts/a11y/semantic-enrich.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,45 +16,88 @@ */ /** - * @fileoverview Mixin that adds semantic enrichment to internal MathML + * @file Mixin that adds semantic enrichment to internal MathML * * @author dpvc@mathjax.org (Davide Cervone) */ -import {mathjax} from '../mathjax.js'; -import {Handler} from '../core/Handler.js'; -import {MathDocument, AbstractMathDocument, MathDocumentConstructor} from '../core/MathDocument.js'; -import {MathItem, AbstractMathItem, STATE, newState} from '../core/MathItem.js'; -import {MmlNode} from '../core/MmlTree/MmlNode.js'; -import {MathML} from '../input/mathml.js'; -import {SerializedMmlVisitor} from '../core/MmlTree/SerializedMmlVisitor.js'; -import {OptionList, expandable} from '../util/Options.js'; -import Sre from './sre.js'; +import { Handler } from '../core/Handler.js'; +import { + MathDocument, + AbstractMathDocument, + MathDocumentConstructor, +} from '../core/MathDocument.js'; +import { + MathItem, + AbstractMathItem, + STATE, + newState, +} from '../core/MathItem.js'; +import { MmlNode } from '../core/MmlTree/MmlNode.js'; +import { HtmlNode } from '../core/MmlTree/MmlNodes/HtmlNode.js'; +import { MathML } from '../input/mathml.js'; +import { SerializedMmlVisitor } from '../core/MmlTree/SerializedMmlVisitor.js'; +import { OptionList, expandable } from '../util/Options.js'; +import * as Sre from './sre.js'; /*==========================================================================*/ -/** - * The current speech setting for Sre - */ -let currentSpeech = 'none'; - /** * Generic constructor for Mixins */ -export type Constructor = new(...args: any[]) => T; +export type Constructor = new (...args: any[]) => T; /*==========================================================================*/ /** * Add STATE value for being enriched (after COMPILED and before TYPESET) */ -newState('ENRICHED', 30); +newState('ENRICHED', STATE.COMPILED + 10); -/** - * Add STATE value for adding speech (after TYPESET) - */ -newState('ATTACHSPEECH', 155); +/*==========================================================================*/ +export class enrichVisitor extends SerializedMmlVisitor { + protected mactionId: number; + + public visitTree(node: MmlNode, math?: MathItem) { + this.mactionId = 0; + const mml = super.visitTree(node); + if (this.mactionId) { + math.inputData.hasMaction = true; + } + return mml; + } + + public visitHtmlNode(node: HtmlNode, _space: string): string { + return node.getSerializedXML(); + } + + public visitMactionNode(node: MmlNode, space: string) { + const [nl, endspace] = + node.childNodes.length === 0 ? ['', ''] : ['\n', space]; + const children = this.childNodeMml(node, space + ' ', nl); + let attributes = this.getAttributes(node); + if (node.attributes.get('actiontype') === 'toggle') { + const id = ++this.mactionId; + node.setProperty('mactionId', id); + // + // Add maction id and make sure selection is the next attribute + // + attributes = + ` data-maction-id="${id}" selection="${node.attributes.get('selection')}"` + + attributes + .replace(/ selection="\d+"/, '') + .replace(/ data-maction-id="\d+"/, ''); + } + return ( + `${space}` + + (children.match(/\S/) ? nl + children + endspace : '') + + '' + ); + } +} + +/*==========================================================================*/ /** * The functions added to MathItem for enrichment @@ -64,6 +107,10 @@ newState('ATTACHSPEECH', 155); * @template D The Document class */ export interface EnrichedMathItem extends MathItem { + /** + * The serialization visitor + */ + toMathML: (node: MmlNode, math: MathItem) => string; /** * @param {MathDocument} document The document where enrichment is occurring @@ -72,9 +119,15 @@ export interface EnrichedMathItem extends MathItem { enrich(document: MathDocument, force?: boolean): void; /** - * @param {MathDocument} document The document where enrichment is occurring + * @param {MathDocument} document The MathDocument for the MathItem + */ + unEnrich(document: MathDocument): void; + + /** + * @param {string} mml The MathML string to enrich + * @returns {string} The enriched MathML */ - attachSpeech(document: MathDocument): void; + toEnriched(mml: string): string; } /** @@ -83,24 +136,32 @@ export interface EnrichedMathItem extends MathItem { * @param {B} BaseMathItem The MathItem class to be extended * @param {MathML} MmlJax The MathML input jax used to convert the enriched MathML * @param {Function} toMathML The function to serialize the internal MathML - * @return {EnrichedMathItem} The enriched MathItem class + * @returns {EnrichedMathItem} The enriched MathItem class * * @template N The HTMLElement node class * @template T The Text node class * @template D The Document class * @template B The MathItem class to extend */ -export function EnrichedMathItemMixin>>( +export function EnrichedMathItemMixin< + N, + T, + D, + B extends Constructor>, +>( BaseMathItem: B, MmlJax: MathML, - toMathML: (node: MmlNode) => string + toMathML: (node: MmlNode, math: MathItem) => string ): Constructor> & B { - return class extends BaseMathItem { + /** + * The MathML serializer + */ + public toMathML = toMathML; /** * @param {any} node The node to be serialized - * @return {string} The serialized version of node + * @returns {string} The serialized version of node */ protected serializeMml(node: any): string { if ('outerHTML' in node) { @@ -109,7 +170,11 @@ export function EnrichedMathItemMixin, force: boolean = false) { if (this.state() >= STATE.ENRICHED) return; if (!this.isEscaped && (document.options.enableEnrichment || force)) { - if (document.options.sre.speech !== currentSpeech) { - currentSpeech = document.options.sre.speech; - mathjax.retryAfter( - Sre.setupEngine(document.options.sre).then( - () => Sre.sreReady())); - } const math = new document.options.MathItem('', MmlJax); try { - const mml = this.inputData.originalMml = toMathML(this.root); - math.math = this.serializeMml(Sre.toEnriched(mml)); + let mml; + if (!this.inputData.originalMml) { + mml = this.inputData.originalMml = this.toMathML(this.root, this); + } else { + mml = this.adjustSelections(); + } + const enriched = Sre.toEnriched(mml); + this.inputData.enrichedMml = math.math = this.serializeMml(enriched); + // + // Replace treeitem with a data attribute marking speech nodes + // and remove unused aria attributes. This will be removed when + // SRE is updated to do this itself. + // + math.math = math.math + .replace(/ role="treeitem"/g, ' data-speech-node="true"') + .replace(/ aria-(?:posinset|owns|setsize)=".*?"/g, ''); math.display = this.display; math.compile(document); this.root = math.root; - this.inputData.enrichedMml = math.math; } catch (err) { document.options.enrichError(document, this, err); } @@ -148,48 +220,48 @@ export function EnrichedMathItemMixin) { - if (this.state() >= STATE.ATTACHSPEECH) return; - const attributes = this.root.attributes; - const speech = (attributes.get('aria-label') || - this.getSpeech(this.root)) as string; - if (speech) { - const adaptor = document.adaptor; - const node = this.typesetRoot; - adaptor.setAttribute(node, 'aria-label', speech); - for (const child of adaptor.childNodes(node) as N[]) { - adaptor.setAttribute(child, 'aria-hidden', 'true'); - } - } - this.state(STATE.ATTACHSPEECH); + public unEnrich(document: MathDocument) { + const mml = this.inputData.originalMml; + if (!mml) return; + const math = new document.options.MathItem('', MmlJax); + math.math = mml; + math.display = this.display; + math.compile(document); + this.root = math.root; } /** - * Retrieves the actual speech element that should be used as aria label. - * @param {MmlNode} node The root node to search from. - * @return {string} The speech content. + * Correct the selection values for the maction items from the original MathML + * + * @returns {string} The updated MathML element. */ - private getSpeech(node: MmlNode): string { - const attributes = node.attributes; - if (!attributes) return ''; - const speech = attributes.getExplicit('data-semantic-speech') as string; - if (!attributes.getExplicit('data-semantic-parent') && speech) { - return speech; - } - for (let child of node.childNodes) { - let value = this.getSpeech(child as MmlNode); - if (value != null) { - return value; + protected adjustSelections(): string { + const mml = this.inputData.originalMml; + if (!this.inputData.hasMaction) return mml; + const maction = [] as MmlNode[]; + this.root.walkTree((node: MmlNode) => { + if (node.isKind('maction')) { + maction[node.attributes.get('data-maction-id') as number] = node; } - } - return ''; + }); + return mml.replace( + /(data-maction-id="(\d+)" selection=)"\d+"/g, + (_match: string, prefix: string, id: number) => + `${prefix}"${maction[id].attributes.get('selection')}"` + ); } - }; - } /*==========================================================================*/ @@ -201,28 +273,25 @@ export function EnrichedMathItemMixin extends AbstractMathDocument { - +export interface EnrichedMathDocument + extends AbstractMathDocument { /** * Perform enrichment on the MathItems in the MathDocument * - * @return {EnrichedMathDocument} The MathDocument (so calls can be chained) + * @returns {EnrichedMathDocument} The MathDocument (so calls can be chained) */ enrich(): EnrichedMathDocument; - /** - * Attach speech to the MathItems in the MathDocument - * - * @return {EnrichedMathDocument} The MathDocument (so calls can be chained) - */ - attachSpeech(): EnrichedMathDocument; - /** * @param {EnrichedMathDocument} doc The MathDocument for the error - * @paarm {EnrichedMathItem} math The MathItem causing the error + * @param {EnrichedMathItem} math The MathItem causing the error * @param {Error} err The error being processed */ - enrichError(doc: EnrichedMathDocument, math: EnrichedMathItem, err: Error): void; + enrichError( + doc: EnrichedMathDocument, + math: EnrichedMathItem, + err: Error + ): void; } /** @@ -230,39 +299,47 @@ export interface EnrichedMathDocument extends AbstractMathDocument>>( +export function EnrichedMathDocumentMixin< + N, + T, + D, + B extends MathDocumentConstructor>, +>( BaseDocument: B, - MmlJax: MathML, + MmlJax: MathML ): MathDocumentConstructor> & B { - return class extends BaseDocument { - /** * @override */ public static OPTIONS: OptionList = { ...BaseDocument.OPTIONS, enableEnrichment: true, - enrichError: (doc: EnrichedMathDocument, - math: EnrichedMathItem, - err: Error) => doc.enrichError(doc, math, err), + enrichError: ( + doc: EnrichedMathDocument, + math: EnrichedMathItem, + err: Error + ) => doc.enrichError(doc, math, err), renderActions: expandable({ ...BaseDocument.OPTIONS.renderActions, - enrich: [STATE.ENRICHED], - attachSpeech: [STATE.ATTACHSPEECH] + enrich: [STATE.ENRICHED], }), + /* prettier-ignore */ sre: expandable({ speech: 'none', // by default no speech is included - domain: 'mathspeak', // speech rules domain + locale: 'en', // switch the locale + domain: 'clearspeak', // speech rules domain style: 'default', // speech rules style - locale: 'en' // switch the locale + braille: 'nemeth', // TODO: Dummy switch for braille + structure: true, // Generates full aria structure + aria: true, }), }; @@ -271,43 +348,36 @@ export function EnrichedMathDocumentMixin visitor.visitTree(node)); - this.options.MathItem = - EnrichedMathItemMixin>>( - this.options.MathItem, MmlJax, toMathML - ); - } - - /** - * Attach speech from a MathItem to a node - */ - public attachSpeech() { - if (!this.processed.isSet('attach-speech')) { - for (const math of this.math) { - (math as EnrichedMathItem).attachSpeech(this); - } - this.processed.set('attach-speech'); - } - return this; + const visitor = new enrichVisitor(this.mmlFactory); + const toMathML = (node: MmlNode, math: MathItem) => + visitor.visitTree(node, math); + this.options.MathItem = EnrichedMathItemMixin< + N, + T, + D, + Constructor> + >(this.options.MathItem, MmlJax, toMathML); } /** * Enrich the MathItems in this MathDocument + * + * @returns {EnrichedMathDocument} The object for chaining. */ - public enrich() { + public enrich(): EnrichedMathDocument { if (!this.processed.isSet('enriched')) { if (this.options.enableEnrichment) { + Sre.setupEngine(this.options.sre); for (const math of this.math) { (math as EnrichedMathItem).enrich(this); } @@ -318,8 +388,13 @@ export function EnrichedMathDocumentMixin, _math: EnrichedMathItem, err: Error) { + public enrichError( + _doc: EnrichedMathDocument, + _math: EnrichedMathItem, + err: Error + ) { console.warn('Enrichment error:', err); } @@ -330,12 +405,15 @@ export function EnrichedMathDocumentMixin= STATE.COMPILED) { + for (const item of this.math) { + (item as EnrichedMathItem).unEnrich(this); + } + } } return this; } - }; - } /*==========================================================================*/ @@ -345,17 +423,22 @@ export function EnrichedMathDocumentMixin(handler: Handler, MmlJax: MathML): Handler { +export function EnrichHandler( + handler: Handler, + MmlJax: MathML +): Handler { MmlJax.setAdaptor(handler.adaptor); - handler.documentClass = - EnrichedMathDocumentMixin>>( - handler.documentClass, MmlJax - ); + handler.documentClass = EnrichedMathDocumentMixin< + N, + T, + D, + MathDocumentConstructor> + >(handler.documentClass, MmlJax); return handler; } diff --git a/ts/a11y/speech.ts b/ts/a11y/speech.ts new file mode 100644 index 000000000..0cf3d1547 --- /dev/null +++ b/ts/a11y/speech.ts @@ -0,0 +1,368 @@ +/************************************************************* + * + * Copyright (c) 2018-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Mixin that adds semantic enrichment to internal MathML + * + * @author dpvc@mathjax.org (Davide Cervone) + */ + +import { Handler } from '../core/Handler.js'; +import { MathDocument, MathDocumentConstructor } from '../core/MathDocument.js'; +import { + EnrichedMathItem, + EnrichedMathDocument, + EnrichHandler, +} from './semantic-enrich.js'; +import { STATE, newState } from '../core/MathItem.js'; +import { MathML } from '../input/mathml.js'; +import { OptionList, expandable } from '../util/Options.js'; +import { GeneratorPool } from './speech/GeneratorPool.js'; +import { WorkerHandler } from './speech/WebWorker.js'; +import { sreRoot } from '#root/sre-root.js'; + +/*==========================================================================*/ + +/** + * Generic constructor for Mixins + */ +export type Constructor = new (...args: any[]) => T; + +/*==========================================================================*/ + +/** + * Add STATE value for adding speech (after INSERTED) + */ +newState('ATTACHSPEECH', STATE.INSERTED + 10); + +/*==========================================================================*/ + +/** + * The functions added to MathItem for enrichment + * + * @template N The HTMLElement node class + * @template T The Text node class + * @template D The Document class + */ +export interface SpeechMathItem extends EnrichedMathItem { + /** + * The speech generators for this math item. + */ + generatorPool: GeneratorPool; + + /** + * @param {MathDocument} document The document where speech is added + */ + attachSpeech(document: MathDocument): void; + + /** + * @param {MathDocument} document The MathDocument for the MathItem + */ + detachSpeech(document: MathDocument): void; + + /** + * @param {string} mml The MathML whose speech is needed. + * @returns {Promise<[string,string]>} A promise for the speech and braille strings + */ + speechFor(mml: string): Promise<[string, string]>; +} + +/** + * The mixin for adding speech to MathItems + * + * @param {B} EnrichedMathItem The MathItem class to be extended + * @returns {SpeechMathItem} The enriched MathItem class + * + * @template N The HTMLElement node class + * @template T The Text node class + * @template D The Document class + * @template B The MathItem class to extend + */ +export function SpeechMathItemMixin< + N, + T, + D, + B extends Constructor>, +>(EnrichedMathItem: B): Constructor> & B { + return class extends EnrichedMathItem { + /** + * @override + */ + public generatorPool = new GeneratorPool(); + + /** + * Attaches the aria labels for speech and braille. + * + * @param {MathDocument} document The MathDocument for the MathItem + */ + public attachSpeech(document: SpeechMathDocument) { + this.outputData.speechPromise = null; + if (this.state() >= STATE.ATTACHSPEECH) return; + this.state(STATE.ATTACHSPEECH); + if ( + this.isEscaped || + !(document.options.enableSpeech || document.options.enableBraille) || + !document.options.enableEnrichment + ) { + return; + } + document.getWebworker(); + this.generatorPool.init( + document.options, + document.adaptor, + document.webworker + ); + this.outputData.mml = this.toMathML(this.root, this); + const promise = this.generatorPool + .Speech(this) + .catch((err) => document.options.speechError(document, this, err)); + document.savePromise(promise); + this.outputData.speechPromise = promise; + } + + /** + * @param {SpeechMathDocument} document The MathDocument for the MathItem + */ + public detachSpeech(document: SpeechMathDocument) { + document.webworker.Detach(this); + } + + /** + * @param {string} mml The MathML whose speech is needed. + * @returns {Promise<[string,string]>} A promise for the speech and braille strings + */ + public async speechFor(mml: string): Promise<[string, string]> { + mml = this.toEnriched(mml); + const data = await this.generatorPool.SpeechFor(this, mml); + return [data.label, data.braillelabel]; + } + + /** + * @override + */ + clear() { + this.generatorPool.cancel(this); + } + }; +} + +/*==========================================================================*/ + +/** + * The functions added to MathDocument for enrichment + * + * @template N The HTMLElement node class + * @template T The Text node class + * @template D The Document class + */ +export interface SpeechMathDocument + extends EnrichedMathDocument { + /** + * The webworker handler for the document + */ + webworker: WorkerHandler; + + /** + * Attach speech to the MathItems in the MathDocument + * + * @returns {SpeechMathDocument} The MathDocument (so calls can be chained) + */ + attachSpeech(): SpeechMathDocument; + + /** + * @param {SpeechMathDocument} doc The MathDocument for the error + * @param {SpeechMathItem} math The MathItem causing the error + * @param {Error} err The error being processed + */ + speechError( + doc: SpeechMathDocument, + math: SpeechMathItem, + err: Error + ): void; + + /** + * Set up the worker handler for this document + */ + getWebworker(): void; +} + +/** + * The mixin for adding enrichment to MathDocuments + * + * @param {B} EnrichedMathDocument The MathDocument class to be extended + * @returns {SpeechMathDocument} The enriched MathDocument class + * + * @template N The HTMLElement node class + * @template T The Text node class + * @template D The Document class + * @template B The MathDocument class to extend + */ +export function SpeechMathDocumentMixin< + N, + T, + D, + B extends MathDocumentConstructor>, +>( + EnrichedMathDocument: B +): MathDocumentConstructor> & B { + return class extends EnrichedMathDocument { + /** + * @override + */ + public static OPTIONS: OptionList = { + ...EnrichedMathDocument.OPTIONS, + enableSpeech: true, + enableBraille: true, + speechError: ( + doc: SpeechMathDocument, + math: SpeechMathItem, + err: Error + ) => doc.speechError(doc, math, err), + renderActions: expandable({ + ...EnrichedMathDocument.OPTIONS.renderActions, + attachSpeech: [STATE.ATTACHSPEECH], + }), + worker: { + path: sreRoot(), + maps: sreRoot().replace(/[cm]js\/a11y\/sre$/, 'bundle/sre/mathmaps'), + worker: 'speech-worker.js', + debug: false, + }, + a11y: expandable({ + speech: true, // // switch on speech output + braille: true, // // switch on Braille output + }), + }; + + /** + * The webworker handler for the document + */ + public webworker: WorkerHandler = null; + + /** + * Enrich the MathItem class used for this MathDocument, and create the + * temporary MathItem used for enrchment + * + * @override + * @class + */ + constructor(...args: any[]) { + super(...args); + const ProcessBits = (this.constructor as typeof EnrichedMathDocument) + .ProcessBits; + if (!ProcessBits.has('attach-speech')) { + ProcessBits.allocate('attach-speech'); + } + this.options.MathItem = SpeechMathItemMixin< + N, + T, + D, + Constructor> + >(this.options.MathItem); + } + + /** + * Set up the worker handler for this document + */ + public getWebworker() { + if (this.webworker) return; + this.webworker = new WorkerHandler(this.adaptor, this.options.worker); + this.webworker.Start(); + } + + /** + * Attach speech from a MathItem to a node + * + * @returns {SpeechMathDocument} The object for chaining. + */ + public attachSpeech(): SpeechMathDocument { + if (!this.processed.isSet('attach-speech')) { + const options = this.options; + if ( + options.enableEnrichment && + (options.enableSpeech || options.enableBraille) + ) { + this.getWebworker(); + for (const math of this.math) { + (math as SpeechMathItem).attachSpeech(this); + } + } + this.processed.set('attach-speech'); + } + return this; + } + + /** + * @override + */ + public speechError( + _doc: SpeechMathDocument, + _math: SpeechMathItem, + err: Error + ) { + console.warn('Speech generation error:', err); + } + + /** + * @override + */ + public state(state: number, restore: boolean = false) { + super.state(state, restore); + if (state < STATE.ATTACHSPEECH) { + this.processed.clear('attach-speech'); + if (state >= STATE.TYPESET) { + for (const math of this.math) { + (math as SpeechMathItem).detachSpeech(this); + } + } + } + return this; + } + + /** + * @override + */ + public async done() { + await this.webworker?.Stop(); + return super.done(); + } + }; +} + +/*==========================================================================*/ + +/** + * Add a speech Handler instance + * + * @param {Handler} handler The Handler instance to speech + * @param {MathML} MmlJax The MathML input jax to use for reading the enriched MathML + * @returns {Handler} The handler that was modified (for purposes of chainging extensions) + * + * @template N The HTMLElement node class + * @template T The Text node class + * @template D The Document class + */ +export function SpeechHandler( + handler: Handler, + MmlJax: MathML +): Handler { + if (!handler.documentClass.prototype.enrich && MmlJax) { + handler = EnrichHandler(handler, MmlJax); + } + handler.documentClass = SpeechMathDocumentMixin(handler.documentClass as any); + return handler; +} diff --git a/ts/a11y/speech/GeneratorPool.ts b/ts/a11y/speech/GeneratorPool.ts new file mode 100644 index 000000000..c004c03a2 --- /dev/null +++ b/ts/a11y/speech/GeneratorPool.ts @@ -0,0 +1,283 @@ +/************************************************************* + * + * Copyright (c) 2009-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Speech generator collections for enrichment and explorers. + * + * @author v.sorge@mathjax.org (Volker Sorge) + */ + +import { OptionList } from '../../util/Options.js'; +import { LiveRegion } from '../explorer/Region.js'; +import { buildLabel, SemAttr } from '../speech/SpeechUtil.js'; +import { DOMAdaptor } from '../../core/DOMAdaptor.js'; +import { SpeechMathItem } from '../speech.js'; +import { WorkerHandler } from './WebWorker.js'; + +/** + * @template N The HTMLElement node class + * @template T The Text node class + * @template D The Document class + */ +export class GeneratorPool { + private webworker: WorkerHandler; + private _element: Element; + + set element(element: Element) { + this._element = element; + } + + get element() { + return this._element; + } + + /** + * The initial start of the promise chain. + */ + public promise: Promise = Promise.resolve(); + + /** + * The adaptor to work with typeset nodes. + */ + public adaptor: DOMAdaptor = null; + + /** + * The current speech setting for Sre + */ + private _options: OptionList = {}; + + /** + * Option setter that takes care of setting up SRE and assembling the options + * for the speech generators. + * + * @param {OptionList} options The option list. + */ + public set options(options: OptionList) { + this._options = Object.assign({}, options?.sre || {}, { + enableSpeech: options.enableSpeech, + enableBraille: options.enableBraille, + }); + delete this._options.custom; + } + + public get options() { + return this._options; + } + + private _init = false; + + /** + * Init method for speech generation. + * + * @param {OptionList} options A list of options. + * @param {DOMAdaptor} adaptor The DOM adaptor providing access to nodes. + * @param {WorkerHandler} webworker The webworker with SRE. + */ + public init( + options: OptionList, + adaptor: DOMAdaptor, + webworker: WorkerHandler + ) { + this.options = options; + if (this._init) return; + this.adaptor = adaptor; + this.webworker = webworker; + this._init = true; + } + + /** + * Update method for speech generation options. Runs a retry until locales have been + * loaded. + * + * @param {OptionList} options A list of options. + */ + public update(options: OptionList) { + Object.assign(this.options, options); + } + + /** + * Compute speech using the original MathML element as reference. + * + * @param {SpeechMathItem} item The SpeechMathItem to add speech to + * @returns {Promise} The promise that resolves when the command is complete + */ + public Speech(item: SpeechMathItem): Promise { + const mml = item.outputData.mml; + const options = Object.assign({}, this.options, { modality: 'speech' }); + return (this.promise = this.webworker.Speech(mml, options, item)); + } + + public SpeechFor(item: SpeechMathItem, mml: string): Promise { + const options = Object.assign({}, this.options, { modality: 'speech' }); + return this.webworker.speechFor(mml, options, item); + } + + /** + * Cancel a pending speech task + * + * @param {SpeechMathItem} item The SpeechMathItem whose task is to be cancelled + */ + public cancel(item: SpeechMathItem) { + this.webworker?.Cancel(item); + } + + /** + * Updates the given speech regions, possibly reinstanting previously saved + * speech. + * + * @param {N} node The typeset node + * @param {LiveRegion} speechRegion The speech region. + * @param {LiveRegion} brailleRegion The braille region. + */ + public updateRegions( + node: N, + speechRegion: LiveRegion, + brailleRegion: LiveRegion + ) { + speechRegion.Update(this.getLabel(node)); + brailleRegion.Update(this.getBraille(node)); + } + + /** + * Retrieves the last options from the node. + * + * @param {N} node The root node of the expression. + * @returns {OptionList} The relevant SRE options. + */ + private getOptions(node: N): OptionList { + return { + locale: this.adaptor.getAttribute(node, 'data-semantic-locale') ?? '', + domain: this.adaptor.getAttribute(node, 'data-semantic-domain') ?? '', + style: this.adaptor.getAttribute(node, 'data-semantic-style') ?? '', + domain2style: + this.adaptor.getAttribute(node, 'data-semantic-domain2style') ?? '', + }; + } + + /** + * Cycles rule sets for the speech generator. + * + * @param {SpeechMathItem} item The SpeechMathItem whose rule set is changing + * @returns {Promise} A promise that resolves when the command completes + */ + public nextRules(item: SpeechMathItem): Promise { + const options = this.getOptions(item.typesetRoot); + this.update(options); + return (this.promise = this.webworker.nextRules( + item.outputData.mml, + Object.assign({}, this.options, { modality: 'speech' }), + item + )); + } + + /** + * Cycles style or preference settings for the speech generator. + * + * @param {N} node The typeset node. + * @param {SpeechMathItem} item The SpeechMathItem whose preferences are changing + * @returns {Promise} A promise that resolves when the command completes + */ + public nextStyle(node: N, item: SpeechMathItem): Promise { + const options = this.getOptions(item.typesetRoot); + this.update(options); + return (this.promise = this.webworker.nextStyle( + item.outputData.mml, + Object.assign({}, this.options, { modality: 'speech' }), + this.adaptor.getAttribute(node, 'data-semantic-id'), + item + )); + } + + /** + * Computes the speech label from the node combining prefixes and postfixes. + * + * @param {N} node The typeset node. + * @param {string=} _center Core speech. Defaults to `data-semantic-speech`. + * @param {string=} sep The speech separator. Defaults to space. + * @returns {string} The assembled label. + */ + public getLabel(node: N, _center: string = '', sep: string = ' '): string { + const adaptor = this.adaptor; + return ( + buildLabel( + adaptor.getAttribute(node, SemAttr.SPEECH_SSML), + adaptor.getAttribute(node, SemAttr.PREFIX_SSML), + // TODO: check if we need this or if it is automatic by the screen readers. + adaptor.getAttribute(node, SemAttr.POSTFIX_SSML), + sep + ) || adaptor.getAttribute(node, 'aria-label') + ); + } + + /** + * Computes the braille label from the node. + * + * @param {N} node The typeset node. + * @returns {string} The assembled label. + */ + public getBraille(node: N): string { + const adaptor = this.adaptor; + return ( + adaptor.getAttribute(node, 'aria-braillelabel') || + adaptor.getAttribute(node, SemAttr.BRAILLE) + ); + } + + /*********************************************************/ + /** + * Menu related functions. + */ + /** + * Computes the clearspeak preferences for the current locale. + * + * @param {Map} prefs Map to store the compute preferences. + * @returns {Promise} The promise that resolves when the command is complete + */ + public getLocalePreferences( + prefs: Map + ): Promise { + return (this.promise = this.webworker.clearspeakLocalePreferences( + this.options, + prefs + )); + } + + /** + * Computes the clearspeak preferences that are semantically relevant for the + * currently focused node. + * + * @param {SpeechMathItem} item The SpeechMathItem where is menu is opened. + * @param {string} semantic The semantic id of the last focused node. + * @param {Map} prefs Map for recording the computed preference. + * @param {number} counter Counter for storing the result in the map. + * @returns {Promise} The promise that resolves when the command is complete + */ + public getRelevantPreferences( + item: SpeechMathItem, + semantic: string, + prefs: Map, + counter: number + ): Promise { + const mml = item.outputData.mml; + return (this.promise = this.webworker.clearspeakRelevantPreferences( + mml, + semantic, + prefs, + counter + )); + } +} diff --git a/ts/output/common/fonts/tex/sans-serif-bold-italic.ts b/ts/a11y/speech/MessageTypes.ts similarity index 60% rename from ts/output/common/fonts/tex/sans-serif-bold-italic.ts rename to ts/a11y/speech/MessageTypes.ts index ae6aaec96..78ff87b57 100644 --- a/ts/output/common/fonts/tex/sans-serif-bold-italic.ts +++ b/ts/a11y/speech/MessageTypes.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,23 @@ * limitations under the License. */ -import {CharMap, CharOptions} from '../../FontData.js'; +/** + * @file Types for Web worker communication. + * + * @author v.sorge@mathjax.org (Volker Sorge) + */ + +export type Message = { [key: string]: any }; -export const sansSerifBoldItalic: CharMap = { - 0x131: [.458, 0, .256], - 0x237: [.458, .205, .286], +export type WorkerCommand = { + cmd: string; + debug: boolean; + data: Message; }; + +export type ClientCommand = { + cmd: string; + data: WorkerCommand | Message; +}; + +export type Structure = { [id: string]: any }; diff --git a/ts/a11y/speech/SpeechMenu.ts b/ts/a11y/speech/SpeechMenu.ts new file mode 100644 index 000000000..97663197d --- /dev/null +++ b/ts/a11y/speech/SpeechMenu.ts @@ -0,0 +1,329 @@ +/************************************************************* + * + * Copyright (c) 2018-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Clearspeak preference menu. + * + * @author v.sorge@mathjax.org (Volker Sorge) + */ + +import { ExplorerMathItem } from '../explorer.js'; +import { MJContextMenu } from '../../ui/menu/MJContextMenu.js'; +import { SubMenu, Submenu } from '../../ui/menu/mj-context-menu.js'; +import * as Sre from '../sre.js'; + +/** + * Values for the ClearSpeak preference variables. + */ +let csPrefsSetting: { [pref: string]: string } = {}; +let previousPrefs: string = null; + +/** + * Computes the current ClearSpeak preference, by either extracting it from the + * settings, returning the previously stored one, or returning the default. + * + * @param {string} settings The current speech rule options setting. + * @returns {string} The current ClearSpeak preference. + */ +function currentPreference(settings?: string): string { + const matcher = settings?.match(/^clearspeak-(.*)/); + previousPrefs = (matcher && matcher[1]) ?? previousPrefs ?? 'default'; + return previousPrefs; +} + +/** + * Generator of all variables for the Clearspeak Preference settings. + * + * @param {MJContextMenu} menu The current context menu. + * @param {string[]} prefs The preferences. + */ +function csPrefsVariables(menu: MJContextMenu, prefs: string[]) { + const srVariable = menu.pool.lookup('speechRules'); + const previous = currentPreference(menu.settings.speechRules); + csPrefsSetting = Sre.fromPreference(previous); // Do here + for (const pref of prefs) { + menu.factory.get('variable')( + menu.factory, + { + name: 'csprf_' + pref, + setter: (value: string) => { + csPrefsSetting[pref] = value; + srVariable.setValue( + 'clearspeak-' + Sre.toPreference(csPrefsSetting) // Do here + ); + }, + getter: () => { + return csPrefsSetting[pref] || 'Auto'; + }, + }, + menu.pool + ); + } +} + +/** + * Map for storing clearspeak preferences per locale, which can vary. They need + * to be computed only once as they should not change during a single run. + */ +const localePreferences: Map = new Map(); + +/** + * Computes the clearspeak preferences for the given locale via the worker. + * + * @param {MJContextMenu} menu The parent menu. + * @param {string} locale The locale to get. + */ +async function getLocalePreferences(menu: MJContextMenu, locale: string) { + if (!localePreferences.has(locale)) { + await ( + menu.mathItem as ExplorerMathItem + ).generatorPool.getLocalePreferences(localePreferences); + } +} + +/** + * Map for temporarily storing clearspeak preference categories that is relevant + * for a particular node that is currently focused. They are computed on the fly + * in the worker. To coordinate messages we use an increasing counter. + */ +const relevantPreferences: Map = new Map(); +let counter = 0; + +/** + * Generate the selection box for the Clearspeak Preferences. + * + * @param {MJContextMenu} menu The current context menu. + * @param {string} locale The current locale. + * @returns {Promise} The constructed selection box sub menu. + */ +function csSelectionBox(menu: MJContextMenu, locale: string): object { + const props = localePreferences.get(locale); + csPrefsVariables(menu, Object.keys(props)); + const items = []; + for (const prop of Object.getOwnPropertyNames(props)) { + items.push({ + title: prop, + values: props[prop].map((x) => x.replace(RegExp('^' + prop + '_'), '')), + variable: 'csprf_' + prop, + }); + } + const sb = menu.factory.get('selectionBox')( + menu.factory, + { + title: 'Clearspeak Preferences', + signature: '', + order: 'alphabetic', + grid: 'square', + selections: items, + }, + menu + ); + return { + type: 'command', + id: 'ClearspeakPreferences', + content: 'Select Preferences', + action: () => sb.post(0, 0), + }; +} + +/** + * Generates the two menu items for the base preference menu: + * 1. No Preferences: All preferences are set to Auto. + * + * 2. Current Preferences: The last chosen preferences for clearspeak. These are + * initially set to: + * default, when no other information is available + * the value read from localStorage if there is one for clearspeak + * previousPrefs that remembers the value before switching to Mathspeak + * + * @param {string} previous The currently set preferences. + * @returns {object[]} The menu items as a list of JSON objects. + */ +function basePreferences(previous: string): object[] { + const items = [ + { + type: 'radio', + content: 'No Preferences', + id: 'clearspeak-default', + variable: 'speechRules', + }, + { + type: 'radio', + content: 'Current Preferences', + id: 'clearspeak-' + previous, + variable: 'speechRules', + }, + { + type: 'rule', + }, + ]; + return items; +} + +/** + * Generates the items for smart preference choices, depending on the top most + * + * @param {string} previous The currently set preferences. + * @param {string} smart The semantic type of the smart preferences. + * @param {string} locale The current locale. + * @returns {object[]} The menu of smart choices as a list of JSON objects. + */ +function smartPreferences( + previous: string, + smart: string, + locale: string +): object[] { + const loc = localePreferences.get(locale); + const items = [ + { type: 'label', content: 'Preferences for ' + smart }, + { type: 'rule' }, + ]; + return items.concat( + loc[smart].map(function (x) { + const [key, value] = x.split('_'); + return { + type: 'radioCompare', + content: value, + id: 'clearspeak-' + Sre.addPreference(previous, key, value), // Do here + variable: 'speechRules', + comparator: (x: string, y: string) => { + if (x === y) { + return true; + } + if (value !== 'Auto') { + return false; + } + const [dom1, pref] = x.split('-'); + const [dom2] = y.split('-'); + return ( + dom1 === dom2 && !Sre.fromPreference(pref)[key] // Do here + ); + }, + }; + }) + ); +} + +/** + * Creates dynamic clearspeak menu. + * + * @param {MJContextMenu} menu The context menu. + * @param {Submenu} sub The submenu to attach elements to. + * @param {(sub: SubMenu) => void} callback Callback to apply on the constructed + * submenu. + */ +export async function clearspeakMenu( + menu: MJContextMenu, + sub: Submenu, + callback: (sub: SubMenu) => void +) { + const exit = (items: object[]) => { + callback( + menu.factory.get('subMenu')( + menu.factory, + { + items: items, + id: 'Clearspeak', + }, + sub + ) + ); + }; + if (!menu.settings.speech || !menu.settings.enrich) { + exit([]); + return; + } + const locale = menu.pool.lookup('locale').getValue() as string; + await getLocalePreferences(menu, locale); + if (!localePreferences.get(locale)) { + exit([]); + return; + } + const box = csSelectionBox(menu, locale); + let items: object[] = []; + if (menu.settings.speech) { + const item = menu.mathItem as ExplorerMathItem; + const explorer = item?.explorers?.speech; + const previous = currentPreference(menu.settings.speechRules); + items = items.concat(basePreferences(previous)); + const focus = explorer?.refocus; + const semantic = focus?.getAttribute('data-semantic-id') ?? null; + const count = counter++; + await item.generatorPool.getRelevantPreferences( + item, + semantic, + relevantPreferences, + count + ); + const smart = relevantPreferences.get(count); + relevantPreferences.delete(count); + if (smart) { + const smartItems = smartPreferences(previous, smart, locale); + items = items.concat(smartItems); + } + } + items.splice(2, 0, box); + exit(items); +} +MJContextMenu.DynamicSubmenus.set('Clearspeak', [clearspeakMenu, 'speech']); + +let LOCALE_MENU: SubMenu = null; + +/** + * Creates dynamic locale menu. + * + * @param {MJContextMenu} menu The context menu. + * @param {Submenu} sub The submenu to attach elements to. + * @param {(sub: SubMenu) => void} callback Callback to apply on the constructed + * submenu. + */ +export function localeMenu( + menu: MJContextMenu, + sub: Submenu, + callback: (sub: SubMenu) => void +) { + if (LOCALE_MENU) { + callback(LOCALE_MENU); + return; + } + const radios: { + type: string; + id: string; + content: string; + variable: string; + }[] = []; + for (const lang of Sre.locales.keys()) { + if (lang === 'nemeth' || lang === 'euro') continue; + radios.push({ + type: 'radio', + id: lang, + content: Sre.locales.get(lang) || lang, + variable: 'locale', + }); + } + radios.sort((x, y) => x.content.localeCompare(y.content, 'en')); + LOCALE_MENU = menu.factory.get('subMenu')( + menu.factory, + { + items: radios, + id: 'Language', + }, + sub + ); + callback(LOCALE_MENU); +} +MJContextMenu.DynamicSubmenus.set('A11yLanguage', [localeMenu, 'speech']); diff --git a/ts/a11y/speech/SpeechUtil.ts b/ts/a11y/speech/SpeechUtil.ts new file mode 100644 index 000000000..837c3408d --- /dev/null +++ b/ts/a11y/speech/SpeechUtil.ts @@ -0,0 +1,260 @@ +/************************************************************* + * + * Copyright (c) 2018-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Provides utility functions for speech handling. + * + * @author v.sorge@mathjax.org (Volker Sorge) + */ + +import * as Sre from '../sre.js'; + +const ProsodyKeys = ['pitch', 'rate', 'volume']; + +interface ProsodyElement { + [propName: string]: string | boolean | number; + pitch?: number; + rate?: number; + volume?: number; +} + +export interface SsmlElement extends ProsodyElement { + pause?: string; + text?: string; + mark?: string; + character?: boolean; + kind?: string; +} + +/** + * Parses a string containing an ssml structure into a list of text strings + * with associated ssml annotation elements. + * + * @param {string} speech The speech string. + * @returns {[string, SsmlElement[]]} The annotation structure. + */ +export function ssmlParsing(speech: string): [string, SsmlElement[]] { + const xml = Sre.parseDOM(speech); + const instr: SsmlElement[] = []; + const text: string[] = []; + recurseSsml(Array.from(xml.childNodes), instr, text); + return [text.join(' '), instr]; +} + +/** + * Tail recursive combination of SSML components. + * + * @param {Node[]} nodes A list of SSML nodes. + * @param {SsmlElement[]} instr Accumulator for collating Ssml annotation + * elements. + * @param {string[]} text A list of text elements. + * @param {ProsodyElement?} prosody The currently active prosody elements. + */ +function recurseSsml( + nodes: Node[], + instr: SsmlElement[], + text: string[], + prosody: ProsodyElement = {} +) { + for (const node of nodes) { + if (node.nodeType === 3) { + const content = node.textContent.trim(); + if (content) { + text.push(content); + instr.push(Object.assign({ text: content }, prosody)); + } + continue; + } + if (node.nodeType === 1) { + const element = node as Element; + const tag = element.tagName; + if (tag === 'speak') { + continue; + } + if (tag === 'prosody') { + recurseSsml( + Array.from(node.childNodes), + instr, + text, + getProsody(element, prosody) + ); + continue; + } + switch (tag) { + case 'break': + instr.push({ pause: element.getAttribute('time') }); + break; + case 'mark': + instr.push({ mark: element.getAttribute('name') }); + break; + case 'say-as': { + const txt = element.textContent; + instr.push(Object.assign({ text: txt, character: true }, prosody)); + text.push(txt); + break; + } + } + } + } +} + +/** + * Maps prosody types to scaling functions. + */ +// TODO: These should be tweaked after more testing. +const combinePros: { [key: string]: (x: number, sign: string) => number } = { + pitch: (x: number, _sign: string) => 1 * (x / 100), + volume: (x: number, _sign: string) => 0.5 * (x / 100), + rate: (x: number, _sign: string) => 1 * (x / 100), +}; + +/** + * Retrieves prosody annotations from an SSML node. + * + * @param {Element} element The SSML node. + * @param {ProsodyElement} prosody The prosody annotation. + * @returns {ProsodyElement} The combined prosody element. + */ +function getProsody(element: Element, prosody: ProsodyElement): ProsodyElement { + const combine: ProsodyElement = {}; + for (const pros of ProsodyKeys) { + if (element.hasAttribute(pros)) { + const [sign, value] = extractProsody(element.getAttribute(pros)); + if (!sign) { + // TODO: Sort out the base value. It is .5 for volume! + combine[pros] = pros === 'volume' ? 0.5 : 1; + continue; + } + let orig = prosody[pros] as number; + orig = orig ? orig : pros === 'volume' ? 0.5 : 1; + const relative = combinePros[pros](parseInt(value, 10), sign); + combine[pros] = sign === '-' ? orig - relative : orig + relative; + } + } + return combine; +} + +/** + * Extracts the prosody value from an attribute. + */ +const prosodyRegexp = /([+-]?)([0-9]+)%/; + +/** + * Extracts the prosody value from an attribute. + * + * @param {string} attr The prosody attribute. + * @returns {[string, string]} The in terms of sign and value. + */ +function extractProsody(attr: string): [string, string] { + const match = attr.match(prosodyRegexp); + if (!match) { + console.warn('Something went wrong with the prosody matching.'); + return ['', '100']; + } + return [match[1], match[2]]; +} + +/** + * Speech, labels and aria + */ + +/** + * Builds a speech label from input components. + * + * @param {string} speech The speech string. + * @param {string} prefix The prefix expression. + * @param {string} postfix The postfix expression. + * @param {string=} sep The separator string. Defaults to space. + * @returns {string} The assembled label. + */ +export function buildLabel( + speech: string, + prefix: string, + postfix: string, + sep: string = ' ' +): string { + if (!speech) { + return ''; + } + const label = [speech]; + if (prefix) { + label.unshift(prefix); + } + if (postfix) { + label.push(postfix); + } + // TODO: Do we need to merge wrt. locale in SRE. + return label.join(sep); +} + +/** + * Builds speechs from SSML markup strings. + * + * @param {string} speech The speech string. + * @param {string=} locale An optional locale. + * @param {string=} rate The base speech rate. + * @returns {[string, SsmlElement[]]} The speech with the ssml annotation structure + */ +export function buildSpeech( + speech: string, + locale: string = 'en', + rate: string = '100' +): [string, SsmlElement[]] { + return ssmlParsing( + '` + + `${speech}` + + '' + ); +} + +/** + * Creates a honking sound. + */ +export function honk() { + const ac = new AudioContext(); + const os = ac.createOscillator(); + os.frequency.value = 300; + os.connect(ac.destination); + os.start(ac.currentTime); + os.stop(ac.currentTime + 0.05); +} + +/** + * In place speech computations. + */ +export enum InPlace { + NONE, + DEPTH, + SUMMARY, +} + +/** + * Speech attributes. + */ +export enum SemAttr { + SPEECH = 'data-semantic-speech-none', + SPEECH_SSML = 'data-semantic-speech', + SUMMARY = 'data-semantic-summary-none', + SUMMARY_SSML = 'data-semantic-summary', + PREFIX = 'data-semantic-prefix-none', + PREFIX_SSML = 'data-semantic-prefix', + POSTFIX = 'data-semantic-postfix-none', + POSTFIX_SSML = 'data-semantic-postfix', + BRAILLE = 'data-semantic-braille', +} diff --git a/ts/a11y/speech/WebWorker.ts b/ts/a11y/speech/WebWorker.ts new file mode 100644 index 000000000..be0a65db5 --- /dev/null +++ b/ts/a11y/speech/WebWorker.ts @@ -0,0 +1,616 @@ +/************************************************************* + * + * Copyright (c) 2018-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Web worker utilities. + * + * @author v.sorge@mathjax.org (Volker Sorge) + */ + +import { DOMAdaptor, minWorker } from '../../core/DOMAdaptor.js'; +import { OptionList } from '../../util/Options.js'; +import { Message, ClientCommand, Structure } from './MessageTypes.js'; +import { SpeechMathItem } from '../speech.js'; +import { SemAttr } from './SpeechUtil.js'; + +/** + * Class for relevant task information. + */ +class Task { + constructor( + public cmd: ClientCommand, + public item: SpeechMathItem, + public resolve: (value: any) => void, + public reject: (cmd: string) => void + ) {} +} + +/** + * The main WorkerHandler class + * + * @template N The HTMLElement node class + * @template T The Text node class + * @template D The Document class + */ +export class WorkerHandler { + /** + * Callback for ready signal + */ + public ready: boolean = false; + + /** + * The task queue + */ + private tasks: Task[] = []; + + /** + * The webworker + */ + protected worker: minWorker; + + /** + * The adaptor to work with typeset nodes. + * + * @param {DOMAdaptor} adaptor The adaptor to use for DOM access. + * @param {OptionList} options The worker options. + */ + constructor( + public adaptor: DOMAdaptor, + private options: OptionList + ) {} + + /** + * This starts the worker. + */ + public async Start() { + if (this.ready) throw Error('Worker already started'); + this.worker = await this.adaptor.createWorker( + this.Listener.bind(this), + this.options + ); + } + + /** + * Debug output when debug flag is set. + * + * @param {string} msg Base message + * @param {...any} rest Remaining arguments + */ + private debug(msg: string, ...rest: any[]) { + if (this.options.debug) { + console.info(msg, ...rest); + } + } + + /** + * Listener for the messages from the worker. + * The message will contain a command and data, and we look + * in the list of commands to see if we have an implementation for the + * given one. If so, we run the command on the data from the message, + * otherwise we throw an error. + * + * @param {MessageEvent} event The message event. + */ + public Listener(event: MessageEvent) { + this.debug('Worker >>> Client:', event.data); + if (Object.hasOwn(this.Commands, event.data.cmd)) { + this.Commands[event.data.cmd](this, event.data.data); + } else { + this.debug('Invalid command from worker: ' + event.data.cmd); + } + } + + /** + * Send messages to the worker. + * + * @param {ClientCommand} msg The command message. + * @param {SpeechMathItem} item Optional SpeechMathItem that is being processed + * command name as input. + * @returns {Promise} A promise that resolves when the command completes + */ + public Post( + msg: ClientCommand, + item?: SpeechMathItem + ): Promise { + const promise = new Promise((resolve, reject) => { + this.tasks.push(new Task(msg, item, resolve, reject)); + }); + if (this.ready && this.tasks.length === 1) { + this.postNext(); + } + return promise; + } + + /** + * Post the next available task, if there is one. + */ + private postNext() { + if (this.tasks.length) { + const msg = Object.assign({}, this.tasks[0].cmd, { + debug: this.options.debug, + }); + this.worker.postMessage(msg); + } + } + + /** + * Remove a task from the task list. + * + * @param {SpeechMathItem} item The item whose task is to be canceled. + */ + public Cancel(item: SpeechMathItem) { + const i = this.tasks.findIndex((task) => task.item === item); + if (i > 0) { + this.tasks[i].reject(`Task ${this.tasks[i].cmd.cmd} cancelled`); + this.tasks.splice(i, 1); + } + } + + /** + * Setup the engine in the SRE worker. + * + * @param {OptionList} options The options list. + * @returns {Promise} A promise that resolves when the command completes + */ + public Setup(options: OptionList): Promise { + return this.Post({ + cmd: 'setup', + data: { + domain: options.domain, + style: options.style, + locale: options.locale, + modality: options.modality, + }, + }); + } + + /** + * Compute speech structure for the math. + * + * @param {string} math The mml string. + * @param {OptionList} options The options list. + * @param {SpeechMathItem} item The mathitem for reattaching the speech. + * @returns {Promise} A promise that resolves when the command completes + */ + public async Speech( + math: string, + options: OptionList, + item: SpeechMathItem + ): Promise { + this.Attach( + item, + options.enableSpeech, + options.enableBraille, + await this.Post( + { + cmd: 'speech', + data: { mml: math, options: options }, + }, + item + ) + ); + } + + /** + * Computes the next rule set for this particular SRE setting. We assume that + * the engine has been set to the options of the current expression. + * + * @param {string} math The mml string. + * @param {OptionList} options The options list. + * @param {SpeechMathItem} item The mathitem for reattaching the speech. + * @returns {Promise} A promise that resolves when the command completes + */ + public async nextRules( + math: string, + options: OptionList, + item: SpeechMathItem + ): Promise { + this.Attach( + item, + options.enableSpeech, + options.enableBraille, + await this.Post( + { + cmd: 'nextRules', + data: { mml: math, options: options }, + }, + item + ) + ); + } + + /** + * Computes the next style for the particular SRE settings and the currently + * focused node. We pass the options of the current expression. + * + * Note, that we compute not only the next style but also the next speech + * structure in the method, as smart computation is done wrt. the semantic + * node, and we do not want to reconstruct the semantic XML tree on the SRE + * side twice. Hence we pass the math expression, plus the semantic ID of the + * currently focused node. + * + * @param {string} math The linearized mml expression. + * @param {OptionList} options The options list. + * @param {string} nodeId The semantic Id of the currenctly focused node. + * @param {SpeechMathItem} item The mathitem for reattaching the speech. + * @returns {Promise} A promise that resolves when the command completes + */ + public async nextStyle( + math: string, + options: OptionList, + nodeId: string, + item: SpeechMathItem + ): Promise { + this.Attach( + item, + options.enableSpeech, + options.enableBraille, + await this.Post( + { + cmd: 'nextStyle', + data: { + mml: math, + options: options, + nodeId: nodeId, + }, + }, + item + ) + ); + } + + /** + * Return speech structure for an arbitrary MathML string + * + * @param {string} math The linearized mml expression. + * @param {OptionList} options The options list. + * @param {SpeechMathItem} item The mathitem for reattaching the speech. + * @returns {Promise} A promise that resolves when the command completes + */ + public async speechFor( + math: string, + options: OptionList, + item: SpeechMathItem + ): Promise { + const data = await this.Post( + { + cmd: 'speech', + data: { mml: math, options: options }, + }, + item + ); + return JSON.parse(data); + } + + /** + * Attach the speech structure to an item's DOM + * + * @param {SpeechMathItem} item The SpeechMathItem to attach to + * @param {boolean} speech True when speech should be added + * @param {boolean} braille True when Braille should be added + * @param {string} structure The speech JSON structure to attach + */ + public Attach( + item: SpeechMathItem, + speech: boolean, + braille: boolean, + structure: string + ) { + const data = JSON.parse(structure) as Structure; + const container = item.typesetRoot; + if (!container) return; // Element is gone, maybe retypeset or removed. + this.setSpecialAttributes(container, data.options, 'data-semantic-', [ + 'locale', + 'domain', + 'style', + 'domain2style', + ]); + const adaptor = this.adaptor; + this.setSpecialAttributes(container, data.translations, 'data-semantic-'); + // Sort out Mactions + for (const [id, sid] of Object.entries(data.mactions)) { + let node = adaptor.getElement('#' + id, container); + if (!node || !adaptor.childNodes(node)[0]) { + continue; + } + node = adaptor.childNodes(node)[0] as N; + adaptor.setAttribute(node, 'data-semantic-type', 'dummy'); + this.setSpecialAttributes(node, sid, ''); + } + this.setSpeechAttributes( + adaptor.childNodes(container)[0], + '', + data, + speech, + braille + ); + if (speech) { + if (data.label) { + adaptor.setAttribute(container, SemAttr.SPEECH, data.label); + adaptor.setAttribute(container, SemAttr.SPEECH_SSML, data.ssml); + item.outputData.speech = data.label; + } + adaptor.setAttribute(container, 'data-speech-attached', 'true'); + } + if (braille) { + if (data.braillelabel) { + adaptor.setAttribute(container, SemAttr.BRAILLE, data.braillelabel); + item.outputData.braille = data.braillelabel; + } + if (data.braille) { + adaptor.setAttribute(container, 'data-braille-attached', 'true'); + } + } + } + + /** + * Add the speech attributes to a node + * + * @param {N} node The node to add speech to + * @param {Structure} data The speech data to use + * @param {boolean} speech True when speech should be added + * @param {boolean} braille True when Braille should be added + */ + protected setSpeechAttribute( + node: N, + data: Structure, + speech: boolean, + braille: boolean + ) { + const adaptor = this.adaptor; + const id = adaptor.getAttribute(node, 'data-semantic-id'); + adaptor.removeAttribute(node, 'data-speech-node'); + if (speech && data.speech[id]['speech-none']) { + adaptor.setAttribute(node, 'data-speech-node', 'true'); + for (let [key, value] of Object.entries(data.speech[id])) { + key = key.replace(/-ssml$/, ''); + if (value) { + adaptor.setAttribute(node, `data-semantic-${key}`, value as string); + } + } + } + if (braille && data.braille?.[id]?.['braille-none']) { + adaptor.setAttribute(node, 'data-speech-node', 'true'); + const value = data.braille[id]['braille-none']; + adaptor.setAttribute(node, SemAttr.BRAILLE, value); + } + } + + /** + * Add the speech attributes to a node's DOM tree + * + * @param {N|T} root The node to add speech to + * @param {string} rootId The root nodes's ID + * @param {Structure} data The speech data to use + * @param {boolean} speech True when speech should be added + * @param {boolean} braille True when Braille should be added + * @returns {string} The updated root ID + */ + protected setSpeechAttributes( + root: N | T, + rootId: string, + data: Structure, + speech: boolean, + braille: boolean + ): string { + const adaptor = this.adaptor; + if ( + !root || + adaptor.kind(root) === '#text' || + adaptor.kind(root) === '#comment' + ) { + return rootId; + } + root = root as N; + if (adaptor.hasAttribute(root, 'data-semantic-id')) { + this.setSpeechAttribute(root, data, speech, braille); + if (!rootId && !adaptor.hasAttribute(root, 'data-semantic-parent')) { + rootId = adaptor.getAttribute(root, 'data-semantic-id'); + } + } + for (const child of Array.from(adaptor.childNodes(root))) { + rootId = this.setSpeechAttributes(child, rootId, data, speech, braille); + } + return rootId; + } + + /** + * Adds a set of attributes to the given node. + * + * @param {N} node The node on which to set attributes. + * @param {OptionList} map The attribute to value map. + * @param {string} prefix A possible prefix for the attribute name. + * @param {string[]} keys An optional list to select only those attributes. + */ + protected setSpecialAttributes( + node: N, + map: OptionList, + prefix: string, + keys?: string[] + ) { + if (!map) return; + keys = keys || Object.keys(map); + for (const key of keys) { + const value = map[key]; + if (value) { + this.adaptor.setAttribute(node, `${prefix}${key.toLowerCase()}`, value); + } + } + } + + /** + * Remove speech attributes from a MathItem + * + * @param {SpeechMathItem} item The MathItem whose speech attributes should be removed. + */ + public Detach(item: SpeechMathItem) { + const container = item.typesetRoot; + this.adaptor.removeAttribute(container, 'data-speech-attached'); + this.adaptor.removeAttribute(container, 'data-braille-attached'); + this.detachSpeech(container); + } + + /** + * Recursively remove speech attributes from a DOM tree + * + * @param {N} node The root node of the tree to modify + */ + public detachSpeech(node: N) { + const adaptor = this.adaptor; + const children = adaptor.childNodes(node); + if (!children) return; + if (adaptor.kind(node) !== '#text') { + for (const key of [ + 'none', + 'summary-none', + 'speech', + 'speech-none', + 'summary', + 'braille', + ]) { + adaptor.removeAttribute(node, `data-semantic-${key}`); + } + } + for (const child of children) { + this.detachSpeech(child as N); + } + } + + /** + * Terminates the worker. + * + * @returns {Promise} The promise for the worker termination. + */ + public Terminate(): Promise | void { + this.debug('Terminating pending tasks'); + for (const task of this.tasks) { + task.reject( + `${task.cmd.data.cmd} cancelled by WorkerHandler termination` + ); + } + this.tasks = []; + this.debug('Terminating worker'); + return this.worker.terminate(); + } + + /** + * Stop the worker and clear the values so that the worker can be + * restarted, if desired. + */ + public async Stop() { + if (!this.worker) { + throw Error('Worker has not been started'); + } + await this.Terminate(); + this.worker = null; + this.ready = false; + } + + /** + * Worker call to compute clearspeak preferences for the current locale. + * + * @param {OptionList} options The options list. + * @param {Map} prefs Map to store the compute preferences. + * @returns {Promise} The promise that resolves when the command is complete + */ + public async clearspeakLocalePreferences( + options: OptionList, + prefs: Map + ): Promise { + await this.Post({ + cmd: 'localePreferences', + data: { + options: options, + }, + }).then((data) => { + prefs.set(options.locale, JSON.parse(data)); + }); + } + + /** + * Computes the clearspeak preference category that are semantically relevant + * for the currently focused node. + * + * @param {string} math The linearized mml expression. + * @param {string} nodeId The semantic id of node to compute the preference for. + * @param {Map} prefs Map for recording the computed preference. + * @param {number} counter Counter for storing the result in the map. + * @returns {Promise} The promise that resolves when the command is complete + */ + public async clearspeakRelevantPreferences( + math: string, + nodeId: string, + prefs: Map, + counter: number + ): Promise { + await this.Post({ + cmd: 'relevantPreferences', + data: { + mml: math, + id: nodeId, + }, + }).then((e) => { + prefs.set(counter, e); + }); + } + + /** + * The list of valid commands from the Worker. + */ + public Commands: { + [id: string]: (handler: WorkerHandler, data: Message) => void; + } = { + /** + * This signals that the worker in the iframe is loaded and ready + * + * @param {WorkerHandler} handler The active handler for the worker. + * @param {Message} _data The data received from the worker. Ignored. + */ + Ready(handler: WorkerHandler, _data: Message) { + handler.ready = true; + handler.postNext(); + }, + + /** + * Signals that the worker has finished its last task. + * + * @param {WorkerHandler} handler The active handler for the worker. + * @param {Message} data The data received from the worker. + */ + Finished(handler: WorkerHandler, data: Message) { + const task = handler.tasks.shift(); + if (data.success) { + task.resolve(data.result); + } else { + task.reject(data.error); + } + handler.postNext(); + }, + + /** + * Logs a message from the worker + * + * @param {WorkerHandler} handler The active handler for the worker. + * @param {Message} data The data received from the worker. + */ + Log(handler: WorkerHandler, data: Message) { + if (handler.options.debug) { + console.log('Log:', data); + } + }, + }; +} diff --git a/ts/a11y/sre.ts b/ts/a11y/sre.ts index 0192a53e5..919c83680 100644 --- a/ts/a11y/sre.ts +++ b/ts/a11y/sre.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,81 +16,43 @@ */ /** - * @fileoverview Provides the interface functionality to SRE. + * @file Provides the interface functionality to SRE. * * @author dpvc@mathjax.org (Davide Cervone) * @author v.sorge@mathjax.org (Volker Sorge) */ -import * as Api from 'speech-rule-engine/js/common/system.js'; -import {Walker} from 'speech-rule-engine/js/walker/walker.js'; -import * as WalkerFactory from 'speech-rule-engine/js/walker/walker_factory.js'; -import * as SpeechGeneratorFactory from 'speech-rule-engine/js/speech_generator/speech_generator_factory.js'; -import * as EngineConst from 'speech-rule-engine/js/common/engine_const.js'; -import Engine from 'speech-rule-engine/js/common/engine.js'; -import {ClearspeakPreferences} from 'speech-rule-engine/js/speech_rules/clearspeak_preferences.js'; -import {Highlighter} from 'speech-rule-engine/js/highlighter/highlighter.js'; -import * as HighlighterFactory from 'speech-rule-engine/js/highlighter/highlighter_factory.js'; -import {SpeechGenerator} from 'speech-rule-engine/js/speech_generator/speech_generator.js'; -import {Variables} from 'speech-rule-engine/js/common/variables.js'; -import MathMaps from './mathmaps.js'; - -export namespace Sre { - - export type highlighter = Highlighter; - - export type speechGenerator = SpeechGenerator; - - export type walker = Walker; - - - export const locales = Variables.LOCALES; - - export const sreReady = Api.engineReady; - - export const setupEngine = Api.setupEngine; - - export const engineSetup = Api.engineSetup; - - export const toEnriched = Api.toEnriched; - - export const toSpeech = Api.toSpeech; - - export const clearspeakPreferences = ClearspeakPreferences; - - export const getHighlighter = HighlighterFactory.highlighter; - - export const getSpeechGenerator = SpeechGeneratorFactory.generator; - - export const getWalker = WalkerFactory.walker; - - export const clearspeakStyle = () => { - return EngineConst.DOMAIN_TO_STYLES['clearspeak']; - }; - - /** - * Loads locales that are already included in the imported MathMaps. Defaults - * to standard loading if a locale is not yet preloaded. - */ - export const preloadLocales = async function(locale: string) { - const json = MathMaps.get(locale); - return json ? new Promise((res, _rej) => res(JSON.stringify(json))) : - Api.localeLoader()(locale); - }; - -} - -/** - * A promise that resolves when SRE is loaded and ready, and rejects if - * SRE can't be loaded, or does not become ready within the timout period. - * - * @deprecated - */ -export const sreReady = Sre.sreReady; - -// Setting delay stops SRE from setting itself up (and loading locales) when it -// is not actually being used. As we are not yet sure in which environment we -// are (browser, node) we can not use a configuration vector. -Engine.getInstance().delay = true; - -export default Sre; +import { Engine } from '#sre/common/engine.js'; +import { parseInput } from '#sre/common/dom_util.js'; +import { Variables } from '#sre/common/variables.js'; +import { semanticMathmlSync } from '#sre/enrich_mathml/enrich.js'; +import { + addPreference as addPref, + fromPreference as fromPref, + toPreference as toPref, +} from '#sre/speech_rules/clearspeak_preference_string.js'; + +export const locales = Variables.LOCALES; + +export const setupEngine = (x: { [key: string]: string | boolean }) => { + return Engine.getInstance().setup(x); +}; + +export const engineSetup = () => { + return Engine.getInstance().json(); +}; + +export const toEnriched = (mml: string) => { + return semanticMathmlSync(mml, Engine.getInstance().options); +}; + +export const parseDOM = parseInput; + +// +// webpack doesn't seem to pick these up when building the ui/menu +// component when they are exported directly, so import first +// and then export. +// +export const addPreference = addPref; +export const fromPreference = fromPref; +export const toPreference = toPref; diff --git a/ts/a11y/sre/require.d.mts b/ts/a11y/sre/require.d.mts new file mode 100644 index 000000000..dcc8de4d6 --- /dev/null +++ b/ts/a11y/sre/require.d.mts @@ -0,0 +1 @@ +export function require(file: string): any; diff --git a/ts/a11y/sre/require.mjs b/ts/a11y/sre/require.mjs new file mode 100644 index 000000000..a45271169 --- /dev/null +++ b/ts/a11y/sre/require.mjs @@ -0,0 +1,2 @@ +import {createRequire} from 'module'; +global.require = createRequire(import.meta.url); diff --git a/ts/a11y/sre/speech-worker.ts b/ts/a11y/sre/speech-worker.ts new file mode 100644 index 000000000..3dd12a20a --- /dev/null +++ b/ts/a11y/sre/speech-worker.ts @@ -0,0 +1,301 @@ +/************************************************************* + * + * Copyright (c) 2018-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This is the code run by the webworkers in the iframe. + * It can load content from the CDN since the iframe runs from there. + * You can add importScripts() commands at the top to preload libraries + * or a Task can run the "import" action to load libraries on the fly. + * + * The actions that can be run are listed in the Commands variable, and + * imported scripts can add to that object to make more commands available. + * If you want to pre-load libraries that add commands, they should be + * imported at the bottom of this file using importScripts(). + */ + +/** + * Don't want to use imports for these, since this is compiled separately + * with different parameters, and that would cause the imported files + * to be compiled with those parameters. + */ +type OptionList = { [name: string]: any }; +type Message = { [key: string]: any }; +type WorkerResult = Promise; +type WorkerFunction = (data: Message) => WorkerResult; + +declare let global: any; +declare const SRE: any; + +/*****************************************************************/ + +(async () => { + // + // Set up for node worker_threads versus browser webworker + // + if (typeof self === 'undefined') { + // + // For node, make self be the global object + // + self = global.self = global; + + // + // This is so SRE knows we are a worker + // + global.DedicatedWorkerGlobalScope = global.constructor; + + // + // Create addEventListener() and postMessage() functions + // + const { parentPort, workerData } = await import( + /* webpackIgnore: true */ 'node:worker_threads' + ); + global.addEventListener = ( + kind: string, + listener: (event: Event) => void + ) => { + parentPort.on(kind, listener); + }; + global.postMessage = (msg: any) => { + parentPort.postMessage({ data: msg }); + }; + + // + // Get the path to the mathmaps + // + global.maps = workerData.maps; + + // + // We use require() to load mathmaps in node + // + if (!global.require) { + await import(/* webpackIgnore: true */ './require.mjs'); + } + global.getMap = (file: string) => + Promise.resolve(JSON.stringify(global.require(file))); + } else { + // + // For web workers, make global be the self object + // + global = (self as any).global = self; + // + // We use fetch() to load mathmaps in web workers + // + global.getMap = (file: string) => + fetch(file) + .then((data) => data.json()) + .catch((err) => console.log(err)); + } + + // + // Custom loader for mathmaps + // + global.SREfeature = { + custom: (locale: string) => global.getMap(`${global.maps}/${locale}.json`), + }; + + // + // Load SRE + // + await ( + global.isLab + ? import(/* webpackIgnore: true */ './sre-lab.js') // for use in the lab + : import('./sre.js') + ).then((SRE) => (global.SRE = SRE)); + + /*****************************************************************/ + + /** + * Add an event listener so that we can act on commands from Iframe. + * We extract the command and data from the event, and look for the + * command in the Commands object below. If the command is defined, + * we try to run the command, and if there is an error, we send it to + * the calling Rule. If the command was not found in the list of valid + * commands, we produce an error. + */ + self.addEventListener( + 'message', + function (event: MessageEvent) { + if (event.data.debug) { + console.log('Client >>> Worker:', event.data); + } + const { cmd, data } = event.data; + if (Object.hasOwn(Commands, cmd)) { + Client('Log', `running ${cmd}`); + Commands[cmd](data) + .then((result) => Finished(cmd, { result })) + .catch((error) => Finished(cmd, { error: error.message })); + } else { + Finished(cmd, { error: `Invalid worker command: ${cmd}` }); + } + }, + false + ); + + /** + * These are the commands that can be sent from the main window via the iframe. + */ + const Commands: { [id: string]: WorkerFunction } = { + /** + * This loads one or more libraries. + * + * @param {Message} data The data object + * @returns {WorkerResult} A promise the completes when the imports are done + */ + import(data: Message): WorkerResult { + return Array.isArray(data.imports) + ? Promise.all(data.imports.map((file: string) => import(file))) + : import(data.imports); + }, + + /** + * Setup the speech rule engine. + * + * @param {Message} data The feature vector for SRE. + * @returns {WorkerResult} A promise that completes when the imports are done + */ + setup(data: Message): WorkerResult { + if (!data) { + return Promise.resolve(); + } + SRE.setupEngine(data); + return SRE.engineReady(); + }, + + /** + * Compute speech + * + * @param {Message} data The data object + * @returns {WorkerResult} Promise fulfilled when computation is complete. + */ + speech(data: Message): WorkerResult { + return Speech(SRE.workerSpeech, data.mml, data.options); + }, + + /** + * Compute speech for the next rule set + * + * @param {Message} data The data object + * @returns {WorkerResult} Promise fulfilled when computation is complete. + */ + nextRules(data: Message): WorkerResult { + return Speech(SRE.workerNextRules, data.mml, data.options); + }, + + /** + * Compute speech for the next style or preference + * + * @param {Message} data The data object + * @returns {WorkerResult} Promise fulfilled when computation is complete. + */ + nextStyle(data: Message): WorkerResult { + return Speech(SRE.workerNextStyle, data.mml, data.options, data.nodeId); + }, + + /** + * Compute clearspeak preferences for a given locale + * + * @param {Message} data The data object + * @returns {WorkerResult} Promise fulfilled when computation is complete. + */ + async localePreferences(data: Message): WorkerResult { + const structure = await SRE.workerLocalePreferences(data.options); + // Not strictly necessary for the menu as there should not be one in node. + // However, it allows for getting the preferences in a different context. + return structure ? JSON.stringify(structure) : structure; + }, + + /** + * Compute relevant clearspeak preference category for a semantic node. + * + * @param {Message} data The data object + * @returns {WorkerResult} Promise fulfilled when computation is complete. + */ + async relevantPreferences(data: Message): WorkerResult { + return (await SRE.workerRelevantPreferences(data.mml, data.id)) ?? ''; + }, + }; + + /** + * Post a command back to the client. Catches the error in case the data cannot be + * JSON stringified. + * + * @param {string} cmd The command to be posted. + * @param {Message} data The data object to be send. + */ + function Client(cmd: string, data: Message | string) { + try { + self.postMessage({ cmd: cmd, data: data }); + } catch (err) { + console.log('Posting error in worker for ', copyError(err)); + } + } + + /** + * Post that the current command is finished to the client. + * + * @param {string} cmd The command that has finished. + * @param {Message} msg The data to send back (error or result) + */ + function Finished(cmd: string, msg: Message) { + Client('Log', `finished ${cmd}`); + Client('Finished', { ...msg, cmd: cmd, success: !msg.error }); + } + + /** + * Post a command that returns a new speech structure. + * + * @param {(mml: string, options: OptionList, rest: string[]) => + * {[id: string]: string}} func + * The function to call for speech computation. + * @param {string} mml The mml expression. + * @param {OptionList} options Setup options for SRE. + * @param {string[]} rest Remaining arguments. + * @returns {Promise} A promise returning the data to be attached to the DOM + */ + async function Speech( + func: (mml: string, options: OptionList, rest: string[]) => string, + mml: string, + options: OptionList, + ...rest: string[] + ): Promise { + if (!mml) return ''; + const structure = (await func.call(null, mml, options, ...rest)) ?? {}; + return JSON.stringify(structure); + } + + /** + * Make a copy of an Error object (since those can't be stringified). + * + * @param {Error} error The error object. + * @returns {Message} The copied error object. + */ + function copyError(error: Error): Message { + return { + message: error.message, + stack: error.stack, + fileName: (error as any).fileName, + lineNumber: (error as any).lineNumber, + }; + } + + /** + * Wait for SRE to set itself up, + * then tell the WorkerPool that we are ready. + */ + await SRE.engineReady(); + Client('Ready', {}); +})(); diff --git a/ts/a11y/sre/sre-lab.ts b/ts/a11y/sre/sre-lab.ts new file mode 100644 index 000000000..01761d2d3 --- /dev/null +++ b/ts/a11y/sre/sre-lab.ts @@ -0,0 +1 @@ +export * from '../../../lab/sre.js'; diff --git a/ts/a11y/sre/sre.ts b/ts/a11y/sre/sre.ts new file mode 100644 index 000000000..8c8547cb4 --- /dev/null +++ b/ts/a11y/sre/sre.ts @@ -0,0 +1,3 @@ +export * from '#sre/common/system.js'; +import { Variables } from '#sre/common/variables.js'; +export const variables = Variables; diff --git a/ts/a11y/sre/worker_threads.d.ts b/ts/a11y/sre/worker_threads.d.ts new file mode 100644 index 000000000..952a5e2a5 --- /dev/null +++ b/ts/a11y/sre/worker_threads.d.ts @@ -0,0 +1,7 @@ +declare module 'node:worker_threads' { + const parentPort: { + on(kind: string, listener: (event: Event) => void): void; + postMessage(msg: any): void; + }; + const workerData: any; +} diff --git a/ts/adaptors/HTMLAdaptor.ts b/ts/adaptors/HTMLAdaptor.ts index 9737ec642..c1a9d68dc 100644 --- a/ts/adaptors/HTMLAdaptor.ts +++ b/ts/adaptors/HTMLAdaptor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,18 @@ */ /** - * @fileoverview Implements the HTML DOM adaptor + * @file Implements the HTML DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {OptionList} from '../util/Options.js'; -import {AttributeData, AbstractDOMAdaptor, DOMAdaptor, PageBBox} from '../core/DOMAdaptor.js'; +import { OptionList } from '../util/Options.js'; +import { + AttributeData, + AbstractDOMAdaptor, + DOMAdaptor, + PageBBox, +} from '../core/DOMAdaptor.js'; /*****************************************************************/ /** @@ -36,13 +41,14 @@ export interface MinDocument { head: N; body: N; title: string; - doctype: {name: string}; - /* tslint:disable:jsdoc-require */ + doctype: { name: string }; + defaultView: MinWindow>; + location: { protocol: string; host: string }; createElement(kind: string): N; createElementNS(ns: string, kind: string): N; createTextNode(text: string): T; querySelectorAll(selector: string): ArrayLike; - /* tslint:enable */ + querySelector(selector: string): N | null; } /*****************************************************************/ @@ -69,18 +75,22 @@ export interface MinHTMLElement { className: string; classList: DOMTokenList; style: OptionList; - sheet?: {insertRule: (rule: string, index?: number) => void}; - + sheet?: { + insertRule: (rule: string, index?: number) => void; + cssRules: Array<{ cssText: string }>; + }; childNodes: (N | T)[] | NodeList; firstChild: N | T | Node; lastChild: N | T | Node; - /* tslint:disable:jsdoc-require */ getElementsByTagName(name: string): N[] | HTMLCollectionOf; - getElementsByTagNameNS(ns: string, name: string): N[] | HTMLCollectionOf; + getElementsByTagNameNS( + ns: string, + name: string + ): N[] | HTMLCollectionOf; contains(child: N | T): boolean; appendChild(child: N | T): N | T | Node; - removeChild(child: N | T): N | T | Node; - replaceChild(nnode: N | T, onode: N | T): N | T | Node; + removeChild(child: N | T): N | T | Node; + replaceChild(nnode: N | T, onode: N | T): N | T | Node; insertBefore(nchild: N | T, ochild: N | T): void; cloneNode(deep: boolean): N | Node; setAttribute(name: string, value: string): void; @@ -88,9 +98,10 @@ export interface MinHTMLElement { getAttribute(name: string): string; removeAttribute(name: string): void; hasAttribute(name: string): boolean; - getBoundingClientRect(): Object; - getBBox?(): {x: number, y: number, width: number, height: number}; - /* tslint:endable */ + getBoundingClientRect(): object; + getBBox?(): { x: number; y: number; width: number; height: number }; + querySelector(selector: string): N | null; + src?: string; } /*****************************************************************/ @@ -140,10 +151,10 @@ export interface MinXMLSerializer { export interface MinWindow { document: D; DOMParser: { - new(): MinDOMParser + new (): MinDOMParser; }; XMLSerializer: { - new(): MinXMLSerializer; + new (): MinXMLSerializer; }; NodeList: any; HTMLCollection: any; @@ -151,6 +162,8 @@ export interface MinWindow { DocumentFragment: any; Document: any; getComputedStyle(node: N): any; + addEventListener(kind: string, listener: (event: any) => void): void; + postMessage(msg: any, domain: string): void; } /*****************************************************************/ @@ -178,8 +191,19 @@ export interface MinHTMLAdaptor extends DOMAdaptor { * @template T The Text node class * @template D The Document class */ -export class HTMLAdaptor, T extends MinText, D extends MinDocument> extends -AbstractDOMAdaptor implements MinHTMLAdaptor { +export class HTMLAdaptor< + N extends MinHTMLElement, + T extends MinText, + D extends MinDocument, + > + extends AbstractDOMAdaptor + implements MinHTMLAdaptor +{ + /** + * The HTML adaptor can measure DOM node sizes + */ + public canMeasureNodes: boolean = true; + /** * The window object for this adaptor */ @@ -192,7 +216,7 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { /** * @override - * @constructor + * @class */ constructor(window: MinWindow) { super(window.document); @@ -211,9 +235,9 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { * @override */ protected create(kind: string, ns?: string) { - return (ns ? - this.document.createElementNS(ns, kind) : - this.document.createElement(kind)); + return ns + ? this.document.createElementNS(ns, kind) + : this.document.createElement(kind); } /** @@ -226,36 +250,38 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { /** * @override */ - public head(doc: D) { + public head(doc: D = this.document) { return doc.head || (doc as any as N); } /** * @override */ - public body(doc: D) { + public body(doc: D = this.document) { return doc.body || (doc as any as N); } /** * @override */ - public root(doc: D) { + public root(doc: D = this.document) { return doc.documentElement || (doc as any as N); } /** * @override */ - public doctype(doc: D) { - return (doc.doctype ? `` : ''); + public doctype(doc: D = this.document) { + return doc.doctype ? `` : ''; } /** * @override */ public tags(node: N, name: string, ns: string = null) { - let nodes = (ns ? node.getElementsByTagNameNS(ns, name) : node.getElementsByTagName(name)); + const nodes = ns + ? node.getElementsByTagNameNS(ns, name) + : node.getElementsByTagName(name); return Array.from(nodes as N[]) as N[]; } @@ -265,11 +291,16 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { public getElements(nodes: (string | N | N[])[], _document: D) { let containers: N[] = []; for (const node of nodes) { - if (typeof(node) === 'string') { - containers = containers.concat(Array.from(this.document.querySelectorAll(node))); + if (typeof node === 'string') { + containers = containers.concat( + Array.from(this.document.querySelectorAll(node)) + ); } else if (Array.isArray(node)) { containers = containers.concat(Array.from(node) as N[]); - } else if (node instanceof this.window.NodeList || node instanceof this.window.HTMLCollection) { + } else if ( + node instanceof this.window.NodeList || + node instanceof this.window.HTMLCollection + ) { containers = containers.concat(Array.from(node as any as N[])); } else { containers.push(node); @@ -278,6 +309,13 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { return containers; } + /** + * @override + */ + public getElement(selector: string, node: D | N = this.document): N { + return node.querySelector(selector); + } + /** * @override */ @@ -323,8 +361,8 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { /** * @override */ - public clone(node: N) { - return node.cloneNode(true) as N; + public clone(node: N, deep: boolean = true) { + return node.cloneNode(deep) as N; } /** @@ -381,7 +419,7 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { */ public kind(node: N | T) { const n = node.nodeType; - return (n === 1 || n === 3 || n === 8 ? node.nodeName.toLowerCase() : ''); + return n === 1 || n === 3 || n === 8 ? node.nodeName.toLowerCase() : ''; } /** @@ -412,6 +450,9 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { return node.outerHTML; } + /** + * @override + */ public serializeXML(node: N) { const serializer = new this.window.XMLSerializer(); return serializer.serializeToString(node) as string; @@ -453,11 +494,9 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { * @override */ public allAttributes(node: N) { - return Array.from(node.attributes).map( - (x: AttributeData) => { - return {name: x.name, value: x.value} as AttributeData; - } - ); + return Array.from(node.attributes).map((x: AttributeData) => { + return { name: x.name, value: x.value } as AttributeData; + }); } /** @@ -478,7 +517,10 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { if (node.classList) { node.classList.remove(name); } else { - node.className = node.className.split(/ /).filter((c) => c !== name).join(' '); + node.className = node.className + .split(/ /) + .filter((c) => c !== name) + .join(' '); } } @@ -489,7 +531,7 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { if (node.classList) { return node.classList.contains(name); } - return node.className.split(/ /).indexOf(name) >= 0; + return node.className.split(/ /).includes(name); } /** @@ -517,15 +559,27 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { * @override */ public insertRules(node: N, rules: string[]) { - for (const rule of rules.reverse()) { + for (const rule of rules) { try { - node.sheet.insertRule(rule, 0); + node.sheet.insertRule(rule, node.sheet.cssRules.length); } catch (e) { console.warn(`MathJax: can't insert css rule '${rule}': ${e.message}`); } } } + /** + * @override + */ + public cssText(node: N) { + if (this.kind(node) !== 'style') { + return ''; + } + return Array.from(node.sheet.cssRules) + .map((rule) => rule.cssText) + .join('\n'); + } + /** * @override */ @@ -547,8 +601,8 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { */ public nodeSize(node: N, em: number = 1, local: boolean = false) { if (local && node.getBBox) { - let {width, height} = node.getBBox(); - return [width / em , height / em] as [number, number]; + const { width, height } = node.getBBox(); + return [width / em, height / em] as [number, number]; } return [node.offsetWidth / em, node.offsetHeight / em] as [number, number]; } @@ -557,7 +611,51 @@ AbstractDOMAdaptor implements MinHTMLAdaptor { * @override */ public nodeBBox(node: N) { - const {left, right, top, bottom} = node.getBoundingClientRect() as PageBBox; - return {left, right, top, bottom}; + const { left, right, top, bottom } = + node.getBoundingClientRect() as PageBBox; + return { left, right, top, bottom }; + } + + /** + * @override + */ + public async createWorker( + listener: (event: any) => void, + options: OptionList + ) { + const { path, maps, worker } = options; + const file = `${path}/${worker}`; + const content = ` + self.maps = '${quoted(maps)}'; + importScripts('${quoted(file)}'); + `; + const url = URL.createObjectURL( + new Blob([content], { type: 'text/javascript' }) + ); + const webworker = new Worker(url); + webworker.onmessage = listener; + URL.revokeObjectURL(url); + return webworker; } } + +/** + * Quote any backslashes or single quotes, and turn non-ASCII + * characters into \u{...} so that the result can be inserted into + * single quotes and return the original string when evaluated. + * + * @param {string} text The text to be quoted + * @returns {string} The quoted text + */ +function quoted(text: string): string { + return [...text] + .map((c) => { + if (c === '\\' || c === "'") { + c = '\\' + c; + } else if (c < ' ' || c > '\u007e') { + c = `\\u{${c.codePointAt(0).toString(16)}}`; + } + return c; + }) + .join(''); +} diff --git a/ts/adaptors/NodeMixin.ts b/ts/adaptors/NodeMixin.ts index 86d9a0e0e..aecf79895 100644 --- a/ts/adaptors/NodeMixin.ts +++ b/ts/adaptors/NodeMixin.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2022-2022 The MathJax Consortium + * Copyright (c) 2022-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,32 @@ */ /** - * @fileoverview Implements a mixin for node-based adaptors that overrides + * @file Implements a mixin for node-based adaptors that overrides * the methods that obtain DOM node sizes, when those aren't * available from the DOM itself. * * @author dpvc@mathjax.org (Davide Cervone) */ -import {DOMAdaptor} from '../core/DOMAdaptor.js'; -import {userOptions, defaultOptions, OptionList} from '../util/Options.js'; +import { DOMAdaptor, minWorker } from '../core/DOMAdaptor.js'; +import { userOptions, defaultOptions, OptionList } from '../util/Options.js'; +import { asyncLoad } from '../util/AsyncLoad.js'; + +/** + * A minimal worker thread interface + */ +export interface WebWorker { + on(kind: string, listener: (event: Event) => void): void; + postMessage(msg: any): void; + terminate(): void; +} /** * A constructor for a given class * * @template T The class to construct */ -export type Constructor = (new(...args: any[]) => T); +export type Constructor = new (...args: any[]) => T; /** * The type of an Adaptor class @@ -41,28 +51,33 @@ export type AdaptorConstructor = Constructor>; /** * The options to the NodeMixin */ +/* prettier-ignore */ export const NodeMixinOptions: OptionList = { badCSS: true, // getComputedStyles() is not implemented in the DOM badSizes: true, // element sizes (e.g., ClientWidth, etc.) are not implemented in the DOM }; /** + * @param {A} Base The base constructor for the adaptor + * @param {NodeMixinOptions} options The options + * @returns {A} The NodeAdaptor mixin class + * * @template N The HTMLElement node class * @template T The Text node class * @template D The Document class + * @template A Extension of AdaptorConstructor */ export function NodeMixin>( Base: A, options: typeof NodeMixinOptions = {} ): A { - options = userOptions(defaultOptions({}, NodeMixinOptions), options); return class NodeAdaptor extends Base { - /** * The default options */ + /* prettier-ignore */ public static OPTIONS: OptionList = { ...(options.badCSS ? { fontSize: 16, // We can't compute the font size, so always use this @@ -78,25 +93,33 @@ export function NodeMixin>( /** * Pattern to identify CJK (i.e., full-width) characters */ - public static cjkPattern = new RegExp([ - '[', - '\u1100-\u115F', // Hangul Jamo - '\u2329\u232A', // LEFT-POINTING ANGLE BRACKET, RIGHT-POINTING ANGLE BRACKET - '\u2E80-\u303E', // CJK Radicals Supplement ... CJK Symbols and Punctuation - '\u3040-\u3247', // Hiragana ... Enclosed CJK Letters and Months - '\u3250-\u4DBF', // Enclosed CJK Letters and Months ... CJK Unified Ideographs Extension A - '\u4E00-\uA4C6', // CJK Unified Ideographs ... Yi Radicals - '\uA960-\uA97C', // Hangul Jamo Extended-A - '\uAC00-\uD7A3', // Hangul Syllables - '\uF900-\uFAFF', // CJK Compatibility Ideographs - '\uFE10-\uFE19', // Vertical Forms - '\uFE30-\uFE6B', // CJK Compatibility Forms ... Small Form Variants - '\uFF01-\uFF60\uFFE0-\uFFE6', // Halfwidth and Fullwidth Forms - '\u{1B000}-\u{1B001}', // Kana Supplement - '\u{1F200}-\u{1F251}', // Enclosed Ideographic Supplement - '\u{20000}-\u{3FFFD}', // CJK Unified Ideographs Extension B ... Tertiary Ideographic Plane - ']' - ].join(''), 'gu'); + public static cjkPattern = new RegExp( + [ + '[', + '\u1100-\u115F', // Hangul Jamo + '\u2329\u232A', // LEFT-POINTING ANGLE BRACKET, RIGHT-POINTING ANGLE BRACKET + '\u2E80-\u303E', // CJK Radicals Supplement ... CJK Symbols and Punctuation + '\u3040-\u3247', // Hiragana ... Enclosed CJK Letters and Months + '\u3250-\u4DBF', // Enclosed CJK Letters and Months ... CJK Unified Ideographs Extension A + '\u4E00-\uA4C6', // CJK Unified Ideographs ... Yi Radicals + '\uA960-\uA97C', // Hangul Jamo Extended-A + '\uAC00-\uD7A3', // Hangul Syllables + '\uF900-\uFAFF', // CJK Compatibility Ideographs + '\uFE10-\uFE19', // Vertical Forms + '\uFE30-\uFE6B', // CJK Compatibility Forms ... Small Form Variants + '\uFF01-\uFF60\uFFE0-\uFFE6', // Halfwidth and Fullwidth Forms + '\u{1B000}-\u{1B001}', // Kana Supplement + '\u{1F200}-\u{1F251}', // Enclosed Ideographic Supplement + '\u{20000}-\u{3FFFD}', // CJK Unified Ideographs Extension B ... Tertiary Ideographic Plane + ']', + ].join(''), + 'gu' + ); + + /** + * The node adaptors can't measure DOM node sizes + */ + public canMeasureNodes: boolean = false; /** * The options for the instance @@ -104,13 +127,13 @@ export function NodeMixin>( public options: OptionList; /** - * @param {any} window The window to work with - * @param {OptionList} options The options for the adaptor - * @constructor + * @param {...any} args Parameters for the mixin class, where the first is + * the window to work with and the second are the options for the adaptor + * @class */ constructor(...args: any[]) { super(args[0]); - let CLASS = this.constructor as typeof NodeAdaptor; + const CLASS = this.constructor as typeof NodeAdaptor; this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), args[1]); } @@ -120,7 +143,7 @@ export function NodeMixin>( * @override */ public fontSize(node: N) { - return (options.badCSS ? this.options.fontSize : super.fontSize(node)); + return options.badCSS ? this.options.fontSize : super.fontSize(node); } /** @@ -129,7 +152,7 @@ export function NodeMixin>( * @override */ public fontFamily(node: N) { - return (options.badCSS ? this.options.fontFamily : super.fontFamily(node)); + return options.badCSS ? this.options.fontFamily : super.fontFamily(node); } /** @@ -140,11 +163,11 @@ export function NodeMixin>( return super.nodeSize(node, em, local); } const text = this.textContent(node); - const non = Array.from(text.replace(NodeAdaptor.cjkPattern, '')).length; // # of non-CJK chars - const CJK = Array.from(text).length - non; // # of cjk chars + const non = Array.from(text.replace(NodeAdaptor.cjkPattern, '')).length; // # of non-CJK chars + const CJK = Array.from(text).length - non; // # of cjk chars return [ CJK * this.options.cjkCharWidth + non * this.options.unknownCharWidth, - this.options.unknownCharHeight + this.options.unknownCharHeight, ] as [number, number]; } @@ -152,9 +175,42 @@ export function NodeMixin>( * @override */ public nodeBBox(node: N) { - return (options.badSizes ? {left: 0, right: 0, top: 0, bottom: 0} : super.nodeBBox(node)); + return options.badSizes + ? { left: 0, right: 0, top: 0, bottom: 0 } + : super.nodeBBox(node); } + /** + * @override + */ + public async createWorker( + listener: (event: any) => void, + options: OptionList + ): Promise { + const { Worker } = await asyncLoad('node:worker_threads'); + class LiteWorker { + protected worker: WebWorker; + constructor(url: string, options: OptionList = {}) { + this.worker = new Worker(url, options); + } + addEventListener(kind: string, listener: (event: any) => void) { + this.worker.on(kind, listener); + } + postMessage(msg: any) { + this.worker.postMessage({ data: msg }); + } + terminate() { + this.worker.terminate(); + } + } + const { path, maps } = options; + const url = `${path}/${options.worker}`; + const worker = new LiteWorker(url, { + type: 'module', + workerData: { maps }, + }); + worker.addEventListener('message', listener); + return worker; + } }; - } diff --git a/ts/adaptors/browserAdaptor.ts b/ts/adaptors/browserAdaptor.ts index 91ef3450b..703518ccf 100644 --- a/ts/adaptors/browserAdaptor.ts +++ b/ts/adaptors/browserAdaptor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ */ /** - * @fileoverview Implements the browser DOM adaptor + * @file Implements the browser DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {HTMLAdaptor} from './HTMLAdaptor.js'; +import { HTMLAdaptor } from './HTMLAdaptor.js'; // // Let Typescript know about these @@ -41,7 +41,7 @@ declare global { /** * Function to create an HTML adpator for browsers * - * @return {HTMLAdaptor} The newly created adaptor + * @returns {HTMLAdaptor} The newly created adaptor */ export function browserAdaptor(): HTMLAdaptor { return new HTMLAdaptor(window); diff --git a/ts/adaptors/chooseAdaptor.ts b/ts/adaptors/chooseAdaptor.ts index 4ab15ae16..0930a397a 100644 --- a/ts/adaptors/chooseAdaptor.ts +++ b/ts/adaptors/chooseAdaptor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,24 +16,16 @@ */ /** - * @fileoverview Chooses between jdsom and browser DOM adaptors + * @file Chooses between jdsom and browser DOM adaptors * * @author dpvc@mathjax.org (Davide Cervone) */ -import {liteAdaptor} from './liteAdaptor.js'; -import {browserAdaptor} from './browserAdaptor.js'; - -let choose; - -try { - document; // errors if not in browser - choose = browserAdaptor; -} catch (e) { - choose = liteAdaptor; -} +import { liteAdaptor } from './liteAdaptor.js'; +import { browserAdaptor } from './browserAdaptor.js'; +import { context } from '../util/context.js'; /** - * Function to select which adaptor to use (depending on whether we are in a browser or node.js) + * Select which adaptor to use (depending on whether we are in a browser or node.js) */ -export const chooseAdaptor = choose; +export const chooseAdaptor = context.document ? browserAdaptor : liteAdaptor; diff --git a/ts/adaptors/jsdomAdaptor.ts b/ts/adaptors/jsdomAdaptor.ts index 02aa21eb9..f19e0f058 100644 --- a/ts/adaptors/jsdomAdaptor.ts +++ b/ts/adaptors/jsdomAdaptor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,31 +16,42 @@ */ /** - * @fileoverview Implements the jdsom DOM adaptor + * @file Implements the jdsom DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {HTMLAdaptor} from './HTMLAdaptor.js'; -import {NodeMixin, Constructor} from './NodeMixin.js'; -import {OptionList} from '../util/Options.js'; +import { HTMLAdaptor } from './HTMLAdaptor.js'; +import { NodeMixin, Constructor } from './NodeMixin.js'; +import { OptionList } from '../util/Options.js'; /** * The constructor for an HTMLAdaptor */ -export type HTMLAdaptorConstructor = Constructor>; +export type HTMLAdaptorConstructor = Constructor< + HTMLAdaptor +>; /** * The JsdomAdaptor class */ -export class JsdomAdaptor extends NodeMixin(HTMLAdaptor) {} +export class JsdomAdaptor extends NodeMixin< + HTMLElement, + Text, + Document, + HTMLAdaptorConstructor +>(HTMLAdaptor) {} /** * Function for creating an HTML adaptor using jsdom * - * @param {any} JSDOM The jsdom object to use for this adaptor - * @return {HTMLAdaptor} The newly created adaptor + * @param {any} JSDOM The jsdom object to use for this adaptor + * @param {OptionList} options The options for the adaptor + * @returns {HTMLAdaptor} The newly created adaptor */ -export function jsdomAdaptor(JSDOM: any, options: OptionList = null): JsdomAdaptor { +export function jsdomAdaptor( + JSDOM: any, + options: OptionList = null +): JsdomAdaptor { return new JsdomAdaptor(new JSDOM().window, options); } diff --git a/ts/adaptors/linkedomAdaptor.ts b/ts/adaptors/linkedomAdaptor.ts index 1d88f8ca6..7cf7851f0 100644 --- a/ts/adaptors/linkedomAdaptor.ts +++ b/ts/adaptors/linkedomAdaptor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2022-2022 The MathJax Consortium + * Copyright (c) 2022-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,25 +16,31 @@ */ /** - * @fileoverview Implements the linkedom DOM adaptor + * @file Implements the linkedom DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {HTMLAdaptor} from './HTMLAdaptor.js'; -import {NodeMixin, Constructor} from './NodeMixin.js'; -import {OptionList} from '../util/Options.js'; +import { HTMLAdaptor } from './HTMLAdaptor.js'; +import { NodeMixin, Constructor } from './NodeMixin.js'; +import { OptionList } from '../util/Options.js'; /** * The constructor for an HTMLAdaptor */ -export type HTMLAdaptorConstructor = Constructor>; +export type HTMLAdaptorConstructor = Constructor< + HTMLAdaptor +>; /** * The LinkedomAdaptor class */ -export class LinkedomAdaptor extends NodeMixin(HTMLAdaptor) { - +export class LinkedomAdaptor extends NodeMixin< + HTMLElement, + Text, + Document, + HTMLAdaptorConstructor +>(HTMLAdaptor) { /** * @override */ @@ -47,25 +53,44 @@ export class LinkedomAdaptor extends NodeMixin'); - window.constructor.prototype.HTMLCollection = class {}; // add fake class for missing HTMLCollecton + // + // Add fake class for missing HTMLCollection + // + window.HTMLCollection = class {}; + // + // Add missing splitText() method + // + window.Text.prototype.splitText = function (offset: number) { + const text = this.data; + if (offset > text.length) { + throw Error('Index Size Error'); + } + const newNode = window.document.createTextNode(text.substring(offset)); + this.parentNode.insertBefore(newNode, this.nextSibling); + this.data = text.substring(0, offset); + return newNode; + }; return new LinkedomAdaptor(window, options); } diff --git a/ts/adaptors/lite/Document.ts b/ts/adaptors/lite/Document.ts index 902afddfb..8ceb27707 100644 --- a/ts/adaptors/lite/Document.ts +++ b/ts/adaptors/lite/Document.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,23 @@ */ /** - * @fileoverview Implements a lightweight DOM adaptor + * @file Implements a lightweight DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {LiteElement} from './Element.js'; +import { LiteElement } from './Element.js'; +import { LiteWindow } from './Window.js'; /************************************************************/ /** * Implements a lightweight Document replacement */ export class LiteDocument { + /** + * The document's parent window + */ + public defaultView: LiteWindow = null; /** * The document's element */ @@ -42,25 +47,29 @@ export class LiteDocument { public body: LiteElement; /** - * the DOCTYPE comment + * The DOCTYPE comment */ public type: string; /** * The kind is always #document + * + * @returns {string} The document string. */ - public get kind() { + public get kind(): string { return '#document'; } /** - * @constructor + * @class + * @param {LiteWindow} window The window for the document (if given) */ - constructor() { + constructor(window: LiteWindow = null) { this.root = new LiteElement('html', {}, [ - this.head = new LiteElement('head'), - this.body = new LiteElement('body') + (this.head = new LiteElement('head')), + (this.body = new LiteElement('body')), ]); this.type = ''; + this.defaultView = window; } } diff --git a/ts/adaptors/lite/Element.ts b/ts/adaptors/lite/Element.ts index e7a332e67..ee8ceb495 100644 --- a/ts/adaptors/lite/Element.ts +++ b/ts/adaptors/lite/Element.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ */ /** - * @fileoverview Implements a lightweight HTML Element replacement + * @file Implements a lightweight HTML Element replacement * * @author dpvc@mathjax.org (Davide Cervone) */ -import {OptionList} from '../../util/Options.js'; -import {Styles} from '../../util/Styles.js'; -import {LiteText} from './Text.js'; +import { OptionList } from '../../util/Options.js'; +import { Styles } from '../../util/Styles.js'; +import { LiteText } from './Text.js'; /** * Type for attribute lists @@ -35,7 +35,6 @@ export type LiteAttributeList = OptionList; */ export type LiteNode = LiteElement | LiteText; - /************************************************************/ /** * Implements a lightweight HTML element replacement @@ -70,11 +69,15 @@ export class LiteElement { * @param {string} kind The type of node to create * @param {LiteAttributeList} attributes The list of attributes to set (if any) * @param {LiteNode[]} children The children for the node (if any) - * @constructor + * @class */ - constructor(kind: string, attributes: LiteAttributeList = {}, children: LiteNode[] = []) { + constructor( + kind: string, + attributes: LiteAttributeList = {}, + children: LiteNode[] = [] + ) { this.kind = kind; - this.attributes = {...attributes}; + this.attributes = { ...attributes }; this.children = [...children]; for (const child of this.children) { child.parent = this; diff --git a/ts/adaptors/lite/List.ts b/ts/adaptors/lite/List.ts index 03f3a7691..a455a3701 100644 --- a/ts/adaptors/lite/List.ts +++ b/ts/adaptors/lite/List.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ */ /** - * @fileoverview Implements a lightweight DOM adaptor + * @file Implements a lightweight DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {LiteNode} from './Element.js'; +import { LiteNode } from './Element.js'; /************************************************************/ /** @@ -37,7 +37,7 @@ export class LiteList { /** * @param {N[]} children The children for the fragment - * @constructor + * @class */ constructor(children: N[]) { this.nodes = [...children]; @@ -52,19 +52,20 @@ export class LiteList { /** * Make this class iterable (so it can be used with Array.from()) + * + * @returns {Iterator} The iterator. */ public [Symbol.iterator](): Iterator { let i = 0; return { /** - * @return {IteratorResult} + * @returns {IteratorResult} The next iterator. */ next(): IteratorResult { - return (i === this.nodes.length ? - {value: null, done: true} : - {value: this.nodes[i++], done: false}); - } + return i === this.nodes.length + ? { value: null, done: true } + : { value: this.nodes[i++], done: false }; + }, }; } - } diff --git a/ts/adaptors/lite/Parser.ts b/ts/adaptors/lite/Parser.ts index 4fe0bbb72..09841c1aa 100644 --- a/ts/adaptors/lite/Parser.ts +++ b/ts/adaptors/lite/Parser.ts @@ -1,7 +1,6 @@ - /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,37 +16,40 @@ */ /** - * @fileoverview Implements a lightweight DOM adaptor + * @file Implements a lightweight DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AttributeData} from '../../core/DOMAdaptor.js'; -import {MinDOMParser} from '../HTMLAdaptor.js'; +import { AttributeData } from '../../core/DOMAdaptor.js'; +import { MinDOMParser } from '../HTMLAdaptor.js'; import * as Entities from '../../util/Entities.js'; -import {LiteDocument} from './Document.js'; -import {LiteElement} from './Element.js'; -import {LiteText, LiteComment} from './Text.js'; -import {LiteAdaptor} from '../liteAdaptor.js'; +import { LiteDocument } from './Document.js'; +import { LiteElement } from './Element.js'; +import { LiteText, LiteComment } from './Text.js'; +import { LiteAdaptor } from '../liteAdaptor.js'; /** * Patterns used in parsing serialized HTML */ -export namespace PATTERNS { - export const TAGNAME = '[a-z][^\\s\\n>]*'; - export const ATTNAME = '[a-z][^\\s\\n>=]*'; - export const VALUE = `(?:'[^']*'|"[^"]*"|[^\\s\\n]+)`; - export const VALUESPLIT = `(?:'([^']*)'|"([^"]*)"|([^\\s\\n]+))`; - export const SPACE = '(?:\\s|\\n)+'; - export const OPTIONALSPACE = '(?:\\s|\\n)*'; - export const ATTRIBUTE = ATTNAME + '(?:' + OPTIONALSPACE + '=' + OPTIONALSPACE + VALUE + ')?'; - export const ATTRIBUTESPLIT = '(' + ATTNAME + ')(?:' + OPTIONALSPACE + '=' + OPTIONALSPACE + VALUESPLIT + ')?'; - export const TAG = '(<(?:' + TAGNAME + '(?:' + SPACE + ATTRIBUTE + ')*' - + OPTIONALSPACE + '/?|/' + TAGNAME + '|!--[^]*?--|![^]*?)(?:>|$))'; - export const tag = new RegExp(TAG, 'i'); - export const attr = new RegExp(ATTRIBUTE, 'i'); - export const attrsplit = new RegExp(ATTRIBUTESPLIT, 'i'); -} + +const SPACE = '[ \\n]+'; +const OPTIONALSPACE = '[ \\n]*'; +const TAGNAME = `[A-Za-z][^\u0000-\u001F "'>/=\u007F-\u009F]*`; +const ATTNAME = `[^\u0000-\u001F "'>/=\u007F-\u009F]+`; +const VALUE = `(?:'[^']*'|"[^"]*"|${SPACE})`; +const VALUESPLIT = `(?:'([^']*)'|"([^"]*)"|(${SPACE}))`; +const ATTRIBUTE = `${ATTNAME}(?:${OPTIONALSPACE}=${OPTIONALSPACE}${VALUE})?`; +const ATTRIBUTESPLIT = `(${ATTNAME})(?:${OPTIONALSPACE}=${OPTIONALSPACE}${VALUESPLIT})?`; +const TAG = + `(<(?:${TAGNAME}(?:${SPACE}${ATTRIBUTE})*` + + `${OPTIONALSPACE}/?|/${TAGNAME}|!--[^]*?--|![^]*?)(?:>|$))`; + +export const PATTERNS = { + tag: new RegExp(TAG, 'u'), + attr: new RegExp(ATTRIBUTE, 'u'), + attrsplit: new RegExp(ATTRIBUTESPLIT, 'u'), +}; /************************************************************/ /** @@ -55,11 +57,10 @@ export namespace PATTERNS { * (Not perfect, but handles most well-formed HTML) */ export class LiteParser implements MinDOMParser { - /** * The list of self-closing tags */ - public static SELF_CLOSING: {[name: string]: boolean} = { + public static SELF_CLOSING: { [name: string]: boolean } = { area: true, base: true, br: true, @@ -76,52 +77,42 @@ export class LiteParser implements MinDOMParser { param: true, source: true, track: true, - wbr: true + wbr: true, }; /** * The list of tags chose content is not parsed (PCDATA) */ - public static PCDATA: {[name: string]: boolean} = { + public static PCDATA: { [name: string]: boolean } = { option: true, textarea: true, fieldset: true, title: true, style: true, - script: true + script: true, }; - /** - * The list of attributes that don't get entity translation - */ - public static CDATA_ATTR: {[name: string]: boolean} = { - style: true, - datafld: true, - datasrc: true, - href: true, - src: true, - longdesc: true, - usemap: true, - cite: true, - datetime: true, - action: true, - axis: true, - profile: true, - content: true, - scheme: true + public static XMLNS: { [name: string]: string } = { + svg: 'http://www.w3.org/2000/svg', + math: 'http://www.w3.org/1998/Math/MathML', + html: 'http://www.w3.org/1999/xhtml', }; /** * @override */ - public parseFromString(text: string, _format: string = 'text/html', adaptor: LiteAdaptor = null) { + public parseFromString( + text: string, + _format: string = 'text/html', + adaptor: LiteAdaptor = null + ) { const root = adaptor.createDocument(); let node = adaptor.body(root); // // Split the HTML into an array of text, tag, text, tag, ... // Then loop through them and add text nodes and process tags. // - let parts = text.replace(/<\?.*?\?>/g, '').split(PATTERNS.tag); + const parts = text.replace(/<\?.*?\?>/g, '').split(PATTERNS.tag); while (parts.length) { const text = parts.shift(); const tag = parts.shift(); @@ -146,9 +137,13 @@ export class LiteParser implements MinDOMParser { * @param {LiteAdaptor} adaptor The adaptor for managing nodes * @param {LiteElement} node The node to add a text element to * @param {string} text The text for the text node - * @return {LiteText} The text element + * @returns {LiteText} The text element */ - protected addText(adaptor: LiteAdaptor, node: LiteElement, text: string): LiteText { + protected addText( + adaptor: LiteAdaptor, + node: LiteElement, + text: string + ): LiteText { text = Entities.translate(text); return adaptor.append(node, adaptor.text(text)) as LiteText; } @@ -157,9 +152,13 @@ export class LiteParser implements MinDOMParser { * @param {LiteAdaptor} adaptor The adaptor for managing nodes * @param {LiteElement} node The node to add a comment to * @param {string} comment The text for the comment node - * @return {LiteComment} The comment element + * @returns {LiteComment} The comment element */ - protected addComment(adaptor: LiteAdaptor, node: LiteElement, comment: string): LiteComment { + protected addComment( + adaptor: LiteAdaptor, + node: LiteElement, + comment: string + ): LiteComment { return adaptor.append(node, new LiteComment(comment)) as LiteComment; } @@ -167,9 +166,13 @@ export class LiteParser implements MinDOMParser { * @param {LiteAdaptor} adaptor The adaptor for managing nodes * @param {LiteElement} node The node to close * @param {string} tag The close tag being processed - * @return {LiteElement} The first unclosed parent node + * @returns {LiteElement} The first unclosed parent node */ - protected closeTag(adaptor: LiteAdaptor, node: LiteElement, tag: string): LiteElement { + protected closeTag( + adaptor: LiteAdaptor, + node: LiteElement, + tag: string + ): LiteElement { const kind = tag.slice(2, tag.length - 1).toLowerCase(); while (adaptor.parent(node) && adaptor.kind(node) !== kind) { node = adaptor.parent(node); @@ -182,22 +185,29 @@ export class LiteParser implements MinDOMParser { * @param {LiteElement} node The parent node for the tag * @param {string} tag The tag being processed * @param {string[]} parts The rest of the text/tag array - * @return {LiteElement} The node to which the next tag will be added + * @returns {LiteElement} The node to which the next tag will be added */ - protected openTag(adaptor: LiteAdaptor, node: LiteElement, tag: string, parts: string[]): LiteElement { + protected openTag( + adaptor: LiteAdaptor, + node: LiteElement, + tag: string, + parts: string[] + ): LiteElement { const PCDATA = (this.constructor as typeof LiteParser).PCDATA; const SELF_CLOSING = (this.constructor as typeof LiteParser).SELF_CLOSING; // // Get the child to be added to the node // - const kind = tag.match(/<(.*?)[\s\n>\/]/)[1].toLowerCase(); + const kind = tag.match(/<(.*?)[\s\n>/]/)[1].toLowerCase(); const child = adaptor.node(kind) as LiteElement; // // Split out the tag attributes as an array of space, name, value1, value3, value3, // where value1, value2, and value3 are the value of the node (only one is defined) // that come from matching quoted strings with ' (value1), " (value2) or no quotes (value3). // - const attributes = tag.replace(/^<.*?[\s\n>]/, '').split(PATTERNS.attrsplit); + const attributes = tag + .replace(/^<.*?[\s\n>]/, '') + .split(PATTERNS.attrsplit); // // If the tag was complete (it ends with > or has no attributes) // @@ -229,14 +239,14 @@ export class LiteParser implements MinDOMParser { * @param {string[]} attributes The array of space, name, value1, value2, value3 * as described above. */ - protected addAttributes(adaptor: LiteAdaptor, node: LiteElement, attributes: string[]) { - const CDATA_ATTR = (this.constructor as typeof LiteParser).CDATA_ATTR; + protected addAttributes( + adaptor: LiteAdaptor, + node: LiteElement, + attributes: string[] + ) { while (attributes.length) { - let [ , name, v1, v2, v3] = attributes.splice(0, 5); - let value = v1 || v2 || v3 || ''; - if (!CDATA_ATTR[name]) { - value = Entities.translate(value); - } + const [, name, v1, v2, v3] = attributes.splice(0, 5); + const value = Entities.translate(v1 || v2 || v3 || ''); adaptor.setAttribute(node, name, value); } } @@ -247,7 +257,12 @@ export class LiteParser implements MinDOMParser { * @param {string} kind The tag name being handled * @param {string[]} parts The array of text/tag data for the document */ - protected handlePCDATA(adaptor: LiteAdaptor, node: LiteElement, kind: string, parts: string[]) { + protected handlePCDATA( + adaptor: LiteAdaptor, + node: LiteElement, + kind: string, + parts: string[] + ) { const pcdata = [] as string[]; const etag = ''; let ptag = ''; @@ -276,7 +291,7 @@ export class LiteParser implements MinDOMParser { * @param {LiteDocument} root The document being checked */ protected checkDocument(adaptor: LiteAdaptor, root: LiteDocument) { - let node = this.getOnlyChild(adaptor, adaptor.body(root)); + const node = this.getOnlyChild(adaptor, adaptor.body(root)); if (!node) return; for (const child of adaptor.childNodes(adaptor.body(root))) { if (child === node) { @@ -287,40 +302,40 @@ export class LiteParser implements MinDOMParser { } } switch (adaptor.kind(node)) { - case 'html': - // - // Look through the children for the head and body - // - for (const child of node.children) { - switch (adaptor.kind(child)) { - case 'head': - root.head = child as LiteElement; - break; - case 'body': - root.body = child as LiteElement; - break; + case 'html': + // + // Look through the children for the head and body + // + for (const child of node.children) { + switch (adaptor.kind(child)) { + case 'head': + root.head = child as LiteElement; + break; + case 'body': + root.body = child as LiteElement; + break; + } } - } - // - // Make sure the elements are linked in properly - // - root.root = node; - adaptor.remove(node); - if (adaptor.parent(root.body) !== node) { - adaptor.append(node, root.body); - } - if (adaptor.parent(root.head) !== node) { - adaptor.insert(root.head, root.body); - } - break; + // + // Make sure the elements are linked in properly + // + root.root = node; + adaptor.remove(node); + if (adaptor.parent(root.body) !== node) { + adaptor.append(node, root.body); + } + if (adaptor.parent(root.head) !== node) { + adaptor.insert(root.head, root.body); + } + break; - case 'head': - root.head = adaptor.replace(node, root.head) as LiteElement; - break; + case 'head': + root.head = adaptor.replace(node, root.head) as LiteElement; + break; - case 'body': - root.body = adaptor.replace(node, root.body) as LiteElement; - break; + case 'body': + root.body = adaptor.replace(node, root.body) as LiteElement; + break; } } @@ -330,7 +345,7 @@ export class LiteParser implements MinDOMParser { * * @param {LiteAdaptor} adaptor The adaptor for managing nodes * @param {LiteElement} body The body element being checked - * @return {LiteElement} The sole LiteElement child of the body, or null if none or more than one + * @returns {LiteElement} The sole LiteElement child of the body, or null if none or more than one */ protected getOnlyChild(adaptor: LiteAdaptor, body: LiteElement): LiteElement { let node: LiteElement = null; @@ -347,59 +362,126 @@ export class LiteParser implements MinDOMParser { * @param {LiteAdaptor} adaptor The adaptor for managing nodes * @param {LiteElement} node The node to serialize * @param {boolean} xml True when producing XML, false for HTML - * @return {string} The serialized element (like outerHTML) + * @returns {string} The serialized element (like outerHTML) */ - public serialize(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string { + public serialize( + adaptor: LiteAdaptor, + node: LiteElement, + xml: boolean = false + ): string { const SELF_CLOSING = (this.constructor as typeof LiteParser).SELF_CLOSING; - const CDATA = (this.constructor as typeof LiteParser).CDATA_ATTR; const tag = adaptor.kind(node); - const attributes = adaptor.allAttributes(node).map( - (x: AttributeData) => x.name + '="' + (CDATA[x.name] ? x.value : this.protectAttribute(x.value)) + '"' - ).join(' '); + const attributes = this.allAttributes(adaptor, node, xml) + .map((x) => x.name + '="' + this.protectAttribute(x.value, xml) + '"') + .join(' '); const content = this.serializeInner(adaptor, node, xml); const html = - '<' + tag + (attributes ? ' ' + attributes : '') - + ((!xml || content) && !SELF_CLOSING[tag] ? `>${content}` : xml ? '/>' : '>'); + `<${tag}` + + (attributes ? ' ' + attributes : '') + + ((!xml || content) && !SELF_CLOSING[tag] + ? `>${content}` + : xml + ? '/>' + : '>'); return html; } /** * @param {LiteAdaptor} adaptor The adaptor for managing nodes * @param {LiteElement} node The node whose innerHTML is needed - * @return {string} The serialized element (like innerHTML) + * @param {boolean} xml True if XML rules should be used (e.g., self-closing tags) + * @returns {string} The serialized element (like innerHTML) */ - public serializeInner(adaptor: LiteAdaptor, node: LiteElement, xml: boolean = false): string { + public serializeInner( + adaptor: LiteAdaptor, + node: LiteElement, + xml: boolean = false + ): string { const PCDATA = (this.constructor as typeof LiteParser).PCDATA; - if (PCDATA.hasOwnProperty(node.kind)) { - return adaptor.childNodes(node).map(x => adaptor.value(x)).join(''); + if (Object.hasOwn(PCDATA, node.kind)) { + return adaptor + .childNodes(node) + .map((x) => adaptor.value(x)) + .join(''); } - return adaptor.childNodes(node).map(x => { - const kind = adaptor.kind(x); - return (kind === '#text' ? this.protectHTML(adaptor.value(x)) : - kind === '#comment' ? (x as LiteComment).value : - this.serialize(adaptor, x as LiteElement, xml)); - }).join(''); + return adaptor + .childNodes(node) + .map((x) => { + const kind = adaptor.kind(x); + return kind === '#text' + ? this.protectHTML(adaptor.value(x)) + : kind === '#comment' + ? (x as LiteComment).value + : this.serialize(adaptor, x as LiteElement, xml); + }) + .join(''); + } + + /** + * @param {LiteAdaptor} adaptor The adaptor for managing nodes + * @param {LiteElement} node The node to serialize + * @param {boolean} xml True when producing XML, false for HTML + * @returns {AttributeData[]} The attribute list + */ + protected allAttributes( + adaptor: LiteAdaptor, + node: LiteElement, + xml: boolean + ): AttributeData[] { + const attributes = adaptor.allAttributes(node); + // + // If we aren't in XML mode, just use the attributes given + // + if (!xml) { + return attributes; + } + // + // Check that we know the namespace for the kind of node + // + const kind = adaptor.kind(node); + const xmlns = (this.constructor as typeof LiteParser).XMLNS; + if (!Object.hasOwn(xmlns, kind)) { + return attributes; + } + // + // Check for existance of xmlns attribute + // + for (const { name } of attributes) { + if (name === 'xmlns') { + return attributes; + } + } + // + // Add one of it is missing + // + attributes.push({ name: 'xmlns', value: xmlns[kind] }); + return attributes; } /** * @param {string} text The attribute value to be HTML escaped - * @return {string} The string with " replaced by entities + * @param {boolean} xml True if XML rules are to be used + * @returns {string} The string with " replaced by entities */ - public protectAttribute(text: string): string { + public protectAttribute(text: string, xml: boolean): string { if (typeof text !== 'string') { text = String(text); } - return text.replace(/"/g, '"'); + text = text.replace(/&/g, '&').replace(/"/g, '"'); + if (xml) { + text = text.replace(//g, '>'); + } + return text; } /** * @param {string} text The text to be HTML escaped - * @return {string} The string with &, <, and > replaced by entities + * @returns {string} The string with &, <, and > replaced by entities */ public protectHTML(text: string): string { - return text.replace(/&/g, '&') + return text + .replace(/&/g, '&') .replace(//g, '>'); } - } diff --git a/ts/adaptors/lite/Text.ts b/ts/adaptors/lite/Text.ts index 82c9044c8..4c311dc12 100644 --- a/ts/adaptors/lite/Text.ts +++ b/ts/adaptors/lite/Text.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ */ /** - * @fileoverview Implements a lightweight Text element replacement + * @file Implements a lightweight Text element replacement * * @author dpvc@mathjax.org (Davide Cervone) */ -import {LiteElement} from './Element.js'; +import { LiteElement } from './Element.js'; /************************************************************/ /** @@ -40,14 +40,16 @@ export class LiteText { /** * The kind of node is #text + * + * @returns {string} The node kind. */ - public get kind() { + public get kind(): string { return '#text'; } /** * @param {string} text The text for the node - * @constructor + * @class */ constructor(text: string = '') { this.value = text; diff --git a/ts/adaptors/lite/Window.ts b/ts/adaptors/lite/Window.ts index 58954a913..18f2bec18 100644 --- a/ts/adaptors/lite/Window.ts +++ b/ts/adaptors/lite/Window.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ */ /** - * @fileoverview Implements a lightweight DOM adaptor + * @file Implements a lightweight DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {LiteElement} from './Element.js'; -import {LiteDocument} from './Document.js'; -import {LiteList} from './List.js'; -import {LiteParser} from './Parser.js'; +import { LiteElement } from './Element.js'; +import { LiteDocument } from './Document.js'; +import { LiteList } from './List.js'; +import { LiteParser } from './Parser.js'; /************************************************************/ /** @@ -54,16 +54,16 @@ export class LiteWindow { /** * The DocumentFragment class */ - public DocumentFragment: typeof LiteList = LiteList; + public DocumentFragment: typeof LiteList = LiteList; /** * The Document class */ - public Document: typeof LiteDocument = LiteDocument; + public Document: typeof LiteDocument = LiteDocument; /** * Create the LiteWindow and its LiteDocument */ constructor() { - this.document = new LiteDocument(); + this.document = new LiteDocument(this); } } diff --git a/ts/adaptors/liteAdaptor.ts b/ts/adaptors/liteAdaptor.ts index e5dfc7b7a..ffe37cfce 100644 --- a/ts/adaptors/liteAdaptor.ts +++ b/ts/adaptors/liteAdaptor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,29 +16,32 @@ */ /** - * @fileoverview Implements a lightweight DOM adaptor + * @file Implements a lightweight DOM adaptor * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractDOMAdaptor} from '../core/DOMAdaptor.js'; -import {NodeMixin, Constructor} from './NodeMixin.js'; -import {LiteDocument} from './lite/Document.js'; -import {LiteElement, LiteNode} from './lite/Element.js'; -import {LiteText, LiteComment} from './lite/Text.js'; -import {LiteList} from './lite/List.js'; -import {LiteWindow} from './lite/Window.js'; -import {LiteParser} from './lite/Parser.js'; -import {Styles} from '../util/Styles.js'; -import {OptionList} from '../util/Options.js'; +import { AbstractDOMAdaptor } from '../core/DOMAdaptor.js'; +import { NodeMixin, Constructor } from './NodeMixin.js'; +import { LiteDocument } from './lite/Document.js'; +import { LiteElement, LiteNode } from './lite/Element.js'; +import { LiteText, LiteComment } from './lite/Text.js'; +import { LiteList } from './lite/List.js'; +import { LiteWindow } from './lite/Window.js'; +import { LiteParser } from './lite/Parser.js'; +import { Styles } from '../util/Styles.js'; +import { OptionList } from '../util/Options.js'; /************************************************************/ - /** * Implements a lightweight DOMAdaptor on liteweight HTML elements */ -export class LiteBase extends AbstractDOMAdaptor { +export class LiteBase extends AbstractDOMAdaptor< + LiteElement, + LiteText, + LiteDocument +> { /** * The document in which the HTML nodes will be created */ @@ -55,8 +58,7 @@ export class LiteBase extends AbstractDOMAdaptor).nodes); } else { containers.push(node); @@ -231,6 +299,32 @@ export class LiteBase extends AbstractDOMAdaptor n === node) : -1); + return node.parent ? node.parent.children.findIndex((n) => n === node) : -1; } /** @@ -310,20 +404,22 @@ export class LiteBase extends AbstractDOMAdaptor { - if (n.kind === '#text') { - return new LiteText((n as LiteText).value); - } else if (n.kind === '#comment') { - return new LiteComment((n as LiteComment).value); - } else { - const m = this.clone(n as LiteElement); - m.parent = nnode; - return m; - } - }); + nnode.attributes = { ...node.attributes }; + nnode.children = !deep + ? [] + : node.children.map((n) => { + if (n.kind === '#text') { + return new LiteText((n as LiteText).value); + } else if (n.kind === '#comment') { + return new LiteComment((n as LiteComment).value); + } else { + const m = this.clone(n as LiteElement); + m.parent = nnode; + return m; + } + }); return nnode; } @@ -345,7 +441,7 @@ export class LiteBase extends AbstractDOMAdaptor= 0 && i < parent.children.length ? parent.children[i] : null); + return i >= 0 && i < parent.children.length ? parent.children[i] : null; } /** @@ -355,7 +451,7 @@ export class LiteBase extends AbstractDOMAdaptor= 0 ? parent.children[i] : null); + return i >= 0 ? parent.children[i] : null; } /** @@ -397,8 +493,11 @@ export class LiteBase extends AbstractDOMAdaptor$/, '$2') : ''); + return node.kind === '#text' + ? (node as LiteText).value + : node.kind === '#comment' + ? (node as LiteComment).value.replace(/^$/, '$2') + : ''; } /** @@ -406,8 +505,14 @@ export class LiteBase extends AbstractDOMAdaptor { - return s + (n.kind === '#text' ? (n as LiteText).value : - n.kind === '#comment' ? '' : this.textContent(n as LiteElement)); + return ( + s + + (n.kind === '#text' + ? (n as LiteText).value + : n.kind === '#comment' + ? '' + : this.textContent(n as LiteElement)) + ); }, ''); } @@ -435,7 +540,12 @@ export class LiteBase extends AbstractDOMAdaptor n === name)) { + const classString = node.attributes['class'] as string; + const classes = classString?.split(/ /) || []; + if (!classes.includes(name)) { classes.push(name); node.attributes['class'] = classes.join(' '); } @@ -496,8 +607,9 @@ export class LiteBase extends AbstractDOMAdaptor n === name); + const classString = node.attributes['class'] as string; + const classes = classString?.split(/ /) || []; + const i = classes.indexOf(name); if (i >= 0) { classes.splice(i, 1); node.attributes['class'] = classes.join(' '); @@ -508,8 +620,8 @@ export class LiteBase extends AbstractDOMAdaptor n === name); + const classes = ((node.attributes['class'] as string) || '').split(/ /); + return classes.includes(name); } /** @@ -548,7 +660,9 @@ export class LiteBase extends AbstractDOMAdaptor { + return null; + } } /** * The LiteAdaptor class (add in the NodeMixin methods and options) */ -export class LiteAdaptor extends NodeMixin>(LiteBase) {} +export class LiteAdaptor extends NodeMixin< + LiteElement, + LiteText, + LiteDocument, + Constructor +>(LiteBase) {} /************************************************************/ /** * The function to call to obtain a LiteAdaptor * * @param {OptionList} options The options for the adaptor - * @return {LiteAdaptor} The newly created adaptor + * @returns {LiteAdaptor} The newly created adaptor */ export function liteAdaptor(options: OptionList = null): LiteAdaptor { return new LiteAdaptor(null, options); diff --git a/ts/components/cjs/root.ts b/ts/components/cjs/root.ts new file mode 100644 index 000000000..137c4a5a2 --- /dev/null +++ b/ts/components/cjs/root.ts @@ -0,0 +1,34 @@ +/************************************************************* + * + * Copyright (c) 2023-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview ES5 shim for getting the MathJax root directory + * + * @author dpvc@mathjax.org (Davide Cervone) + */ + +/** + * The location of this file + */ +declare const __dirname: string; + +/** + * @return {string} The MathJax component root directory + */ +export function mjxRoot(): string { + return __dirname.replace(/[cm]js\/components\/[cm]js$/, 'bundle'); +} diff --git a/ts/components/cjs/sre-root.ts b/ts/components/cjs/sre-root.ts new file mode 100644 index 000000000..bb8cff7e9 --- /dev/null +++ b/ts/components/cjs/sre-root.ts @@ -0,0 +1,34 @@ +/************************************************************* + * + * Copyright (c) 2023-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @fileoverview ES5 shim for getting the MathJax root directory + * + * @author dpvc@mathjax.org (Davide Cervone) + */ + +/** + * The location of this file + */ +declare const __dirname: string; + +/** + * @return {string} The MathJax mjs SRE root directory + */ +export function sreRoot(): string { + return __dirname.replace(/components\/[cm]js$/, 'a11y/sre'); +} diff --git a/ts/components/global.ts b/ts/components/global.ts index 9ef413fd4..44316c65e 100644 --- a/ts/components/global.ts +++ b/ts/components/global.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Handles using MathJax global as config object, and to hold + * @file Handles using MathJax global as config object, and to hold * methods and data to be available to the page author * * @author dpvc@mathjax.org (Davide Cervone) */ -import {VERSION} from './version.js'; +import { VERSION } from './version.js'; /** * The MathJax variable as a configuration object @@ -49,11 +49,25 @@ export interface MathJaxObject { config: MathJaxConfig; } -declare const global: {MathJax: MathJaxObject | MathJaxConfig}; +/** + * The node/webpack global object + */ +declare const global: typeof globalThis; + +/** + * Get the global object as the window, global, globalThis, or a separate global + */ +const defaultGlobal = {}; +export const GLOBAL = (() => { + if (typeof window !== 'undefined') return window; // for browsers + if (typeof global !== 'undefined') return global; // for node + if (typeof globalThis !== 'undefined') return globalThis; + return defaultGlobal; // fallback shared object +})() as any as Window & { MathJax: MathJaxObject | MathJaxConfig }; /** * @param {any} x An item to test if it is an object - * @return {boolean} True if the item is a non-null object + * @returns {boolean} True if the item is a non-null object */ export function isObject(x: any): boolean { return typeof x === 'object' && x !== null; @@ -63,17 +77,24 @@ export function isObject(x: any): boolean { * Combine user-produced configuration with existing defaults. Values * from src will replace those in dst. * - * @param {any} dst The destination config object (to be merged into) - * @param {any} src The source configuration object (to replace defaul values in dst} - * @return {any} The resulting (modified) config object + * @param {any} dst The destination config object (to be merged into) + * @param {any} src The source configuration object (to replace default values in dst} + * @param {boolean} check True when combining into MathJax._ to avoid setting a property with a getter + * @returns {any} The resulting (modified) config object */ -export function combineConfig(dst: any, src: any): any { +export function combineConfig(dst: any, src: any, check: boolean = false): any { for (const id of Object.keys(src)) { - if (id === '__esModule') continue; - if (isObject(dst[id]) && isObject(src[id]) && - !(src[id] instanceof Promise) /* needed for IE polyfill */) { - combineConfig(dst[id], src[id]); - } else if (src[id] !== null && src[id] !== undefined) { + if ( + id === '__esModule' || + dst[id] === src[id] || + src[id] === null || + src[id] === undefined + ) { + continue; + } + if (isObject(dst[id]) && isObject(src[id])) { + combineConfig(dst[id], src[id], check || id === '_'); + } else if (!check || !Object.getOwnPropertyDescriptor(dst, id)?.get) { dst[id] = src[id]; } } @@ -87,8 +108,8 @@ export function combineConfig(dst: any, src: any): any { * * @param {any} dst The destination config object (to be merged into) * @param {string} name The id of the configuration block to modify (created if doesn't exist) - * @param {any} src The source configuration object (to replace defaul values in dst} - * @return {any} The resulting (modified) config object + * @param {any} src The source configuration object (to replace default values in dst} + * @returns {any} The resulting (modified) config object */ export function combineDefaults(dst: any, name: string, src: any): any { if (!dst[name]) { @@ -109,17 +130,20 @@ export function combineDefaults(dst: any, name: string, src: any): any { * Combine configuration or data with the existing MathJax object * * @param {any} config The data to be merged into the MathJax object + * @returns {MathJaxObject} The combined configuration object */ export function combineWithMathJax(config: any): MathJaxObject { return combineConfig(MathJax, config); } - /** - * Create the MathJax global, if it doesn't exist + * Create the MathJax global, if it doesn't exist or is not an object literal */ -if (typeof global.MathJax === 'undefined') { - global.MathJax = {} as MathJaxConfig; +if ( + typeof GLOBAL.MathJax === 'undefined' || + GLOBAL.MathJax.constructor !== {}.constructor +) { + GLOBAL.MathJax = {} as MathJaxConfig; } /** @@ -127,15 +151,15 @@ if (typeof global.MathJax === 'undefined') { * MathJaxObject containing the version, class library, and user * configuration. */ -if (!(global.MathJax as MathJaxObject).version) { - global.MathJax = { +if (!(GLOBAL.MathJax as MathJaxObject).version) { + GLOBAL.MathJax = { version: VERSION, _: {}, - config: global.MathJax + config: GLOBAL.MathJax, }; } /** * Export the global MathJax object for convenience */ -export const MathJax = global.MathJax as MathJaxObject; +export const MathJax = GLOBAL.MathJax as MathJaxObject; diff --git a/ts/components/latest.ts b/ts/components/latest.ts deleted file mode 100644 index 3a02752dd..000000000 --- a/ts/components/latest.ts +++ /dev/null @@ -1,407 +0,0 @@ -/************************************************************* - * - * Copyright (c) 2019-2022 The MathJax Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * The data for a CDN - */ -type CdnData = { - api: string, // URL for JSON containing version number - key: string, // key for versionb string in JSON data - base?: string // base URL for MathJax on the CDN (version is appended to get actual URL) -}; - -/** - * A map of server names to CDN data - */ -type CdnList = Map; - -/** - * The data from a script tag for latest.js - */ -type ScriptData = { - tag: HTMLScriptElement, // the script DOM element - src: string, // the script's (possibly modified) source attribute - id: string, // the script's (possibly empty) id string - version: string, // the MathJax version where latest.js was loaded - dir: string, // the subdirectory where latest.js was loaded from (e.g., /es5) - file: string, // the file to be loaded by latest.js - cdn: CdnData // the CDN where latest.js was loaded -} | null; - -/** - * Add XMLHttpRequest and ActiveXObject (for IE) - */ -declare const window: { - XMLHttpRequest: XMLHttpRequest; - ActiveXObject: any; -}; - -/*=====================================================================*/ - - -/** - * The various CDNs and their data for how to obtain versions - */ -const CDN: CdnList = new Map([ - ['cdnjs.cloudflare.com', { - api: 'https://api.cdnjs.com/libraries/mathjax?fields=version', - key: 'version', - base: 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/' - }], - - ['rawcdn.githack.com', { - api: 'https://api.github.com/repos/mathjax/mathjax/releases/latest', - key: 'tag_name', - base: 'https://rawcdn.githack.com/mathjax/MathJax/' - }], - - ['gitcdn.xyz', { - api: 'https://api.github.com/repos/mathjax/mathjax/releases/latest', - key: 'tag_name', - base: 'https://gitcdn.xyz/mathjax/MathJax/' - }], - - ['cdn.statically.io', { - api: 'https://api.github.com/repos/mathjax/mathjax/releases/latest', - key: 'tag_name', - base: 'https://cdn.statically.io/gh/mathjax/MathJax/' - }], - - ['unpkg.com', { - api: 'https://api.github.com/repos/mathjax/mathjax/releases/latest', - key: 'tag_name', - base: 'https://unpkg.com/mathjax@' - }], - - ['cdn.jsdelivr.net', { - api: 'https://api.github.com/repos/mathjax/mathjax/releases/latest', - key: 'tag_name', - base: 'https://cdn.jsdelivr.net/npm/mathjax@' - }] -]); - -/** - * The data for getting release versions from GitHub - */ -const GITHUB: CdnData = { - api: 'https://api.github.com/repos/mathjax/mathjax/releases', - key: 'tag_name' -}; - -/** - * The major version number for MathJax (we will load the highest version with this initial number) - */ -const MJX_VERSION = 3; - -/** - * The name to use for the version in localStorage - */ -const MJX_LATEST = 'mjx-latest-version'; - -/** - * The amount of time a cached version number is valid - */ -const SAVE_TIME = 1000 * 60 * 60 * 24 * 7; // one week - -/** - * Data for the script that loaded latest.js - */ -let script: ScriptData = null; - -/*=====================================================================*/ - -/** - * Produce an error message on the console - * - * @param {string} message The error message to display - */ -function Error(message: string) { - if (console && console.error) { - console.error('MathJax(latest.js): ' + message); - } -} - -/** - * Create a ScriptData object from the given script tag and CDN - * - * @param {HTMLScriptElement} script The script tag whose data is desired - * @param {CdnData} cdn The CDN data already obtained for the script (or null) - * @return {ScriptData} The data for the given script - */ -function scriptData(script: HTMLScriptElement, cdn: CdnData = null): ScriptData { - script.parentNode.removeChild(script); - let src = script.src; - let file = src.replace(/.*?\/latest\.js(\?|$)/, ''); - if (file === '') { - file = 'startup.js'; - src = src.replace(/\?$/, '') + '?' + file; - } - const version = (src.match(/(\d+\.\d+\.\d+)(\/es\d+)?\/latest.js\?/) || ['', ''])[1]; - const dir = (src.match(/(\/es\d+)\/latest.js\?/) || ['', ''])[1] || ''; - return { - tag: script, - src: src, - id: script.id, - version: version, - dir: dir, - file: file, - cdn: cdn - }; -} - -/** - * Check if a script refers to MathJax on one of the CDNs - * - * @param {HTMLScriptElement} script The script tag to check - * @return {ScriptData | null} Non-null if the script is from a MathJax CDN - */ -function checkScript(script: HTMLScriptElement): ScriptData | null { - for (const server of CDN.keys()) { - const cdn = CDN.get(server); - const url = cdn.base; - const src = script.src; - if (src && src.substr(0, url.length) === url && src.match(/\/latest\.js(\?|$)/)) { - return scriptData(script, cdn); - } - } - return null; -} - -/** - * @return {ScriptData} The data for the script tag that loaded latest.js - */ -function getScript(): ScriptData { - if (document.currentScript) { - return scriptData(document.currentScript as HTMLScriptElement); - } - const script = document.getElementById('MathJax-script') as HTMLScriptElement; - if (script && script.nodeName.toLowerCase() === 'script') { - return checkScript(script); - } - const scripts = document.getElementsByTagName('script'); - for (const script of Array.from(scripts)) { - const data = checkScript(script); - if (data) { - return data; - } - } - return null; -} - -/*=====================================================================*/ - -/** - * Save the version and date information in localStorage so we don't - * have to contact the CDN for every page that uses MathJax. - * - * @param {string} version The version to save - */ -function saveVersion(version: string) { - try { - const data = version + ' ' + Date.now(); - localStorage.setItem(MJX_LATEST, data); - } catch (err) {} -} - -/** - * Get the version from localStorage, and make sure it is fresh enough to use - * - * @return {string|null} The version string (if one has been saved) or null (if not) - */ -function getSavedVersion(): string | null { - try { - const [version, date] = localStorage.getItem(MJX_LATEST).split(/ /); - if (date && Date.now() - parseInt(date) < SAVE_TIME) { - return version; - } - } catch (err) {} - return null; -} - -/*=====================================================================*/ - -/** - * Create a script tag that loads the given URL - * - * @param {string} url The URL of the javascript file to be loaded - * @param {string} id The id to use for the script tag - */ -function loadMathJax(url: string, id: string) { - const script = document.createElement('script'); - script.type = 'text/javascript'; - script.async = true; - script.src = url; - if (id) { - script.id = id; - } - const head = document.head || document.getElementsByTagName('head')[0] || document.body; - if (head) { - head.appendChild(script); - } else { - Error('Can\'t find the document element'); - } -} - -/** - * When we can't find the current version, use the original URL but remove the "latest.js" - */ -function loadDefaultMathJax() { - if (script) { - loadMathJax(script.src.replace(/\/latest\.js\?/, '/'), script.id); - } else { - Error('Can\'t determine the URL for loading MathJax'); - } -} - -/** - * Load the given version using the base URL and file to load - * (if the versions differ, run latest.js from the new version - * in case there are important changes there) - * - * @param {string} version The version of MathJax to load from - */ -function loadVersion(version: string) { - if (script.version && script.version !== version) { - script.file = 'latest.js?' + script.file; - } - loadMathJax(script.cdn.base + version + script.dir + '/' + script.file, script.id); -} - -/** - * Check if the given version is acceptable and load it if it is. - * - * @param {string} version The version to check if it is the latest (valid) one - * @return {boolean} True if it is the latest version, false if not - */ -function checkVersion(version: string): boolean { - const major = parseInt(version.split(/\./)[0]); - if (major === MJX_VERSION && !version.match(/-(beta|rc)/)) { - saveVersion(version); - loadVersion(version); - return true; - } - return false; -} - -/*=====================================================================*/ - -/** - * Create an XMLHttpRequest object, if possible - * - * @return {XMLHttpRequest} The XMLHttpRequest instance - */ -function getXMLHttpRequest(): XMLHttpRequest { - if (window.XMLHttpRequest) { - return new XMLHttpRequest(); - } - if (window.ActiveXObject) { - try { return new window.ActiveXObject('Msxml2.XMLHTTP'); } catch (err) {} - try { return new window.ActiveXObject('Microsoft.XMLHTTP'); } catch (err) {} - } - return null; -} - -/** - * Request JSON data from a CDN. If it loads OK, call the action() function - * on the data. If not, or if the action returns false, run the failure() function. - * - * @param {CdnData} cdn The CDN whose API will be used - * @param {Function} action The function to perform when the data are received - * @param {Function} failure The function to perform if data can't be obtained, - * or if action() returns false - */ -function requestXML(cdn: CdnData, action: (json: JSON | JSON[]) => boolean, failure: () => void) { - const request = getXMLHttpRequest(); - if (request) { - // tslint:disable-next-line:jsdoc-require - request.onreadystatechange = function () { - if (request.readyState === 4) { - if (request.status === 200) { - !action(JSON.parse(request.responseText)) && failure(); - } else { - Error('Problem acquiring MathJax version: status = ' + request.status); - failure(); - } - } - }; - request.open('GET', cdn.api, true); - request.send(null); - } else { - Error('Can\'t create XMLHttpRequest object'); - failure(); - } -} - -/** - * Look through the list of versions on GitHub and find the first one that - * has the MJX_VERSION as its major version number, and load that. If none - * is found, run the version from which latest.js was loaded. - */ -function loadLatestGitVersion() { - requestXML(GITHUB, (json: JSON[]) => { - if (!(json instanceof Array)) return false; - for (const data of json) { - if (checkVersion((data as any)[GITHUB.key])) { - return true; - } - } - return false; - }, loadDefaultMathJax); -} - -/** - * Check the CDN for its latest version, and load that, if it is an - * acceptable version, otherwise, (e.g., the current version has a - * higher major version that MJX_VERSION), find the highest version on - * GitHub with the given major version and use that. If one can't be - * found, use the version where latest.js was loaded. - */ -function loadLatestCdnVersion() { - requestXML(script.cdn, function (json) { - if (json instanceof Array) { - json = json[0]; - } - if (!checkVersion((json as any)[script.cdn.key])) { - loadLatestGitVersion(); - } - return true; - }, loadDefaultMathJax); -} - -/*=====================================================================*/ - - -/** - * Find the script that loaded latest.js - * If the script is from a known CDN: - * Retrieve the cached version (if any) - * Load the given version of the file, if the version is cached, - * Otherwise find the latest version and load that. - * Otherwise, - * Load using the version where latest.js was loaded. - */ -export function loadLatest() { - script = getScript(); - if (script && script.cdn) { - const version = getSavedVersion(); - version ? - loadVersion(version) : - loadLatestCdnVersion(); - } else { - loadDefaultMathJax(); - } -} diff --git a/ts/components/loader.ts b/ts/components/loader.ts index 7e10e6b20..34c2e2e56 100644 --- a/ts/components/loader.ts +++ b/ts/components/loader.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,37 +16,49 @@ */ /** - * @fileoverview A dynamic loader for loading MathJax components based + * @file A dynamic loader for loading MathJax components based * on a user configuration, while handling timing of * dependencies properly * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MathJax as MJGlobal, MathJaxObject as MJObject, MathJaxLibrary, - MathJaxConfig as MJConfig, combineWithMathJax, combineDefaults} from './global.js'; - -import {Package, PackageError, PackageReady, PackageFailed} from './package.js'; -export {Package, PackageError, PackageReady, PackageFailed} from './package.js'; -export {MathJaxLibrary} from './global.js'; - -import {FunctionList} from '../util/FunctionList.js'; - -/* - * The current directory (for webpack), and the browser document (if any) - */ -declare var __dirname: string; -declare var document: Document; +import { + MathJax as MJGlobal, + MathJaxObject as MJObject, + MathJaxLibrary, + MathJaxConfig as MJConfig, + combineWithMathJax, + combineDefaults, +} from './global.js'; +import { + Package, + PackageError, + PackageReady, + PackageFailed, + PackageConfig, +} from './package.js'; +import { FunctionList } from '../util/FunctionList.js'; +import { mjxRoot } from '#root/root.js'; +import { context } from '../util/context.js'; /** * Function used to determine path to a given package. */ -export type PathFilterFunction = (data: {name: string, original: string, addExtension: boolean}) => boolean; -export type PathFilterList = (PathFilterFunction | [PathFilterFunction, number])[]; +export type PathFilterFunction = (data: { + name: string; + original: string; + addExtension: boolean; +}) => boolean; +export type PathFilterList = ( + | PathFilterFunction + | [PathFilterFunction, number] +)[]; /** * Update the configuration structure to include the loader configuration */ +/* prettier-ignore */ export interface MathJaxConfig extends MJConfig { loader?: { paths?: {[name: string]: string}; // The path prefixes for use in locations @@ -71,12 +83,14 @@ export interface MathJaxObject extends MJObject { config: MathJaxConfig; loader: { ready: (...names: string[]) => Promise; // Get a promise for when all the named packages are loaded - load: (...names: string[]) => Promise; // Load the packages and return a promise for when ready - preLoad: (...names: string[]) => void; // Indicate that packages are already loaded by hand - defaultReady: () => void; // The function performed when all packages are loaded - getRoot: () => string; // Find the root URL for the MathJax files - checkVersion: (name: string, version: string) => boolean; // Check the version of an extension - pathFilters: FunctionList; // the filters to use for looking for package paths + load: (...names: string[]) => Promise; // Load the packages and return a promise for when ready + preLoaded: (...names: string[]) => void; // Indicate that packages are already loaded by hand + defaultReady: () => void; // The function performed when all packages are loaded + getRoot: () => string; // Find the root URL for the MathJax files + checkVersion: (name: string, version: string) => boolean; // Check the version of an extension + saveVersion: (name: string) => void; // Set the version for a combined component + pathFilters: FunctionList; // The filters to use for looking for package paths + addPackageData: (name: string, data: PackageConfig) => void; // Add more package data for a package }; startup?: any; } @@ -84,60 +98,83 @@ export interface MathJaxObject extends MJObject { /** * Functions used to filter the path to a package */ -export const PathFilters: {[name: string]: PathFilterFunction} = { +export const PathFilters: { [name: string]: PathFilterFunction } = { /** * Look up the path in the configuration's source list + * + * @param {PathFilterFunction} data The data object containing the filter functions + * @returns {boolean} True */ source: (data) => { - if (CONFIG.source.hasOwnProperty(data.name)) { + if (Object.hasOwn(CONFIG.source, data.name)) { data.name = CONFIG.source[data.name]; } return true; }, /** - * Add [mathjax] before any relative path, and add .js if needed + * Add [mathjax] before any relative path + * + * @param {PathFilterFunction} data The data object containing the filter functions + * @returns {boolean} True */ normalize: (data) => { const name = data.name; if (!name.match(/^(?:[a-z]+:\/)?\/|[a-z]:\\|\[/i)) { data.name = '[mathjax]/' + name.replace(/^\.\//, ''); } - if (data.addExtension && !name.match(/\.[^\/]+$/)) { - data.name += '.js'; - } return true; }, /** * Recursively replace path prefixes (e.g., [mathjax], [tex], etc.) + * + * @param {PathFilterFunction} data The data object containing the filter functions + * @returns {boolean} True */ prefix: (data) => { let match; while ((match = data.name.match(/^\[([^\]]*)\]/))) { - if (!CONFIG.paths.hasOwnProperty(match[1])) break; - data.name = CONFIG.paths[match[1]] + data.name.substr(match[0].length); + if (!Object.hasOwn(CONFIG.paths, match[1])) break; + data.name = CONFIG.paths[match[1]] + data.name.substring(match[0].length); } return true; - } + }, + /** + * Add .js, if missing + * + * @param {PathFilterFunction} data The data object containing the filter functions + * @returns {boolean} True + */ + addExtension: (data) => { + if (data.addExtension && !data.name.match(/\.[^/]+$/)) { + data.name += '.js'; + } + return true; + }, }; +/** + * The version of MathJax that is running. + */ +const VERSION = MJGlobal.version; /** * The implementation of the dynamic loader */ -export namespace Loader { - +export const Loader = { /** - * The version of MathJax that is running. + * The versions of all the loaded extensions. */ - const VERSION = MJGlobal.version; + versions: new Map(), /** - * The versions of all the loaded extensions. + * Array of nested load promises so if component performs additional + * loads (like an output jax with an alternate font), then the + * outer load promises won't resolve until the inner ones are complete. */ - export const versions: Map = new Map(); + nestedLoads: [] as Promise[], /** * Get a promise that is resolved when all the named packages have been loaded. @@ -145,7 +182,7 @@ export namespace Loader { * @param {string[]} names The packages to wait for * @returns {Promise} A promise that resolves when all the named packages are ready */ - export function ready(...names: string[]): Promise { + ready(...names: string[]): Promise { if (names.length === 0) { names = Array.from(Package.packages.keys()); } @@ -155,43 +192,97 @@ export namespace Loader { promises.push(extension.promise); } return Promise.all(promises); - } + }, /** * Load the named packages and return a promise that is resolved when they are all loaded * * @param {string[]} names The packages to load - * @returns {Promise} A promise that resolves when all the named packages are ready + * @returns {Promise} A promise that resolves when all the named packages are ready */ - export function load(...names: string[]): Promise { + load(...names: string[]): Promise { if (names.length === 0) { - return Promise.resolve(); + return Promise.resolve([]); } - const promises = []; - for (const name of names) { - let extension = Package.packages.get(name); - if (!extension) { - extension = new Package(name); - extension.provides(CONFIG.provides[name]); - } - extension.checkNoLoad(); - promises.push(extension.promise.then(() => { - if (!CONFIG.versionWarnings) return; - if (extension.isLoaded && !versions.has(Package.resolvePath(name))) { - console.warn(`No version information available for component ${name}`); + // + // Add a new array to store promises for this load() call + // + let nested = [] as Promise[]; + this.nestedLoads.unshift(nested); + // + // Create a promise for this load() call + // + const promise = Promise.resolve().then(async () => { + // + // Collect the promises for all the named packages, + // creating the package if needed, and add checks + // for the version numbers used in the components. + // + const promises = []; + for (const name of names) { + let extension = Package.packages.get(name); + if (!extension) { + extension = new Package(name); + extension.provides(CONFIG.provides[name]); } - }) as Promise); - } - Package.loadAll(); - return Promise.all(promises); - } + extension.checkNoLoad(); + promises.push( + extension.promise.then(() => { + if ( + CONFIG.versionWarnings && + extension.isLoaded && + !Loader.versions.has(Package.resolvePath(name)) + ) { + console.warn( + `No version information available for component ${name}` + ); + } + return extension.result; + }) as Promise + ); + } + // + // Load everything that was requested and wait for + // them to be loaded. + // + Package.loadAll(); + const result = await Promise.all(promises); + // + // If any other loads occurred while we were waiting, + // Wait for those promises, and clear the list so that + // if even MORE loads occur while waiting for those, + // we can wait for them, too. Keep doing that until + // no additional loads occurred, in which case we are + // now done. + // + while (nested.length) { + const promise = Promise.all(nested); + nested = this.nestedLoads[this.nestedLoads.indexOf(nested)] = []; + await promise; + } + // + // Remove the (empty) list from the nested list, + // and return the result. + // + this.nestedLoads.splice(this.nestedLoads.indexOf(nested), 1); + return result; + }); + // + // Add this load promise to the lists for any parent load() call that are + // pending when this load() was performed, then return the load promise. + // + this.nestedLoads + .slice(1) + .forEach((list: Promise[]) => list.push(promise)); + return promise; + }, /** * Indicate that the named packages are being loaded by hand (e.g., as part of a larger package). * * @param {string[]} names The packages to load */ - export function preLoad(...names: string[]) { + preLoaded(...names: string[]) { for (const name of names) { let extension = Package.packages.get(name); if (!extension) { @@ -200,62 +291,99 @@ export namespace Loader { } extension.loaded(); } - } + }, + + /** + * Insert options into a package configuration + * + * @param {string} name The package whose configuration is being augmented + * @param {PackageConfig} data The extra configuraiton information to add + */ + addPackageData(name: string, data: PackageConfig) { + let config = CONFIG[name]; + if (!config) { + config = CONFIG[name] = {}; + } + for (const [key, value] of Object.entries(data)) { + if (Array.isArray(value)) { + if (!config[key]) { + config[key] = []; + } + const set = new Set([...config[key], ...value]); + config[key] = [...set]; + } else { + config[key] = value; + } + } + }, /** * The default function to perform when all the packages are loaded */ - export function defaultReady() { + defaultReady() { if (typeof MathJax.startup !== 'undefined') { MathJax.config.startup.ready(); } - } + }, /** * Get the root location for where the MathJax package files are found * * @returns {string} The root location (directory for node.js, URL for browser) */ - export function getRoot(): string { - let root = __dirname + '/../../es5'; - if (typeof document !== 'undefined') { - const script = document.currentScript || document.getElementById('MathJax-script'); - if (script) { - root = (script as HTMLScriptElement).src.replace(/\/[^\/]*$/, ''); + getRoot(): string { + if (context.document) { + const script = + context.document.currentScript || + context.document.getElementById('MathJax-script'); + if (script && script instanceof HTMLScriptElement) { + return script.src.replace(/\/[^/]*$/, ''); } } - return root; - } + return mjxRoot(); + }, /** * Check the version of an extension and report an error if not correct * * @param {string} name The name of the extension being checked * @param {string} version The version of the extension to check - * @param {string} type The type of extension (future code may use this to check ranges of versions) - * @return {boolean} True if there was a mismatch, false otherwise + * @param {string} _type The type of extension (future code may use this to check ranges of versions) + * @returns {boolean} True if there was a mismatch, false otherwise */ - export function checkVersion(name: string, version: string, _type?: string): boolean { - versions.set(Package.resolvePath(name), VERSION); + checkVersion(name: string, version: string, _type?: string): boolean { + this.saveVersion(name); if (CONFIG.versionWarnings && version !== VERSION) { - console.warn(`Component ${name} uses ${version} of MathJax; version in use is ${VERSION}`); + console.warn( + `Component ${name} uses ${version} of MathJax; version in use is ${VERSION}` + ); return true; } return false; - } + }, /** - * The filters to use to modify the paths used to obtain the packages + * Set the version of an extension (used for combined components so they can be loaded) + * + * @param {string} name The name of the extension being checked */ - export const pathFilters = new FunctionList(); + saveVersion(name: string) { + Loader.versions.set(Package.resolvePath(name), VERSION); + }, /** - * The default filters to use. + * The filters to use to modify the paths used to obtain the packages */ - pathFilters.add(PathFilters.source, 0); - pathFilters.add(PathFilters.normalize, 10); - pathFilters.add(PathFilters.prefix, 20); -} + pathFilters: new FunctionList(), +}; + +/** + * The default filters to use. + */ +Loader.pathFilters.add(PathFilters.source, 0); +Loader.pathFilters.add(PathFilters.normalize, 10); +Loader.pathFilters.add(PathFilters.prefix, 20); +Loader.pathFilters.add(PathFilters.addExtension, 30); /** * Export the global MathJax object for convenience @@ -268,23 +396,23 @@ export const MathJax = MJGlobal as MathJaxObject; * Add any path filters from the configuration. */ if (typeof MathJax.loader === 'undefined') { - combineDefaults(MathJax.config, 'loader', { paths: { - mathjax: Loader.getRoot() + mathjax: Loader.getRoot(), }, source: {}, dependencies: {}, provides: {}, load: [], ready: Loader.defaultReady.bind(Loader), - failed: (error: PackageError) => console.log(`MathJax(${error.package || '?'}): ${error.message}`), + failed: (error: PackageError) => + console.log(`MathJax(${error.package || '?'}): ${error.message}`), require: null, pathFilters: [], - versionWarnings: true + versionWarnings: true, }); combineWithMathJax({ - loader: Loader + loader: Loader, }); // diff --git a/ts/output/common/fonts/tex/double-struck.ts b/ts/components/mjs/root.ts similarity index 62% rename from ts/output/common/fonts/tex/double-struck.ts rename to ts/components/mjs/root.ts index e24f3be2a..d8e328158 100644 --- a/ts/output/common/fonts/tex/double-struck.ts +++ b/ts/components/mjs/root.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2023-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,7 +15,18 @@ * limitations under the License. */ -import {CharMap, CharOptions} from '../../FontData.js'; +/** + * @file ES6 shim for getting the MathJax root directory + * + * @author dpvc@mathjax.org (Davide Cervone) + */ -export const doubleStruck: CharMap = { -}; +/** + * @returns {string} The MathJax component root directory + */ +export function mjxRoot(): string { + return new URL(import.meta.url).pathname.replace( + /[cm]js\/components\/[cm]js\/root.js$/, + 'bundle' + ); +} diff --git a/ts/output/common/fonts/tex/bold-italic.ts b/ts/components/mjs/sre-root.ts similarity index 62% rename from ts/output/common/fonts/tex/bold-italic.ts rename to ts/components/mjs/sre-root.ts index 4943787d3..99c44f78f 100644 --- a/ts/output/common/fonts/tex/bold-italic.ts +++ b/ts/components/mjs/sre-root.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2023-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,13 +15,18 @@ * limitations under the License. */ -import {CharMap, CharOptions} from '../../FontData.js'; +/** + * @file ES6 shim for getting the MathJax root directory + * + * @author dpvc@mathjax.org (Davide Cervone) + */ -export const boldItalic: CharMap = { - 0x2F: [.711, .21, .894], - 0x131: [.452, .008, .394, {sk: .0319}], - 0x237: [.451, .201, .439, {sk: .0958}], - 0x2044: [.711, .21, .894], - 0x2206: [.711, 0, .958, {sk: .192}], - 0x29F8: [.711, .21, .894], -}; +/** + * @returns {string} The MathJax mjs SRE root directory + */ +export function sreRoot(): string { + return new URL(import.meta.url).pathname.replace( + /components\/[cm]js\/sre-root.js$/, + 'a11y/sre' + ); +} diff --git a/ts/components/package.ts b/ts/components/package.ts index b5f41bb16..f18832cd2 100644 --- a/ts/components/package.ts +++ b/ts/components/package.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,14 @@ */ /** - * @fileoverview Implements component Package object for handling + * @file Implements component Package object for handling * dynamic loading of components. * * @author dpvc@mathjax.org (Davide Cervone) */ -import {CONFIG, Loader} from './loader.js'; - -/* - * The browser document (for creating scripts to load components) - */ -declare var document: Document; +import { CONFIG, Loader } from './loader.js'; +import { context } from '../util/context.js'; /** * A map of package names to Package instances @@ -38,13 +34,11 @@ export type PackageMap = Map; * An error class that includes the package name */ export class PackageError extends Error { - /* tslint:disable:jsdoc-require */ public package: string; constructor(message: string, name: string) { super(message); this.package = name; } - /* tslint:enable */ } /** @@ -52,16 +46,22 @@ export class PackageError extends Error { */ export type PackageReady = (name: string) => string | void; export type PackageFailed = (message: PackageError) => void; -export type PackagePromise = (resolve: PackageReady, reject: PackageFailed) => void; +export type PackagePromise = ( + resolve: PackageReady, + reject: PackageFailed +) => void; /** * The configuration data for a package */ +/* prettier-ignore */ export interface PackageConfig { ready?: PackageReady; // Function to call when package is loaded successfully failed?: PackageFailed; // Function to call when package fails to load checkReady?: () => Promise; // Function called to see if package is fully loaded // (may cause additional packages to load, for example) + extraLoads?: string[]; // Extra packages to load after this one + rendererExtensions?: string[]; // Font extensions to load when renderer changes } /** @@ -88,6 +88,11 @@ export class Package { */ public promise: Promise; + /** + * The result of loading a module via the custom loader + */ + public result: any = {}; + /** * True when the package is being loaded but hasn't yet finished loading */ @@ -96,7 +101,7 @@ export class Package { /** * True if the package has failed to load */ - protected hasFailed: boolean = false; + public hasFailed: boolean = false; /** * True if this package should be loaded automatically (e.g., it was created in reference @@ -135,12 +140,30 @@ export class Package { protected provided: Package[] = []; /** - * @return {boolean} True when the package can be loaded (i.e., its dependencies are all loaded, + * @returns {boolean} True when the package can be loaded (i.e., its dependencies are all loaded, * it is allowed to be loaded, isn't already loading, and hasn't failed to load * in the past) */ get canLoad(): boolean { - return this.dependencyCount === 0 && !this.noLoad && !this.isLoading && !this.hasFailed; + return ( + this.dependencyCount === 0 && + !this.noLoad && + !this.isLoading && + !this.hasFailed + ); + } + + /** + * @param {string} name The package configuration to be loaded + * @returns {Promise} A promise for when extra files and checkReady have been fulfilled + */ + public static loadPromise(name: string): Promise { + const config = (CONFIG[name] || {}) as PackageConfig; + const promise = config.extraLoads + ? Loader.load(...config.extraLoads) + : Promise.resolve(); + const checkReady = config.checkReady || (() => Promise.resolve()); + return promise.then(() => checkReady()) as Promise; } /** @@ -148,10 +171,13 @@ export class Package { * * @param {string} name The name of the package to resolve * @param {boolean} addExtension True if .js should be added automatically - * @return {string} The path (file or URL) for this package + * @returns {string} The path (file or URL) for this package */ - public static resolvePath(name: string, addExtension: boolean = true): string { - const data = {name, original: name, addExtension}; + public static resolvePath( + name: string, + addExtension: boolean = true + ): string { + const data = { name, original: name, addExtension }; Loader.pathFilters.execute(data); return data.name; } @@ -182,7 +208,7 @@ export class Package { } /** - * @return {Promise[]} The array of promises that must be resolved before this package + * @returns {Promise[]} The array of promises that must be resolved before this package * can be loaded */ protected makeDependencies(): Promise[] { @@ -194,10 +220,10 @@ export class Package { // Get the dependencies for this package // const dependencies = [] as string[]; - if (CONFIG.dependencies.hasOwnProperty(name)) { + if (Object.hasOwn(CONFIG.dependencies, name)) { dependencies.push(...CONFIG.dependencies[name]); } else if (name !== 'core') { - dependencies.push('core'); // Add 'core' dependency by default + dependencies.push('core'); // Add 'core' dependency by default } // // Add all the dependencies (creating them, if needed) @@ -205,7 +231,7 @@ export class Package { // for (const dependent of dependencies) { const extension = map.get(dependent) || new Package(dependent, noLoad); - if (this.dependencies.indexOf(extension) < 0) { + if (!this.dependencies.includes(extension)) { extension.addDependent(this, noLoad); this.dependencies.push(extension); if (!extension.isLoaded) { @@ -223,8 +249,9 @@ export class Package { /** * @param {Promise[]} promises The array or promises that must be resolved before * this package can load + * @returns {Promise} The promise indicating when this file is loaded */ - protected makePromise(promises: Promise[]) { + protected makePromise(promises: Promise[]): Promise { // // Make a promise and save its resolve/reject functions // @@ -238,7 +265,9 @@ export class Package { // const config = (CONFIG[this.name] || {}) as PackageConfig; if (config.ready) { - promise = promise.then((_name: string) => config.ready(this.name)) as Promise; + promise = promise.then((_name: string) => + config.ready(this.name) + ) as Promise; } // // If there are promises for dependencies, @@ -247,14 +276,18 @@ export class Package { // if (promises.length) { promises.push(promise); - promise = Promise.all(promises).then((names: string[]) => names.join(', ')); + promise = Promise.all(promises).then((names: string[]) => + names.join(', ') + ); } // // If there is a failed() function in the configuration for this package, // Add a catch to handle the error // if (config.failed) { - promise.catch((message: string) => config.failed(new PackageError(message, this.name))); + promise.catch((message: string) => + config.failed(new PackageError(message, this.name)) + ); } // // Return the promise that represents when this file is loaded @@ -279,14 +312,21 @@ export class Package { /** * Load using a custom require method (usually the one from node.js) + * + * @param {string} url The URL to load from */ protected loadCustom(url: string) { try { const result = CONFIG.require(url); if (result instanceof Promise) { - result.then(() => this.checkLoad()) - .catch((err) => this.failed('Can\'t load "' + url + '"\n' + err.message.trim())); + result + .then((result) => (this.result = result)) + .then(() => this.checkLoad()) + .catch((err) => + this.failed('Can\'t load "' + url + '"\n' + err.message.trim()) + ); } else { + this.result = result; this.checkLoad(); } } catch (err) { @@ -296,15 +336,17 @@ export class Package { /** * Load in a browser by inserting a script to load the proper URL + * + * @param {string} url The URL to load from */ protected loadScript(url: string) { - const script = document.createElement('script'); + const script = context.document.createElement('script'); script.src = url; script.charset = 'UTF-8'; script.onload = (_event) => this.checkLoad(); script.onerror = (_event) => this.failed('Can\'t load "' + url + '"'); // FIXME: Should there be a timeout failure as well? - document.head.appendChild(script); + context.document.head.appendChild(script); } /** @@ -344,17 +386,17 @@ export class Package { /** * Check if a package is really ready to be marked as loaded * (When it is loaded, it may set its own checkReady() function - * as a means of loading additional packages. E.g., an output - * jax may load a font package, dependent on its configuration.) + * or extraLoads array as a means of loading additional packages. + * E.g., an output jax may load a font package, dependent on its + * configuration.) * * The configuration's checkReady() function returns a promise * that allows the loader to wait for addition actions to finish * before marking the file as loaded (or failing to load). */ protected checkLoad() { - const config = (CONFIG[this.name] || {}) as PackageConfig; - const checkReady = config.checkReady || (() => Promise.resolve()); - checkReady().then(() => this.loaded()) + Package.loadPromise(this.name) + .then(() => this.loaded()) .catch((message) => this.failed(message)); } @@ -422,5 +464,4 @@ export class Package { } } } - } diff --git a/ts/components/startup.ts b/ts/components/startup.ts index 44149ada6..777bd5c70 100644 --- a/ts/components/startup.ts +++ b/ts/components/startup.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ */ /** - * @fileoverview Implements a startup module that allows dynamically + * @file Implements a startup module that allows dynamically * loaded components to register themselves, and then * creates MathJax methods for typesetting and converting * math based on the registered components. @@ -24,25 +24,32 @@ * @author dpvc@mathjax.org (Davide Cervone) */ -import {MathJax as MJGlobal, MathJaxObject as MJObject, - MathJaxConfig as MJConfig, combineWithMathJax, combineDefaults} from './global.js'; - -import {MathDocument} from '../core/MathDocument.js'; -import {MmlNode} from '../core/MmlTree/MmlNode.js'; -import {Handler} from '../core/Handler.js'; -import {InputJax} from '../core/InputJax.js'; -import {OutputJax} from '../core/OutputJax.js'; -import {CommonOutputJax} from '../output/common/OutputJax.js'; -import {DOMAdaptor} from '../core/DOMAdaptor.js'; -import {PrioritizedList} from '../util/PrioritizedList.js'; -import {OptionList, OPTIONS} from '../util/Options.js'; - -import {TeX} from '../input/tex.js'; - +import { + MathJax as MJGlobal, + MathJaxObject as MJObject, + MathJaxConfig as MJConfig, + combineWithMathJax, + combineDefaults, + GLOBAL as global, +} from './global.js'; + +import { MathDocument } from '../core/MathDocument.js'; +import { MmlNode } from '../core/MmlTree/MmlNode.js'; +import { Handler } from '../core/Handler.js'; +import { InputJax } from '../core/InputJax.js'; +import { OutputJax } from '../core/OutputJax.js'; +import { CommonOutputJax } from '../output/common.js'; +import { DOMAdaptor } from '../core/DOMAdaptor.js'; +import { PrioritizedList } from '../util/PrioritizedList.js'; +import { OptionList, OPTIONS } from '../util/Options.js'; +import { context } from '../util/context.js'; + +import { TeX } from '../input/tex.js'; /** * Update the configuration structure to include the startup configuration */ +/* prettier-ignore */ export interface MathJaxConfig extends MJConfig { startup?: { input?: string[]; // The names of the input jax to use @@ -56,6 +63,7 @@ export interface MathJaxConfig extends MJConfig { pageReady?: () => void; // Function to perform when page is ready invalidOption?: 'fatal' | 'warn'; // Do invalid options produce a warning, or throw an error? optionError?: (message: string, key: string) => void, // Function to report invalid options + loadAllFontFiles: false; // true means force all dynamic font files to load initially [name: string]: any; // Other configuration blocks }; } @@ -63,14 +71,23 @@ export interface MathJaxConfig extends MJConfig { /** * Generic types for the standard MathJax objects */ -export type MATHDOCUMENT = MathDocument; +export type MATHDOCUMENT = MathDocument & { + menu?: { loadingPromise: Promise }; +}; export type HANDLER = Handler; export type DOMADAPTOR = DOMAdaptor; export type INPUTJAX = InputJax; export type OUTPUTJAX = OutputJax; -export type COMMONJAX = CommonOutputJax; +/* prettier-ignore */ +export type COMMONJAX = + CommonOutputJax; export type TEX = TeX; +/** + * Array of InputJax also with keys using name of jax + */ +export type JAXARRAY = INPUTJAX[] & { [name: string]: INPUTJAX }; + /** * A function to extend a handler class */ @@ -82,15 +99,14 @@ export type HandlerExtension = (handler: HANDLER) => HANDLER; export interface MathJaxObject extends MJObject { config: MathJaxConfig; startup: { - constructors: {[name: string]: any}; - input: INPUTJAX[]; + constructors: { [name: string]: any }; + input: JAXARRAY; output: OUTPUTJAX; handler: HANDLER; adaptor: DOMADAPTOR; elements: any[]; document: MATHDOCUMENT; - promise: Promise; - /* tslint:disable:jsdoc-require */ + promise: Promise; registerConstructor(name: string, constructor: any): void; useHandler(name: string, force?: boolean): void; useAdaptor(name: string, force?: boolean): void; @@ -100,103 +116,102 @@ export interface MathJaxObject extends MJObject { toMML(node: MmlNode): string; defaultReady(): void; defaultPageReady(): Promise; + defaultOptionError(message: string, key: string): void; getComponents(): void; makeMethods(): void; makeTypesetMethods(): void; makeOutputMethods(iname: string, oname: string, input: INPUTJAX): void; makeMmlMethods(name: string, input: INPUTJAX): void; makeResetMethod(name: string, input: INPUTJAX): void; - getInputJax(): INPUTJAX[]; + getInputJax(): JAXARRAY; getOutputJax(): OUTPUTJAX; getAdaptor(): DOMADAPTOR; getHandler(): HANDLER; - /* tslint:enable */ }; - [name: string]: any; // Needed for the methods created by the startup module + [name: string]: any; // Needed for the methods created by the startup module } -/* - * Access to the browser document - */ -declare var global: {document: Document}; - /** * The implementation of the startup module */ -export namespace Startup { - +export abstract class Startup { /** * The array of handler extensions */ - const extensions = new PrioritizedList(); + static extensions = new PrioritizedList(); - let visitor: any; // the visitor for toMML(); - let mathjax: any; // the mathjax variable from mathjax.js + static visitor: any; // the visitor for toMML(); + static mathjax: any; // the mathjax variable from mathjax.js /** * The constructors (or other data) registered by the loaded packages */ - export const constructors: {[name: string]: any} = {}; + public static constructors: { [name: string]: any } = {}; /** * The array of InputJax instances (created after everything is loaded) */ - export let input: INPUTJAX[] = []; + public static input: JAXARRAY = [] as JAXARRAY; /** * The OutputJax instance (created after everything is loaded) */ - export let output: OUTPUTJAX = null; + public static output: OUTPUTJAX = null; /** * The Handler instance (created after everything is loaded) */ - export let handler: HANDLER = null; + public static handler: HANDLER = null; /** * The DOMAdaptor instance (created after everything is loaded) */ - export let adaptor: DOMADAPTOR = null; + public static adaptor: DOMADAPTOR = null; /** * The elements to process (set when typeset or conversion method is called) */ - export let elements: any[] = null; + public static elements: any[] = null; /** * The MathDocument instance being used (based on the browser DOM or configuration value) */ - export let document: MATHDOCUMENT = null; + public static document: MATHDOCUMENT = null; /** * The function that resolves the first promise defined below * (called in the defaultReady() function when MathJax is finished with * its initial typesetting) */ - export let promiseResolve: () => void; + public static promiseResolve: (value?: any) => any; /** * The function that rejects the first promise defined below * (called in the defaultReady() function when MathJax's initial * typesetting fails) */ - export let promiseReject: (reason: any) => void; + public static promiseReject: (reason: any) => void; /** * The promise for the startup process (the initial typesetting). - * It is resolves or rejected in the ready() function. + * It is resolved or rejected in the ready() function. */ - export let promise = new Promise((resolve, reject) => { - promiseResolve = resolve; - promiseReject = reject; + public static promise = new Promise((resolve, reject) => { + Startup.promiseResolve = resolve; + Startup.promiseReject = reject; }); /** * A promise that is resolved when the page contents are available * for processing. */ - export let pagePromise = new Promise((resolve, _reject) => { + public static pagePromise = new Promise((resolve, _reject) => { const doc = global.document; - if (!doc || !doc.readyState || doc.readyState === 'complete' || doc.readyState === 'interactive') { + if ( + !doc || + !doc.readyState || + doc.readyState === 'complete' || + doc.readyState === 'interactive' + ) { resolve(); } else { const listener = () => resolve(); @@ -205,27 +220,34 @@ export namespace Startup { } }); + /** + * This is true when MathJax.typeset() or MathJax.typesetPromise() have been called + * (used by the menu code to tell if a rerender action is needed when a component is + * loaded dynamically). + */ + public static hasTypeset: boolean = false; + /** * @param {MmlNode} node The root of the tree to convert to serialized MathML - * @return {string} The serialized MathML from the tree + * @returns {string} The serialized MathML from the tree */ - export function toMML(node: MmlNode): string { - return visitor.visitTree(node, document); + public static toMML(node: MmlNode): string { + return Startup.visitor.visitTree(node, this.document); } /** * @param {string} name The identifier for the constructor * @param {any} constructor The constructor function for the named object */ - export function registerConstructor(name: string, constructor: any) { - constructors[name] = constructor; + public static registerConstructor(name: string, constructor: any) { + Startup.constructors[name] = constructor; } /** * @param {string} name The identifier for the Handler to use * @param {boolean} force True to force the Handler to be used even if one is already registered */ - export function useHandler(name: string, force: boolean = false) { + public static useHandler(name: string, force: boolean = false) { if (!CONFIG.handler || force) { CONFIG.handler = name; } @@ -235,7 +257,7 @@ export namespace Startup { * @param {string} name The identifier for the DOMAdaptor to use * @param {boolean} force True to force the DOMAdaptor to be used even if one is already registered */ - export function useAdaptor(name: string, force: boolean = false) { + public static useAdaptor(name: string, force: boolean = false) { if (!CONFIG.adaptor || force) { CONFIG.adaptor = name; } @@ -246,7 +268,7 @@ export namespace Startup { * @param {boolean} force True to force the InputJax to be used even if the configuration already * included an array of input jax */ - export function useInput(name: string, force: boolean = false) { + public static useInput(name: string, force: boolean = false) { if (!inputSpecified || force) { CONFIG.input.push(name); } @@ -256,7 +278,7 @@ export namespace Startup { * @param {string} name The identifier for the OutputJax to use * @param {boolean} force True to force the OutputJax to be used even if one is already registered */ - export function useOutput(name: string, force: boolean = false) { + public static useOutput(name: string, force: boolean = false) { if (!CONFIG.output || force) { CONFIG.output = name; } @@ -266,8 +288,8 @@ export namespace Startup { * @param {HandlerExtension} extend A function to extend the handler class * @param {number} priority The priority of the extension */ - export function extendHandler(extend: HandlerExtension, priority: number = 10) { - extensions.add(extend, priority); + public static extendHandler(extend: HandlerExtension, priority: number = 10) { + Startup.extensions.add(extend, priority); } /** @@ -281,43 +303,76 @@ export namespace Startup { * individual methods below to perform portions of the default * startup actions. */ - export function defaultReady() { - getComponents(); - makeMethods(); - pagePromise - .then(() => CONFIG.pageReady()) // usually the initial typesetting call - .then(() => promiseResolve()) - .catch((err) => promiseReject(err)); + public static defaultReady() { + Startup.getComponents(); + Startup.makeMethods(); + Startup.pagePromise + .then(() => CONFIG.pageReady()) // usually the initial typesetting call + .then(() => Startup.promiseResolve()) + .catch((err) => Startup.promiseReject(err)); } /** * The default pageReady() function called when the page is ready to be processed, - * which returns the function that performs the initial typesetting, if needed. + * which returns a promise that does any initial font loading, plus the initial + * typesetting, if needed. * * Setting Mathjax.startup.pageReady in the configuration will override this. + * + * @returns {Promise} Promise resolving when page is ready to process. + */ + public static defaultPageReady(): Promise { + return ( + CONFIG.loadAllFontFiles && (Startup.output as COMMONJAX).font + ? (Startup.output as COMMONJAX).font.loadDynamicFiles() + : Promise.resolve() + ) + .then(() => Startup.document.menu?.loadingPromise) + .then( + CONFIG.typeset && MathJax.typesetPromise + ? () => Startup.typesetPromise(CONFIG.elements) + : Promise.resolve() + ) + .then(() => Startup.promiseResolve()); + } + + /** + * The default OptionError function */ - export function defaultPageReady() { - return (CONFIG.typeset && MathJax.typesetPromise ? - MathJax.typesetPromise(CONFIG.elements) as Promise : - Promise.resolve()); + public static defaultOptionError = OPTIONS.optionError; + + /** + * Perform the typesetting with handling of retries + * + * @param {any[]} elements The list of elements to typeset + * @returns {Promise} The promise that resolves when elements are typeset + */ + public static typesetPromise(elements: any[]): Promise { + this.hasTypeset = true; + return Startup.document.whenReady(async () => { + Startup.document.options.elements = elements; + Startup.document.reset(); + await Startup.document.renderPromise(); + }); } /** * Create the instances of the registered components */ - export function getComponents() { - visitor = new MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor(); - mathjax = MathJax._.mathjax.mathjax; - input = getInputJax(); - output = getOutputJax(); - adaptor = getAdaptor(); - if (handler) { - mathjax.handlers.unregister(handler); + public static getComponents() { + Startup.visitor = + new MathJax._.core.MmlTree.SerializedMmlVisitor.SerializedMmlVisitor(); + Startup.mathjax = MathJax._.mathjax.mathjax; + Startup.input = Startup.getInputJax(); + Startup.output = Startup.getOutputJax(); + Startup.adaptor = Startup.getAdaptor(); + if (Startup.handler) { + Startup.mathjax.handlers.unregister(Startup.handler); } - handler = getHandler(); - if (handler) { - mathjax.handlers.register(handler); - document = getDocument(); + Startup.handler = Startup.getHandler(); + if (Startup.handler) { + Startup.mathjax.handlers.register(Startup.handler); + Startup.document = Startup.getDocument(); } } @@ -331,20 +386,25 @@ export namespace Startup { * Make input2mml() and input2mmlPromise() conversion methods and inputReset() method * If there is a registered output jax * Make input2output() and input2outputPromise conversion methods and outputStylesheet() method + * Create the MathJax.done() method. + * Create the MathJax.whenReady() method. */ - export function makeMethods() { - if (input && output) { - makeTypesetMethods(); + public static makeMethods() { + if (Startup.input && Startup.output) { + Startup.makeTypesetMethods(); } - const oname = (output ? output.name.toLowerCase() : ''); - for (const jax of input) { + const oname = Startup.output ? Startup.output.name.toLowerCase() : ''; + for (const jax of Startup.input) { const iname = jax.name.toLowerCase(); - makeMmlMethods(iname, jax); - makeResetMethod(iname, jax); - if (output) { - makeOutputMethods(iname, oname, jax); + Startup.makeMmlMethods(iname, jax); + Startup.makeResetMethod(iname, jax); + if (Startup.output) { + Startup.makeOutputMethods(iname, oname, jax); } } + MathJax.done = () => Startup.document.done(); + MathJax.whenReady = (action: () => any) => + Startup.document.whenReady(action); } /** @@ -355,24 +415,21 @@ export namespace Startup { * * TypeseClear() clears all the MathItems from the document. */ - export function makeTypesetMethods() { + public static makeTypesetMethods() { MathJax.typeset = (elements: any[] = null) => { - document.options.elements = elements; - document.reset(); - document.render(); + this.hasTypeset = true; + Startup.document.options.elements = elements; + Startup.document.reset(); + Startup.document.render(); }; MathJax.typesetPromise = (elements: any[] = null) => { - document.options.elements = elements; - document.reset(); - return mathjax.handleRetriesFor(() => { - document.render(); - }); + return Startup.typesetPromise(elements); }; MathJax.typesetClear = (elements: any[] = null) => { if (elements) { - document.clearMathItemsWithin(elements); + Startup.document.clearMathItemsWithin(elements); } else { - document.clear(); + Startup.document.clear(); } }; } @@ -396,22 +453,25 @@ export namespace Startup { * @param {string} oname The name of the output jax * @param {INPUTJAX} input The input jax instance */ - export function makeOutputMethods(iname: string, oname: string, input: INPUTJAX) { + public static makeOutputMethods( + iname: string, + oname: string, + input: INPUTJAX + ) { const name = iname + '2' + oname; - MathJax[name] = - (math: string, options: OptionList = {}) => { - options.format = input.name; - return document.convert(math, options); - }; - MathJax[name + 'Promise'] = - (math: string, options: OptionList = {}) => { - options.format = input.name; - return mathjax.handleRetriesFor(() => document.convert(math, options)); - }; - MathJax[oname + 'Stylesheet'] = () => output.styleSheet(document); - if ('getMetricsFor' in output) { + MathJax[name] = (math: string, options: OptionList = {}) => { + options = { ...options, format: input.name }; + return Startup.document.convert(math, options); + }; + MathJax[name + 'Promise'] = (math: string, options: OptionList = {}) => { + options = { ...options, format: input.name }; + return Startup.document.convertPromise(math, options); + }; + MathJax[oname + 'Stylesheet'] = () => + Startup.output.styleSheet(Startup.document); + if ('getMetricsFor' in Startup.output) { MathJax.getMetricsFor = (node: any, display: boolean) => { - return (output as COMMONJAX).getMetricsFor(node, display); + return (Startup.output as COMMONJAX).getMetricsFor(node, display); }; } } @@ -427,20 +487,20 @@ export namespace Startup { * @param {string} name The name of the input jax * @param {INPUTJAX} input The input jax itself */ - export function makeMmlMethods(name: string, input: INPUTJAX) { + public static makeMmlMethods(name: string, input: INPUTJAX) { const STATE = MathJax._.core.MathItem.STATE; - MathJax[name + '2mml'] = - (math: string, options: OptionList = {}) => { - options.end = STATE.CONVERT; - options.format = input.name; - return toMML(document.convert(math, options)); - }; - MathJax[name + '2mmlPromise'] = - (math: string, options: OptionList = {}) => { - options.end = STATE.CONVERT; - options.format = input.name; - return mathjax.handleRetriesFor(() => toMML(document.convert(math, options))); - }; + MathJax[name + '2mml'] = (math: string, options: OptionList = {}) => { + options = { ...options, end: STATE.CONVERT, format: input.name }; + return Startup.toMML(Startup.document.convert(math, options)); + }; + MathJax[name + '2mmlPromise'] = async ( + math: string, + options: OptionList = {} + ) => { + options = { ...options, end: STATE.CONVERT, format: input.name }; + const node = await Startup.document.convertPromise(math, options); + return Startup.toMML(node); + }; } /** @@ -451,65 +511,74 @@ export namespace Startup { * @param {string} name The name of the input jax * @param {INPUTJAX} input The input jax itself */ - export function makeResetMethod(name: string, input: INPUTJAX) { + public static makeResetMethod(name: string, input: INPUTJAX) { MathJax[name + 'Reset'] = (...args: any[]) => input.reset(...args); } /** - * @return {INPUTJAX[]} The array of instances of the registered input jax + * @returns {JAXARRAY} The array of instances of the registered input jax */ - export function getInputJax(): INPUTJAX[] { - const jax = [] as INPUTJAX[]; + public static getInputJax(): JAXARRAY { + const jax = [] as JAXARRAY; for (const name of CONFIG.input) { - const inputClass = constructors[name]; + const inputClass = Startup.constructors[name]; if (inputClass) { - jax.push(new inputClass(MathJax.config[name])); + jax[name] = new inputClass(MathJax.config[name]); + jax.push(jax[name]); } else { - throw Error('Input Jax "' + name + '" is not defined (has it been loaded?)'); + throw Error( + 'Input Jax "' + name + '" is not defined (has it been loaded?)' + ); } } return jax; } /** - * @return {OUTPUTJAX} The instance of the registered output jax + * @returns {OUTPUTJAX} The instance of the registered output jax */ - export function getOutputJax(): OUTPUTJAX { + public static getOutputJax(): OUTPUTJAX { const name = CONFIG.output; if (!name) return null; - const outputClass = constructors[name]; + const outputClass = Startup.constructors[name]; if (!outputClass) { - throw Error('Output Jax "' + name + '" is not defined (has it been loaded?)'); + throw Error( + 'Output Jax "' + name + '" is not defined (has it been loaded?)' + ); } return new outputClass(MathJax.config[name]); } /** - * @return {DOMADAPTOR} The instance of the registered DOMAdator (the registered constructor + * @returns {DOMADAPTOR} The instance of the registered DOMAdator (the registered constructor * in this case is a function that creates the adaptor, not a class) */ - export function getAdaptor(): DOMADAPTOR { + public static getAdaptor(): DOMADAPTOR { const name = CONFIG.adaptor; if (!name || name === 'none') return null; - const adaptor = constructors[name]; + const adaptor = Startup.constructors[name]; if (!adaptor) { - throw Error('DOMAdaptor "' + name + '" is not defined (has it been loaded?)'); + throw Error( + 'DOMAdaptor "' + name + '" is not defined (has it been loaded?)' + ); } return adaptor(MathJax.config[name]); } /** - * @return {HANDLER} The instance of the registered Handler, extended by the registered extensions + * @returns {HANDLER} The instance of the registered Handler, extended by the registered extensions */ - export function getHandler(): HANDLER { + public static getHandler(): HANDLER { const name = CONFIG.handler; - if (!name || name === 'none' || !adaptor) return null; - const handlerClass = constructors[name]; + if (!name || name === 'none' || !Startup.adaptor) return null; + const handlerClass = Startup.constructors[name]; if (!handlerClass) { - throw Error('Handler "' + name + '" is not defined (has it been loaded?)'); + throw Error( + 'Handler "' + name + '" is not defined (has it been loaded?)' + ); } - let handler = new handlerClass(adaptor, 5); - for (const extend of extensions) { + let handler = new handlerClass(Startup.adaptor, 5); + for (const extend of Startup.extensions) { handler = extend.item(handler); } return handler; @@ -521,11 +590,11 @@ export namespace Startup { * @param {any=} root The Document to use as the root document (or null to use the configured document) * @returns {MathDocument} The MathDocument with the configured input and output jax */ - export function getDocument(root: any = null): MathDocument { - return mathjax.document(root || CONFIG.document, { - ...MathJax.config.options, - InputJax: input, - OutputJax: output + public static getDocument(root: any = null): MathDocument { + return Startup.mathjax.document(root || CONFIG.document, { + ...MathJax.config.options, + InputJax: Startup.input, + OutputJax: Startup.output, }); } } @@ -541,21 +610,20 @@ export const MathJax = MJGlobal as MathJaxObject; * set the method for handling invalid options, if provided. */ if (typeof MathJax._.startup === 'undefined') { - combineDefaults(MathJax.config, 'startup', { input: [], output: '', handler: null, adaptor: null, - document: (typeof document === 'undefined' ? '' : document), + document: context.document || '', elements: null, typeset: true, ready: Startup.defaultReady.bind(Startup), - pageReady: Startup.defaultPageReady.bind(Startup) + pageReady: Startup.defaultPageReady.bind(Startup), }); combineWithMathJax({ startup: Startup, - options: {} + options: {}, }); if (MathJax.config.startup.invalidOption) { @@ -564,7 +632,6 @@ if (typeof MathJax._.startup === 'undefined') { if (MathJax.config.startup.optionError) { OPTIONS.optionError = MathJax.config.startup.optionError; } - } /** @@ -572,7 +639,6 @@ if (typeof MathJax._.startup === 'undefined') { */ export const CONFIG = MathJax.config.startup; - /* * Tells if the user configuration included input jax or not */ diff --git a/ts/components/version.ts b/ts/components/version.ts index b32757d34..30ad036c5 100644 --- a/ts/components/version.ts +++ b/ts/components/version.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2022 The MathJax Consortium + * Copyright (c) 2023 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,10 +16,10 @@ */ /** - * @fileoverview The version of MathJax (used to tell what version a component - * was compiled against). + * @file The version of MathJax (used to tell what version a component + * was compiled against). * * @author dpvc@mathjax.org (Davide Cervone) */ -export const VERSION = '3.2.2'; +export const VERSION = '4.0.0'; diff --git a/ts/core/DOMAdaptor.ts b/ts/core/DOMAdaptor.ts index 511c4d7ee..16889ddcb 100644 --- a/ts/core/DOMAdaptor.ts +++ b/ts/core/DOMAdaptor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,31 +16,39 @@ */ /** - * @fileoverview The DOMAdaptor interface and abstract class + * @file The DOMAdaptor interface and abstract class * * @author dpvc@mathjax.org (Davide Cervone) */ -import {OptionList} from '../util/Options.js'; +import { OptionList } from '../util/Options.js'; /** * The data for an attribute */ export type AttributeData = { - name: string, - value: string + name: string; + value: string; }; /** * The data for an elements page-based bounding box */ export type PageBBox = { - left: number, - right: number, - top: number, - bottom: number + left: number; + right: number; + top: number; + bottom: number; }; +/** + * A minimal webworker interface + */ +export interface minWorker { + addEventListener(kind: string, listener: (event: Event) => void): void; + postMessage(msg: any): void; + terminate(): Promise | void; +} /*****************************************************************/ /** @@ -56,10 +64,15 @@ export interface DOMAdaptor { */ document: D; + /** + * True when the adaptor can measure DOM node sizes + */ + canMeasureNodes: boolean; + /** * @param {string} text The serialized document to be parsed * @param {string} format The format (e.g., 'text/html' or 'text/xhtml') - * @return {D} The parsed document + * @returns {D} The parsed document */ parse(text: string, format?: string): D; @@ -68,45 +81,45 @@ export interface DOMAdaptor { * @param {OptionList} def The properties to set for the created node * @param {(N|T)[]} children The child nodes for the created HTML node * @param {string} ns The namespace in which to create the node - * @return {N} The generated HTML tree + * @returns {N} The generated HTML tree */ node(kind: string, def?: OptionList, children?: (N | T)[], ns?: string): N; /** * @param {string} text The text from which to create an HTML text node - * @return {T} The generated text node with the given text + * @returns {T} The generated text node with the given text */ text(text: string): T; /** * @param {D} doc The document whose head is to be obtained - * @return {N} The document.head element + * @returns {N} The document.head element */ - head(doc: D): N; + head(doc?: D): N; /** * @param {D} doc The document whose body is to be obtained - * @return {N} The document.body element + * @returns {N} The document.body element */ - body(doc: D): N; + body(doc?: D): N; /** * @param {D} doc The document whose documentElement is to be obtained - * @return {N} The documentElement + * @returns {N} The documentElement */ - root(doc: D): N; + root(doc?: D): N; /** * @param {D} doc The document whose doctype is to be obtained - * @return {string} The DOCTYPE comment + * @returns {string} The DOCTYPE comment */ - doctype(doc: D): string; + doctype(doc?: D): string; /** * @param {N} node The node to search for tags * @param {string} name The name of the tag to search for * @param {string} ns The namespace to search in (or null for no namespace) - * @return {N[]} The list of tags found + * @returns {N[]} The list of tags found */ tags(node: N, name: string, ns?: string): N[]; @@ -116,29 +129,38 @@ export interface DOMAdaptor { * * @param {(string | N | N[])[]} nodes The array of items to make into a container list * @param {D} document The document in which to search - * @return {N[]} The array of containers to search + * @returns {N[]} The array of containers to search */ getElements(nodes: (string | N | N[])[], document: D): N[]; + /** + * Get an element specified by CSS selector. + * + * @param {string} selector The selector to locate + * @param {D | N} node The document or element in which to search + * @returns {N | null} The first matching element + */ + getElement(selector: string, node?: D | N): N | null; + /** * Determine if a container node contains a given node somewhere in its DOM tree * * @param {N} container The container to search * @param {N|T} node The node to look for - * @return {boolean} True if the node is in the container's DOM tree + * @returns {boolean} True if the node is in the container's DOM tree */ contains(container: N, node: N | T): boolean; /** * @param {N|T} node The HTML node whose parent is to be obtained - * @return {N} The parent node of the given one + * @returns {N} The parent node of the given one */ parent(node: N | T): N; /** * @param {N} node The HTML node to be appended to * @param {N|T} child The node or text to be appended - * @return {N|T} The appended node + * @returns {N|T} The appended node */ append(node: N, child: N | T): N | T; @@ -150,22 +172,23 @@ export interface DOMAdaptor { /** * @param {N|T} child The node or text to be removed from its parent - * @return {N|T} The removed node + * @returns {N|T} The removed node */ remove(child: N | T): N | T; /** * @param {N|T} nnode The node to replace with * @param {N|T} onode The child to be replaced - * @return {N|T} The removed node + * @returns {N|T} The removed node */ replace(nnode: N | T, onode: N | T): N | T; /** - * @param {N} node The HTML node to be cloned - * @return {N} The copied node + * @param {N} node The HTML node to be cloned + * @param {boolean} deep True if children should be cloned + * @returns {N} The copied node */ - clone(node: N): N; + clone(node: N, deep?: boolean): N; /** * @param {T} node The HTML text node to be split @@ -175,84 +198,103 @@ export interface DOMAdaptor { /** * @param {N|T} node The HTML node whose sibling is to be obtained - * @return {N|T} The node following the given one (or null) + * @returns {N|T} The node following the given one (or null) */ next(node: N | T): N | T; /** * @param {N|T} node The HTML node whose sibling is to be obtained - * @return {N|T} The node preceding the given one (or null) + * @returns {N|T} The node preceding the given one (or null) */ previous(node: N | T): N | T; /** * @param {N} node The HTML node whose child is to be obtained - * @return {N|T} The first child of the given node (or null) + * @returns {N|T} The first child of the given node (or null) */ firstChild(node: N): N | T; /** * @param {N} node The HTML node whose child is to be obtained - * @return {N} The last child of the given node (or null) + * @returns {N} The last child of the given node (or null) */ lastChild(node: N): N | T; /** * @param {N} node The HTML node whose children are to be obtained - * @return {(N|T)[]} Array of children for the given node (not a live list) + * @returns {(N|T)[]} Array of children for the given node (not a live list) */ childNodes(node: N): (N | T)[]; /** * @param {N} node The HTML node whose child is to be obtained * @param {number} i The index of the child to return - * @return {N|T} The i-th child node of the given node (or null) + * @returns {N|T} The i-th child node of the given node (or null) */ childNode(node: N, i: number): N | T; /** * @param {N | T} node The HTML node whose tag or node name is to be obtained - * @return {string} The tag or node name of the given node + * @returns {string} The tag or node name of the given node */ kind(node: N | T): string; /** * @param {N|T} node The HTML node whose value is to be obtained - * @return {string} The value of the given node + * @returns {string} The value of the given node */ value(node: N | T): string; /** * @param {N} node The HTML node whose text content is to be obtained - * @return {string} The text content of the given node + * @returns {string} The text content of the given node */ textContent(node: N): string; /** * @param {N} node The HTML node whose inner HTML string is to be obtained - * @return {string} The serialized content of the node + * @returns {string} The serialized content of the node */ innerHTML(node: N): string; /** * @param {N} node The HTML node whose outer HTML string is to be obtained - * @return {string} The serialized node and its content + * @returns {string} The serialized node and its content */ outerHTML(node: N): string; /** * @param {N} node The HTML node whose serialized string is to be obtained - * @return {string} The serialized node and its content + * @returns {string} The serialized node and its content */ serializeXML(node: N): string; + /** + * @param {N} node The HTML node whose property is to be set + * @param {string} name The property to set + * @param {any} value The property's new value + */ + setProperty(node: N, name: string, value: any): void; + + /** + * @param {N} node The HTML node whose property is to be retrieved + * @param {string} name The property to get + * @returns {any} The property's value + */ + getProperty(node: N, name: string): any; + /** * @param {N} node The HTML node whose attribute is to be set * @param {string|number} name The name of the attribute to set * @param {string} value The new value of the attribute * @param {string=} ns The namespace to use for the attribute */ - setAttribute(node: N, name: string, value: string | number, ns?: string): void; + setAttribute( + node: N, + name: string, + value: string | number, + ns?: string + ): void; /** * @param {N} node The HTML element whose attributes are to be set @@ -263,7 +305,7 @@ export interface DOMAdaptor { /** * @param {N} node The HTML node whose attribute is to be obtained * @param {string} name The name of the attribute to get - * @return {string} The value of the given attribute of the given node + * @returns {string} The value of the given attribute of the given node */ getAttribute(node: N, name: string): string; @@ -276,13 +318,13 @@ export interface DOMAdaptor { /** * @param {N} node The HTML node whose attribute is to be tested * @param {string} name The name of the attribute to test - * @return {boolean} True of the node has the given attribute defined + * @returns {boolean} True of the node has the given attribute defined */ hasAttribute(node: N, name: string): boolean; /** * @param {N} node The HTML node whose attributes are to be returned - * @return {AttributeData[]} The list of attributes + * @returns {AttributeData[]} The list of attributes */ allAttributes(node: N): AttributeData[]; @@ -301,13 +343,13 @@ export interface DOMAdaptor { /** * @param {N} node The HTML node whose class is to be tested * @param {string} name The class to test - * @return {boolean} True if the node has the given class + * @returns {boolean} True if the node has the given class */ hasClass(node: N, name: string): boolean; /** * @param {N} node The HTML node whose class list is needed - * @return {string[]} An array of the class names for this node + * @returns {string[]} An array of the class names for this node */ allClasses(node: N): string[]; @@ -321,13 +363,13 @@ export interface DOMAdaptor { /** * @param {N} node The HTML node whose style is to be obtained * @param {string} name The style to be obtained - * @return {string} The value of the style + * @returns {string} The value of the style */ getStyle(node: N, name: string): string; /** * @param {N} node The HTML node whose styles are to be returned - * @return {string} The cssText for the styles + * @returns {string} The cssText for the styles */ allStyles(node: N): string; @@ -337,15 +379,21 @@ export interface DOMAdaptor { */ insertRules(node: N, rules: string[]): void; + /** + * @param {N} node The stylesheet node whose rules are to be returned + * @returns {string} The string version of the stylesheet rules + */ + cssText(node: N): string; + /** * @param {N} node The HTML node whose font size is to be determined - * @return {number} The font size (in pixels) of the node + * @returns {number} The font size (in pixels) of the node */ fontSize(node: N): number; /** * @param {N} node The HTML node whose font family is to be determined - * @return {string} The font family + * @returns {string} The font family */ fontFamily(node: N): string; @@ -353,16 +401,25 @@ export interface DOMAdaptor { * @param {N} node The HTML node whose dimensions are to be determined * @param {number} em The number of pixels in an em * @param {boolean} local True if local coordinates are to be used in SVG elements - * @return {[number, number]} The width and height (in ems) of the element + * @returns {[number, number]} The width and height (in ems) of the element */ nodeSize(node: N, em?: number, local?: boolean): [number, number]; - /** * @param {N} node The HTML node whose BBox is to be determined - * @return {PageBBox} BBox as {left, right, top, bottom} position on the page (in pixels) + * @returns {PageBBox} BBox as {left, right, top, bottom} position on the page (in pixels) */ nodeBBox(node: N): PageBBox; + + /** + * @param {(event: any) => void} listener The event listener for messages from the worker + * @param {OptionList} options The worker options (for path and worker name) + * @returns {Promise} A promise for the worker instance that was created + */ + createWorker( + listener: (event: any) => void, + options: OptionList + ): Promise; } /*****************************************************************/ @@ -373,16 +430,22 @@ export interface DOMAdaptor { * @template T The Text node class * @template D The Document class */ -export abstract class AbstractDOMAdaptor implements DOMAdaptor { - +export abstract class AbstractDOMAdaptor + implements DOMAdaptor +{ /** * The document in which the HTML nodes will be created */ public document: D; + /** + * True when the adaptor can measure DOM node sizes + */ + public canMeasureNodes: boolean = true; + /** * @param {D} document The document in which the nodes will be created - * @constructor + * @class */ constructor(document: D = null) { this.document = document; @@ -396,7 +459,12 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor /** * @override */ - public node(kind: string, def: OptionList = {}, children: (N | T)[] = [], ns?: string) { + public node( + kind: string, + def: OptionList = {}, + children: (N | T)[] = [], + ns?: string + ) { const node = this.create(kind, ns); this.setAttributes(node, def); for (const child of children) { @@ -408,7 +476,7 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor /** * @param {string} kind The type of the node to create * @param {string} ns The optional namespace in which to create the node - * @return {N} The created node + * @returns {N} The created node */ protected abstract create(kind: string, ns?: string): N; @@ -417,23 +485,44 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor */ public abstract text(text: string): T; + /** + * @override + */ + public setProperty(node: N, name: string, value: any) { + (node as any)[name] = value; + } + + /** + * @override + */ + public getProperty(node: N, name: string): any { + return (node as any)[name]; + } + /** * @param {N} node The HTML element whose attributes are to be set * @param {OptionList} def The attributes to set on that node */ public setAttributes(node: N, def: OptionList) { - if (def.style && typeof(def.style) !== 'string') { - for (let key of Object.keys(def.style)) { - this.setStyle(node, key.replace(/-([a-z])/g, (_m, c) => c.toUpperCase()), def.style[key]); + if (def.style && typeof def.style !== 'string') { + for (const key of Object.keys(def.style)) { + this.setStyle( + node, + key.replace(/-([a-z])/g, (_m, c) => c.toUpperCase()), + def.style[key] + ); } } if (def.properties) { - for (let key of Object.keys(def.properties)) { + for (const key of Object.keys(def.properties)) { (node as OptionList)[key] = def.properties[key]; } } - for (let key of Object.keys(def)) { - if ((key !== 'style' || typeof(def.style) === 'string') && key !== 'properties') { + for (const key of Object.keys(def)) { + if ( + (key !== 'style' || typeof def.style === 'string') && + key !== 'properties' + ) { this.setAttribute(node, key, def[key]); } } @@ -442,22 +531,22 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor /** * @override */ - public abstract head(doc: D): N; + public abstract head(doc?: D): N; /** * @override */ - public abstract body(doc: D): N; + public abstract body(doc?: D): N; /** * @override */ - public abstract root(doc: D): N; + public abstract root(doc?: D): N; /** * @override */ - public abstract doctype(doc: D): string; + public abstract doctype(doc?: D): string; /** * @override @@ -469,6 +558,11 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor */ public abstract getElements(nodes: (string | N | N[])[], document: D): N[]; + /** + * @override + */ + public abstract getElement(selector: string, node?: D | N): N; + /** * @override */ @@ -506,7 +600,7 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor /** * @override */ - public abstract clone(node: N): N; + public abstract clone(node: N, deep: boolean): N; /** * @override @@ -578,7 +672,12 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor /** * @override */ - public abstract setAttribute(node: N, name: string, value: string, ns?: string): void; + public abstract setAttribute( + node: N, + name: string, + value: string, + ns?: string + ): void; /** * @override @@ -595,7 +694,6 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor */ public abstract hasAttribute(node: N, name: string): boolean; - /** * @override */ @@ -621,8 +719,13 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor */ public allClasses(node: N) { const classes = this.getAttribute(node, 'class'); - return (!classes ? [] as string[] : - classes.replace(/ +/g, ' ').replace(/^ /, '').replace(/ $/, '').split(/ /)); + return !classes + ? ([] as string[]) + : classes + .replace(/ +/g, ' ') + .replace(/^ /, '') + .replace(/ $/, '') + .split(/ /); } /** @@ -645,6 +748,13 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor */ public abstract insertRules(node: N, rules: string[]): void; + /** + * @override + */ + public cssText(node: N) { + return this.kind(node) === 'style' ? this.textContent(node) : ''; + } + /** * @override */ @@ -658,11 +768,22 @@ export abstract class AbstractDOMAdaptor implements DOMAdaptor /** * @override */ - public abstract nodeSize(node: N, em?: number, local?: boolean): [number, number]; + public abstract nodeSize( + node: N, + em?: number, + local?: boolean + ): [number, number]; /** * @override */ public abstract nodeBBox(node: N): PageBBox; + /** + * @override + */ + public abstract createWorker( + listener: (event: any) => void, + options: OptionList + ): Promise; } diff --git a/ts/core/FindMath.ts b/ts/core/FindMath.ts index 59e1ca2f3..2977d2039 100644 --- a/ts/core/FindMath.ts +++ b/ts/core/FindMath.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Interfaces and abstract classes for FindMath objects + * @file Interfaces and abstract classes for FindMath objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {userOptions, defaultOptions, OptionList} from '../util/Options.js'; -import {ProtoItem} from './MathItem.js'; +import { userOptions, defaultOptions, OptionList } from '../util/Options.js'; +import { ProtoItem } from './MathItem.js'; /*****************************************************************/ /** @@ -38,13 +38,13 @@ export interface FindMath { * or look through an array of strings for delimited math. * * @param {N} node The node to search for math - * @return {ProtoItem[]} + * @returns {ProtoItem[]} */ findMath(node: N): ProtoItem[]; /** * * @param {string[]} strings The strings to search for math - * @return {ProtoItem[]} + * @returns {ProtoItem[]} */ findMath(strings: string[]): ProtoItem[]; } @@ -60,7 +60,6 @@ export interface FindMath { * @template D The Document class */ export abstract class AbstractFindMath implements FindMath { - /** * The default options for FindMath */ @@ -75,7 +74,7 @@ export abstract class AbstractFindMath implements FindMath { * @param {OptionList} options The user options for this instance */ constructor(options: OptionList) { - let CLASS = this.constructor as typeof AbstractFindMath; + const CLASS = this.constructor as typeof AbstractFindMath; this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options); } @@ -83,8 +82,7 @@ export abstract class AbstractFindMath implements FindMath { * Locate math in an Element or a string array; * * @param {Element | string[]} where The node or string array to search for math - * @return {ProtoItem[]} The array of proto math items found + * @returns {ProtoItem[]} The array of proto math items found */ public abstract findMath(where: N | string[]): ProtoItem[]; - } diff --git a/ts/core/Handler.ts b/ts/core/Handler.ts index b15c1ff6c..9da7e3a17 100644 --- a/ts/core/Handler.ts +++ b/ts/core/Handler.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,18 @@ */ /** - * @fileoverview Interfaces and abstract classes for Handler objects + * @file Interfaces and abstract classes for Handler objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MathDocument, AbstractMathDocument, MathDocumentConstructor} from './MathDocument.js'; -import {OptionList} from '../util/Options.js'; -import {DOMAdaptor} from '../core/DOMAdaptor.js'; +import { + MathDocument, + AbstractMathDocument, + MathDocumentConstructor, +} from './MathDocument.js'; +import { OptionList } from '../util/Options.js'; +import { DOMAdaptor } from '../core/DOMAdaptor.js'; /*****************************************************************/ /** @@ -60,7 +64,7 @@ export interface Handler { * Checks to see if the handler can process a given document * * @param {any} document The document to be processed (string, window, etc.) - * @return {boolean} True if this handler can process the given document + * @returns {boolean} True if this handler can process the given document */ handlesDocument(document: any): boolean; @@ -69,7 +73,7 @@ export interface Handler { * * @param {any} document The document to be handled * @param {OptionList} options The options for the handling of the document - * @return {MathDocument} The MathDocument object that manages the processing + * @returns {MathDocument} The MathDocument object that manages the processing */ create(document: any, options: OptionList): MathDocument; } @@ -93,7 +97,6 @@ class DefaultMathDocument extends AbstractMathDocument {} * @template D The Document class */ export abstract class AbstractHandler implements Handler { - /** * The name of this class */ @@ -113,12 +116,14 @@ export abstract class AbstractHandler implements Handler { * The class implementing the MathDocument for this handler * (so it can be subclassed by extensions as needed) */ - public documentClass: MathDocumentConstructor> = DefaultMathDocument; + public documentClass: MathDocumentConstructor> = + DefaultMathDocument; /** + * @param {DOMAdaptor} adaptor The DOM adaptor * @param {number} priority The priority to use for this handler * - * @constructor + * @class */ constructor(adaptor: DOMAdaptor, priority: number = 5) { this.adaptor = adaptor; @@ -126,7 +131,7 @@ export abstract class AbstractHandler implements Handler { } /** - * @return {string} The name of this handler class + * @returns {string} The name of this handler class */ public get name(): string { return (this.constructor as typeof AbstractHandler).NAME; @@ -143,7 +148,10 @@ export abstract class AbstractHandler implements Handler { * @override */ public create(document: any, options: OptionList) { - return new this.documentClass(document, this.adaptor, options) as MathDocument; + return new this.documentClass( + document, + this.adaptor, + options + ) as MathDocument; } - } diff --git a/ts/core/HandlerList.ts b/ts/core/HandlerList.ts index 0af1e2917..47613d1da 100644 --- a/ts/core/HandlerList.ts +++ b/ts/core/HandlerList.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ */ /** - * @fileoverview Implements the interface and abstract class for HandlerList objects + * @file Implements the interface and abstract class for HandlerList objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PrioritizedList} from '../util/PrioritizedList.js'; -import {OptionList} from '../util/Options.js'; -import {Handler} from './Handler.js'; -import {MathDocument} from './MathDocument.js'; +import { PrioritizedList } from '../util/PrioritizedList.js'; +import { OptionList } from '../util/Options.js'; +import { Handler } from './Handler.js'; +import { MathDocument } from './MathDocument.js'; /*****************************************************************/ /** @@ -38,18 +38,17 @@ import {MathDocument} from './MathDocument.js'; * @template T The Text node class * @template D The Document class */ -export class HandlerList extends PrioritizedList> { - +export class HandlerList extends PrioritizedList> { /** * @param {Handler} handler The handler to register - * @return {Handler} The list item created for the handler + * @returns {Handler} The list item created for the handler */ public register(handler: Handler): Handler { return this.add(handler, handler.priority); } /** - * @param {Handler} Handler The handler to remove from the list + * @param {Handler} handler The handler to remove from the list */ public unregister(handler: Handler) { this.remove(handler); @@ -57,11 +56,11 @@ export class HandlerList extends PrioritizedList> { /** * @param {any} document The document (string, window, DOM element, etc) to be handled - * @return {Handler} The handler from the list that can process the given document + * @returns {Handler} The handler from the list that can process the given document */ public handlesDocument(document: any): Handler { for (const item of this) { - let handler = item.item; + const handler = item.item; if (handler.handlesDocument(document)) { return handler; } @@ -72,10 +71,12 @@ export class HandlerList extends PrioritizedList> { /** * @param {any} document The document to be processed * @param {OptionList} options The options for the handler - * @return {MathDocument} The MathDocument created by the handler for this document + * @returns {MathDocument} The MathDocument created by the handler for this document */ - public document(document: any, options: OptionList = null): MathDocument { + public document( + document: any, + options: OptionList = null + ): MathDocument { return this.handlesDocument(document).create(document, options); } - } diff --git a/ts/core/InputJax.ts b/ts/core/InputJax.ts index fe278accb..7d42d14a3 100644 --- a/ts/core/InputJax.ts +++ b/ts/core/InputJax.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,18 @@ */ /** - * @fileoverview Implements the interface and abstract class for the InputJax + * @file Implements the interface and abstract class for the InputJax * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MathDocument} from './MathDocument.js'; -import {MathItem, ProtoItem} from './MathItem.js'; -import {MmlNode} from './MmlTree/MmlNode.js'; -import {MmlFactory} from './MmlTree/MmlFactory.js'; -import {userOptions, defaultOptions, OptionList} from '../util/Options.js'; -import {FunctionList} from '../util/FunctionList.js'; -import {DOMAdaptor} from '../core/DOMAdaptor.js'; +import { MathDocument } from './MathDocument.js'; +import { MathItem, ProtoItem } from './MathItem.js'; +import { MmlNode } from './MmlTree/MmlNode.js'; +import { MmlFactory } from './MmlTree/MmlFactory.js'; +import { userOptions, defaultOptions, OptionList } from '../util/Options.js'; +import { FunctionList } from '../util/FunctionList.js'; +import { DOMAdaptor } from '../core/DOMAdaptor.js'; /*****************************************************************/ /** @@ -97,7 +97,7 @@ export interface InputJax { * * @param {N | string[]} which The element or array of strings to be searched for math * @param {OptionList} options The options for the search, if any - * @return {ProtoItem[]} Array of proto math items found (further processed by the + * @returns {ProtoItem[]} Array of proto math items found (further processed by the * handler to produce actual MathItem objects) */ findMath(which: N | string[], options?: OptionList): ProtoItem[]; @@ -107,7 +107,7 @@ export interface InputJax { * * @param {MathItem} math The MathItem whose math content is to processed * @param {MathDocument} document The MathDocument for this input jax. - * @return {MmlNode} The resulting internal node tree for the math + * @returns {MmlNode} The resulting internal node tree for the math */ compile(math: MathItem, document: MathDocument): MmlNode; } @@ -121,7 +121,6 @@ export interface InputJax { * @template D The Document class */ export abstract class AbstractInputJax implements InputJax { - /** * The name of the input jax */ @@ -130,7 +129,10 @@ export abstract class AbstractInputJax implements InputJax { /** * The default options for the input jax */ - public static OPTIONS: OptionList = {}; + public static OPTIONS: OptionList = { + preFilters: [], + postFilters: [], + }; /** * The actual options supplied to the input jax @@ -150,26 +152,26 @@ export abstract class AbstractInputJax implements InputJax { /** * The DOMAdaptor for the MathDocument for this input jax */ - public adaptor: DOMAdaptor = null; // set by the handler + public adaptor: DOMAdaptor = null; // set by the handler /** * The MathML node factory */ - public mmlFactory: MmlFactory = null; // set by the handler + public mmlFactory: MmlFactory = null; // set by the handler /** * @param {OptionList} options The options to apply to this input jax * - * @constructor + * @class */ constructor(options: OptionList = {}) { - let CLASS = this.constructor as typeof AbstractInputJax; + const CLASS = this.constructor as typeof AbstractInputJax; this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options); - this.preFilters = new FunctionList(); - this.postFilters = new FunctionList(); + this.preFilters = new FunctionList(this.options.preFilters); + this.postFilters = new FunctionList(this.options.postFilters); } /** - * @return {string} The name of this input jax class + * @returns {string} The name of this input jax class */ public get name(): string { return (this.constructor as typeof AbstractInputJax).NAME; @@ -192,17 +194,15 @@ export abstract class AbstractInputJax implements InputJax { /** * @override */ - public initialize() { - } + public initialize() {} /** * @override */ - public reset(..._args: any[]) { - } + public reset(..._args: any[]) {} /** - * @return {boolean} True means find math in string array, false means in DOM element + * @returns {boolean} True means find math in string array, false means in DOM element */ public get processStrings(): boolean { return true; @@ -218,7 +218,10 @@ export abstract class AbstractInputJax implements InputJax { /** * @override */ - public abstract compile(math: MathItem, document: MathDocument): MmlNode; + public abstract compile( + math: MathItem, + document: MathDocument + ): MmlNode; /** * Execute a set of filters, passing them the MathItem and any needed data, @@ -228,15 +231,16 @@ export abstract class AbstractInputJax implements InputJax { * @param {MathItem} math The math item that is being processed * @param {MathDocument} document The math document containg the math item * @param {any} data Whatever other data is needed - * @return {any} The (possibly modified) data + * @returns {any} The (possibly modified) data */ protected executeFilters( - filters: FunctionList, math: MathItem, - document: MathDocument, data: any + filters: FunctionList, + math: MathItem, + document: MathDocument, + data: any ): any { - let args = {math: math, document: document, data: data}; + const args = { math: math, document: document, data: data }; filters.execute(args); return args.data; } - } diff --git a/ts/core/MathDocument.ts b/ts/core/MathDocument.ts index 7e64cee39..a4d068687 100644 --- a/ts/core/MathDocument.ts +++ b/ts/core/MathDocument.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,27 @@ */ /** - * @fileoverview Implements the interface and abstract class for MathDocument objects + * @file Implements the interface and abstract class for MathDocument objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {userOptions, defaultOptions, OptionList, expandable} from '../util/Options.js'; -import {InputJax, AbstractInputJax} from './InputJax.js'; -import {OutputJax, AbstractOutputJax} from './OutputJax.js'; -import {MathList, AbstractMathList} from './MathList.js'; -import {MathItem, AbstractMathItem, STATE} from './MathItem.js'; -import {MmlNode, TextNode} from './MmlTree/MmlNode.js'; -import {MmlFactory} from '../core/MmlTree/MmlFactory.js'; -import {DOMAdaptor} from '../core/DOMAdaptor.js'; -import {BitField, BitFieldClass} from '../util/BitField.js'; - -import {PrioritizedList} from '../util/PrioritizedList.js'; +import { + userOptions, + defaultOptions, + OptionList, + expandable, +} from '../util/Options.js'; +import { InputJax, AbstractInputJax } from './InputJax.js'; +import { OutputJax, AbstractOutputJax } from './OutputJax.js'; +import { MathList, AbstractMathList } from './MathList.js'; +import { MathItem, AbstractMathItem, STATE } from './MathItem.js'; +import { MmlNode, TextNode } from './MmlTree/MmlNode.js'; +import { MmlFactory } from '../core/MmlTree/MmlFactory.js'; +import { DOMAdaptor } from '../core/DOMAdaptor.js'; +import { BitField, BitFieldClass } from '../util/BitField.js'; +import { PrioritizedList } from '../util/PrioritizedList.js'; +import { handleRetriesFor } from '../util/Retries.js'; /*****************************************************************/ @@ -51,7 +56,10 @@ export type RenderDoc = (document: MathDocument) => boolean; * @template T The Text node class * @template D The Document class */ -export type RenderMath = (math: MathItem, document: MathDocument) => boolean; +export type RenderMath = ( + math: MathItem, + document: MathDocument +) => boolean; /** * The data for an action to perform during rendering or conversion @@ -60,6 +68,7 @@ export type RenderMath = (math: MathItem, document: MathDocume * @template T The Text node class * @template D The Document class */ +/* prettier-ignore */ export type RenderData = { id: string, // The name for the action renderDoc: RenderDoc, // The action to take during a render() call @@ -77,6 +86,7 @@ export type RenderData = { * @template T The Text node class * @template D The Document class */ +/* prettier-ignore */ export type RenderAction = [number] | // id (i.e., key) is method name to use [number, string] | // string is method to call @@ -85,7 +95,7 @@ export type RenderAction = [number, boolean] | // same as first above, with boolean for convert [number, string, boolean] | // same as second above, with boolean for convert [number, string, string, boolean] | // same as third above, with boolean for convert - [number, RenderDoc, RenderMath, boolean]; // same as forth above, with boolean for convert + [number, RenderDoc, RenderMath, boolean]; // same as forth above, with boolean for convert /** * An object representing a collection of rendering actions (id's tied to priority-and-method data) @@ -94,7 +104,7 @@ export type RenderAction = * @template T The Text node class * @template D The Document class */ -export type RenderActions = {[id: string]: RenderAction}; +export type RenderActions = { [id: string]: RenderAction }; /** * Implements a prioritized list of render actions. Extensions can add actions to the list @@ -105,14 +115,15 @@ export type RenderActions = {[id: string]: RenderAction}; * @template D The Document class */ export class RenderList extends PrioritizedList> { - /** * Creates a new RenderList from an initial list of rendering actions * * @param {RenderActions} actions The list of actions to take during render(), rerender(), and convert() calls * @returns {RenderList} The newly created prioritied list */ - public static create(actions: RenderActions): RenderList { + public static create( + actions: RenderActions + ): RenderList { const list = new this(); for (const id of Object.keys(actions)) { const [action, priority] = this.action(id, actions[id]); @@ -131,27 +142,44 @@ export class RenderList extends PrioritizedList> { * @param {RenderAction} action The RenderAction defining the action * @returns {[RenderData,number]} The corresponding RenderData definition for the action and its priority */ - public static action(id: string, action: RenderAction): [RenderData, number] { + public static action( + id: string, + action: RenderAction + ): [RenderData, number] { let renderDoc, renderMath; let convert = true; - let priority = action[0]; + const priority = action[0]; if (action.length === 1 || typeof action[1] === 'boolean') { - action.length === 2 && (convert = action[1] as boolean); + if (action.length === 2) { + convert = action[1] as boolean; + } [renderDoc, renderMath] = this.methodActions(id); } else if (typeof action[1] === 'string') { if (typeof action[2] === 'string') { - action.length === 4 && (convert = action[3] as boolean); + if (action.length === 4) { + convert = action[3] as boolean; + } const [method1, method2] = action.slice(1) as [string, string]; [renderDoc, renderMath] = this.methodActions(method1, method2); } else { - action.length === 3 && (convert = action[2] as boolean); + if (action.length === 3) { + convert = action[2] as boolean; + } [renderDoc, renderMath] = this.methodActions(action[1] as string); } } else { - action.length === 4 && (convert = action[3] as boolean); - [renderDoc, renderMath] = action.slice(1) as [RenderDoc, RenderMath]; + if (action.length === 4) { + convert = action[3] as boolean; + } + [renderDoc, renderMath] = action.slice(1) as [ + RenderDoc, + RenderMath, + ]; } - return [{id, renderDoc, renderMath, convert} as RenderData, priority]; + return [ + { id, renderDoc, renderMath, convert } as RenderData, + priority, + ]; } /** @@ -159,12 +187,28 @@ export class RenderList extends PrioritizedList> { * (a blank name is a no-op) * * @param {string} method1 The method to use for the render() call - * @param {string} method1 The method to use for the rerender() and convert() calls + * @param {string} method2 The method to use for the rerender() and convert() calls + * + * @returns {[(document: any) => boolean, (math: any, document: any) => boolean]} + * Two render action methods wrapping the parameter methods. */ - protected static methodActions(method1: string, method2: string = method1) { + protected static methodActions( + method1: string, + method2: string = method1 + ): [(document: any) => boolean, (math: any, document: any) => boolean] { return [ - (document: any) => {method1 && document[method1](); return false; }, - (math: any, document: any) => {method2 && math[method2](document); return false; } + (document: any) => { + if (method1) { + document[method1](); + } + return false; + }, + (math: any, document: any) => { + if (method2) { + math[method2](document); + } + return false; + }, ]; } @@ -174,7 +218,10 @@ export class RenderList extends PrioritizedList> { * @param {MathDocument} document The MathDocument whose methods are to be called * @param {number=} start The state at which to start rendering (default is UNPROCESSED) */ - public renderDoc(document: MathDocument, start: number = STATE.UNPROCESSED) { + public renderDoc( + document: MathDocument, + start: number = STATE.UNPROCESSED + ) { for (const item of this.items) { if (item.priority >= start) { if (item.item.renderDoc(document)) return; @@ -189,7 +236,11 @@ export class RenderList extends PrioritizedList> { * @param {MathDocument} document The MathDocument to pass to the MathItem methods * @param {number=} start The state at which to start rendering (default is UNPROCESSED) */ - public renderMath(math: MathItem, document: MathDocument, start: number = STATE.UNPROCESSED) { + public renderMath( + math: MathItem, + document: MathDocument, + start: number = STATE.UNPROCESSED + ) { for (const item of this.items) { if (item.priority >= start) { if (item.item.renderMath(math, document)) return; @@ -204,7 +255,11 @@ export class RenderList extends PrioritizedList> { * @param {MathDocument} document The MathDocument to pass to the MathItem methods * @param {number=} end The state at which to end rendering (default is LAST) */ - public renderConvert(math: MathItem, document: MathDocument, end: number = STATE.LAST) { + public renderConvert( + math: MathItem, + document: MathDocument, + end: number = STATE.LAST + ) { for (const item of this.items) { if (item.priority > end) return; if (item.item.convert) { @@ -227,7 +282,6 @@ export class RenderList extends PrioritizedList> { } return null; } - } /*****************************************************************/ @@ -244,10 +298,10 @@ export type ContainerList = string | N | (string | N | N[])[]; * The options allowed for the reset() method */ export type ResetList = { - all?: boolean, - processed?: boolean, - inputJax?: any[], - outputJax?: any[] + all?: boolean; + processed?: boolean; + inputJax?: any[]; + outputJax?: any[]; }; /** @@ -257,7 +311,7 @@ export const resetOptions: ResetList = { all: false, processed: false, inputJax: null, - outputJax: null + outputJax: null, }; /** @@ -267,7 +321,7 @@ export const resetAllOptions: ResetList = { all: true, processed: true, inputJax: [], - outputJax: [] + outputJax: [], }; /*****************************************************************/ @@ -359,60 +413,107 @@ export interface MathDocument { /** * Perform the renderActions on the document + * + * @returns {MathDocument} The math document instance */ render(): MathDocument; + /** + * Perform the renderActions on the document with retry handling + * + * @returns {Promise} A promise that resolves when the render is complete + */ + renderPromise(): Promise>; + /** * Rerender the MathItems on the page * - * @param {number=} start The state to start rerendering at - * @return {MathDocument} The math document instance + * @param {number} start The state to start rerendering at + * @returns {MathDocument} The math document instance */ rerender(start?: number): MathDocument; + /** + * Rerender the MathItems on the page + * + * @param {number} start The state to start rerendering at + * @returns {Promise} A promise that resolves when the rerender is complete + */ + rerenderPromise(start?: number): Promise>; + /** * Convert a math string to the document's output format * * @param {string} math The math string to convert - * @params {OptionList} options The options for the conversion (e.g., format, ex, em, etc.) - * @return {MmlNode|N} The MmlNode or N node for the converted content + * @param {OptionList} options The options for the conversion (e.g., format, ex, em, etc.) + * @returns {MmlNode|N} The MmlNode or N node for the converted content */ convert(math: string, options?: OptionList): MmlNode | N; + /** + * Convert a math string to the document's output format + * + * @param {string} math The math string to convert + * @param {OptionList} options The options for the conversion (e.g., format, ex, em, etc.) + * @returns {Promise} A promise that resolves when the conversion is complete + */ + convertPromise(math: string, options?: OptionList): Promise; + + /** + * Perform an action when previous actions are complete. + * (Used to chain promise-based typeset and conversion actions.) + */ + whenReady(action: () => any): Promise; + + /** + * Return a promise that resolves when all of the action promises have been resolved + */ + actionPromises(): Promise; + + /** + * Clear the action promises + */ + clearPromises(): void; + + /** + * Save a promise in the action romises list + */ + savePromise(promise: Promise): void; + /** * Locates the math in the document and constructs the MathList * for the document. * * @param {OptionList} options The options for locating the math - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ findMath(options?: OptionList): MathDocument; /** * Calls the input jax to process the MathItems in the MathList * - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ compile(): MathDocument; /** * Gets the metric information for the MathItems * - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ getMetrics(): MathDocument; /** * Calls the output jax to process the compiled math in the MathList * - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ typeset(): MathDocument; /** * Updates the document to include the typeset math * - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ updateDocument(): MathDocument; @@ -421,7 +522,7 @@ export interface MathDocument { * * @param {boolean} restore True if the original math should be put * back into the document as well - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ removeFromDocument(restore?: boolean): MathDocument; @@ -432,7 +533,7 @@ export interface MathDocument { * @param {number} state The new state of the document * @param {boolean} restore True if the original math should be put * back into the document during the rollback - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ state(state: number, restore?: boolean): MathDocument; @@ -440,7 +541,7 @@ export interface MathDocument { * Clear the processed values so that the document can be reprocessed * * @param {ResetList} options The things to be reset - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ reset(options?: ResetList): MathDocument; @@ -448,15 +549,20 @@ export interface MathDocument { * Reset the processed values and clear the MathList (so that new math * can be processed in the document). * - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ clear(): MathDocument; + /** + * Indicate that the MathDocument is no longer needed. + */ + done(): Promise; + /** * Merges a MathList into the list for this document. * * @param {MathList} list The MathList to be merged into this document's list - * @return {MathDocument} The math document instance + * @returns {MathDocument} The math document instance */ concat(list: MathList): MathDocument; @@ -466,8 +572,8 @@ export interface MathDocument { * container has been updated and you want to remove the * associated MathItems) * - * @param {ContainerList} elements The container DOM elements whose math items are to be removed - * @return {MathItem[]} The removed MathItems + * @param {ContainerList} containers The container DOM elements whose math items are to be removed + * @returns {MathItem[]} The removed MathItems */ clearMathItemsWithin(containers: ContainerList): MathItem[]; @@ -475,10 +581,9 @@ export interface MathDocument { * Get the typeset MathItems that are within a given container. * * @param {ContainerList} elements The container DOM elements whose math items are to be found - * @return {MathItem[]} The list of MathItems within that container + * @returns {MathItem[]} The list of MathItems within that container */ getMathItemsWithin(elements: ContainerList): MathItem[]; - } /*****************************************************************/ @@ -510,7 +615,10 @@ class DefaultOutputJax extends AbstractOutputJax { /** * @override */ - public typeset(_math: MathItem, _document: MathDocument = null) { + public typeset( + _math: MathItem, + _document: MathDocument = null + ) { return null as N; } /** @@ -547,8 +655,9 @@ class DefaultMathItem extends AbstractMathItem {} * @template T The Text node class * @template D The Document class */ -export abstract class AbstractMathDocument implements MathDocument { - +export abstract class AbstractMathDocument + implements MathDocument +{ /** * The type of MathDocument */ @@ -558,30 +667,44 @@ export abstract class AbstractMathDocument implements MathDocument, math: MathItem, err: Error) => { + compileError: ( + doc: AbstractMathDocument, + math: MathItem, + err: Error + ) => { doc.compileError(math, err); }, - typesetError: (doc: AbstractMathDocument, math: MathItem, err: Error) => { + typesetError: ( + doc: AbstractMathDocument, + math: MathItem, + err: Error + ) => { doc.typesetError(math, err); }, renderActions: expandable({ - find: [STATE.FINDMATH, 'findMath', '', false], + find: [STATE.FINDMATH, 'findMath', '', false], compile: [STATE.COMPILED], metrics: [STATE.METRICS, 'getMetrics', '', false], typeset: [STATE.TYPESET], - update: [STATE.INSERTED, 'updateDocument', false] - }) as RenderActions + update: [STATE.INSERTED, 'updateDocument', false], + }) as RenderActions, }; /** * A bit-field for the actions that have been processed */ - public static ProcessBits = BitFieldClass('findMath', 'compile', 'getMetrics', 'typeset', 'updateDocument'); + public static ProcessBits = BitFieldClass( + 'findMath', + 'compile', + 'getMetrics', + 'typeset', + 'updateDocument' + ); /** * The document managed by this MathDocument @@ -602,6 +725,18 @@ export abstract class AbstractMathDocument implements MathDocument; + /** + * The render action promise list + */ + protected _actionPromises: Promise[]; + + /** + * Promise for the current typeset or conversion action + * (used to chain the promise-based calls so they don't + * overlap). + */ + protected _readyPromise: Promise; + /** * The bit-field used to tell what steps have been taken on the document (for retries) */ @@ -627,21 +762,25 @@ export abstract class AbstractMathDocument implements MathDocument, options: OptionList) { - let CLASS = this.constructor as typeof AbstractMathDocument; + constructor(document: D, adaptor: DOMAdaptor, options: OptionList) { + const CLASS = this.constructor as typeof AbstractMathDocument; this.document = document; this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options); this.math = new (this.options['MathList'] || DefaultMathList)(); - this.renderActions = RenderList.create(this.options['renderActions']); + this.renderActions = RenderList.create( + this.options['renderActions'] + ); + this._actionPromises = []; + this._readyPromise = Promise.resolve(); this.processed = new AbstractMathDocument.ProcessBits(); - this.outputJax = this.options['OutputJax'] || new DefaultOutputJax(); + this.outputJax = + this.options['OutputJax'] || new DefaultOutputJax(); let inputJax = this.options['InputJax'] || [new DefaultInputJax()]; if (!Array.isArray(inputJax)) { inputJax = [inputJax]; @@ -652,21 +791,21 @@ export abstract class AbstractMathDocument implements MathDocument jax.setAdaptor(adaptor)); + this.inputJax.map((jax) => jax.setAdaptor(adaptor)); // // Pass the MmlFactory to the jax // this.mmlFactory = this.options['MmlFactory'] || new MmlFactory(); - this.inputJax.map(jax => jax.setMmlFactory(this.mmlFactory)); + this.inputJax.map((jax) => jax.setMmlFactory(this.mmlFactory)); // // Do any initialization that requires adaptors or factories // this.outputJax.initialize(); - this.inputJax.map(jax => jax.initialize()); + this.inputJax.map((jax) => jax.initialize()); } /** - * @return {string} The kind of document + * @returns {string} The kind of document */ public get kind(): string { return (this.constructor as typeof AbstractMathDocument).KIND; @@ -676,7 +815,10 @@ export abstract class AbstractMathDocument implements MathDocument(id, action as RenderAction); + const [fn, p] = RenderList.action( + id, + action as RenderAction + ); this.renderActions.add(fn, p); } @@ -694,10 +836,25 @@ export abstract class AbstractMathDocument implements MathDocument + handleRetriesFor(async () => { + this.render(); + await this.actionPromises(); + this.clearPromises(); + return this; + }) + ); + } + /** * @override */ @@ -707,29 +864,131 @@ export abstract class AbstractMathDocument implements MathDocument + handleRetriesFor(async () => { + this.rerender(start); + await this.actionPromises(); + this.clearPromises(); + return this; + }) + ); + } + /** * @override */ public convert(math: string, options: OptionList = {}) { - let {format, display, end, ex, em, containerWidth, lineWidth, scale, family} = userOptions({ - format: this.inputJax[0].name, display: true, end: STATE.LAST, - em: 16, ex: 8, containerWidth: null, lineWidth: 1000000, scale: 1, family: '' - }, options); + let { format, display, end, ex, em, containerWidth, scale, family } = + userOptions( + { + format: this.inputJax[0].name, + display: true, + end: STATE.LAST, + em: 16, + ex: 8, + containerWidth: null, + scale: 1, + family: '', + }, + options + ); if (containerWidth === null) { containerWidth = 80 * ex; } - const jax = this.inputJax.reduce((jax, ijax) => (ijax.name === format ? ijax : jax), null); + const jax = this.inputJax.reduce( + (jax, ijax) => (ijax.name === format ? ijax : jax), + null + ); const mitem = new this.options.MathItem(math, jax, display); mitem.start.node = this.adaptor.body(this.document); - mitem.setMetrics(em, ex, containerWidth, lineWidth, scale); - if (this.outputJax.options.mtextInheritFont) { + mitem.setMetrics(em, ex, containerWidth, scale); + if (family && this.outputJax.options.mtextInheritFont) { mitem.outputData.mtextFamily = family; } - if (this.outputJax.options.merrorInheritFont) { + if (family && this.outputJax.options.merrorInheritFont) { mitem.outputData.merrorFamily = family; } + this.clearPromises(); mitem.convert(this, end); - return (mitem.typesetRoot || mitem.root); + return mitem.typesetRoot || mitem.root; + } + + /** + * @override + */ + public convertPromise(math: string, options: OptionList = {}) { + return this.whenReady(() => + handleRetriesFor(async () => { + const node = this.convert(math, options); + await this.actionPromises(); + this.clearPromises(); + return node; + }) + ); + } + + /** + * @override + */ + public whenReady(action: () => any): Promise { + return (this._readyPromise = this._readyPromise + .catch((_) => {}) + .then(() => { + // + // Cache old _readyPromise and replace it with a resolved + // promise in case action() calls whenReady(), so we don't get + // a circular dependency where the action is waiting on itself. + // + const ready = this._readyPromise; + this._readyPromise = Promise.resolve(); + // + // Do the action and save its result. + // + const result = action(); + // + // Get a promise that returns the result after + // any new _readyPromise resolves (in case action + // called whenReady() or another function that does). + // + const promise = this._readyPromise.then(() => result); + // + // Put back the original promise. + // + this._readyPromise = ready; + // + // Return promise that returns the result. The original + // _readyPromise will wait on it to complete before it resolves, + // since promises that return promises automatically chain. + // This inserts any new _readyPromise promises into the + // original _readyPromise chain at this point. + // + return promise; + })); + } + + /** + * @override + */ + public actionPromises() { + return Promise.all(this._actionPromises); + } + + /** + * @override + */ + public clearPromises() { + this._actionPromises = []; + } + + /** + * @override + */ + public savePromise(promise: Promise) { + this._actionPromises.push(promise); } /** @@ -793,11 +1052,17 @@ export abstract class AbstractMathDocument implements MathDocument, err: Error) { math.root = this.mmlFactory.create('math', null, [ - this.mmlFactory.create('merror', {'data-mjx-error': err.message, title: err.message}, [ - this.mmlFactory.create('mtext', null, [ - (this.mmlFactory.create('text') as TextNode).setText('Math input error') - ]) - ]) + this.mmlFactory.create( + 'merror', + { 'data-mjx-error': err.message, title: err.message }, + [ + this.mmlFactory.create('mtext', null, [ + (this.mmlFactory.create('text') as TextNode).setText( + 'Math input error' + ), + ]), + ] + ), ]); if (math.display) { math.root.attributes.set('display', 'block'); @@ -833,29 +1098,35 @@ export abstract class AbstractMathDocument implements MathDocument, err: Error) { - math.typesetRoot = this.adaptor.node('mjx-container', { - class: 'MathJax mjx-output-error', - jax: this.outputJax.name, - }, [ - this.adaptor.node('span', { - 'data-mjx-error': err.message, - title: err.message, - style: { - color: 'red', - 'background-color': 'yellow', - 'line-height': 'normal' - } - }, [ - this.adaptor.text('Math output error') - ]) - ]); + math.typesetRoot = this.adaptor.node( + 'mjx-container', + { + class: 'MathJax mjx-output-error', + jax: this.outputJax.name, + }, + [ + this.adaptor.node( + 'span', + { + 'data-mjx-error': err.message, + title: err.message, + style: { + color: 'red', + 'background-color': 'yellow', + 'line-height': 'normal', + }, + }, + [this.adaptor.text('Math output error')] + ), + ] + ); if (math.display) { this.adaptor.setAttributes(math.typesetRoot, { style: { display: 'block', margin: '1em 0', - 'text-align': 'center' - } + 'text-align': 'center', + }, }); } math.outputData.error = err.message; @@ -909,18 +1180,29 @@ export abstract class AbstractMathDocument implements MathDocument jax.reset(...options.inputJax)); - options.outputJax && this.outputJax.reset(...options.outputJax); + if (options.all) { + Object.assign(options, resetAllOptions); + } + if (options.processed) { + this.processed.reset(); + } + if (options.inputJax) { + this.inputJax.forEach((jax) => jax.reset(...options.inputJax)); + } + if (options.outputJax) { + this.outputJax.reset(...options.outputJax); + } return this; } @@ -933,6 +1215,13 @@ export abstract class AbstractMathDocument implements MathDocument implements MathDocument) { const items = this.getMathItemsWithin(containers); + for (const item of items.slice(0).reverse()) { + item.clear(); + } this.math.remove(...items); return items; } @@ -960,8 +1252,7 @@ export abstract class AbstractMathDocument implements MathDocument[]; const containers = adaptor.getElements(elements, this.document); - ITEMS: - for (const item of this.math) { + ITEMS: for (const item of this.math) { for (const container of containers) { if (item.start.node && adaptor.contains(container, item.start.node)) { items.push(item); @@ -971,7 +1262,6 @@ export abstract class AbstractMathDocument implements MathDocument implements MathDocument> { +export interface MathDocumentConstructor< + D extends MathDocument, +> { KIND: string; OPTIONS: OptionList; ProcessBits: typeof BitField; diff --git a/ts/core/MathItem.ts b/ts/core/MathItem.ts index b4626e88c..6a12d6931 100644 --- a/ts/core/MathItem.ts +++ b/ts/core/MathItem.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ */ /** - * @fileoverview Implements the interface and abstract class for MathItem objects + * @file Implements the interface and abstract class for MathItem objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MathDocument} from './MathDocument.js'; -import {InputJax} from './InputJax.js'; -import {OptionList} from '../util/Options.js'; -import {MmlNode} from './MmlTree/MmlNode.js'; +import { MathDocument } from './MathDocument.js'; +import { InputJax } from './InputJax.js'; +import { OptionList } from '../util/Options.js'; +import { MmlNode } from './MmlTree/MmlNode.js'; /*****************************************************************/ /** @@ -52,7 +52,6 @@ export type Metrics = { em: number; ex: number; containerWidth: number; - lineWidth: number; scale: number; }; @@ -178,10 +177,9 @@ export interface MathItem { * @param {number} em The size of 1 em in pixels * @param {number} ex The size of 1 ex in pixels * @param {number} cwidth The container width in pixels - * @param {number} lwidth The line breaking width in pixels * @param {number} scale The scaling factor (unitless) */ - setMetrics(em: number, ex: number, cwidth: number, lwidth: number, scale: number): void; + setMetrics(em: number, ex: number, cwidth: number, scale: number): void; /** * Set or return the current processing state of this expression, @@ -202,6 +200,11 @@ export interface MathItem { * to the document when rolling back a typeset version */ reset(restore?: boolean): void; + + /** + * Clear any data (the MathItem's container is being removed) + */ + clear(): void; } /*****************************************************************/ @@ -216,6 +219,7 @@ export interface MathItem { * @template N The HTMLElement node class * @template T The Text node class */ +/* prettier-ignore */ export type ProtoItem = { math: string; // The math expression itself start: Location; // The starting location of the math @@ -229,13 +233,35 @@ export type ProtoItem = { /** * Produce a proto math item that can be turned into a MathItem * - * @template N The HTMLElement node class - * @template T The Text node class + * @param {string} open The opening delimiter + * @param {string} math The math expression itself + * @param {string} close The closing delimiter + * @param {number} n The index of the string in which this math is + * @param {number} start The starting location of the math + * @param {number} end The ending location of the math + * @param {boolean} display True means display mode, false is inline mode + * @returns {ProtoItem} The proto math item + * @template N The HTMLElement node class + * @template T The Text node class */ -export function protoItem(open: string, math: string, close: string, n: number, - start: number, end: number, display: boolean = null) { - let item: ProtoItem = {open: open, math: math, close: close, - n: n, start: {n: start}, end: {n: end}, display: display}; +export function protoItem( + open: string, + math: string, + close: string, + n: number, + start: number, + end: number, + display: boolean = null +): ProtoItem { + const item: ProtoItem = { + open: open, + math: math, + close: close, + n: n, + start: { n: start }, + end: { n: end }, + display: display, + }; return item; } @@ -248,7 +274,6 @@ export function protoItem(open: string, math: string, close: string, n: nu * @template D The Document class */ export abstract class AbstractMathItem implements MathItem { - /** * The source text for the math (e.g., TeX string) */ @@ -304,7 +329,7 @@ export abstract class AbstractMathItem implements MathItem { protected _state: number = STATE.UNPROCESSED; /** - * @return {boolean} True when this item is an escaped delimiter + * @returns {boolean} True when this item is an escaped delimiter */ public get isEscaped(): boolean { return this.display === null; @@ -312,15 +337,19 @@ export abstract class AbstractMathItem implements MathItem { /** * @param {string} math The math expression for this item - * @param {Inputjax} jax The input jax to use for this item + * @param {InputJax} jax The input jax to use for this item * @param {boolean} display True if display mode, false if inline * @param {Location} start The starting position of the math in the document * @param {Location} end The ending position of the math in the document - * @constructor - */ - constructor (math: string, jax: InputJax, display: boolean = true, - start: Location = {i: 0, n: 0, delim: ''}, - end: Location = {i: 0, n: 0, delim: ''}) { + * @class + */ + constructor( + math: string, + jax: InputJax, + display: boolean = true, + start: Location = { i: 0, n: 0, delim: '' }, + end: Location = { i: 0, n: 0, delim: '' } + ) { this.math = math; this.inputJax = jax; this.display = display; @@ -343,7 +372,10 @@ export abstract class AbstractMathItem implements MathItem { /** * @override */ - public rerender(document: MathDocument, start: number = STATE.RERENDER) { + public rerender( + document: MathDocument, + start: number = STATE.RERENDER + ) { if (this.state() >= start) { this.state(start - 1); } @@ -372,7 +404,9 @@ export abstract class AbstractMathItem implements MathItem { */ public typeset(document: MathDocument) { if (this.state() < STATE.TYPESET) { - this.typesetRoot = document.outputJax[this.isEscaped ? 'escaped' : 'typeset'](this, document); + this.typesetRoot = document.outputJax[ + this.isEscaped ? 'escaped' : 'typeset' + ](this, document); this.state(STATE.TYPESET); } } @@ -385,17 +419,19 @@ export abstract class AbstractMathItem implements MathItem { /** * @override */ - public removeFromDocument(_restore: boolean = false) {} + public removeFromDocument(_restore: boolean = false) { + this.clear(); + } /** * @override */ - public setMetrics(em: number, ex: number, cwidth: number, lwidth: number, scale: number) { + public setMetrics(em: number, ex: number, cwidth: number, scale: number) { this.metrics = { - em: em, ex: ex, + em: em, + ex: ex, containerWidth: cwidth, - lineWidth: lwidth, - scale: scale + scale: scale, }; } @@ -425,6 +461,10 @@ export abstract class AbstractMathItem implements MathItem { this.state(STATE.UNPROCESSED, restore); } + /** + * @override + */ + clear() {} } /*****************************************************************/ @@ -432,7 +472,7 @@ export abstract class AbstractMathItem implements MathItem { * The various states that a MathItem (or MathDocument) can be in * (open-ended so that extensions can add to it) */ -export const STATE: {[state: string]: number} = { +export const STATE: { [state: string]: number } = { UNPROCESSED: 0, FINDMATH: 10, COMPILED: 20, @@ -441,7 +481,7 @@ export const STATE: {[state: string]: number} = { RERENDER: 125, TYPESET: 150, INSERTED: 200, - LAST: 10000 + LAST: 10000, }; /** diff --git a/ts/core/MathList.ts b/ts/core/MathList.ts index 3bd8f538d..dfd0da422 100644 --- a/ts/core/MathList.ts +++ b/ts/core/MathList.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the interface and abstract class for MathList objects + * @file Implements the interface and abstract class for MathList objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {LinkedList} from '../util/LinkedList.js'; -import {MathItem} from './MathItem.js'; +import { LinkedList } from '../util/LinkedList.js'; +import { MathItem } from './MathItem.js'; /*****************************************************************/ /** @@ -50,14 +50,17 @@ export interface MathList extends LinkedList> { * @template T The Text node class * @template D The Document class */ -export abstract class AbstractMathList extends -LinkedList> implements MathList { - +export abstract class AbstractMathList + extends LinkedList> + implements MathList +{ /** * @override */ public isBefore(a: MathItem, b: MathItem) { - return (a.start.i < b.start.i || (a.start.i === b.start.i && a.start.n < b.start.n)); + return ( + a.start.i < b.start.i || + (a.start.i === b.start.i && a.start.n < b.start.n) + ); } - } diff --git a/ts/core/MmlTree/Attributes.ts b/ts/core/MmlTree/Attributes.ts index 1da32a886..a6e055acd 100644 --- a/ts/core/MmlTree/Attributes.ts +++ b/ts/core/MmlTree/Attributes.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ */ /** - * @fileoverview Implements Attribute class for MmlNodes + * @file Implements Attribute class for MmlNodes * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList, Property} from '../Tree/Node.js'; +import { PropertyList, Property } from '../Tree/Node.js'; /** * A constant for when a property should be inherited from the global defaults lists @@ -58,7 +58,7 @@ export class Attributes { * @param {PropertyList} defaults The defaults for this node type * @param {PropertyList} global The global properties (from the math node) * - * @constructor + * @class */ constructor(defaults: PropertyList, global: PropertyList) { this.global = global; @@ -83,9 +83,16 @@ export class Attributes { Object.assign(this.attributes, list); } + /** + * @param {string} name The name of the attribute to remove + */ + public unset(name: string) { + delete this.attributes[name]; + } + /** * @param {string} name The name of the attribute whose value is to be returned - * @return {Property} The value of the named attribute (including inheritance and defaults) + * @returns {Property} The value of the named attribute (including inheritance and defaults) */ public get(name: string): Property { let value = this.attributes[name]; @@ -97,22 +104,40 @@ export class Attributes { /** * @param {string} name The value of the attribute whose value is to be returned - * @return {Property} The attribute whose name was given if it is explicit on the + * @returns {Property} The attribute whose name was given if it is explicit on the * node (not inherited or defaulted), null otherwise */ public getExplicit(name: string): Property { - if (!this.attributes.hasOwnProperty(name)) { - return undefined; + return this.hasExplicit(name) ? this.attributes[name] : undefined; + } + + /** + * @param {string} name The value of the attribute whose presence is to be checked + * @returns {boolean} True if the attribute is explicitly given on this node + */ + public hasExplicit(name: string): boolean { + return Object.hasOwn(this.attributes, name); + } + + /** + * @param {string[]} names The attribute names to look for. + * @returns {boolean} True if one of the names is an explicit attribute, false otherwise + */ + public hasOneOf(names: string[]): boolean { + for (const name of names) { + if (this.hasExplicit(name)) { + return true; + } } - return this.attributes[name]; + return false; } /** * @param {string[]} names The names of attributes whose values are to be returned - * @return {PropertyList} An object containing the attributes and their values + * @returns {PropertyList} An object containing the attributes and their values */ public getList(...names: string[]): PropertyList { - let values: PropertyList = {}; + const values: PropertyList = {}; for (const name of names) { values[name] = this.get(name); } @@ -129,7 +154,7 @@ export class Attributes { /** * @param {string} name The name of an inherited attribute whose value is to be returned - * @return {Property} The value of the named attribute if it is inherited, null otherwise + * @returns {Property} The value of the named attribute if it is inherited, null otherwise */ public getInherited(name: string): Property { return this.inherited[name]; @@ -137,7 +162,7 @@ export class Attributes { /** * @param {string} name The name of a default attribute whose value is to be returned - * @return {Property} The value of the named attribute if a default exists for it, null otherwise + * @returns {Property} The value of the named attribute if a default exists for it, null otherwise */ public getDefault(name: string): Property { return this.defaults[name]; @@ -145,75 +170,77 @@ export class Attributes { /** * @param {string} name The name of a attribute to check - * @return {boolean} True if attribute is set explicitly or inherited + * @returns {boolean} True if attribute is set explicitly or inherited * from an explicit mstyle or math attribute */ public isSet(name: string): boolean { - return this.attributes.hasOwnProperty(name) || this.inherited.hasOwnProperty(name); + return ( + Object.hasOwn(this.attributes, name) || + Object.hasOwn(this.inherited, name) + ); } /** * @param {string} name The name of an attribute to test for the existence of a default - * @return {boolean} True of there is a default for the named attribute, false otherwise + * @returns {boolean} True of there is a default for the named attribute, false otherwise */ public hasDefault(name: string): boolean { - return (name in this.defaults); + return name in this.defaults; } /** - * @return {string[]} The names of all the attributes explicitly set on the node + * @returns {string[]} The names of all the attributes explicitly set on the node */ public getExplicitNames(): string[] { return Object.keys(this.attributes); } /** - * @return {string[]} The names of all the inherited attributes for the node + * @returns {string[]} The names of all the inherited attributes for the node */ public getInheritedNames(): string[] { return Object.keys(this.inherited); } /** - * @return {string[]} The names of all the default attributes for the node + * @returns {string[]} The names of all the default attributes for the node */ public getDefaultNames(): string[] { return Object.keys(this.defaults); } /** - * @return {string[]} The names of all the global attributes + * @returns {string[]} The names of all the global attributes */ public getGlobalNames(): string[] { return Object.keys(this.global); } /** - * @return {PropertyList} The attribute object + * @returns {PropertyList} The attribute object */ public getAllAttributes(): PropertyList { return this.attributes; } /** - * @return {PropertyList} The inherited object + * @returns {PropertyList} The inherited object */ public getAllInherited(): PropertyList { return this.inherited; } /** - * @return {PropertyList} The defaults object + * @returns {PropertyList} The defaults object */ public getAllDefaults(): PropertyList { return this.defaults; } /** - * @return {PropertyList} The global object + * @returns {PropertyList} The global object */ public getAllGlobals(): PropertyList { return this.global; } - } diff --git a/ts/core/MmlTree/JsonMmlVisitor.ts b/ts/core/MmlTree/JsonMmlVisitor.ts index ec254ca69..1e292b678 100644 --- a/ts/core/MmlTree/JsonMmlVisitor.ts +++ b/ts/core/MmlTree/JsonMmlVisitor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,35 +16,35 @@ */ /** - * @fileoverview A visitor that produces a JSON version of an MmlNode tree + * @file A visitor that produces a JSON version of an MmlNode tree * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../Tree/Node.js'; -import {MmlVisitor} from './MmlVisitor.js'; -import {MmlNode, TextNode, XMLNode} from './MmlNode.js'; +import { PropertyList } from '../Tree/Node.js'; +import { MmlVisitor } from './MmlVisitor.js'; +import { MmlNode, TextNode, XMLNode } from './MmlNode.js'; export type MmlNodeJSON = { - kind: string, - texClass: number - isEmbellished?: boolean, - isSpacelike?: boolean, - isInferred?: boolean, - childNodes: MmlJSON[], - attributes: PropertyList, - inherited: PropertyList, - properties: PropertyList + kind: string; + texClass: number; + isEmbellished?: boolean; + isSpacelike?: boolean; + isInferred?: boolean; + childNodes: MmlJSON[]; + attributes: PropertyList; + inherited: PropertyList; + properties: PropertyList; }; export type MmlTextJSON = { - kind: string, - text: string + kind: string; + text: string; }; export type MmlXmlJSON = { - kind: string, - xml: any + kind: string; + xml: any; }; export type MmlJSON = MmlNodeJSON | MmlTextJSON | MmlXmlJSON; @@ -59,7 +59,7 @@ export class JsonMmlVisitor extends MmlVisitor { * Convert the tree rooted at a particular node into a JSON structure * * @param {MmlNode} node The node to use as the root of the tree to traverse - * @return {MmlJSON} The JSON object representing the internal tree + * @returns {MmlJSON} The JSON object representing the internal tree */ public visitTree(node: MmlNode): MmlJSON { return this.visitNode(node); @@ -67,18 +67,18 @@ export class JsonMmlVisitor extends MmlVisitor { /** * @param {TextNode} node The text node to visit - * @return {MmlJSON} The JSON for the text element + * @returns {MmlJSON} The JSON for the text element */ public visitTextNode(node: TextNode): MmlTextJSON { - return {kind: node.kind, text: node.getText()}; + return { kind: node.kind, text: node.getText() }; } /** * @param {XMLNode} node The XML node to visit - * @return {MmlJSON} The JSON for the XML node + * @returns {MmlJSON} The JSON for the XML node */ public visitXMLNode(node: XMLNode): MmlXmlJSON { - return {kind: node.kind, xml: node.getXML()}; + return { kind: node.kind, xml: node.getXML() }; } /** @@ -89,16 +89,16 @@ export class JsonMmlVisitor extends MmlVisitor { * Append the new node to the DOM parent. * * @param {MmlNode} node The node to visit - * @return {MmlJSON} The JSON object representing it + * @returns {MmlJSON} The JSON object representing it */ public visitDefault(node: MmlNode): MmlJSON { - let json: MmlJSON = { + const json: MmlJSON = { kind: node.kind.replace(/inferredM/, 'm'), texClass: node.texClass, attributes: this.getAttributes(node), inherited: this.getInherited(node), properties: this.getProperties(node), - childNodes: this.getChildren(node) + childNodes: this.getChildren(node), }; if (node.isInferred) { json.isInferred = true; @@ -114,10 +114,10 @@ export class JsonMmlVisitor extends MmlVisitor { /** * @param {MmlNode} node The node whose children are to be copied - * @return {MmlJSON[]} The array of child JSON objects + * @returns {MmlJSON[]} The array of child JSON objects */ public getChildren(node: MmlNode): MmlJSON[] { - let children = []; + const children = []; for (const child of node.childNodes) { children.push(this.visitNode(child)); } @@ -126,7 +126,7 @@ export class JsonMmlVisitor extends MmlVisitor { /** * @param {MmlNode} node The node whose attributes are to be copied - * @return {PropertyList} The object containing the attributes; + * @returns {PropertyList} The object containing the attributes; */ public getAttributes(node: MmlNode): PropertyList { return Object.assign({}, node.attributes.getAllAttributes()); @@ -134,7 +134,7 @@ export class JsonMmlVisitor extends MmlVisitor { /** * @param {MmlNode} node The node whose inherited attributes are to be copied - * @return {PropertyList} The object containing the inherited attributes; + * @returns {PropertyList} The object containing the inherited attributes; */ public getInherited(node: MmlNode): PropertyList { return Object.assign({}, node.attributes.getAllInherited()); @@ -142,10 +142,9 @@ export class JsonMmlVisitor extends MmlVisitor { /** * @param {MmlNode} node The node whose properties are to be copied - * @return {PropertyList} The object containing the properties; + * @returns {PropertyList} The object containing the properties; */ public getProperties(node: MmlNode): PropertyList { return Object.assign({}, node.getAllProperties()); } - } diff --git a/ts/core/MmlTree/LegacyMmlVisitor.ts b/ts/core/MmlTree/LegacyMmlVisitor.ts index b39b528a5..7013c49e7 100644 --- a/ts/core/MmlTree/LegacyMmlVisitor.ts +++ b/ts/core/MmlTree/LegacyMmlVisitor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,19 @@ */ /** - * @fileoverview A visitor to convert the new to the old internal format. + * @file A visitor to convert the new to the old internal format. * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MmlVisitor} from './MmlVisitor.js'; -import {MmlNode, TextNode, XMLNode} from './MmlNode.js'; +import { MmlVisitor } from './MmlVisitor.js'; +import { MmlNode, TextNode, XMLNode } from './MmlNode.js'; /** * Get access to legacy MML Element Jax */ -declare var MathJax: any; -let MML = MathJax.ElementJax.mml; +declare const MathJax: any; +const MML = MathJax.ElementJax.mml; /*****************************************************************/ /** @@ -36,13 +36,12 @@ let MML = MathJax.ElementJax.mml; */ export class LegacyMmlVisitor extends MmlVisitor { - /** * Convert the tree rooted at a particular node into the old-style * internal format used by MathJax v2. * * @param {MmlNode} node The node to use as the root of the tree to traverse - * @return {any} The old-style internal format equivalent of the tree + * @returns {any} The old-style internal format equivalent of the tree */ public visitTree(node: MmlNode): any { let root = MML.mrow(); @@ -93,7 +92,7 @@ export class LegacyMmlVisitor extends MmlVisitor { * @param {any} parent The old-style parent to which this node should be added */ public visitDefault(node: MmlNode, parent: any) { - let mml = MML[node.kind](); + const mml = MML[node.kind](); this.addAttributes(node, mml); this.addProperties(node, mml); for (const child of node.childNodes) { @@ -107,8 +106,8 @@ export class LegacyMmlVisitor extends MmlVisitor { * @param {any} mml The old-style node to which attributes are being added */ public addAttributes(node: MmlNode, mml: any) { - let attributes = node.attributes; - let names = attributes.getExplicitNames(); + const attributes = node.attributes; + const names = attributes.getExplicitNames(); for (const name of names) { mml[name] = attributes.getExplicit(name); } @@ -119,10 +118,9 @@ export class LegacyMmlVisitor extends MmlVisitor { * @param {any} mml The old-stype node to which the properties are being copied */ public addProperties(node: MmlNode, mml: any) { - let names = node.getPropertyNames(); + const names = node.getPropertyNames(); for (const name of names) { mml[name] = node.getProperty(name); } } - } diff --git a/ts/core/MmlTree/MML.ts b/ts/core/MmlTree/MML.ts index 939398187..199081b07 100644 --- a/ts/core/MmlTree/MML.ts +++ b/ts/core/MmlTree/MML.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,51 +16,60 @@ */ /** - * @fileoverview An object listing all the MathML node types + * @file An object listing all the MathML node types * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MmlNodeClass, TextNode, XMLNode} from './MmlNode.js'; - -import {MmlMath} from './MmlNodes/math.js'; - -import {MmlMi} from './MmlNodes/mi.js'; -import {MmlMn} from './MmlNodes/mn.js'; -import {MmlMo} from './MmlNodes/mo.js'; -import {MmlMtext} from './MmlNodes/mtext.js'; -import {MmlMspace} from './MmlNodes/mspace.js'; -import {MmlMs} from './MmlNodes/ms.js'; - -import {MmlMrow, MmlInferredMrow} from './MmlNodes/mrow.js'; -import {MmlMfrac} from './MmlNodes/mfrac.js'; -import {MmlMsqrt} from './MmlNodes/msqrt.js'; -import {MmlMroot} from './MmlNodes/mroot.js'; -import {MmlMstyle} from './MmlNodes/mstyle.js'; -import {MmlMerror} from './MmlNodes/merror.js'; -import {MmlMpadded} from './MmlNodes/mpadded.js'; -import {MmlMphantom} from './MmlNodes/mphantom.js'; -import {MmlMfenced} from './MmlNodes/mfenced.js'; -import {MmlMenclose} from './MmlNodes/menclose.js'; - -import {MmlMaction} from './MmlNodes/maction.js'; - -import {MmlMsubsup, MmlMsub, MmlMsup} from './MmlNodes/msubsup.js'; -import {MmlMunderover, MmlMunder, MmlMover} from './MmlNodes/munderover.js'; -import {MmlMmultiscripts, MmlMprescripts, MmlNone} from './MmlNodes/mmultiscripts.js'; - -import {MmlMtable} from './MmlNodes/mtable.js'; -import {MmlMtr, MmlMlabeledtr} from './MmlNodes/mtr.js'; -import {MmlMtd} from './MmlNodes/mtd.js'; -import {MmlMaligngroup} from './MmlNodes/maligngroup.js'; -import {MmlMalignmark} from './MmlNodes/malignmark.js'; - -import {MmlMglyph} from './MmlNodes/mglyph.js'; - -import {MmlSemantics, MmlAnnotation, MmlAnnotationXML} from './MmlNodes/semantics.js'; - -import {TeXAtom} from './MmlNodes/TeXAtom.js'; -import {MathChoice} from './MmlNodes/mathchoice.js'; +import { MmlNodeClass, TextNode, XMLNode } from './MmlNode.js'; + +import { MmlMath } from './MmlNodes/math.js'; + +import { MmlMi } from './MmlNodes/mi.js'; +import { MmlMn } from './MmlNodes/mn.js'; +import { MmlMo } from './MmlNodes/mo.js'; +import { MmlMtext } from './MmlNodes/mtext.js'; +import { MmlMspace } from './MmlNodes/mspace.js'; +import { MmlMs } from './MmlNodes/ms.js'; + +import { MmlMrow, MmlInferredMrow } from './MmlNodes/mrow.js'; +import { MmlMfrac } from './MmlNodes/mfrac.js'; +import { MmlMsqrt } from './MmlNodes/msqrt.js'; +import { MmlMroot } from './MmlNodes/mroot.js'; +import { MmlMstyle } from './MmlNodes/mstyle.js'; +import { MmlMerror } from './MmlNodes/merror.js'; +import { MmlMpadded } from './MmlNodes/mpadded.js'; +import { MmlMphantom } from './MmlNodes/mphantom.js'; +import { MmlMfenced } from './MmlNodes/mfenced.js'; +import { MmlMenclose } from './MmlNodes/menclose.js'; + +import { MmlMaction } from './MmlNodes/maction.js'; + +import { MmlMsubsup, MmlMsub, MmlMsup } from './MmlNodes/msubsup.js'; +import { MmlMunderover, MmlMunder, MmlMover } from './MmlNodes/munderover.js'; +import { + MmlMmultiscripts, + MmlMprescripts, + MmlNone, +} from './MmlNodes/mmultiscripts.js'; + +import { MmlMtable } from './MmlNodes/mtable.js'; +import { MmlMtr, MmlMlabeledtr } from './MmlNodes/mtr.js'; +import { MmlMtd } from './MmlNodes/mtd.js'; +import { MmlMaligngroup } from './MmlNodes/maligngroup.js'; +import { MmlMalignmark } from './MmlNodes/malignmark.js'; + +import { MmlMglyph } from './MmlNodes/mglyph.js'; + +import { + MmlSemantics, + MmlAnnotation, + MmlAnnotationXML, +} from './MmlNodes/semantics.js'; + +import { TeXAtom } from './MmlNodes/TeXAtom.js'; +import { MathChoice } from './MmlNodes/mathchoice.js'; +import { HtmlNode } from './MmlNodes/HtmlNode.js'; /************************************************************************/ /** @@ -70,7 +79,7 @@ import {MathChoice} from './MmlNodes/mathchoice.js'; * classes as necessary. */ -export let MML: {[kind: string]: MmlNodeClass} = { +export const MML: { [kind: string]: MmlNodeClass } = { [MmlMath.prototype.kind]: MmlMath, [MmlMi.prototype.kind]: MmlMi, @@ -121,5 +130,6 @@ export let MML: {[kind: string]: MmlNodeClass} = { [MathChoice.prototype.kind]: MathChoice, [TextNode.prototype.kind]: TextNode, - [XMLNode.prototype.kind]: XMLNode + [XMLNode.prototype.kind]: XMLNode, + [HtmlNode.prototype.kind]: HtmlNode, }; diff --git a/ts/core/MmlTree/MathMLVisitor.ts b/ts/core/MmlTree/MathMLVisitor.ts index efc585001..c1e5ea8ee 100644 --- a/ts/core/MmlTree/MathMLVisitor.ts +++ b/ts/core/MmlTree/MathMLVisitor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,14 @@ */ /** - * @fileoverview A visitor that produces MathML DOM nodes from the iternal nodes + * @file A visitor that produces MathML DOM nodes from the internal nodes * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MmlVisitor} from './MmlVisitor.js'; -import {MmlNode, TextNode, XMLNode} from './MmlNode.js'; +import { MmlVisitor } from './MmlVisitor.js'; +import { MmlNode, TextNode, XMLNode } from './MmlNode.js'; +import { HtmlNode } from './MmlNodes/HtmlNode.js'; /*****************************************************************/ /** @@ -40,11 +41,11 @@ export class MathMLVisitor extends MmlVisitor { * * @param {MmlNode} node The node to use as the root of the tree to traverse * @param {Document} document The document in which the nodes are created - * @return {Node} The MathML DOM nodes representing the internal tree + * @returns {Node} The MathML DOM nodes representing the internal tree */ public visitTree(node: MmlNode, document: Document): Node { this.document = document; - let root = document.createElement('top'); + const root = document.createElement('top'); this.visitNode(node, root); this.document = null; return root.firstChild; @@ -66,6 +67,14 @@ export class MathMLVisitor extends MmlVisitor { parent.appendChild((node.getXML() as Element).cloneNode(true)); } + /** + * @param {HtmlNode} node The HTML node to visit + * @param {Element} parent The DOM parent to which this node should be added + */ + public visitHtmlNode(node: HtmlNode, parent: Element) { + parent.appendChild((node.getHTML() as Element).cloneNode(true)); + } + /** * Visit an inferred mrow, but don't add the inferred row itself (since * it is supposed to be inferred). @@ -90,23 +99,22 @@ export class MathMLVisitor extends MmlVisitor { * @param {Element} parent The DOM parent to which this node should be added */ public visitDefault(node: MmlNode, parent: Element) { - let mml = this.document.createElement(node.kind); + const mml = this.document.createElement(this.getKind(node)); this.addAttributes(node, mml); for (const child of node.childNodes) { this.visitNode(child, mml); } parent.appendChild(mml); } + /** * @param {MmlNode} node The node who attributes are to be copied * @param {Element} mml The MathML DOM node to which attributes are being added */ public addAttributes(node: MmlNode, mml: Element) { - let attributes = node.attributes; - let names = attributes.getExplicitNames(); - for (const name of names) { - mml.setAttribute(name, attributes.getExplicit(name).toString()); + const attributes = this.getAttributeList(node); + for (const name of Object.keys(attributes)) { + mml.setAttribute(name, attributes[name].toString()); } } - } diff --git a/ts/core/MmlTree/MmlFactory.ts b/ts/core/MmlTree/MmlFactory.ts index 2df52c88f..99bd4c3e3 100644 --- a/ts/core/MmlTree/MmlFactory.ts +++ b/ts/core/MmlTree/MmlFactory.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ */ /** - * @fileoverview Implements the MmlFactory to create Mml Nodes + * @file Implements the MmlFactory to create Mml Nodes * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractNodeFactory} from '../Tree/NodeFactory.js'; -import {MmlNode, MmlNodeClass} from './MmlNode.js'; -import {MML} from './MML.js'; +import { AbstractNodeFactory } from '../Tree/NodeFactory.js'; +import { MmlNode, MmlNodeClass } from './MmlNode.js'; +import { MML } from './MML.js'; /*****************************************************************/ /** @@ -31,18 +31,16 @@ import {MML} from './MML.js'; */ export class MmlFactory extends AbstractNodeFactory { - /** * The default node-creation functions */ public static defaultNodes = MML; /** - * @return {Object} The list of node-creation functions (similar to the + * @returns {object} The list of node-creation functions (similar to the * MML object from MathJax v2). */ - get MML(): Object { + get MML(): object { return this.node; } - } diff --git a/ts/core/MmlTree/MmlNode.ts b/ts/core/MmlTree/MmlNode.ts index b63f8a0b8..c19b49414 100644 --- a/ts/core/MmlTree/MmlNode.ts +++ b/ts/core/MmlTree/MmlNode.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,24 +16,32 @@ */ /** - * @fileoverview Interfaces and abstract classes for MmlNode objects + * @file Interfaces and abstract classes for MmlNode objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {Attributes, INHERIT} from './Attributes.js'; -import {Property, PropertyList, Node, AbstractNode, AbstractEmptyNode, NodeClass} from '../Tree/Node.js'; -import {MmlFactory} from './MmlFactory.js'; -import {DOMAdaptor} from '../DOMAdaptor.js'; +import { Attributes, INHERIT } from './Attributes.js'; +import { + Property, + PropertyList, + Node, + AbstractNode, + AbstractEmptyNode, + NodeClass, +} from '../Tree/Node.js'; +import { MmlFactory } from './MmlFactory.js'; +import { DOMAdaptor } from '../DOMAdaptor.js'; /** * Used in setInheritedAttributes() to pass originating node kind as well as property value */ -export type AttributeList = {[attribute: string]: [string, Property]}; +export type AttributeList = { [attribute: string]: [string, Property] }; /** * These are the TeX classes for spacing computations */ +/* prettier-ignore */ export const TEXCLASS = { ORD: 0, OP: 1, @@ -43,20 +51,34 @@ export const TEXCLASS = { CLOSE: 5, PUNCT: 6, INNER: 7, - VCENTER: 8, // Used in TeXAtom, but not for spacing - NONE: -1 + NONE: -1, }; -export const TEXCLASSNAMES = ['ORD', 'OP', 'BIN', 'REL', 'OPEN', 'CLOSE', 'PUNCT', 'INNER', 'VCENTER']; +export const TEXCLASSNAMES = [ + 'ORD', + 'OP', + 'BIN', + 'REL', + 'OPEN', + 'CLOSE', + 'PUNCT', + 'INNER', +]; /** * The spacing sizes used by the TeX spacing table below. */ -const TEXSPACELENGTH = ['', 'thinmathspace', 'mediummathspace', 'thickmathspace']; +const TEXSPACELENGTH = [ + '', + 'thinmathspace', + 'mediummathspace', + 'thickmathspace', +]; /** * See TeXBook Chapter 18 (p. 170) */ +/* prettier-ignore */ const TEXSPACE = [ [ 0, -1, 2, 3, 0, 0, 0, 1], // ORD [-1, -1, 0, 3, 0, 0, 0, 1], // OP @@ -68,12 +90,39 @@ const TEXSPACE = [ [ 1, -1, 2, 3, 1, 0, 1, 1] // INNER ]; +/** + * The valid mathvariants + */ + +export const MATHVARIANTS = new Set([ + 'normal', + 'bold', + 'italic', + 'bold-italic', + 'double-struck', + 'fraktur', + 'bold-fraktur', + 'script', + 'bold-script', + 'sans-serif', + 'bold-sans-serif', + 'sans-serif-italic', + 'sans-serif-bold-italic', + 'monospace', + 'inital', + 'tailed', + 'looped', + 'stretched', +]); + /** * Attributes used to determine indentation and shifting */ export const indentAttributes = [ - 'indentalign', 'indentalignfirst', - 'indentshift', 'indentshiftfirst' + 'indentalign', + 'indentalignfirst', + 'indentshift', + 'indentshiftfirst', ]; /** @@ -86,8 +135,7 @@ export type MMLNODE = MmlNode | TextNode | XMLNode; * The MmlNode interface (extends Node interface) */ -export interface MmlNode extends Node { - +export interface MmlNode extends Node { /** * Test various properties of MathML nodes */ @@ -95,7 +143,7 @@ export interface MmlNode extends Node { readonly isEmbellished: boolean; readonly isSpacelike: boolean; readonly linebreakContainer: boolean; - readonly hasNewLine: boolean; + readonly linebreakAlign: string; /** * The expected number of children (-1 means use inferred mrow) @@ -115,9 +163,17 @@ export interface MmlNode extends Node { */ parent: MmlNode; + /** + * @ override + */ + childNodes: MmlNode[]; + /** * values needed for TeX spacing computations */ + /** + * The TeX class for this node + */ texClass: number; prevClass: number; prevLevel: number; @@ -128,43 +184,51 @@ export interface MmlNode extends Node { attributes: Attributes; /** - * @return {MmlNode} For embellished operators, the child node that contains the + * @override + * + * @param {boolean} keepIds True if id attributes should be preserved + * @returns {MmlNode} A copy of the MmlNode and its children (without inherited attributes) + */ + copy(keepIds?: boolean): MmlNode; + + /** + * @returns {MmlNode} For embellished operators, the child node that contains the * core node. For non-embellished nodes, the original node. */ core(): MmlNode; /** - * @return {MmlNode} For embellished operators, the core element (at whatever + * @returns {MmlNode} For embellished operators, the core element (at whatever * depth). For non-embellished nodes, the original node itself. */ coreMO(): MmlNode; /** - * @return {number} For embellished operators, the index of the child node containing + * @returns {number} For embellished operators, the index of the child node containing * the core . For non-embellished nodes, 0. */ coreIndex(): number; /** - * @return {number} The index of this node in its parent's childNodes array. + * @returns {number} The index of this node in its parent's childNodes array. */ childPosition(): number; /** * @param {MmlNode} prev The node that is before this one for TeX spacing purposes * (not all nodes count in TeX measurements) - * @return {MmlNode} The node that should be the previous node for the next one + * @returns {MmlNode} The node that should be the previous node for the next one * in the tree (usually, either the last child, or the node itself) */ setTeXclass(prev: MmlNode): MmlNode; /** - * @return {string} The spacing to use before this element (one of TEXSPACELENGTH array above) + * @returns {string} The spacing to use before this element (one of TEXSPACELENGTH array above) */ texSpacing(): string; /** - * @return {boolean} The core mo element has an explicit 'form', 'lspace', or 'rspace' attribute + * @returns {boolean} The core mo element has an explicit 'form', 'lspace', or 'rspace' attribute */ hasSpacingAttributes(): boolean; @@ -177,7 +241,12 @@ export interface MmlNode extends Node { * @param {number} level The scriptlevel to inherit * @param {boolean} prime The TeX prime style to inherit (T vs. T', etc). */ - setInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean): void; + setInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ): void; /** * Set the nodes inherited attributes based on the attributes of the given node @@ -193,7 +262,7 @@ export interface MmlNode extends Node { * @param {string} message The error message to use * @param {PropertyList} options The options telling how much to verify * @param {boolean} short True means use just the kind if not using full errors - * @return {MmlNode} The construted merror + * @returns {MmlNode} The construted merror */ mError(message: string, options: PropertyList, short?: boolean): MmlNode; @@ -205,14 +274,12 @@ export interface MmlNode extends Node { verifyTree(options?: PropertyList): void; } - /*****************************************************************/ /** * The MmlNode class interface (extends the NodeClass) */ -export interface MmlNodeClass extends NodeClass { - +export interface MmlNodeClass extends NodeClass { /** * The list of default attribute values for nodes of this class */ @@ -223,33 +290,37 @@ export interface MmlNodeClass extends NodeClass { * of attributes, and an array of children and returns the desired MmlNode with * those attributes and children * - * @constructor + * @class * @param {MmlFactory} factory The MathML node factory to use to create additional nodes * @param {PropertyList} attributes The list of initial attributes for the node * @param {MmlNode[]} children The initial child nodes (more can be added later) */ - new (factory: MmlFactory, attributes?: PropertyList, children?: MmlNode[]): MmlNode; - + new ( + factory: MmlFactory, + attributes?: PropertyList, + children?: MmlNode[] + ): MmlNode; } - /*****************************************************************/ /** * The abstract MmlNode class (extends the AbstractNode class and implements * the IMmlNode interface) */ -export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { - +export abstract class AbstractMmlNode + extends AbstractNode + implements MmlNode +{ /** * The properties common to all MathML nodes */ public static defaults: PropertyList = { mathbackground: INHERIT, mathcolor: INHERIT, - mathsize: INHERIT, // technically only for token elements, but should + mathsize: INHERIT, // technically only for token elements, but should // scale all spaces, fractions, etc. - dir: INHERIT + dir: INHERIT, }; /** @@ -260,24 +331,52 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { * * For example, an mpadded element will not inherit a width attribute from an mstyle node. */ - public static noInherit: {[node1: string]: {[node2: string]: {[attribute: string]: boolean}}} = { + public static noInherit: { + [node1: string]: { [node2: string]: { [attribute: string]: boolean } }; + } = { mstyle: { - mpadded: {width: true, height: true, depth: true, lspace: true, voffset: true}, - mtable: {width: true, height: true, depth: true, align: true} + mpadded: { + width: true, + height: true, + depth: true, + lspace: true, + voffset: true, + }, + mtable: { width: true, height: true, depth: true, align: true }, }, maligngroup: { - mrow: {groupalign: true}, - mtable: {groupalign: true} - } + mrow: { groupalign: true }, + mtable: { groupalign: true }, + }, + mtr: { + msqrt: { 'data-vertical-align': true }, + mroot: { 'data-vertical-align': true }, + }, + mlabeledtr: { + msqrt: { 'data-vertical-align': true }, + mroot: { 'data-vertical-align': true }, + }, + }; + + /** + * This lists the attributes that should not be propagated to child nodes of the + * given kind of node (so that table attributes don't bleed through to nested + * tables -- see issue mathjax/MathJax#2890). + */ + public static stopInherit: { + [node: string]: { [attribute: string]: boolean }; + } = { + mtd: { columnalign: true, rowalign: true, groupalign: true }, }; /** * This lists the attributes that should always be inherited, * even when there is no default value for the attribute. */ - public static alwaysInherit: {[name: string]: boolean} = { + public static alwaysInherit: { [name: string]: boolean } = { scriptminsize: true, - scriptsizemultiplier: true + scriptsizemultiplier: true, + infixlinebreakstyle: true, }; /** @@ -286,9 +385,10 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { public static verifyDefaults: PropertyList = { checkArity: true, checkAttributes: false, + checkMathvariants: true, fullErrors: false, fixMmultiscripts: true, - fixMtables: true + fixMtables: true, }; /* @@ -339,7 +439,11 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { * * @override */ - constructor(factory: MmlFactory, attributes: PropertyList = {}, children: MmlNode[] = []) { + constructor( + factory: MmlFactory, + attributes: PropertyList = {}, + children: MmlNode[] = [] + ) { super(factory); if (this.arity < 0) { this.childNodes = [factory.create('inferredMrow')]; @@ -357,12 +461,11 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { * @override * * @param {boolean} keepIds True to copy id attributes, false to skip them. - * (May cause error in the future, since not part of the interface.) - * @return {AbstractMmlNode} The copied node tree. + * @returns {AbstractMmlNode} The copied node tree. */ public copy(keepIds: boolean = false): AbstractMmlNode { const node = this.factory.create(this.kind) as AbstractMmlNode; - node.properties = {...this.properties}; + node.properties = { ...this.properties }; if (this.attributes) { const attributes = this.attributes.getAllAttributes(); for (const name of Object.keys(attributes)) { @@ -388,56 +491,57 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { } /** - * The TeX class for this node + * @override */ public get texClass(): number { return this.texclass; } /** - * The TeX class for this node + * @override */ public set texClass(texClass: number) { this.texclass = texClass; } /** - * @return {boolean} true if this is a token node + * @returns {boolean} true if this is a token node */ public get isToken(): boolean { return false; } /** - * @return {boolean} true if this is an embellished operator + * @returns {boolean} true if this is an embellished operator */ public get isEmbellished(): boolean { return false; } /** - * @return {boolean} true if this is a space-like node + * @returns {boolean} true if this is a space-like node */ public get isSpacelike(): boolean { return false; } /** - * @return {boolean} true if this is a node that supports linebreaks in its children + * @returns {boolean} true if this is a node that supports linebreaks in its children */ public get linebreakContainer(): boolean { return false; } /** - * @return {boolean} true if this node contains a line break + * @returns {string} the attribute used to seed the indentalign value in + * linebreak containers (overridden in subclasses when needed) */ - public get hasNewLine(): boolean { - return false; + public get linebreakAlign(): string { + return 'data-align'; } /** - * @return {number} The number of children allowed, or Infinity for any number, + * @returns {number} The number of children allowed, or Infinity for any number, * or -1 for when an inferred row is needed for the children. * Special case is 1, meaning at least one (other numbers * mean exactly that many). @@ -447,14 +551,14 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { } /** - * @return {boolean} true if this is an inferred mrow + * @returns {boolean} true if this is an inferred mrow */ public get isInferred(): boolean { return false; } /** - * @return {MmlNode} The logical parent of this node (skipping over inferred rows + * @returns {MmlNode} The logical parent of this node (skipping over inferred rows * some other node types) */ public get Parent(): MmlNode { @@ -466,14 +570,14 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { } /** - * @return {boolean} true if this is a node that doesn't count as a parent node in Parent() + * @returns {boolean} true if this is a node that doesn't count as a parent node in Parent() */ public get notParent(): boolean { return false; } /** - * If there is an inferred row, the the children of that instead + * If there is an inferred row, set the children of that instead * * @override */ @@ -554,12 +658,13 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { * @override */ public childPosition() { - let child: MmlNode = this; - let parent = child.parent; + let child: MmlNode = null; + let parent = this.parent; while (parent && parent.notParent) { child = parent; parent = parent.parent; } + child = child || this; if (parent) { let i = 0; for (const node of parent.childNodes) { @@ -577,7 +682,7 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { */ public setTeXclass(prev: MmlNode): MmlNode { this.getPrevClass(prev); - return (this.texClass != null ? this : prev); + return this.texClass != null ? this : prev; } /** * For embellished operators, get the data from the core and clear the core @@ -605,29 +710,27 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { } /** - * @return {string} returns the spacing to use before this node + * @returns {string} returns the spacing to use before this node */ public texSpacing(): string { - let prevClass = (this.prevClass != null ? this.prevClass : TEXCLASS.NONE); - let texClass = this.texClass || TEXCLASS.ORD; + const prevClass = this.prevClass != null ? this.prevClass : TEXCLASS.NONE; + const texClass = this.texClass || TEXCLASS.ORD; if (prevClass === TEXCLASS.NONE || texClass === TEXCLASS.NONE) { return ''; } - if (prevClass === TEXCLASS.VCENTER) { - prevClass = TEXCLASS.ORD; - } - if (texClass === TEXCLASS.VCENTER) { - texClass = TEXCLASS.ORD; - } - let space = TEXSPACE[prevClass][texClass]; - if ((this.prevLevel > 0 || this.attributes.get('scriptlevel') > 0) && space >= 0) { + const space = TEXSPACE[prevClass][texClass]; + if ( + (this.prevLevel > 0 || + (this.attributes.get('scriptlevel') as number) > 0) && + space >= 0 + ) { return ''; } return TEXSPACELENGTH[Math.abs(space)]; } /** - * @return {boolean} The core mo element has an explicit 'form' attribute + * @returns {boolean} The core mo element has an explicit 'form' attribute */ public hasSpacingAttributes(): boolean { return this.isEmbellished && this.coreMO().hasSpacingAttributes(); @@ -643,36 +746,51 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { * If the node doesn't have an explicit scriptstyle, inherit it * If the prime style is true, set it as a property (it is not a MathML attribute) * Check that the number of children is correct - * Finally, push any inherited attributes to teh children. + * Reset the indent attributes for linebreak containers + * Finally, push any inherited attributes to the children. * * @override */ - public setInheritedAttributes(attributes: AttributeList = {}, - display: boolean = false, level: number = 0, prime: boolean = false) { - let defaults = this.attributes.getAllDefaults(); + public setInheritedAttributes( + attributes: AttributeList = {}, + display: boolean = false, + level: number = 0, + prime: boolean = false + ) { + const defaults = this.attributes.getAllDefaults(); for (const key of Object.keys(attributes)) { - if (defaults.hasOwnProperty(key) || AbstractMmlNode.alwaysInherit.hasOwnProperty(key)) { - let [node, value] = attributes[key]; - let noinherit = (AbstractMmlNode.noInherit[node] || {})[this.kind] || {}; - if (!noinherit[key]) { + if ( + Object.hasOwn(defaults, key) || + Object.hasOwn(AbstractMmlNode.alwaysInherit, key) + ) { + const [node, value] = attributes[key]; + if (!AbstractMmlNode.noInherit[node]?.[this.kind]?.[key]) { this.attributes.setInherited(key, value); } } + if (AbstractMmlNode.stopInherit[this.kind]?.[key]) { + attributes = { ...attributes }; + delete attributes[key]; + } } - let displaystyle = this.attributes.getExplicit('displaystyle'); + const displaystyle = this.attributes.getExplicit('displaystyle'); if (displaystyle === undefined) { this.attributes.setInherited('displaystyle', display); } - let scriptlevel = this.attributes.getExplicit('scriptlevel'); + const scriptlevel = this.attributes.getExplicit('scriptlevel'); if (scriptlevel === undefined) { this.attributes.setInherited('scriptlevel', level); } if (prime) { this.setProperty('texprimestyle', prime); } - let arity = this.arity; - if (arity >= 0 && arity !== Infinity && ((arity === 1 && this.childNodes.length === 0) || - (arity !== 1 && this.childNodes.length !== arity))) { + const arity = this.arity; + if ( + arity >= 0 && + arity !== Infinity && + ((arity === 1 && this.childNodes.length === 0) || + (arity !== 1 && this.childNodes.length !== arity)) + ) { // // Make sure there are the right number of child nodes // (trim them or add empty mrows) @@ -685,6 +803,23 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { } } } + // + // If this is a linebreak container, reset the indent attributes + // + if (this.linebreakContainer && !this.isEmbellished) { + const align = this.linebreakAlign; + if (align) { + const indentalign = this.attributes.get(align) || 'left'; + attributes = this.addInheritedAttributes(attributes, { + indentalign, + indentshift: '0', + indentalignfirst: indentalign, + indentshiftfirst: '0', + indentalignlast: 'indentalign', + indentshiftlast: 'indentshift', + }); + } + } this.setChildInheritedAttributes(attributes, display, level, prime); } /** @@ -697,22 +832,37 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { * @param {number} level The scriptlevel to inherit * @param {boolean} prime The TeX prime style to inherit (T vs. T', etc). */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { for (const child of this.childNodes) { child.setInheritedAttributes(attributes, display, level, prime); } } + /** * Used by subclasses to add their own attributes to the inherited list * (e.g., mstyle uses this to augment the inherited attibutes) * * @param {AttributeList} current The current list of inherited attributes * @param {PropertyList} attributes The new attributes to add into the list + * + * @returns {AttributeList} The updated attributes list. */ - protected addInheritedAttributes(current: AttributeList, attributes: PropertyList) { - let updated: AttributeList = {...current}; + protected addInheritedAttributes( + current: AttributeList, + attributes: PropertyList + ): AttributeList { + const updated: AttributeList = { ...current }; for (const name of Object.keys(attributes)) { - if (name !== 'displaystyle' && name !== 'scriptlevel' && name !== 'style') { + if ( + name !== 'displaystyle' && + name !== 'scriptlevel' && + name !== 'style' + ) { updated[name] = [this.kind, attributes[name]]; } } @@ -729,10 +879,10 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { const attributes = node.attributes; const display = attributes.get('displaystyle') as boolean; const scriptlevel = attributes.get('scriptlevel') as number; - const defaults: AttributeList = (!attributes.isSet('mathsize') ? {} : { - mathsize: ['math', attributes.get('mathsize')] - }); - const prime = node.getProperty('texprimestyle') as boolean || false; + const defaults: AttributeList = !attributes.isSet('mathsize') + ? {} + : { mathsize: ['math', attributes.get('mathsize')] }; + const prime = (node.getProperty('texprimestyle') as boolean) || false; this.setInheritedAttributes(defaults, display, scriptlevel, prime); } @@ -747,12 +897,19 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { return; } this.verifyAttributes(options); - let arity = this.arity; + const arity = this.arity; if (options['checkArity']) { - if (arity >= 0 && arity !== Infinity && - ((arity === 1 && this.childNodes.length === 0) || - (arity !== 1 && this.childNodes.length !== arity))) { - this.mError('Wrong number of children for "' + this.kind + '" node', options, true); + if ( + arity >= 0 && + arity !== Infinity && + ((arity === 1 && this.childNodes.length === 0) || + (arity !== 1 && this.childNodes.length !== arity)) + ) { + this.mError( + 'Wrong number of children for "' + this.kind + '" node', + options, + true + ); } } this.verifyChildren(options); @@ -764,19 +921,35 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { * @param {PropertyList} options The options telling how much to verify */ protected verifyAttributes(options: PropertyList) { - if (options['checkAttributes']) { + if (options.checkAttributes) { const attributes = this.attributes; const bad = []; for (const name of attributes.getExplicitNames()) { - if (name.substr(0, 5) !== 'data-' && attributes.getDefault(name) === undefined && - !name.match(/^(?:class|style|id|(?:xlink:)?href)$/)) { + if ( + name.substring(0, 5) !== 'data-' && + attributes.getDefault(name) === undefined && + !name.match(/^(?:class|style|id|(?:xlink:)?href)$/) + ) { // FIXME: provide a configurable checker for names that are OK bad.push(name); } // FIXME: add ability to check attribute values? } if (bad.length) { - this.mError('Unknown attributes for ' + this.kind + ' node: ' + bad.join(', '), options); + this.mError( + 'Unknown attributes for ' + this.kind + ' node: ' + bad.join(', '), + options + ); + } + } + if (options.checkMathvariants) { + const variant = this.attributes.getExplicit('mathvariant') as string; + if ( + variant && + !MATHVARIANTS.has(variant) && + !this.getProperty('ignore-variant') + ) { + this.mError(`Invalid mathvariant: ${variant}`, options, true); } } } @@ -798,28 +971,34 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { * @param {string} message The error message to use * @param {PropertyList} options The options telling how much to verify * @param {boolean} short True means use just the kind if not using full errors - * @return {MmlNode} The constructed merror + * @returns {MmlNode} The constructed merror */ - public mError(message: string, options: PropertyList, short: boolean = false): MmlNode { + public mError( + message: string, + options: PropertyList, + short: boolean = false + ): MmlNode { if (this.parent && this.parent.isKind('merror')) { return null; } - let merror = this.factory.create('merror'); + const merror = this.factory.create('merror'); merror.attributes.set('data-mjx-message', message); - if (options['fullErrors'] || short) { - let mtext = this.factory.create('mtext'); - let text = this.factory.create('text') as TextNode; - text.setText(options['fullErrors'] ? message : this.kind); + if (options.fullErrors || short) { + const mtext = this.factory.create('mtext'); + const text = this.factory.create('text') as any as TextNode; + text.setText(options.fullErrors ? message : this.kind); mtext.appendChild(text); merror.appendChild(mtext); this.parent.replaceChild(merror, this); + if (!options.fullErrors) { + merror.attributes.set('title', message); + } } else { this.parent.replaceChild(merror, this); merror.appendChild(this); } return merror; } - } /*****************************************************************/ @@ -828,14 +1007,13 @@ export abstract class AbstractMmlNode extends AbstractNode implements MmlNode { */ export abstract class AbstractMmlTokenNode extends AbstractMmlNode { - /** * Add the attributes common to all token nodes */ public static defaults: PropertyList = { - ...AbstractMmlNode.defaults, + ...AbstractMmlNode.defaults, mathvariant: 'normal', - mathsize: INHERIT + mathsize: INHERIT, }; /** @@ -848,12 +1026,16 @@ export abstract class AbstractMmlTokenNode extends AbstractMmlNode { /** * Get the text of the token node (skipping mglyphs, and combining * multiple text nodes) + * + * @returns {string} Return the node's text */ - public getText() { + public getText(): string { let text = ''; for (const child of this.childNodes) { if (child instanceof TextNode) { text += child.getText(); + } else if ('textContent' in child) { + text += (child as any).textContent(); } } return text; @@ -864,7 +1046,12 @@ export abstract class AbstractMmlTokenNode extends AbstractMmlNode { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { for (const child of this.childNodes) { if (child instanceof AbstractMmlNode) { child.setInheritedAttributes(attributes, display, level, prime); @@ -874,9 +1061,10 @@ export abstract class AbstractMmlTokenNode extends AbstractMmlNode { /** * Only step into children that are AbstractMmlNodes (not TextNodes) + * * @override */ - public walkTree(func: (node: Node, data?: any) => void, data?: any) { + public walkTree(func: (node: MmlNode, data?: any) => void, data?: any) { func(this, data); for (const child of this.childNodes) { if (child instanceof AbstractMmlNode) { @@ -885,10 +1073,8 @@ export abstract class AbstractMmlTokenNode extends AbstractMmlNode { } return data; } - } - /*****************************************************************/ /** * The abstract MmlNode Layout class (extends the AbstractMmlNode) @@ -898,7 +1084,6 @@ export abstract class AbstractMmlTokenNode extends AbstractMmlNode { */ export abstract class AbstractMmlLayoutNode extends AbstractMmlNode { - /** * Use the same defaults as AbstractMmlNodes */ @@ -959,7 +1144,6 @@ export abstract class AbstractMmlLayoutNode extends AbstractMmlNode { */ export abstract class AbstractMmlBaseNode extends AbstractMmlNode { - /** * Use the same defaults as AbstractMmlNodes */ @@ -992,24 +1176,22 @@ export abstract class AbstractMmlBaseNode extends AbstractMmlNode { public setTeXclass(prev: MmlNode) { this.getPrevClass(prev); this.texClass = TEXCLASS.ORD; - let base = this.childNodes[0]; + const base = this.childNodes[0]; + let result = null; if (base) { if (this.isEmbellished || base.isKind('mi')) { - prev = base.setTeXclass(prev); + result = base.setTeXclass(prev); this.updateTeXclass(this.core()); } else { base.setTeXclass(null); - prev = this; } - } else { - prev = this; } for (const child of this.childNodes.slice(1)) { if (child) { child.setTeXclass(null); } } - return prev; + return result || this; } } @@ -1022,106 +1204,113 @@ export abstract class AbstractMmlBaseNode extends AbstractMmlNode { * goes with an MmlNode. */ -export abstract class AbstractMmlEmptyNode extends AbstractEmptyNode implements MmlNode { - +export abstract class AbstractMmlEmptyNode + extends AbstractEmptyNode + implements MmlNode +{ /** * Parent is an MmlNode */ public parent: MmlNode; /** - * @return {boolean} Not a token element + * @override + */ + public childNodes: MmlNode[]; + + /** + * @returns {boolean} Not a token element */ public get isToken(): boolean { return false; } /** - * @return {boolean} Not embellished + * @returns {boolean} Not embellished */ public get isEmbellished(): boolean { return false; } /** - * @return {boolean} Not space-like + * @returns {boolean} Not space-like */ public get isSpacelike(): boolean { return false; } /** - * @return {boolean} Not a container of any kind + * @returns {boolean} Not a container of any kind */ public get linebreakContainer(): boolean { return false; } /** - * @return {boolean} Does not contain new lines + * @returns {string} Don't set the indentalign and indentshift attributes in this case */ - public get hasNewLine(): boolean { - return false; + public get linebreakAlign(): string { + return ''; } /** - * @return {number} No children + * @returns {number} No children */ public get arity(): number { return 0; } /** - * @return {boolean} Is not an inferred row + * @returns {boolean} Is not an inferred row */ public get isInferred(): boolean { return false; } /** - * @return {boolean} Is not a container element + * @returns {boolean} Is not a container element */ public get notParent(): boolean { return false; } /** - * @return {MmlNode} Parent is the actual parent + * @returns {MmlNode} Parent is the actual parent */ public get Parent(): MmlNode { return this.parent; } /** - * @return {number} No TeX class + * @returns {number} No TeX class */ public get texClass(): number { return TEXCLASS.NONE; } /** - * @return {number} No previous element + * @returns {number} No previous element */ public get prevClass(): number { return TEXCLASS.NONE; } /** - * @return {number} No previous element + * @returns {number} No previous element */ public get prevLevel(): number { return 0; } /** - * @return {boolean} The core mo element has an explicit 'form' attribute + * @returns {boolean} The core mo element has an explicit 'form' attribute */ public hasSpacingAttributes(): boolean { return false; } /** - * return {Attributes} No attributes, so don't store one + * @returns {Attributes} No attributes, so don't store one */ public get attributes(): Attributes { return null; @@ -1173,7 +1362,12 @@ export abstract class AbstractMmlEmptyNode extends AbstractEmptyNode implements * * @override */ - public setInheritedAttributes(_attributes: AttributeList, _display: boolean, _level: number, _prime: boolean) {} + public setInheritedAttributes( + _attributes: AttributeList, + _display: boolean, + _level: number, + _prime: boolean + ) {} /** * No children or attributes, so ignore this call. @@ -1185,17 +1379,20 @@ export abstract class AbstractMmlEmptyNode extends AbstractEmptyNode implements /** * No children or attributes, so ignore this call. * - * @param {PropertyList} options The options for the check + * @param {PropertyList} _options The options for the check */ public verifyTree(_options: PropertyList) {} /** * @override */ - public mError(_message: string, _options: PropertyList, _short: boolean = false) { + public mError( + _message: string, + _options: PropertyList, + _short: boolean = false + ) { return null as MmlNode; } - } /*****************************************************************/ @@ -1217,7 +1414,7 @@ export class TextNode extends AbstractMmlEmptyNode { } /** - * @return {string} Return the node's text + * @returns {string} Return the node's text */ public getText(): string { return this.text; @@ -1225,7 +1422,7 @@ export class TextNode extends AbstractMmlEmptyNode { /** * @param {string} text The text to use for the node - * @return {TextNode} The text node (for chaining of method calls) + * @returns {TextNode} The text node (for chaining of method calls) */ public setText(text: string): TextNode { this.text = text; @@ -1241,14 +1438,14 @@ export class TextNode extends AbstractMmlEmptyNode { /** * Just use the text + * + * @override */ public toString() { return this.text; } - } - /*****************************************************************/ /** * The XMLNode Class (extends AbstractMmlEmptyNode) @@ -1258,7 +1455,7 @@ export class XMLNode extends AbstractMmlEmptyNode { /** * The XML content for this node */ - protected xml: Object = null; + protected xml: object = null; /** * DOM adaptor for the content @@ -1273,25 +1470,28 @@ export class XMLNode extends AbstractMmlEmptyNode { } /** - * @return {Object} Return the node's XML content + * @returns {object} Return the node's XML content */ - public getXML(): Object { + public getXML(): object { return this.xml; } /** * @param {object} xml The XML content to be saved * @param {DOMAdaptor} adaptor DOM adaptor for the content - * @return {XMLNode} The XML node (for chaining of method calls) + * @returns {XMLNode} The XML node (for chaining of method calls) */ - public setXML(xml: Object, adaptor: DOMAdaptor = null): XMLNode { + public setXML( + xml: Object, // eslint-disable-line @typescript-eslint/no-wrapper-object-types + adaptor: DOMAdaptor = null + ): XMLNode { this.xml = xml; this.adaptor = adaptor; return this; } /** - * @return {string} The serialized XML content + * @returns {string} The serialized XML content */ public getSerializedXML(): string { return this.adaptor.serializeXML(this.xml); @@ -1301,14 +1501,17 @@ export class XMLNode extends AbstractMmlEmptyNode { * @override */ public copy(): XMLNode { - return (this.factory.create(this.kind) as XMLNode).setXML(this.adaptor.clone(this.xml)); + return (this.factory.create(this.kind) as XMLNode).setXML( + this.adaptor.clone(this.xml) + ); } /** * Just indicate that this is XML data + * + * @override */ public toString() { return 'XML data'; } - } diff --git a/ts/core/MmlTree/MmlNodes/HtmlNode.ts b/ts/core/MmlTree/MmlNodes/HtmlNode.ts new file mode 100644 index 000000000..266e204af --- /dev/null +++ b/ts/core/MmlTree/MmlNodes/HtmlNode.ts @@ -0,0 +1,102 @@ +/************************************************************* + * + * Copyright (c) 2022-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Implement html-in-mathml internal node type + * + * @author dpvc@mathjax.org (Davide Cervone) + */ + +import { XMLNode } from '../MmlNode.js'; +import { DOMAdaptor } from '../../DOMAdaptor.js'; +import { PropertyList } from '../../Tree/Node.js'; + +/******************************************************************/ +/** + * The HtmlNode class for storing HTML within token elements + * + * @template N The HTMLElement class + */ +export class HtmlNode extends XMLNode { + /** + * @override + */ + public get kind() { + return 'html'; + } + + /** + * @returns {N} Return the node's HTML content + */ + public getHTML(): N { + return this.getXML() as any as N; + } + + /** + * @param {N} html The HTML content to be saved + * @param {DOMAdaptor} adaptor DOM adaptor for the content + * @returns {HtmlNode} The HTML node (for chaining of method calls) + */ + public setHTML( + html: N, + adaptor: DOMAdaptor = null + ): HtmlNode { + // + // Test if the HTML element has attributes and wrap in a if not + // + try { + adaptor.getAttribute(html, 'data-mjx-hdw'); + } catch (_error) { + html = adaptor.node('span', {}, [html]); + } + return this.setXML(html, adaptor) as HtmlNode; + } + + /** + * @returns {string} The serialized HTML content + */ + public getSerializedHTML(): string { + return this.adaptor.outerHTML(this.xml); + } + + /** + * @returns {string} The text of the HTML content + */ + public textContent(): string { + return this.adaptor.textContent(this.xml); + } + + /** + * Just indicate that this is HTML data + * + * @override + */ + public toString() { + const kind = this.adaptor.kind(this.xml); + return `HTML=<${kind}>...`; + } + + /** + * @override + */ + public verifyTree(options: PropertyList) { + if (this.parent && !this.parent.isToken) { + this.mError('HTML can only be a child of a token element', options, true); + return; + } + } +} diff --git a/ts/core/MmlTree/MmlNodes/TeXAtom.ts b/ts/core/MmlTree/MmlNodes/TeXAtom.ts index 11e3f3179..1c6267fb1 100644 --- a/ts/core/MmlTree/MmlNodes/TeXAtom.ts +++ b/ts/core/MmlTree/MmlNodes/TeXAtom.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ */ /** - * @fileoverview Implements the TeXAtom node + * @file Implements the TeXAtom node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MmlFactory} from '../MmlFactory.js'; -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlBaseNode, MmlNode, TEXCLASS} from '../MmlNode.js'; -import {MmlMo} from './mo.js'; +import { MmlFactory } from '../MmlFactory.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlBaseNode, MmlNode, TEXCLASS } from '../MmlNode.js'; +import { MmlMo } from './mo.js'; /*****************************************************************/ /** @@ -32,12 +32,11 @@ import {MmlMo} from './mo.js'; */ export class TeXAtom extends AbstractMmlBaseNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlBaseNode.defaults + ...AbstractMmlBaseNode.defaults, }; /** @@ -54,6 +53,7 @@ export class TeXAtom extends AbstractMmlBaseNode { /** * Inferred mrow with any number of children + * * @override */ public get arity() { @@ -62,18 +62,23 @@ export class TeXAtom extends AbstractMmlBaseNode { /** * This element is not considered a MathML container + * * @override */ public get notParent() { - return this.childNodes[0] && this.childNodes[0].childNodes.length === 1; + return true; } /** * @override */ - constructor(factory: MmlFactory, attributes: PropertyList, children: MmlNode[]) { + constructor( + factory: MmlFactory, + attributes: PropertyList, + children: MmlNode[] + ) { super(factory, attributes, children); - this.setProperty('texClass', this.texClass); // needed for serialization to include the texClass + this.setProperty('texClass', this.texClass); // needed for serialization to include the texClass } /** @@ -92,7 +97,6 @@ export class TeXAtom extends AbstractMmlBaseNode { public adjustTeXclass(prev: MmlNode) { return prev; } - } /** * Use the method from the MmlMo class diff --git a/ts/core/MmlTree/MmlNodes/maction.ts b/ts/core/MmlTree/MmlNodes/maction.ts index 2c23c8a52..3dc9f9099 100644 --- a/ts/core/MmlTree/MmlNodes/maction.ts +++ b/ts/core/MmlTree/MmlNodes/maction.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMaction node + * @file Implements the MmlMaction node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlNode} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { MmlNode, AbstractMmlNode, AttributeList } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,14 +30,13 @@ import {MmlNode, AbstractMmlNode} from '../MmlNode.js'; */ export class MmlMaction extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { ...AbstractMmlNode.defaults, actiontype: 'toggle', - selection: 1 + selection: 1, }; /** @@ -49,6 +48,7 @@ export class MmlMaction extends AbstractMmlNode { /** * At least one child + * * @override */ public get arity() { @@ -56,7 +56,7 @@ export class MmlMaction extends AbstractMmlNode { } /** - * @return {MmlNode} The selected child node (or an mrow if none selected) + * @returns {MmlNode} The selected child node (or an mrow if none selected) */ public get selected(): MmlNode { const selection = this.attributes.get('selection') as number; @@ -97,10 +97,11 @@ export class MmlMaction extends AbstractMmlNode { */ protected verifyAttributes(options: PropertyList) { super.verifyAttributes(options); - if (this.attributes.get('actiontype') !== 'toggle' && - this.attributes.getExplicit('selection') !== undefined) { - const attributes = this.attributes.getAllAttributes(); - delete attributes.selection; + if ( + this.attributes.get('actiontype') !== 'toggle' && + this.attributes.hasExplicit('selection') + ) { + this.attributes.unset('selection'); } } @@ -114,7 +115,7 @@ export class MmlMaction extends AbstractMmlNode { if (this.attributes.get('actiontype') === 'tooltip' && this.childNodes[1]) { this.childNodes[1].setTeXclass(null); } - let selected = this.selected; + const selected = this.selected; prev = selected.setTeXclass(prev); this.updateTeXclass(selected); return prev; @@ -124,11 +125,37 @@ export class MmlMaction extends AbstractMmlNode { * Select the next child for a toggle action */ public nextToggleSelection() { - let selection = Math.max(1, (this.attributes.get('selection') as number) + 1); + let selection = Math.max( + 1, + parseInt(this.attributes.get('selection') as string) + 1 + ); if (selection > this.childNodes.length) { selection = 1; } this.attributes.set('selection', selection); } + /** + * @override + */ + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { + if ( + (this.attributes.get('actiontype') as string).toLowerCase() !== 'tooltip' + ) { + super.setChildInheritedAttributes(attributes, display, level, prime); + return; + } + this.childNodes[0]?.setInheritedAttributes( + attributes, + display, + level, + prime + ); + this.childNodes[1]?.setInheritedAttributes(attributes, false, 1, false); + } } diff --git a/ts/core/MmlTree/MmlNodes/maligngroup.ts b/ts/core/MmlTree/MmlNodes/maligngroup.ts index cd06ce610..28203f29f 100644 --- a/ts/core/MmlTree/MmlNodes/maligngroup.ts +++ b/ts/core/MmlTree/MmlNodes/maligngroup.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ */ /** - * @fileoverview Implements the MmlMaligngroup node + * @file Implements the MmlMaligngroup node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlLayoutNode, AttributeList} from '../MmlNode.js'; -import {INHERIT} from '../Attributes.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlLayoutNode, AttributeList } from '../MmlNode.js'; +import { INHERIT } from '../Attributes.js'; /*****************************************************************/ /** @@ -31,13 +31,12 @@ import {INHERIT} from '../Attributes.js'; */ export class MmlMaligngroup extends AbstractMmlLayoutNode { - /** * @override */ public static defaults: PropertyList = { ...AbstractMmlLayoutNode.defaults, - groupalign: INHERIT + groupalign: INHERIT, }; /** @@ -49,6 +48,7 @@ export class MmlMaligngroup extends AbstractMmlLayoutNode { /** * is space-like + * * @override */ public get isSpacelike() { @@ -57,11 +57,19 @@ export class MmlMaligngroup extends AbstractMmlLayoutNode { /** * Children can inherit from + * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { - attributes = this.addInheritedAttributes(attributes, this.attributes.getAllAttributes()); + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { + attributes = this.addInheritedAttributes( + attributes, + this.attributes.getAllAttributes() + ); super.setChildInheritedAttributes(attributes, display, level, prime); } - } diff --git a/ts/core/MmlTree/MmlNodes/malignmark.ts b/ts/core/MmlTree/MmlNodes/malignmark.ts index 7aeffb3e9..7349b1083 100644 --- a/ts/core/MmlTree/MmlNodes/malignmark.ts +++ b/ts/core/MmlTree/MmlNodes/malignmark.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMalignmark node + * @file Implements the MmlMalignmark node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlNode} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlNode } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,13 +30,12 @@ import {AbstractMmlNode} from '../MmlNode.js'; */ export class MmlMalignmark extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { ...AbstractMmlNode.defaults, - edge: 'left' + edge: 'left', }; /** @@ -48,6 +47,7 @@ export class MmlMalignmark extends AbstractMmlNode { /** * No children allowed + * * @override */ public get arity() { @@ -56,10 +56,10 @@ export class MmlMalignmark extends AbstractMmlNode { /** * is space-like + * * @override */ public get isSpacelike() { return true; } - } diff --git a/ts/core/MmlTree/MmlNodes/math.ts b/ts/core/MmlTree/MmlNodes/math.ts index 04b788b72..5d02fb5b4 100644 --- a/ts/core/MmlTree/MmlNodes/math.ts +++ b/ts/core/MmlTree/MmlNodes/math.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMath node + * @file Implements the MmlMath node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlLayoutNode, AttributeList} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlLayoutNode, AttributeList } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,7 +30,6 @@ import {AbstractMmlLayoutNode, AttributeList} from '../MmlNode.js'; */ export class MmlMath extends AbstractMmlLayoutNode { - /** * These are used as the defaults for any attributes marked INHERIT in other classes */ @@ -53,17 +52,17 @@ export class MmlMath extends AbstractMmlLayoutNode { alttext: '', cdgroup: '', scriptsizemultiplier: 1 / Math.sqrt(2), - scriptminsize: '8px', // Should be 8pt, but that's too big + scriptminsize: '.4em', // Should be 8pt, but that's too big infixlinebreakstyle: 'before', - lineleading: '1ex', + lineleading: '100%', linebreakmultchar: '\u2062', // Invisible times - indentshift: 'auto', // Use user configuration + indentshift: 'auto', // Use user configuration indentalign: 'auto', indenttarget: '', indentalignfirst: 'indentalign', indentshiftfirst: 'indentshift', - indentalignlast: 'indentalign', - indentshiftlast: 'indentshift' + indentalignlast: 'indentalign', + indentshiftlast: 'indentshift', }; /** @@ -75,12 +74,22 @@ export class MmlMath extends AbstractMmlLayoutNode { /** * Linebreaking can occur in math nodes + * * @override */ public get linebreakContainer() { return true; } + /** + * Don't reset indent attributes + * + * @override + */ + public get linebreakAlign() { + return ''; + } + /** * The attributes of math nodes are inherited, so add them into the list. * The displaystyle attribute comes from the display attribute if not given explicitly @@ -88,17 +97,36 @@ export class MmlMath extends AbstractMmlLayoutNode { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { if (this.attributes.get('mode') === 'display') { this.attributes.setInherited('display', 'block'); } - attributes = this.addInheritedAttributes(attributes, this.attributes.getAllAttributes()); - display = (!!this.attributes.get('displaystyle') || - (!this.attributes.get('displaystyle') && this.attributes.get('display') === 'block')); + attributes = this.addInheritedAttributes( + attributes, + this.attributes.getAllAttributes() + ); + display = + !!this.attributes.get('displaystyle') || + (!this.attributes.get('displaystyle') && + this.attributes.get('display') === 'block'); this.attributes.setInherited('displaystyle', display); level = (this.attributes.get('scriptlevel') || - (this.constructor as typeof MmlMath).defaults['scriptlevel']) as number; + (this.constructor as typeof MmlMath).defaults['scriptlevel']) as number; super.setChildInheritedAttributes(attributes, display, level, prime); } + /** + * @override + */ + public verifyTree(options: PropertyList = null) { + super.verifyTree(options); + if (this.parent) { + this.mError('Improper nesting of math tags', options, true); + } + } } diff --git a/ts/core/MmlTree/MmlNodes/mathchoice.ts b/ts/core/MmlTree/MmlNodes/mathchoice.ts index cd798af54..2cd6c566c 100644 --- a/ts/core/MmlTree/MmlNodes/mathchoice.ts +++ b/ts/core/MmlTree/MmlNodes/mathchoice.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MathChoice node + * @file Implements the MathChoice node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlBaseNode, AttributeList} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlBaseNode, AttributeList } from '../MmlNode.js'; /*****************************************************************/ /** @@ -33,12 +33,11 @@ import {AbstractMmlBaseNode, AttributeList} from '../MmlNode.js'; */ export class MathChoice extends AbstractMmlBaseNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlBaseNode.defaults + ...AbstractMmlBaseNode.defaults, }; /** @@ -50,6 +49,7 @@ export class MathChoice extends AbstractMmlBaseNode { /** * 4 children (display, text, script, and scriptscript styles) + * * @override */ public get arity() { @@ -58,6 +58,7 @@ export class MathChoice extends AbstractMmlBaseNode { /** * This element is not considered a MathML container + * * @override */ public get notParent() { @@ -70,11 +71,15 @@ export class MathChoice extends AbstractMmlBaseNode { * * @override */ - public setInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { - const selection = (display ? 0 : Math.max(0, Math.min(level, 2)) + 1); + public setInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { + const selection = display ? 0 : Math.max(0, Math.min(level, 2)) + 1; const child = this.childNodes[selection] || this.factory.create('mrow'); this.parent.replaceChild(child, this); child.setInheritedAttributes(attributes, display, level, prime); } - } diff --git a/ts/core/MmlTree/MmlNodes/menclose.ts b/ts/core/MmlTree/MmlNodes/menclose.ts index 5ac956cff..8d1aee32d 100644 --- a/ts/core/MmlTree/MmlNodes/menclose.ts +++ b/ts/core/MmlTree/MmlNodes/menclose.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMenclose node + * @file Implements the MmlMenclose node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { MmlNode, AbstractMmlNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,13 +30,12 @@ import {MmlNode, AbstractMmlNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMenclose extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { ...AbstractMmlNode.defaults, - notation: 'longdiv' + notation: 'longdiv', }; /** @@ -46,6 +45,7 @@ export class MmlMenclose extends AbstractMmlNode { /** * The menclose kind + * * @override */ public get kind() { @@ -54,6 +54,7 @@ export class MmlMenclose extends AbstractMmlNode { /** * has an inferred mrow + * * @override */ public get arity() { @@ -62,9 +63,10 @@ export class MmlMenclose extends AbstractMmlNode { /** * is a linebreak container + * * @override */ - public get linebreakContininer() { + public get linebreakContainer() { return true; } @@ -76,5 +78,4 @@ export class MmlMenclose extends AbstractMmlNode { this.updateTeXclass(this.childNodes[0]); return prev; } - } diff --git a/ts/core/MmlTree/MmlNodes/merror.ts b/ts/core/MmlTree/MmlNodes/merror.ts index 9e1007762..f0bd98fa8 100644 --- a/ts/core/MmlTree/MmlNodes/merror.ts +++ b/ts/core/MmlTree/MmlNodes/merror.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMerror node + * @file Implements the MmlMerror node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,12 +30,11 @@ import {AbstractMmlNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMerror extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlNode.defaults + ...AbstractMmlNode.defaults, }; /** @@ -52,6 +51,7 @@ export class MmlMerror extends AbstractMmlNode { /** * gets an inferred mrow + * * @override */ public get arity() { @@ -60,10 +60,10 @@ export class MmlMerror extends AbstractMmlNode { /** * can contain line breaks + * * @override */ public get linebreakContainer() { return true; } - } diff --git a/ts/core/MmlTree/MmlNodes/mfenced.ts b/ts/core/MmlTree/MmlNodes/mfenced.ts index d91eef909..570bf1510 100644 --- a/ts/core/MmlTree/MmlNodes/mfenced.ts +++ b/ts/core/MmlTree/MmlNodes/mfenced.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,19 @@ */ /** - * @fileoverview Implements the MmlMfenced node + * @file Implements the MmlMfenced node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, TextNode, AbstractMmlNode, AttributeList, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { + MmlNode, + TextNode, + AbstractMmlNode, + AttributeList, + TEXCLASS, +} from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,15 +36,14 @@ import {MmlNode, TextNode, AbstractMmlNode, AttributeList, TEXCLASS} from '../Mm */ export class MmlMfenced extends AbstractMmlNode { - /** - * @overeride + * @override */ public static defaults: PropertyList = { ...AbstractMmlNode.defaults, open: '(', close: ')', - separators: ',' + separators: ',', }; /** @@ -101,7 +106,12 @@ export class MmlMfenced extends AbstractMmlNode { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { this.addFakeNodes(); for (const child of [this.open, this.close].concat(this.separators)) { if (child) { @@ -115,8 +125,11 @@ export class MmlMfenced extends AbstractMmlNode { * Create elements for the open and close delimiters, and for the separators (if any) */ protected addFakeNodes() { - let {open, close, separators} = this.attributes.getList('open', 'close', 'separators') as - {open: string, close: string, separators: string}; + let { open, close, separators } = this.attributes.getList( + 'open', + 'close', + 'separators' + ) as { open: string; close: string; separators: string }; open = open.replace(/[ \t\n\r]/g, ''); close = close.replace(/[ \t\n\r]/g, ''); separators = separators.replace(/[ \t\n\r]/g, ''); @@ -124,7 +137,11 @@ export class MmlMfenced extends AbstractMmlNode { // Create open node // if (open) { - this.open = this.fakeNode(open, {fence: true, form: 'prefix'}, TEXCLASS.OPEN); + this.open = this.fakeNode( + open, + { fence: true, form: 'prefix' }, + TEXCLASS.OPEN + ); } // // Create nodes for the separators @@ -144,7 +161,11 @@ export class MmlMfenced extends AbstractMmlNode { // Create close node // if (close) { - this.close = this.fakeNode(close, {fence: true, form: 'postfix'}, TEXCLASS.CLOSE); + this.close = this.fakeNode( + close, + { fence: true, form: 'postfix' }, + TEXCLASS.CLOSE + ); } } @@ -152,14 +173,17 @@ export class MmlMfenced extends AbstractMmlNode { * @param {string} c The character for the text of the node * @param {PropertyList} properties The attributes for the node * @param {number} texClass The TeX class for the node - * @return {MmlNode} The generated node + * @returns {MmlNode} The generated node */ - protected fakeNode(c: string, properties: PropertyList = {}, texClass: number = null): MmlNode { - let text = (this.factory.create('text') as TextNode).setText(c); - let node = this.factory.create('mo', properties, [text]); + protected fakeNode( + c: string, + properties: PropertyList = {}, + texClass: number = null + ): MmlNode { + const text = (this.factory.create('text') as TextNode).setText(c); + const node = this.factory.create('mo', properties, [text]); node.texClass = texClass; node.parent = this; return node; } - } diff --git a/ts/core/MmlTree/MmlNodes/mfrac.ts b/ts/core/MmlTree/MmlNodes/mfrac.ts index 5486e99ee..e1149f3ce 100644 --- a/ts/core/MmlTree/MmlNodes/mfrac.ts +++ b/ts/core/MmlTree/MmlNodes/mfrac.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMfrac node + * @file Implements the MmlMfrac node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlBaseNode, AttributeList} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { MmlNode, AbstractMmlBaseNode, AttributeList } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,7 +30,6 @@ import {MmlNode, AbstractMmlBaseNode, AttributeList} from '../MmlNode.js'; */ export class MmlMfrac extends AbstractMmlBaseNode { - /** * @override */ @@ -39,7 +38,7 @@ export class MmlMfrac extends AbstractMmlBaseNode { linethickness: 'medium', numalign: 'center', denomalign: 'center', - bevelled: false + bevelled: false, }; /** @@ -51,6 +50,7 @@ export class MmlMfrac extends AbstractMmlBaseNode { /** * requires two children + * * @override */ public get arity() { @@ -59,14 +59,25 @@ export class MmlMfrac extends AbstractMmlBaseNode { /** * The children of can include line breaks + * * @override */ public get linebreakContainer() { return true; } + /** + * Alignment is handled separately for the child nodes + * + * @override + */ + public get linebreakAlign() { + return ''; + } + /** * Update the children separately + * * @override */ public setTeXclass(prev: MmlNode) { @@ -79,14 +90,53 @@ export class MmlMfrac extends AbstractMmlBaseNode { /** * Adjust the display level, and use prime style in denominator + * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { if (!display || level > 0) { level++; } - this.childNodes[0].setInheritedAttributes(attributes, false, level, prime); - this.childNodes[1].setInheritedAttributes(attributes, false, level, true); + const numalign = this.attributes.get('numalign'); + const denalign = this.attributes.get('denomalign'); + const numAttributes = this.addInheritedAttributes( + { ...attributes }, + { + numalign, + indentshift: '0', + indentalignfirst: numalign, + indentshiftfirst: '0', + indentalignlast: 'indentalign', + indentshiftlast: 'indentshift', + } + ); + const denAttributes = this.addInheritedAttributes( + { ...attributes }, + { + denalign, + indentshift: '0', + indentalignfirst: denalign, + indentshiftfirst: '0', + indentalignlast: 'indentalign', + indentshiftlast: 'indentshift', + } + ); + this.childNodes[0].setInheritedAttributes( + numAttributes, + false, + level, + prime + ); + this.childNodes[1].setInheritedAttributes( + denAttributes, + false, + level, + true + ); } - } diff --git a/ts/core/MmlTree/MmlNodes/mglyph.ts b/ts/core/MmlTree/MmlNodes/mglyph.ts index ead80a576..ce9c1e083 100644 --- a/ts/core/MmlTree/MmlNodes/mglyph.ts +++ b/ts/core/MmlTree/MmlNodes/mglyph.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMglyph node + * @file Implements the MmlMglyph node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlTokenNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,7 +30,6 @@ import {AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMglyph extends AbstractMmlTokenNode { - /** * @override */ @@ -41,7 +40,7 @@ export class MmlMglyph extends AbstractMmlTokenNode { index: '', width: 'auto', height: 'auto', - valign: '0em' + valign: '0em', }; /** @@ -60,12 +59,19 @@ export class MmlMglyph extends AbstractMmlTokenNode { * @override */ public verifyAttributes(options: PropertyList) { - const {src, fontfamily, index} = this.attributes.getList('src', 'fontfamily', 'index'); + const { src, fontfamily, index } = this.attributes.getList( + 'src', + 'fontfamily', + 'index' + ); if (src === '' && (fontfamily === '' || index === '')) { - this.mError('mglyph must have either src or fontfamily and index attributes', options, true); + this.mError( + 'mglyph must have either src or fontfamily and index attributes', + options, + true + ); } else { super.verifyAttributes(options); } } - } diff --git a/ts/core/MmlTree/MmlNodes/mi.ts b/ts/core/MmlTree/MmlNodes/mi.ts index 3e6fa23d9..ecbaa73fb 100644 --- a/ts/core/MmlTree/MmlNodes/mi.ts +++ b/ts/core/MmlTree/MmlNodes/mi.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,18 @@ */ /** - * @fileoverview Implements the MmlMi node + * @file Implements the MmlMi node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlTokenNode, AbstractMmlNode, AttributeList, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { + AbstractMmlTokenNode, + AbstractMmlNode, + AttributeList, + TEXCLASS, +} from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,12 +35,11 @@ import {AbstractMmlTokenNode, AbstractMmlNode, AttributeList, TEXCLASS} from '.. */ export class MmlMi extends AbstractMmlTokenNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlTokenNode.defaults + ...AbstractMmlTokenNode.defaults, }; /** @@ -66,10 +70,14 @@ export class MmlMi extends AbstractMmlTokenNode { * * @override */ - public setInheritedAttributes(attributes: AttributeList = {}, - display: boolean = false, level: number = 0, prime: boolean = false) { + public setInheritedAttributes( + attributes: AttributeList = {}, + display: boolean = false, + level: number = 0, + prime: boolean = false + ) { super.setInheritedAttributes(attributes, display, level, prime); - let text = this.getText(); + const text = this.getText(); if (text.match(MmlMi.singleCharacter) && !attributes.mathvariant) { this.attributes.setInherited('mathvariant', 'italic'); } @@ -82,15 +90,17 @@ export class MmlMi extends AbstractMmlTokenNode { */ public setTeXclass(prev: AbstractMmlNode) { this.getPrevClass(prev); - let name = this.getText(); - if (name.length > 1 && name.match(MmlMi.operatorName) && - this.attributes.get('mathvariant') === 'normal' && - this.getProperty('autoOP') === undefined && - this.getProperty('texClass') === undefined) { + const name = this.getText(); + if ( + name.length > 1 && + name.match(MmlMi.operatorName) && + this.attributes.get('mathvariant') === 'normal' && + this.getProperty('autoOP') === undefined && + this.getProperty('texClass') === undefined + ) { this.texClass = TEXCLASS.OP; this.setProperty('autoOP', true); } return this; } - } diff --git a/ts/core/MmlTree/MmlNodes/mmultiscripts.ts b/ts/core/MmlTree/MmlNodes/mmultiscripts.ts index 8d03081e3..c30aee244 100644 --- a/ts/core/MmlTree/MmlNodes/mmultiscripts.ts +++ b/ts/core/MmlTree/MmlNodes/mmultiscripts.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ */ /** - * @fileoverview Implements the MmlMmultiscripts node + * @file Implements the MmlMmultiscripts node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlNode, AttributeList} from '../MmlNode.js'; -import {MmlMsubsup} from './msubsup.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlNode, AttributeList } from '../MmlNode.js'; +import { MmlMsubsup } from './msubsup.js'; /*****************************************************************/ /** @@ -31,12 +31,11 @@ import {MmlMsubsup} from './msubsup.js'; */ export class MmlMmultiscripts extends MmlMsubsup { - /** * @override */ public static defaults: PropertyList = { - ...MmlMsubsup.defaults + ...MmlMsubsup.defaults, }; /** @@ -48,6 +47,7 @@ export class MmlMmultiscripts extends MmlMsubsup { /** * requires at least one child (the base) + * * @override */ public get arity() { @@ -62,30 +62,45 @@ export class MmlMmultiscripts extends MmlMsubsup { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { - this.childNodes[0].setInheritedAttributes(attributes, display, level, prime); + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { + this.childNodes[0].setInheritedAttributes( + attributes, + display, + level, + prime + ); let prescripts = false; for (let i = 1, n = 0; i < this.childNodes.length; i++) { - let child = this.childNodes[i]; + const child = this.childNodes[i]; if (child.isKind('mprescripts')) { if (!prescripts) { prescripts = true; if (i % 2 === 0) { - let mrow = this.factory.create('mrow'); - this.childNodes.splice(i, 0, mrow); - mrow.parent = this; + const none = this.factory.create('none'); + this.childNodes.splice(i, 0, none); + none.parent = this; i++; } } } else { - let primestyle = prime || (n % 2 === 0); + const primestyle = prime || n % 2 === 0; child.setInheritedAttributes(attributes, false, level + 1, primestyle); n++; } } if (this.childNodes.length % 2 === (prescripts ? 1 : 0)) { - this.appendChild(this.factory.create('mrow')); - this.childNodes[this.childNodes.length - 1].setInheritedAttributes(attributes, false, level + 1, prime); + this.appendChild(this.factory.create('none')); + this.childNodes[this.childNodes.length - 1].setInheritedAttributes( + attributes, + false, + level + 1, + prime + ); } } @@ -96,26 +111,35 @@ export class MmlMmultiscripts extends MmlMsubsup { */ protected verifyChildren(options: PropertyList) { let prescripts = false; - let fix = options['fixMmultiscripts']; + const fix = options['fixMmultiscripts']; for (let i = 0; i < this.childNodes.length; i++) { - let child = this.childNodes[i]; + const child = this.childNodes[i]; if (child.isKind('mprescripts')) { if (prescripts) { - child.mError(child.kind + ' can only appear once in ' + this.kind, options, true); + child.mError( + child.kind + ' can only appear once in ' + this.kind, + options, + true + ); } else { prescripts = true; if (i % 2 === 0 && !fix) { - this.mError('There must be an equal number of prescripts of each type', options); + this.mError( + 'There must be an equal number of prescripts of each type', + options + ); } } } } if (this.childNodes.length % 2 === (prescripts ? 1 : 0) && !fix) { - this.mError('There must be an equal number of scripts of each type', options); + this.mError( + 'There must be an equal number of scripts of each type', + options + ); } super.verifyChildren(options); } - } /*****************************************************************/ @@ -124,23 +148,22 @@ export class MmlMmultiscripts extends MmlMsubsup { */ export class MmlMprescripts extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlNode.defaults + ...AbstractMmlNode.defaults, }; /** - * @return {string} The mprescripts kind + * @returns {string} The mprescripts kind */ public get kind(): string { return 'mprescripts'; } /** - * @return {number} can have no children + * @returns {number} can have no children */ public get arity(): number { return 0; @@ -154,10 +177,13 @@ export class MmlMprescripts extends AbstractMmlNode { public verifyTree(options: PropertyList) { super.verifyTree(options); if (this.parent && !this.parent.isKind('mmultiscripts')) { - this.mError(this.kind + ' must be a child of mmultiscripts', options, true); + this.mError( + this.kind + ' must be a child of mmultiscripts', + options, + true + ); } } - } /*****************************************************************/ @@ -166,23 +192,22 @@ export class MmlMprescripts extends AbstractMmlNode { */ export class MmlNone extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlNode.defaults + ...AbstractMmlNode.defaults, }; /** - * @return {string} The none kind + * @returns {string} The none kind */ public get kind(): string { return 'none'; } /** - * @return {number} can have no children + * @returns {number} can have no children */ public get arity(): number { return 0; @@ -196,8 +221,11 @@ export class MmlNone extends AbstractMmlNode { public verifyTree(options: PropertyList) { super.verifyTree(options); if (this.parent && !this.parent.isKind('mmultiscripts')) { - this.mError(this.kind + ' must be a child of mmultiscripts', options, true); + this.mError( + this.kind + ' must be a child of mmultiscripts', + options, + true + ); } } - } diff --git a/ts/core/MmlTree/MmlNodes/mn.ts b/ts/core/MmlTree/MmlNodes/mn.ts index ac50952b3..3875aecd1 100644 --- a/ts/core/MmlTree/MmlNodes/mn.ts +++ b/ts/core/MmlTree/MmlNodes/mn.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMn node + * @file Implements the MmlMn node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlTokenNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,12 +30,11 @@ import {AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMn extends AbstractMmlTokenNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlTokenNode.defaults + ...AbstractMmlTokenNode.defaults, }; /** @@ -49,5 +48,4 @@ export class MmlMn extends AbstractMmlTokenNode { public get kind() { return 'mn'; } - } diff --git a/ts/core/MmlTree/MmlNodes/mo.ts b/ts/core/MmlTree/MmlNodes/mo.ts index 02603594c..2f83d8b52 100644 --- a/ts/core/MmlTree/MmlNodes/mo.ts +++ b/ts/core/MmlTree/MmlNodes/mo.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,29 @@ */ /** - * @fileoverview Implements the MmlMo node + * @file Implements the MmlMo node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlTokenNode, MmlNode, AttributeList, TEXCLASS} from '../MmlNode.js'; -import {MmlMrow} from './mrow.js'; -import {MmlMover, MmlMunder, MmlMunderover} from './munderover.js'; -import {OperatorList, OPTABLE, getRange, MMLSPACING} from '../OperatorDictionary.js'; -import {unicodeChars, unicodeString} from '../../../util/string.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { + AbstractMmlTokenNode, + MmlNode, + AttributeList, + TEXCLASS, +} from '../MmlNode.js'; +import { MmlMrow } from './mrow.js'; +import { MmlMover, MmlMunder, MmlMunderover } from './munderover.js'; +import { + OperatorDef, + OperatorList, + OPTABLE, + OPDEF, + getRange, + MMLSPACING, +} from '../OperatorDictionary.js'; +import { unicodeChars, unicodeString } from '../../../util/string.js'; /*****************************************************************/ /** @@ -34,7 +46,6 @@ import {unicodeChars, unicodeString} from '../../../util/string.js'; */ export class MmlMo extends AbstractMmlTokenNode { - /** * @override */ @@ -53,7 +64,7 @@ export class MmlMo extends AbstractMmlTokenNode { movablelimits: false, accent: false, linebreak: 'auto', - lineleading: '1ex', + lineleading: '100%', linebreakstyle: 'before', indentalign: 'auto', indentshift: '0', @@ -61,7 +72,7 @@ export class MmlMo extends AbstractMmlTokenNode { indentalignfirst: 'indentalign', indentshiftfirst: 'indentshift', indentalignlast: 'indentalign', - indentshiftlast: 'indentshift' + indentshiftlast: 'indentshift', }; /** @@ -72,11 +83,12 @@ export class MmlMo extends AbstractMmlTokenNode { /** * The Operator Dictionary */ - public static OPTABLE: {[form: string]: OperatorList} = OPTABLE; + public static OPTABLE: { [form: string]: OperatorList } = OPTABLE; /** * Pattern for matching when the contents is one ore more pseudoscripts */ + /* prettier-ignore */ public static pseudoScripts = new RegExp([ '^["\'*`', '\u00AA', // FEMININE ORDINAL INDICATOR @@ -95,33 +107,42 @@ export class MmlMo extends AbstractMmlTokenNode { /** * Pattern for when contents is a collection of primes */ - protected static primes = new RegExp([ - '^["\'`', - '\u2018-\u201F', // Various double and single quotation marks (up and down) - ']+$' - ].join('')); - - /** - * Default map for remapping prime characters - */ - protected static remapPrimes: {[n: number]: number} = { - 0x0022: 0x2033, // double quotes - 0x0027: 0x2032, // single quote - 0x0060: 0x2035, // back quote - 0x2018: 0x2035, // open single quote - 0x2019: 0x2032, // close single quote - 0x201A: 0x2032, // low open single quote - 0x201B: 0x2035, // reversed open single quote - 0x201C: 0x2036, // open double quote - 0x201D: 0x2033, // close double quote - 0x201E: 0x2033, // low open double quote - 0x201F: 0x2036, // reversed open double quote + protected static primes = new RegExp( + [ + '^["\'', + '\u2018-\u201F', // Various double and single quotation marks (up and down) + ']+$', + ].join('') + ); + + /** + * Pattern to use to identify a multiletter operator + */ + protected static opPattern = /^[a-zA-Z]{2,}$/; + + /** + * Default map for remapping prime characters + */ + protected static remapPrimes: { [n: number]: number } = { + 0x0022: 0x2033, // double quotes + 0x0027: 0x2032, // single quote + 0x2018: 0x2035, // open single quote + 0x2019: 0x2032, // close single quote + 0x201a: 0x2032, // low open single quote + 0x201b: 0x2035, // reversed open single quote + 0x201c: 0x2036, // open double quote + 0x201d: 0x2033, // close double quote + 0x201e: 0x2033, // low open double quote + 0x201f: 0x2036, // reversed open double quote }; /** * Regular expression matching characters that are marked as math accents + * (property mathaccent = true) */ - protected static mathaccents = new RegExp([ + /* prettier-ignore */ + /* eslint-disable no-misleading-character-class */ + public static mathaccents = new RegExp([ '^[', '\u00B4\u0301\u02CA', // acute '\u0060\u0300\u02CB', // grave @@ -131,7 +152,8 @@ export class MmlMo extends AbstractMmlTokenNode { '\u02D8\u0306', // breve '\u02C7\u030C', // check '\u005E\u0302\u02C6', // hat - '\u2192\u20D7', // vec + '\u20D0\u20D1', // harpoons + '\u20D6\u20D7\u20E1', // vec (backward, forward, double) '\u02D9\u0307', // dot '\u02DA\u030A', // mathring '\u20DB', // dddot @@ -139,6 +161,19 @@ export class MmlMo extends AbstractMmlTokenNode { ']$' ].join('')); + /** + * Regular expression matching characters that are marked as math accents + * whose widths are to be respected (property mathaccent = false) + */ + /* prettier-ignore */ + public static mathaccentsWithWidth = new RegExp([ + '^[', + '\u2190\u2192\u2194', // arrows + '\u23DC\u23DD', // over and under parens + '\u23DE\u23DF', // over and under braces + ']$' + ].join('')); + /** * The internal TeX class of the node (for use with getter/setter below) */ @@ -148,14 +183,12 @@ export class MmlMo extends AbstractMmlTokenNode { * Use a getter to look up the TeX class from the operator table if it hasn't * been set yet (but don't save it in case the form changes when it is in its * location). + * + * @returns {number} The TeX class. */ public get texClass() { if (this._texClass === null) { - let mo = this.getText(); - let [form1, form2, form3] = this.handleExplicitForm(this.getForms()); - let OPTABLE = (this.constructor as typeof MmlMo).OPTABLE; - let def = OPTABLE[form1][mo] || OPTABLE[form2][mo] || OPTABLE[form3][mo]; - return def ? def[2] : TEXCLASS.REL; + return this.getOperatorDef(this.getText())[2]; } return this._texClass; } @@ -170,13 +203,13 @@ export class MmlMo extends AbstractMmlTokenNode { /** * The default MathML spacing on the left */ - /* tslint:disable-next-line:whitespace */ + /* prettier-ignore */ public lspace = 5/18; /** * The default MathML spacing on the right */ - /* tslint:disable-next-line:whitespace */ + /* prettier-ignore */ public rspace = 5/18; /** @@ -188,6 +221,7 @@ export class MmlMo extends AbstractMmlTokenNode { /** * All are considered embellished + * * @override */ public get isEmbellished() { @@ -195,30 +229,28 @@ export class MmlMo extends AbstractMmlTokenNode { } /** - * @return {boolean} Is marked as an explicit linebreak? - */ - public get hasNewLine(): boolean { - return this.attributes.get('linebreak') === 'newline'; - } - - /** - * @return {MmlNode} The node that is the outermost embellished operator + * @returns {MmlNode} The node that is the outermost embellished operator * with this node as its core */ public coreParent(): MmlNode { - let embellished = this as MmlNode; + let embellished = null; let parent = this as MmlNode; - let math = this.factory.getNodeClass('math'); - while (parent && parent.isEmbellished && parent.coreMO() === this && !(parent instanceof math)) { + const math = this.factory.getNodeClass('math'); + while ( + parent && + parent.isEmbellished && + parent.coreMO() === this && + !(parent instanceof math) + ) { embellished = parent; parent = (parent as MmlNode).parent; } - return embellished; + return embellished || this; } /** * @param {MmlNode} parent The node whose core text is to be obtained - * @return {string} The text of the core MO of the given parent element + * @returns {string} The text of the core MO of the given parent element */ public coreText(parent: MmlNode): string { if (!parent) { @@ -227,46 +259,54 @@ export class MmlMo extends AbstractMmlTokenNode { if (parent.isEmbellished) { return (parent.coreMO() as MmlMo).getText(); } - while ((((parent.isKind('mrow') || - (parent.isKind('TeXAtom') && parent.texClass !== TEXCLASS.VCENTER) || - parent.isKind('mstyle') || - parent.isKind('mphantom')) && parent.childNodes.length === 1) || - parent.isKind('munderover')) && parent.childNodes[0]) { - parent = parent.childNodes[0] as MmlNode; + while ( + (((parent.isKind('mrow') || + parent.isKind('TeXAtom') || + parent.isKind('mstyle') || + parent.isKind('mphantom')) && + parent.childNodes.length === 1) || + parent.isKind('munderover')) && + parent.childNodes[0] + ) { + parent = parent.childNodes[0]; } - return (parent.isToken ? (parent as AbstractMmlTokenNode).getText() : ''); + return parent.isToken ? (parent as AbstractMmlTokenNode).getText() : ''; } /** * @override */ public hasSpacingAttributes() { - return this.attributes.isSet('lspace') || - this.attributes.isSet('rspace'); + return this.attributes.isSet('lspace') || this.attributes.isSet('rspace'); } /** - * @return {boolean} True is this mo is an accent in an munderover construction + * @returns {boolean} True is this mo is an accent in an munderover construction */ get isAccent(): boolean { let accent = false; const node = this.coreParent().parent; if (node) { - const key = (node.isKind('mover') ? - ((node.childNodes[(node as MmlMover).over] as MmlNode).coreMO() ? - 'accent' : '') : - node.isKind('munder') ? - ((node.childNodes[(node as MmlMunder).under] as MmlNode).coreMO() ? - 'accentunder' : '') : - node.isKind('munderover') ? - (this === (node.childNodes[(node as MmlMunderover).over] as MmlNode).coreMO() ? - 'accent' : - this === (node.childNodes[(node as MmlMunderover).under] as MmlNode).coreMO() ? - 'accentunder' : '') : - ''); + const key = node.isKind('mover') + ? node.childNodes[(node as MmlMover).over].coreMO() + ? 'accent' + : '' + : node.isKind('munder') + ? node.childNodes[(node as MmlMunder).under].coreMO() + ? 'accentunder' + : '' + : node.isKind('munderover') + ? this === node.childNodes[(node as MmlMunderover).over].coreMO() + ? 'accent' + : this === node.childNodes[(node as MmlMunderover).under].coreMO() + ? 'accentunder' + : '' + : ''; if (key) { const value = node.attributes.getExplicit(key); - accent = (value !== undefined ? accent : this.attributes.get('accent')) as boolean; + accent = ( + value !== undefined ? accent : this.attributes.get('accent') + ) as boolean; } } return accent; @@ -278,9 +318,14 @@ export class MmlMo extends AbstractMmlTokenNode { * @override */ public setTeXclass(prev: MmlNode): MmlNode { - let {form, fence} = this.attributes.getList('form', 'fence') as {form: string, fence: string}; - if (this.getProperty('texClass') === undefined && - (this.attributes.isSet('lspace') || this.attributes.isSet('rspace'))) { + const { form, fence } = this.attributes.getList('form', 'fence') as { + form: string; + fence: string; + }; + if ( + this.getProperty('texClass') === undefined && + this.hasSpacingAttributes() + ) { return null; } if (fence && this.texClass === TEXCLASS.REL) { @@ -297,43 +342,61 @@ export class MmlMo extends AbstractMmlTokenNode { * Follow the TeXBook rules for adjusting the TeX class once its neighbors are known * * @param {MmlNode} prev The node appearing before this one in the output - * @return {MmlNode} The last node displayed (this node) + * @returns {MmlNode} The last node displayed (this node) */ public adjustTeXclass(prev: MmlNode): MmlNode { - let texClass = this.texClass; + const texClass = this.texClass; let prevClass = this.prevClass; if (texClass === TEXCLASS.NONE) { return prev; } if (prev) { - if (prev.getProperty('autoOP') && (texClass === TEXCLASS.BIN || texClass === TEXCLASS.REL)) { + if ( + prev.getProperty('autoOP') && + (texClass === TEXCLASS.BIN || texClass === TEXCLASS.REL) + ) { prevClass = prev.texClass = TEXCLASS.ORD; } - prevClass = this.prevClass = (prev.texClass || TEXCLASS.ORD); + prevClass = this.prevClass = prev.texClass || TEXCLASS.ORD; this.prevLevel = this.attributes.getInherited('scriptlevel') as number; } else { prevClass = this.prevClass = TEXCLASS.NONE; } - if (texClass === TEXCLASS.BIN && - (prevClass === TEXCLASS.NONE || prevClass === TEXCLASS.BIN || prevClass === TEXCLASS.OP || - prevClass === TEXCLASS.REL || prevClass === TEXCLASS.OPEN || prevClass === TEXCLASS.PUNCT)) { + if ( + texClass === TEXCLASS.BIN && + (prevClass === TEXCLASS.NONE || + prevClass === TEXCLASS.BIN || + prevClass === TEXCLASS.OP || + prevClass === TEXCLASS.REL || + prevClass === TEXCLASS.OPEN || + prevClass === TEXCLASS.PUNCT) + ) { this.texClass = TEXCLASS.ORD; - } else if (prevClass === TEXCLASS.BIN && - (texClass === TEXCLASS.REL || texClass === TEXCLASS.CLOSE || texClass === TEXCLASS.PUNCT)) { + } else if ( + prevClass === TEXCLASS.BIN && + (texClass === TEXCLASS.REL || + texClass === TEXCLASS.CLOSE || + texClass === TEXCLASS.PUNCT) + ) { prev.texClass = this.prevClass = TEXCLASS.ORD; } else if (texClass === TEXCLASS.BIN) { // // Check if node is the last one in its container since the rule // above only takes effect if there is a node that follows. // - let child: MmlNode = this; + let child: MmlNode = null; let parent = this.parent; - while (parent && parent.parent && parent.isEmbellished && - (parent.childNodes.length === 1 || - (!parent.isKind('mrow') && parent.core() === child))) { + while ( + parent && + parent.parent && + parent.isEmbellished && + (parent.childNodes.length === 1 || + (!parent.isKind('mrow') && parent.core() === child)) + ) { child = parent; parent = parent.parent; } + child = child || this; if (parent.childNodes[parent.childNodes.length - 1] === child) { this.texClass = TEXCLASS.ORD; } @@ -347,10 +410,14 @@ export class MmlMo extends AbstractMmlTokenNode { * * @override */ - public setInheritedAttributes(attributes: AttributeList = {}, - display: boolean = false, level: number = 0, prime: boolean = false) { + public setInheritedAttributes( + attributes: AttributeList = {}, + display: boolean = false, + level: number = 0, + prime: boolean = false + ) { super.setInheritedAttributes(attributes, display, level, prime); - let mo = this.getText(); + const mo = this.getText(); this.checkOperatorTable(mo); this.checkPseudoScripts(mo); this.checkPrimes(mo); @@ -358,44 +425,55 @@ export class MmlMo extends AbstractMmlTokenNode { } /** - * Set the attributes from the operator table + * get the operator definition from the operator table * - * @param {string} mo The test of the mo element + * @param {string} mo The text of the mo element + * @returns {OperatorDef} The operator definition */ - protected checkOperatorTable(mo: string) { - let [form1, form2, form3] = this.handleExplicitForm(this.getForms()); + protected getOperatorDef(mo: string): OperatorDef { + const [form1, form2, form3] = this.handleExplicitForm(this.getForms()); this.attributes.setInherited('form', form1); - let OPTABLE = (this.constructor as typeof MmlMo).OPTABLE; - let def = OPTABLE[form1][mo] || OPTABLE[form2][mo] || OPTABLE[form3][mo]; + const CLASS = this.constructor as typeof MmlMo; + const OPTABLE = CLASS.OPTABLE; + const def = OPTABLE[form1][mo] || OPTABLE[form2][mo] || OPTABLE[form3][mo]; if (def) { - if (this.getProperty('texClass') === undefined) { - this.texClass = def[2]; - } - for (const name of Object.keys(def[3] || {})) { - this.attributes.setInherited(name, def[3][name]); - } - this.lspace = (def[0] + 1) / 18; - this.rspace = (def[1] + 1) / 18; - } else { - let range = getRange(mo); - if (range) { - if (this.getProperty('texClass') === undefined) { - this.texClass = range[2]; - } - const spacing = (this.constructor as typeof MmlMo).MMLSPACING[range[2]]; - this.lspace = (spacing[0] + 1) / 18; - this.rspace = (spacing[1] + 1) / 18; - } + return def; + } + this.setProperty('noDictDef', true); + const limits = this.attributes.get('movablelimits'); + const isOP = !!mo.match(CLASS.opPattern); + if ((isOP || limits) && this.getProperty('texClass') === undefined) { + return OPDEF(1, 2, TEXCLASS.OP); + } + const range = getRange(mo); + const [l, r] = CLASS.MMLSPACING[range[2]]; + return OPDEF(l, r, range[2]); + } + + /** + * Set the attributes from the operator table + * + * @param {string} mo The text of the mo element + */ + protected checkOperatorTable(mo: string) { + const def = this.getOperatorDef(mo); + if (this.getProperty('texClass') === undefined) { + this.texClass = def[2]; } + for (const name of Object.keys(def[3] || {})) { + this.attributes.setInherited(name, def[3][name]); + } + this.lspace = ((def[0] || -1) + 1) / 18; + this.rspace = ((def[1] || -1) + 1) / 18; } /** - * @return {[string, string, string]} The list of form attribute values in the + * @returns {[string, string, string]} The list of form attribute values in the * order they should be tested, based on the * position of the element in its parent. */ public getForms(): [string, string, string] { - let core: MmlNode = this; + let core: MmlNode = null; let parent = this.parent; let Parent = this.Parent; while (Parent && Parent.isEmbellished) { @@ -403,7 +481,12 @@ export class MmlMo extends AbstractMmlTokenNode { parent = Parent.parent; Parent = Parent.Parent; } - if (parent && parent.isKind('mrow') && (parent as MmlMrow).nonSpaceLength() !== 1) { + core = core || this; + if ( + parent && + parent.isKind('mrow') && + (parent as MmlMrow).nonSpaceLength() !== 1 + ) { if ((parent as MmlMrow).firstNonSpace() === core) { return ['prefix', 'infix', 'postfix']; } @@ -416,12 +499,12 @@ export class MmlMo extends AbstractMmlTokenNode { /** * @param {string[]} forms The three forms in the default order they are to be tested - * @return {string[]} The forms in the new order, if there is an explicit form attribute + * @returns {string[]} The forms in the new order, if there is an explicit form attribute */ protected handleExplicitForm(forms: string[]): string[] { if (this.attributes.isSet('form')) { const form = this.attributes.get('form') as string; - forms = [form].concat(forms.filter(name => (name !== form))); + forms = [form].concat(forms.filter((name) => name !== form)); } return forms; } @@ -436,7 +519,8 @@ export class MmlMo extends AbstractMmlTokenNode { const PSEUDOSCRIPTS = (this.constructor as typeof MmlMo).pseudoScripts; if (!mo.match(PSEUDOSCRIPTS)) return; const parent = this.coreParent().Parent; - const isPseudo = !parent || !(parent.isKind('msubsup') && !parent.isKind('msub')); + const isPseudo = + !parent || !(parent.isKind('msubsup') && !parent.isKind('msub')); this.setProperty('pseudoscript', isPseudo); if (isPseudo) { this.attributes.setInherited('lspace', 0); @@ -453,7 +537,7 @@ export class MmlMo extends AbstractMmlTokenNode { const PRIMES = (this.constructor as typeof MmlMo).primes; if (!mo.match(PRIMES)) return; const REMAP = (this.constructor as typeof MmlMo).remapPrimes; - const primes = unicodeString(unicodeChars(mo).map(c => REMAP[c])); + const primes = unicodeString(unicodeChars(mo).map((c) => REMAP[c])); this.setProperty('primes', primes); } @@ -464,13 +548,43 @@ export class MmlMo extends AbstractMmlTokenNode { */ protected checkMathAccent(mo: string) { const parent = this.Parent; - if (this.getProperty('mathaccent') !== undefined || !parent || !parent.isKind('munderover')) return; - const base = parent.childNodes[0] as MmlNode; + if ( + this.getProperty('mathaccent') !== undefined || + !parent || + !parent.isKind('munderover') + ) + return; + const [base, under, over] = parent.childNodes; if (base.isEmbellished && base.coreMO() === this) return; - const MATHACCENT = (this.constructor as typeof MmlMo).mathaccents; - if (mo.match(MATHACCENT)) { - this.setProperty('mathaccent', true); + const isUnder = !!(under && under.isEmbellished && under.coreMO() === this); + const isOver = !!(over && over.isEmbellished && under.coreMO() === this); + if (!isUnder && !isOver) return; + if (this.isMathAccent(mo)) { + this.setProperty('mathaccent', true); // math accent whose width is replaced by 0 + } else if (this.isMathAccentWithWidth(mo)) { + this.setProperty('mathaccent', false); // math accent whose width is normal } } + /** + * Check a string for being a mathaccent + * + * @param {string} mo The string to check + * @returns {boolean} True if the string should be a mathaccent + */ + public isMathAccent(mo: string = this.getText()): boolean { + const MATHACCENT = (this.constructor as typeof MmlMo).mathaccents; + return !!mo.match(MATHACCENT); + } + + /** + * Check a string for being a mathaccent with non-zero width + * + * @param {string} mo The string to check + * @returns {boolean} True if the string should be a mathaccent + */ + public isMathAccentWithWidth(mo: string = this.getText()): boolean { + const MATHACCENT = (this.constructor as typeof MmlMo).mathaccentsWithWidth; + return !!mo.match(MATHACCENT); + } } diff --git a/ts/core/MmlTree/MmlNodes/mpadded.ts b/ts/core/MmlTree/MmlNodes/mpadded.ts index ef6f27315..c456460b4 100644 --- a/ts/core/MmlTree/MmlNodes/mpadded.ts +++ b/ts/core/MmlTree/MmlNodes/mpadded.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMpadded node + * @file Implements the MmlMpadded node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlLayoutNode} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlLayoutNode, TEXCLASS, MmlNode } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,7 +30,6 @@ import {AbstractMmlLayoutNode} from '../MmlNode.js'; */ export class MmlMpadded extends AbstractMmlLayoutNode { - /** * @override */ @@ -40,7 +39,7 @@ export class MmlMpadded extends AbstractMmlLayoutNode { height: '', depth: '', lspace: 0, - voffset: 0 + voffset: 0, }; /** @@ -50,4 +49,23 @@ export class MmlMpadded extends AbstractMmlLayoutNode { return 'mpadded'; } + /** + * @override + */ + public get linebreakContainer() { + return true; + } + + /** + * @override + */ + public setTeXclass(prev: MmlNode): MmlNode { + if (!this.getProperty('vbox')) { + return super.setTeXclass(prev); + } + this.getPrevClass(prev); + this.texClass = TEXCLASS.ORD; + this.childNodes[0].setTeXclass(null); + return this; + } } diff --git a/ts/core/MmlTree/MmlNodes/mphantom.ts b/ts/core/MmlTree/MmlNodes/mphantom.ts index ed9edf4ad..ee4fb6354 100644 --- a/ts/core/MmlTree/MmlNodes/mphantom.ts +++ b/ts/core/MmlTree/MmlNodes/mphantom.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMphantom node + * @file Implements the MmlMphantom node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlLayoutNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlLayoutNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,12 +30,11 @@ import {AbstractMmlLayoutNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMphantom extends AbstractMmlLayoutNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlLayoutNode.defaults + ...AbstractMmlLayoutNode.defaults, }; /** @@ -49,5 +48,4 @@ export class MmlMphantom extends AbstractMmlLayoutNode { public get kind() { return 'mphantom'; } - } diff --git a/ts/core/MmlTree/MmlNodes/mroot.ts b/ts/core/MmlTree/MmlNodes/mroot.ts index 0d7ff1ce2..5c042ad43 100644 --- a/ts/core/MmlTree/MmlNodes/mroot.ts +++ b/ts/core/MmlTree/MmlNodes/mroot.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,18 @@ */ /** - * @fileoverview Implements the MmlMroot node + * @file Implements the MmlMroot node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlNode, AttributeList, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { + MmlNode, + AbstractMmlNode, + AttributeList, + TEXCLASS, +} from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,12 +35,12 @@ import {MmlNode, AbstractMmlNode, AttributeList, TEXCLASS} from '../MmlNode.js'; */ export class MmlMroot extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlNode.defaults + ...AbstractMmlNode.defaults, + 'data-vertical-align': 'bottom', }; /** @@ -52,12 +57,22 @@ export class MmlMroot extends AbstractMmlNode { /** * requires two children + * * @override */ public get arity() { return 2; } + /** + * can contain line breaks + * + * @override + */ + public get linebreakContainer() { + return true; + } + /** * Set the TeX class for the content of the root and the root separately. * Return ourself as the previous item. @@ -76,9 +91,18 @@ export class MmlMroot extends AbstractMmlNode { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { this.childNodes[0].setInheritedAttributes(attributes, display, level, true); - this.childNodes[1].setInheritedAttributes(attributes, false, level + 2, prime); + this.childNodes[1].setInheritedAttributes( + attributes, + false, + level + 2, + prime + ); } - } diff --git a/ts/core/MmlTree/MmlNodes/mrow.ts b/ts/core/MmlTree/MmlNodes/mrow.ts index 34aacbcb6..b94a7d108 100644 --- a/ts/core/MmlTree/MmlNodes/mrow.ts +++ b/ts/core/MmlTree/MmlNodes/mrow.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMrow node + * @file Implements the MmlMrow node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { MmlNode, AbstractMmlNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,12 +30,11 @@ import {MmlNode, AbstractMmlNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMrow extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlNode.defaults + ...AbstractMmlNode.defaults, }; /** @@ -111,7 +110,7 @@ export class MmlMrow extends AbstractMmlNode { } /** - * @return {number} The number of non-spacelike child nodes + * @returns {number} The number of non-spacelike child nodes */ public nonSpaceLength(): number { let n = 0; @@ -124,7 +123,7 @@ export class MmlMrow extends AbstractMmlNode { } /** - * @return {MmlNode|null} The first non-space-like child node + * @returns {MmlNode|null} The first non-space-like child node */ public firstNonSpace(): MmlNode | null { for (const child of this.childNodes) { @@ -136,12 +135,12 @@ export class MmlMrow extends AbstractMmlNode { } /** - * @return {MmlNode|null} The last non-space-like child node + * @returns {MmlNode|null} The last non-space-like child node */ public lastNonSpace(): MmlNode | null { let i = this.childNodes.length; while (--i >= 0) { - let child = this.childNodes[i]; + const child = this.childNodes[i]; if (child && !child.isSpacelike) { return child; } @@ -152,7 +151,7 @@ export class MmlMrow extends AbstractMmlNode { /** * @override */ - public setTeXclass(prev: MmlNode) { + public setTeXclass(prev: MmlNode): MmlNode { if (this.getProperty('open') != null || this.getProperty('close') != null) { // // looks like it came from \left...\right @@ -169,44 +168,41 @@ export class MmlMrow extends AbstractMmlNode { if (this.texClass == null) { this.texClass = TEXCLASS.INNER; } - } else { - // - // Normal , so treat as though mrow is not there - // - for (const child of this.childNodes) { - prev = child.setTeXclass(prev); - } - if (this.childNodes[0]) { - this.updateTeXclass(this.childNodes[0]); - } + return this; + } + // + // Normal , so treat as though mrow is not there + // + for (const child of this.childNodes) { + prev = child.setTeXclass(prev); + } + if (this.childNodes[0]) { + this.updateTeXclass(this.childNodes[0]); } return prev; } - } - /*****************************************************************/ /** * Implements the MmlInferredMrow node class (subclass of MmlMrow) */ export class MmlInferredMrow extends MmlMrow { - /** * @override */ public static defaults: PropertyList = MmlMrow.defaults; /** - * @return {string} The inferred-mrow kind + * @returns {string} The inferred-mrow kind */ public get kind(): string { return 'inferredMrow'; } /** - * @return {boolean} This is inferred + * @returns {boolean} This is inferred */ public get isInferred(): boolean { return true; @@ -221,9 +217,10 @@ export class MmlInferredMrow extends MmlMrow { /** * Show the child nodes in brackets + * + * @returns {string} The child nodes string */ public toString() { return '[' + this.childNodes.join(',') + ']'; } - } diff --git a/ts/core/MmlTree/MmlNodes/ms.ts b/ts/core/MmlTree/MmlNodes/ms.ts index 8c63e6d99..226b72e46 100644 --- a/ts/core/MmlTree/MmlNodes/ms.ts +++ b/ts/core/MmlTree/MmlNodes/ms.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMs node + * @file Implements the MmlMs node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlTokenNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,14 +30,13 @@ import {AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMs extends AbstractMmlTokenNode { - /** * @override */ public static defaults: PropertyList = { ...AbstractMmlTokenNode.defaults, lquote: '"', - rquote: '"' + rquote: '"', }; /** @@ -51,5 +50,4 @@ export class MmlMs extends AbstractMmlTokenNode { public get kind() { return 'ms'; } - } diff --git a/ts/core/MmlTree/MmlNodes/mspace.ts b/ts/core/MmlTree/MmlNodes/mspace.ts index 7b0d0c18a..0bf1d58ef 100644 --- a/ts/core/MmlTree/MmlNodes/mspace.ts +++ b/ts/core/MmlTree/MmlNodes/mspace.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMspace node + * @file Implements the MmlMspace node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { MmlNode, AbstractMmlTokenNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,16 +30,34 @@ import {MmlNode, AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMspace extends AbstractMmlTokenNode { + /** + * Attributes that make an mpsace not spacelike + */ + public static NONSPACELIKE = [ + /* 'width' */ // spec says not to allow breaks here, but we allow it + 'height', + 'depth', + 'style', + 'mathbackground', + 'background', + ]; /** * @override */ public static defaults: PropertyList = { ...AbstractMmlTokenNode.defaults, - width: '0em', + width: '0em', height: '0ex', - depth: '0ex', - linebreak: 'auto' + depth: '0ex', + linebreak: 'auto', + indentshift: 'auto', // Use user configuration + indentalign: 'auto', + indenttarget: '', + indentalignfirst: 'indentalign', + indentshiftfirst: 'indentshift', + indentalignlast: 'indentalign', + indentshiftlast: 'indentshift', }; /** @@ -63,6 +81,7 @@ export class MmlMspace extends AbstractMmlTokenNode { /** * mspace can't have children + * * @override */ public get arity() { @@ -70,10 +89,12 @@ export class MmlMspace extends AbstractMmlTokenNode { } /** + * Only make mspace be space-like if it doesn't have certain attributes + * * @override */ public get isSpacelike() { - return true; + return !this.attributes.hasExplicit('linebreak') && this.canBreak; } /** @@ -82,9 +103,22 @@ export class MmlMspace extends AbstractMmlTokenNode { * @override */ public get hasNewline() { - let attributes = this.attributes; - return (attributes.getExplicit('width') == null && attributes.getExplicit('height') == null && - attributes.getExplicit('depth') == null && attributes.get('linebreak') === 'newline'); + const linebreak = this.attributes.get('linebreak'); + return ( + this.canBreak && + (linebreak === 'newline' || linebreak === 'indentingnewline') + ); } + /** + * @returns {boolean} True if mspace is allowed to break, i.e., + * no height/depth, no styles, no background color, + * and width non-negative. + */ + public get canBreak(): boolean { + return ( + !this.attributes.hasOneOf(MmlMspace.NONSPACELIKE) && + String(this.attributes.get('width')).trim().charAt(0) !== '-' + ); + } } diff --git a/ts/core/MmlTree/MmlNodes/msqrt.ts b/ts/core/MmlTree/MmlNodes/msqrt.ts index e7f289e80..88a79d68c 100644 --- a/ts/core/MmlTree/MmlNodes/msqrt.ts +++ b/ts/core/MmlTree/MmlNodes/msqrt.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,18 @@ */ /** - * @fileoverview Implements the MmlMsqrt node + * @file Implements the MmlMsqrt node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlNode, AttributeList, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { + MmlNode, + AbstractMmlNode, + AttributeList, + TEXCLASS, +} from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,12 +35,12 @@ import {MmlNode, AbstractMmlNode, AttributeList, TEXCLASS} from '../MmlNode.js'; */ export class MmlMsqrt extends AbstractMmlNode { - /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlNode.defaults + ...AbstractMmlNode.defaults, + 'data-vertical-align': 'bottom', }; /** @@ -52,6 +57,7 @@ export class MmlMsqrt extends AbstractMmlNode { /** * has an inferred mrow + * * @override */ public get arity() { @@ -60,6 +66,7 @@ export class MmlMsqrt extends AbstractMmlNode { /** * can contain line breaks + * * @override */ public get linebreakContainer() { @@ -80,8 +87,12 @@ export class MmlMsqrt extends AbstractMmlNode { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, _prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + _prime: boolean + ) { this.childNodes[0].setInheritedAttributes(attributes, display, level, true); } - } diff --git a/ts/core/MmlTree/MmlNodes/mstyle.ts b/ts/core/MmlTree/MmlNodes/mstyle.ts index 91e836b84..79345bd9e 100644 --- a/ts/core/MmlTree/MmlNodes/mstyle.ts +++ b/ts/core/MmlTree/MmlNodes/mstyle.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ */ /** - * @fileoverview Implements the MmlMstyle node + * @file Implements the MmlMstyle node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlLayoutNode, AttributeList} from '../MmlNode.js'; -import {INHERIT} from '../Attributes.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlLayoutNode, AttributeList } from '../MmlNode.js'; +import { INHERIT } from '../Attributes.js'; /*****************************************************************/ /** @@ -31,7 +31,6 @@ import {INHERIT} from '../Attributes.js'; */ export class MmlMstyle extends AbstractMmlLayoutNode { - /** * @override */ @@ -40,11 +39,11 @@ export class MmlMstyle extends AbstractMmlLayoutNode { scriptlevel: INHERIT, displaystyle: INHERIT, scriptsizemultiplier: 1 / Math.sqrt(2), - scriptminsize: '8px', // should be 8pt, but that is too large + scriptminsize: '.4em', // should be 8pt, but that is too large mathbackground: INHERIT, mathcolor: INHERIT, dir: INHERIT, - infixlinebreakstyle: 'before' + infixlinebreakstyle: 'before', }; /** @@ -61,12 +60,31 @@ export class MmlMstyle extends AbstractMmlLayoutNode { return this.childNodes[0] && this.childNodes[0].childNodes.length === 1; } + /** + * @override + */ + public setInheritedAttributes( + attributes: AttributeList = {}, + display: boolean = false, + level: number = 0, + prime: boolean = false + ) { + this.attributes.setInherited('displaystyle', display); + this.attributes.setInherited('scriptlevel', level); + super.setInheritedAttributes(attributes, display, level, prime); + } + /** * Handle scriptlevel changes, and add mstyle attributes to the ones being inherited. * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { let scriptlevel = this.attributes.getExplicit('scriptlevel'); if (scriptlevel != null) { scriptlevel = scriptlevel.toString(); @@ -75,19 +93,26 @@ export class MmlMstyle extends AbstractMmlLayoutNode { } else { level = parseInt(scriptlevel); } - prime = false; // style change resets tex prime style + prime = false; // style change resets tex prime style } - let displaystyle = this.attributes.getExplicit('displaystyle') as boolean; + const displaystyle = this.attributes.getExplicit('displaystyle') as boolean; if (displaystyle != null) { - display = (displaystyle === true); - prime = false; // style change resets tex prime style + display = displaystyle === true; + prime = false; // style change resets tex prime style } - const cramped = this.attributes.getExplicit('data-cramped') as boolean; // manual control of tex prime style + const cramped = this.attributes.getExplicit('data-cramped') as boolean; // manual control of tex prime style if (cramped != null) { prime = cramped; } - attributes = this.addInheritedAttributes(attributes, this.attributes.getAllAttributes()); - this.childNodes[0].setInheritedAttributes(attributes, display, level, prime); + attributes = this.addInheritedAttributes( + attributes, + this.attributes.getAllAttributes() + ); + this.childNodes[0].setInheritedAttributes( + attributes, + display, + level, + prime + ); } - } diff --git a/ts/core/MmlTree/MmlNodes/msubsup.ts b/ts/core/MmlTree/MmlNodes/msubsup.ts index e30a534cd..a4aca276c 100644 --- a/ts/core/MmlTree/MmlNodes/msubsup.ts +++ b/ts/core/MmlTree/MmlNodes/msubsup.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMsubsup, MmlMsub, and MmlMsup nodes + * @file Implements the MmlMsubsup, MmlMsub, and MmlMsup nodes * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlBaseNode, AttributeList} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlBaseNode, AttributeList } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,14 +30,13 @@ import {AbstractMmlBaseNode, AttributeList} from '../MmlNode.js'; */ export class MmlMsubsup extends AbstractMmlBaseNode { - /** * @override */ public static defaults: PropertyList = { ...AbstractMmlBaseNode.defaults, subscriptshift: '', - superscriptshift: '' + superscriptshift: '', }; /** @@ -49,6 +48,7 @@ export class MmlMsubsup extends AbstractMmlBaseNode { /** * requires three children + * * @override */ public get arity() { @@ -56,21 +56,21 @@ export class MmlMsubsup extends AbstractMmlBaseNode { } /** - * @return {number} The position of the base element + * @returns {number} The position of the base element */ public get base(): number { return 0; } /** - * @return {number} The position of the subscript (overridden in msup below) + * @returns {number} The position of the subscript (overridden in msup below) */ public get sub(): number { return 1; } /** - * @return {number} The position of the superscript (overridden in msup below) + * @returns {number} The position of the superscript (overridden in msup below) */ public get sup(): number { return 2; @@ -81,16 +81,30 @@ export class MmlMsubsup extends AbstractMmlBaseNode { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { - let nodes = this.childNodes; + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { + const nodes = this.childNodes; nodes[0].setInheritedAttributes(attributes, display, level, prime); - nodes[1].setInheritedAttributes(attributes, false, level + 1, prime || this.sub === 1); + nodes[1].setInheritedAttributes( + attributes, + false, + level + 1, + prime || this.sub === 1 + ); if (!nodes[2]) { return; } - nodes[2].setInheritedAttributes(attributes, false, level + 1, prime || this.sub === 2); + nodes[2].setInheritedAttributes( + attributes, + false, + level + 1, + prime || this.sub === 2 + ); } - } /*****************************************************************/ @@ -99,12 +113,11 @@ export class MmlMsubsup extends AbstractMmlBaseNode { */ export class MmlMsub extends MmlMsubsup { - /** * @override */ public static defaults: PropertyList = { - ...MmlMsubsup.defaults + ...MmlMsubsup.defaults, }; /** @@ -116,12 +129,12 @@ export class MmlMsub extends MmlMsubsup { /** * only gets two children + * * @override */ public get arity() { return 2; } - } /*****************************************************************/ @@ -130,12 +143,11 @@ export class MmlMsub extends MmlMsubsup { */ export class MmlMsup extends MmlMsubsup { - /** * @override */ public static defaults: PropertyList = { - ...MmlMsubsup.defaults + ...MmlMsubsup.defaults, }; /** @@ -147,6 +159,7 @@ export class MmlMsup extends MmlMsubsup { /** * only gets two children + * * @override */ get arity() { @@ -155,6 +168,7 @@ export class MmlMsup extends MmlMsubsup { /** * child 1 is superscript + * * @override */ get sup() { @@ -163,11 +177,10 @@ export class MmlMsup extends MmlMsubsup { /** * child 2 is null (no subscript) + * * @override */ get sub() { return 2; } - } - diff --git a/ts/core/MmlTree/MmlNodes/mtable.ts b/ts/core/MmlTree/MmlNodes/mtable.ts index fe9bef34f..87c9d377c 100644 --- a/ts/core/MmlTree/MmlNodes/mtable.ts +++ b/ts/core/MmlTree/MmlNodes/mtable.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,20 @@ */ /** - * @fileoverview Implements the MmlMtable node + * @file Implements the MmlMtable node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlNode, AttributeList, TEXCLASS, indentAttributes} from '../MmlNode.js'; -import {split} from '../../../util/string.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { + MmlNode, + AbstractMmlNode, + AttributeList, + TEXCLASS, + indentAttributes, +} from '../MmlNode.js'; +import { split } from '../../../util/string.js'; /*****************************************************************/ /** @@ -31,7 +37,6 @@ import {split} from '../../../util/string.js'; */ export class MmlMtable extends AbstractMmlNode { - /** * @override */ @@ -54,14 +59,15 @@ export class MmlMtable extends AbstractMmlNode { equalcolumns: false, displaystyle: false, side: 'right', - minlabelspacing: '0.8em' + minlabelspacing: '0.8em', + 'data-break-align': 'top', // list of top/bottom/center for how broken cells should be aligned by column }; /** * Extra properties for this node */ public properties = { - useHeight: true + useHeight: true, }; /** @@ -78,6 +84,7 @@ export class MmlMtable extends AbstractMmlNode { /** * Linebreaks are allowed in tables + * * @override */ public get linebreakContainer() { @@ -85,9 +92,23 @@ export class MmlMtable extends AbstractMmlNode { } /** + * Don't reset indent attributes + * * @override */ - public setInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + public get linebreakAlign() { + return ''; + } + + /** + * @override + */ + public setInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { // // Force inheritance of shift and align values (since they are needed to output tables with labels) // but make sure they are not given explicitly on the tag. @@ -96,8 +117,8 @@ export class MmlMtable extends AbstractMmlNode { if (attributes[name]) { this.attributes.setInherited(name, attributes[name][1]); } - if (this.attributes.getExplicit(name) !== undefined) { - delete (this.attributes.getAllAttributes())[name]; + if (this.attributes.hasExplicit(name)) { + this.attributes.unset(name); } } super.setInheritedAttributes(attributes, display, level, prime); @@ -110,18 +131,25 @@ export class MmlMtable extends AbstractMmlNode { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, _prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + _prime: boolean + ) { for (const child of this.childNodes) { if (!child.isKind('mtr')) { - this.replaceChild(this.factory.create('mtr'), child) - .appendChild(child); + this.replaceChild(this.factory.create('mtr'), child).appendChild(child); } } - level = this.getProperty('scriptlevel') as number || level; - display = !!(this.attributes.getExplicit('displaystyle') || this.attributes.getDefault('displaystyle')); + display = !!( + this.attributes.getExplicit('displaystyle') || + this.attributes.getDefault('displaystyle') + ); attributes = this.addInheritedAttributes(attributes, { columnalign: this.attributes.get('columnalign'), - rowalign: 'center' + rowalign: 'center', + 'data-break-align': this.attributes.get('data-break-align'), }); const cramped = this.attributes.getExplicit('data-cramped') as boolean; const ralign = split(this.attributes.get('rowalign') as string); @@ -137,12 +165,12 @@ export class MmlMtable extends AbstractMmlNode { * @override */ protected verifyChildren(options: PropertyList) { - let mtr: MmlNode = null; // all consecutive non-mtr elements are collected into one mtr + let mtr: MmlNode = null; // all consecutive non-mtr elements are collected into one mtr const factory = this.factory; for (let i = 0; i < this.childNodes.length; i++) { const child = this.childNodes[i]; if (child.isKind('mtr')) { - mtr = null; // start a new row if there are non-mtr children + mtr = null; // start a new row if there are non-mtr children } else { const isMtd = child.isKind('mtd'); // @@ -151,17 +179,24 @@ export class MmlMtable extends AbstractMmlNode { // if (mtr) { this.removeChild(child); - i--; // there is one fewer child now + i--; // there is one fewer child now } else { - mtr = this.replaceChild(factory.create('mtr'), child) as MmlNode; + mtr = this.replaceChild(factory.create('mtr'), child); } - mtr.appendChild(isMtd ? child : factory.create('mtd', {}, [child])); // Move the child into the mtr + mtr.appendChild(isMtd ? child : factory.create('mtd', {}, [child])); // Move the child into the mtr if (!options['fixMtables']) { - child.parent.removeChild(child); // remove the child from its mtd or mtr - child.parent = this; // ... and make it think it is a child of the table again - isMtd && mtr.appendChild(factory.create('mtd')); // child will be replaced, so make sure there is an mtd - const merror = child.mError('Children of ' + this.kind + ' must be mtr or mlabeledtr', options, isMtd); - mtr.childNodes[mtr.childNodes.length - 1].appendChild(merror); // append the error to the mtd in the mtr + child.parent.removeChild(child); // remove the child from its mtd or mtr + child.parent = this; // ... and make it think it is a child of the table again + if (isMtd) { + // child will be replaced, so make sure there is an mtd + mtr.appendChild(factory.create('mtd')); + } + const merror = child.mError( + 'Children of ' + this.kind + ' must be mtr or mlabeledtr', + options, + isMtd + ); + mtr.childNodes[mtr.childNodes.length - 1].appendChild(merror); // append the error to the mtd in the mtr } } } @@ -178,5 +213,4 @@ export class MmlMtable extends AbstractMmlNode { } return this; } - } diff --git a/ts/core/MmlTree/MmlNodes/mtd.ts b/ts/core/MmlTree/MmlNodes/mtd.ts index 926e448ec..7d1670cd3 100644 --- a/ts/core/MmlTree/MmlNodes/mtd.ts +++ b/ts/core/MmlTree/MmlNodes/mtd.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,14 @@ */ /** - * @fileoverview Implements the MmlMtd node + * @file Implements the MmlMtd node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlBaseNode, MmlNode} from '../MmlNode.js'; -import {INHERIT} from '../Attributes.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlBaseNode, MmlNode } from '../MmlNode.js'; +import { INHERIT } from '../Attributes.js'; /*****************************************************************/ /** @@ -31,7 +31,6 @@ import {INHERIT} from '../Attributes.js'; */ export class MmlMtd extends AbstractMmlBaseNode { - /** * @override */ @@ -41,7 +40,8 @@ export class MmlMtd extends AbstractMmlBaseNode { columnspan: 1, rowalign: INHERIT, columnalign: INHERIT, - groupalign: INHERIT + groupalign: INHERIT, + 'data-vertical-align': 'top', }; /** @@ -53,7 +53,8 @@ export class MmlMtd extends AbstractMmlBaseNode { /** * has an inferred mrow - * @overrride + * + * @override */ public get arity() { return -1; @@ -61,12 +62,20 @@ export class MmlMtd extends AbstractMmlBaseNode { /** * can contain line breaks + * * @override */ public get linebreakContainer() { return true; } + /** + * @override + */ + public get linebreakAlign() { + return 'columnalign'; + } + /** * Check that parent is mtr * @@ -74,7 +83,11 @@ export class MmlMtd extends AbstractMmlBaseNode { */ protected verifyChildren(options: PropertyList) { if (this.parent && !this.parent.isKind('mtr')) { - this.mError(this.kind + ' can only be a child of an mtr or mlabeledtr', options, true); + this.mError( + this.kind + ' can only be a child of an mtr or mlabeledtr', + options, + true + ); return; } super.verifyChildren(options); @@ -88,5 +101,4 @@ export class MmlMtd extends AbstractMmlBaseNode { this.childNodes[0].setTeXclass(null); return this; } - } diff --git a/ts/core/MmlTree/MmlNodes/mtext.ts b/ts/core/MmlTree/MmlNodes/mtext.ts index 1ead09fbe..0c83ebd45 100644 --- a/ts/core/MmlTree/MmlNodes/mtext.ts +++ b/ts/core/MmlTree/MmlNodes/mtext.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMtext node + * @file Implements the MmlMtext node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlTokenNode, TEXCLASS } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,12 +30,16 @@ import {AbstractMmlTokenNode, TEXCLASS} from '../MmlNode.js'; */ export class MmlMtext extends AbstractMmlTokenNode { + /** + * Attributes that make an mpsace not spacelike + */ + public static NONSPACELIKE = ['style', 'mathbackground', 'background']; /** * @override */ public static defaults: PropertyList = { - ...AbstractMmlTokenNode.defaults + ...AbstractMmlTokenNode.defaults, }; /** @@ -51,11 +55,16 @@ export class MmlMtext extends AbstractMmlTokenNode { } /** - * is always space-like according to the spec + * According to the spec, is always space-like, + * but we make it so only if it contains only spaces and + * doesn't have certain attributes. + * * @override */ public get isSpacelike() { - return true; + return ( + !!this.getText().match(/^\s*$/) && + !this.attributes.hasOneOf(MmlMtext.NONSPACELIKE) + ); } - } diff --git a/ts/core/MmlTree/MmlNodes/mtr.ts b/ts/core/MmlTree/MmlNodes/mtr.ts index a75061323..d7d1236dc 100644 --- a/ts/core/MmlTree/MmlNodes/mtr.ts +++ b/ts/core/MmlTree/MmlNodes/mtr.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ */ /** - * @fileoverview Implements the MmlMtr and MmlMlabeledtr nodes + * @file Implements the MmlMtr and MmlMlabeledtr nodes * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {MmlNode, AbstractMmlNode, AttributeList} from '../MmlNode.js'; -import {INHERIT} from '../Attributes.js'; -import {split} from '../../../util/string.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { MmlNode, AbstractMmlNode, AttributeList } from '../MmlNode.js'; +import { INHERIT } from '../Attributes.js'; +import { split } from '../../../util/string.js'; /*****************************************************************/ /** @@ -32,7 +32,6 @@ import {split} from '../../../util/string.js'; */ export class MmlMtr extends AbstractMmlNode { - /** * @override */ @@ -40,7 +39,8 @@ export class MmlMtr extends AbstractMmlNode { ...AbstractMmlNode.defaults, rowalign: INHERIT, columnalign: INHERIT, - groupalign: INHERIT + groupalign: INHERIT, + 'data-break-align': 'top', // how the broken cells in this row should be aligned }; /** @@ -52,34 +52,55 @@ export class MmlMtr extends AbstractMmlNode { /** * can contain linebreaks + * * @override */ public get linebreakContainer() { return true; } + /** + * Don't reset indent attributes + * + * @override + */ + public get linebreakAlign() { + return ''; + } + /** * Inherit the mtr attributes * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { for (const child of this.childNodes) { if (!child.isKind('mtd')) { - this.replaceChild(this.factory.create('mtd'), child) - .appendChild(child); + this.replaceChild(this.factory.create('mtd'), child).appendChild(child); } } const calign = split(this.attributes.get('columnalign') as string); + const balign = split(this.attributes.get('data-break-align') as string); if (this.arity === 1) { calign.unshift(this.parent.attributes.get('side') as string); + balign.unshift('top'); } attributes = this.addInheritedAttributes(attributes, { rowalign: this.attributes.get('rowalign'), - columnalign: 'center' + columnalign: 'center', + 'data-break-align': 'top', }); for (const child of this.childNodes) { attributes.columnalign[1] = calign.shift() || attributes.columnalign[1]; + attributes['data-vertical-align'] = [ + this.kind, + balign.shift() || attributes['data-break-align'][1], + ]; child.setInheritedAttributes(attributes, display, level, prime); } } @@ -91,12 +112,16 @@ export class MmlMtr extends AbstractMmlNode { */ protected verifyChildren(options: PropertyList) { if (this.parent && !this.parent.isKind('mtable')) { - this.mError(this.kind + ' can only be a child of an mtable', options, true); + this.mError( + this.kind + ' can only be a child of an mtable', + options, + true + ); return; } for (const child of this.childNodes) { if (!child.isKind('mtd')) { - let mtd = this.replaceChild(this.factory.create('mtd'), child) as MmlNode; + const mtd = this.replaceChild(this.factory.create('mtd'), child); mtd.appendChild(child); if (!options['fixMtables']) { child.mError('Children of ' + this.kind + ' must be mtd', options); @@ -116,7 +141,6 @@ export class MmlMtr extends AbstractMmlNode { } return this; } - } /*****************************************************************/ @@ -125,7 +149,6 @@ export class MmlMtr extends AbstractMmlNode { */ export class MmlMlabeledtr extends MmlMtr { - /** * @override */ @@ -135,10 +158,10 @@ export class MmlMlabeledtr extends MmlMtr { /** * requires at least one child (the label) + * * @override */ get arity() { return 1; } - } diff --git a/ts/core/MmlTree/MmlNodes/munderover.ts b/ts/core/MmlTree/MmlNodes/munderover.ts index 074418b44..0471987b9 100644 --- a/ts/core/MmlTree/MmlNodes/munderover.ts +++ b/ts/core/MmlTree/MmlNodes/munderover.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlMunderover node + * @file Implements the MmlMunderover node * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlBaseNode, AttributeList} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlBaseNode, AttributeList } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,7 +30,6 @@ import {AbstractMmlBaseNode, AttributeList} from '../MmlNode.js'; */ export class MmlMunderover extends AbstractMmlBaseNode { - /** * @override */ @@ -38,7 +37,7 @@ export class MmlMunderover extends AbstractMmlBaseNode { ...AbstractMmlBaseNode.defaults, accent: false, accentunder: false, - align: 'center' + align: 'center', }; /** @@ -55,6 +54,7 @@ export class MmlMunderover extends AbstractMmlBaseNode { /** * requires three children + * * @override */ public get arity() { @@ -62,21 +62,21 @@ export class MmlMunderover extends AbstractMmlBaseNode { } /** - * @return {number} The base is child 0 + * @returns {number} The base is child 0 */ public get base(): number { return 0; } /** - * @return {number} Child 1 goes under (overridden by mover below) + * @returns {number} Child 1 goes under (overridden by mover below) */ public get under(): number { return 1; } /** - * @return {number} Child 2 goes over (overridden by mover below) + * @returns {number} Child 2 goes over (overridden by mover below) */ public get over(): number { return 2; @@ -84,6 +84,7 @@ export class MmlMunderover extends AbstractMmlBaseNode { /** * can contain line breaks + * * @override */ public get linebreakContainer() { @@ -98,21 +99,39 @@ export class MmlMunderover extends AbstractMmlBaseNode { * * @override */ - protected setChildInheritedAttributes(attributes: AttributeList, display: boolean, level: number, prime: boolean) { - let nodes = this.childNodes; - nodes[0].setInheritedAttributes(attributes, display, level, prime || !!nodes[this.over]); - let force = !!(!display && nodes[0].coreMO().attributes.get('movablelimits')); - let ACCENTS = (this.constructor as typeof MmlMunderover).ACCENTS; - nodes[1].setInheritedAttributes(attributes, false, - this.getScriptlevel(ACCENTS[1], force, level), - prime || this.under === 1); + protected setChildInheritedAttributes( + attributes: AttributeList, + display: boolean, + level: number, + prime: boolean + ) { + const nodes = this.childNodes; + nodes[0].setInheritedAttributes( + attributes, + display, + level, + prime || !!nodes[this.over] + ); + const force = !!( + !display && nodes[0].coreMO().attributes.get('movablelimits') + ); + const ACCENTS = (this.constructor as typeof MmlMunderover).ACCENTS; + nodes[1].setInheritedAttributes( + attributes, + false, + this.getScriptlevel(ACCENTS[1], force, level), + prime || this.under === 1 + ); this.setInheritedAccent(1, ACCENTS[1], display, level, prime, force); if (!nodes[2]) { return; } - nodes[2].setInheritedAttributes(attributes, false, - this.getScriptlevel(ACCENTS[2], force, level), - prime || this.under === 2); + nodes[2].setInheritedAttributes( + attributes, + false, + this.getScriptlevel(ACCENTS[2], force, level), + prime || this.under === 2 + ); this.setInheritedAccent(2, ACCENTS[2], display, level, prime, force); } @@ -120,9 +139,13 @@ export class MmlMunderover extends AbstractMmlBaseNode { * @param {string} accent The name of the accent attribute to check ("accent" or "accentunder") * @param {boolean} force True if the scriptlevel change is to be forced to occur * @param {number} level The current scriptlevel - * @return {number} The new script level based on the accent attribute + * @returns {number} The new script level based on the accent attribute */ - protected getScriptlevel(accent: string, force: boolean, level: number): number { + protected getScriptlevel( + accent: string, + force: boolean, + level: number + ): number { if (force || !this.attributes.get(accent)) { level++; } @@ -141,18 +164,28 @@ export class MmlMunderover extends AbstractMmlBaseNode { * @param {number} prime The TeX prime style * @param {boolean} force Whether to force the scriptlevel change */ - protected setInheritedAccent(n: number, accent: string, display: boolean, level: number, - prime: boolean, force: boolean) { - let node = this.childNodes[n]; - if (this.attributes.getExplicit(accent) == null && node.isEmbellished) { - let value = node.coreMO().attributes.get('accent'); + protected setInheritedAccent( + n: number, + accent: string, + display: boolean, + level: number, + prime: boolean, + force: boolean + ) { + const node = this.childNodes[n]; + if (!this.attributes.hasExplicit(accent) && node.isEmbellished) { + const value = node.coreMO().attributes.get('accent'); this.attributes.setInherited(accent, value); if (value !== this.attributes.getDefault(accent)) { - node.setInheritedAttributes({}, display, this.getScriptlevel(accent, force, level), prime); + node.setInheritedAttributes( + {}, + display, + this.getScriptlevel(accent, force, level), + prime + ); } } } - } /*****************************************************************/ @@ -161,12 +194,11 @@ export class MmlMunderover extends AbstractMmlBaseNode { */ export class MmlMunder extends MmlMunderover { - /** * @override */ public static defaults: PropertyList = { - ...MmlMunderover.defaults + ...MmlMunderover.defaults, }; /** @@ -178,12 +210,12 @@ export class MmlMunder extends MmlMunderover { /** * has only two children + * * @override */ public get arity() { return 2; } - } /*****************************************************************/ @@ -192,12 +224,11 @@ export class MmlMunder extends MmlMunderover { */ export class MmlMover extends MmlMunderover { - /** * @override */ public static defaults: PropertyList = { - ...MmlMunderover.defaults + ...MmlMunderover.defaults, }; /** * The first child is the over accent (second never occurs) @@ -213,6 +244,7 @@ export class MmlMover extends MmlMunderover { /** * has only two children + * * @override */ get arity() { @@ -221,6 +253,7 @@ export class MmlMover extends MmlMunderover { /** * Child 1 is the over node + * * @override */ public get over() { @@ -229,10 +262,10 @@ export class MmlMover extends MmlMunderover { /** * Child 2 is the null (the under node) + * * @override */ public get under() { return 2; } - } diff --git a/ts/core/MmlTree/MmlNodes/semantics.ts b/ts/core/MmlTree/MmlNodes/semantics.ts index a81f5cb85..2292c6fc5 100644 --- a/ts/core/MmlTree/MmlNodes/semantics.ts +++ b/ts/core/MmlTree/MmlNodes/semantics.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Implements the MmlSemantics, MmlAnnotation, and MmlAnnotationXML nodes + * @file Implements the MmlSemantics, MmlAnnotation, and MmlAnnotationXML nodes * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../../Tree/Node.js'; -import {AbstractMmlNode, AbstractMmlBaseNode} from '../MmlNode.js'; +import { PropertyList } from '../../Tree/Node.js'; +import { AbstractMmlNode, AbstractMmlBaseNode } from '../MmlNode.js'; /*****************************************************************/ /** @@ -30,14 +30,13 @@ import {AbstractMmlNode, AbstractMmlBaseNode} from '../MmlNode.js'; */ export class MmlSemantics extends AbstractMmlBaseNode { - /** * @override */ public static defaults: PropertyList = { ...AbstractMmlBaseNode.defaults, definitionUrl: null, - encoding: null + encoding: null, }; /** @@ -49,6 +48,7 @@ export class MmlSemantics extends AbstractMmlBaseNode { /** * requires at least one node + * * @override */ public get arity() { @@ -57,12 +57,12 @@ export class MmlSemantics extends AbstractMmlBaseNode { /** * Ignore when looking for partent node + * * @override */ public get notParent() { return true; } - } /*****************************************************************/ @@ -71,7 +71,6 @@ export class MmlSemantics extends AbstractMmlBaseNode { */ export class MmlAnnotationXML extends AbstractMmlNode { - /** * @override */ @@ -81,7 +80,7 @@ export class MmlAnnotationXML extends AbstractMmlNode { encoding: null, cd: 'mathmlkeys', name: '', - src: null + src: null, }; /** @@ -93,10 +92,10 @@ export class MmlAnnotationXML extends AbstractMmlNode { /** * Children are XMLNodes, so don't bother inheritting to them + * * @override */ protected setChildInheritedAttributes() {} - } /*****************************************************************/ @@ -105,19 +104,18 @@ export class MmlAnnotationXML extends AbstractMmlNode { */ export class MmlAnnotation extends MmlAnnotationXML { - /** * @override */ public static defaults = { - ...MmlAnnotationXML.defaults + ...MmlAnnotationXML.defaults, }; /** * Extra properties for this node */ public properties = { - isChars: true + isChars: true, }; /** @@ -126,5 +124,4 @@ export class MmlAnnotation extends MmlAnnotationXML { public get kind() { return 'annotation'; } - } diff --git a/ts/core/MmlTree/MmlVisitor.ts b/ts/core/MmlTree/MmlVisitor.ts index 3efe2bec8..b05ba1ee2 100644 --- a/ts/core/MmlTree/MmlVisitor.ts +++ b/ts/core/MmlTree/MmlVisitor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,27 @@ */ /** - * @fileoverview A visitor class that visits MmlNode trees + * @file A visitor class that visits MmlNode trees * * @author dpvc@mathjax.org (Davide Cervone) */ -import {TextNode, XMLNode} from './MmlNode.js'; -import {MmlFactory} from './MmlFactory.js'; -import {AbstractVisitor} from '../Tree/Visitor.js'; +import { + MmlNode, + TextNode, + XMLNode, + TEXCLASS, + TEXCLASSNAMES, +} from './MmlNode.js'; +import { MmlMo } from './MmlNodes/mo.js'; +import { MmlMi } from './MmlNodes/mi.js'; +import { HtmlNode } from './MmlNodes/HtmlNode.js'; +import { MmlFactory } from './MmlFactory.js'; +import { AbstractVisitor } from '../Tree/Visitor.js'; +import { PropertyList } from '../Tree/Node.js'; +import { lookup } from '../../util/Options.js'; + +export const DATAMJX = 'data-mjx-'; /*****************************************************************/ /** @@ -31,12 +44,39 @@ import {AbstractVisitor} from '../Tree/Visitor.js'; * for visitors that accept MmlNode trees) */ -export class MmlVisitor extends AbstractVisitor { +export class MmlVisitor extends AbstractVisitor { + /** + * MmlNode kinds to replace with other names + */ + public static rename: PropertyList = { + TeXAtom: 'mrow', + }; + + /** + * Translations for the internal mathvariants + */ + public static variants: PropertyList = { + '-tex-calligraphic': 'script', + '-tex-bold-calligraphic': 'bold-script', + '-tex-oldstyle': 'normal', + '-tex-bold-oldstyle': 'bold', + '-tex-mathit': 'italic', + }; + + /** + * Attributes to include on every element of a given kind + */ + public static defaultAttributes: { [kind: string]: PropertyList } = { + math: { + xmlns: 'http://www.w3.org/1998/Math/MathML', + }, + }; + /** * @param {MmlFactory} factory The MmlNode factory (defaults to MmlFactory if not given) * - * @constructor - * @extends {AbstractVisitor} + * @class + * @augments {AbstractVisitor} */ constructor(factory: MmlFactory = null) { if (!factory) { @@ -51,17 +91,138 @@ export class MmlVisitor extends AbstractVisitor { */ /** - * @param {TextNode} node The TextNode to visit - * @param {any[]} args Any arguments needed by the visitor - * @return {any} Any return value needed for the visitor + * @param {TextNode} _node The TextNode to visit + * @param {any[]} _args Any arguments needed by the visitor + * @returns {any} Any return value needed for the visitor */ public visitTextNode(_node: TextNode, ..._args: any[]): any {} /** - * @param {XMLNode} node The XMLNode to visit - * @param {any[]} args Any arguments needed by the visitor - * @return {any} Any return value needed for the visitor + * @param {XMLNode} _node The XMLNode to visit + * @param {any[]} _args Any arguments needed by the visitor + * @returns {any} Any return value needed for the visitor */ public visitXMLNode(_node: XMLNode, ..._args: any[]): any {} + /** + * @param {HtmlNode} _node The XMLNode to visit + * @param {any[]} _args Any arguments needed by the visitor + * @returns {any} Any return value needed for the visitor + */ + public visitHtmlNode(_node: HtmlNode, ..._args: any[]): any {} + + /***********************************************/ + /** + * Utilities for handling attributes + */ + + /** + * @param {MmlNode} node The node whose kind is needed + * @returns {string} The MamlML node name for that kind + */ + protected getKind(node: MmlNode): string { + const kind = node.kind; + return lookup(kind, (this.constructor as typeof MmlVisitor).rename, kind); + } + + /***********************************************/ + /** + * Utilities for handling attributes + */ + + /** + * @param {MmlNode} node The node whose attributes are to be produced + * @returns {PropertyList} The attribute list + */ + protected getAttributeList(node: MmlNode): PropertyList { + const CLASS = this.constructor as typeof MmlVisitor; + const defaults = lookup(node.kind, CLASS.defaultAttributes, {}); + const attributes = Object.assign( + {}, + defaults, + this.getDataAttributes(node), + node.attributes.getAllAttributes() + ) as PropertyList; + const variants = CLASS.variants; + if (Object.hasOwn(attributes, 'mathvariant')) { + if (Object.hasOwn(variants, attributes.mathvariant as string)) { + attributes.mathvariant = variants[attributes.mathvariant as string]; + } else if (node.getProperty('ignore-variant')) { + delete attributes.mathvariant; + } + } + return attributes; + } + + /** + * Create the list of data-mjx-* attributes + * + * @param {MmlNode} node The node whose data list is to be generated + * @returns {PropertyList} The final class attribute list + */ + protected getDataAttributes(node: MmlNode): PropertyList { + const data = {} as PropertyList; + const variant = node.attributes.getExplicit('mathvariant') as string; + const variants = (this.constructor as typeof MmlVisitor).variants; + if ( + variant && + (node.getProperty('ignore-variant') || Object.hasOwn(variants, variant)) + ) { + this.setDataAttribute(data, 'variant', variant); + } + if (node.getProperty('variantForm')) { + this.setDataAttribute(data, 'alternate', '1'); + } + if (node.getProperty('pseudoscript')) { + this.setDataAttribute(data, 'pseudoscript', 'true'); + } + if (node.getProperty('autoOP') === false) { + this.setDataAttribute(data, 'auto-op', 'false'); + } + const vbox = node.getProperty('vbox') as string; + if (vbox) { + this.setDataAttribute(data, 'vbox', vbox); + } + const scriptalign = node.getProperty('scriptalign') as string; + if (scriptalign) { + this.setDataAttribute(data, 'script-align', scriptalign); + } + const accent = node.getProperty('mathaccent') as boolean; + if (accent !== undefined) { + if ( + (accent && !(node as MmlMo).isMathAccent()) || + (!accent && !(node as MmlMo).isMathAccentWithWidth()) + ) { + this.setDataAttribute(data, 'mathaccent', accent.toString()); + } + } + const texclass = node.getProperty('texClass') as number; + if (texclass !== undefined) { + let setclass = true; + if (texclass === TEXCLASS.OP && node.isKind('mi')) { + const name = (node as MmlMi).getText(); + setclass = !(name.length > 1 && name.match(MmlMi.operatorName)); + } + if (setclass) { + this.setDataAttribute( + data, + 'texclass', + texclass < 0 ? 'NONE' : TEXCLASSNAMES[texclass] + ); + } + } + if (node.getProperty('smallmatrix')) { + this.setDataAttribute(data, 'smallmatrix', 'true'); + } + return data; + } + + /** + * @param {PropertyList} data The class attribute list + * @param {string} name The name for the data-mjx-name attribute + * @param {string} value The value of the attribute + */ + protected setDataAttribute(data: PropertyList, name: string, value: string) { + data[DATAMJX + name] = value; + } } diff --git a/ts/core/MmlTree/OperatorDictionary.ts b/ts/core/MmlTree/OperatorDictionary.ts index 25b755150..bf35d289c 100644 --- a/ts/core/MmlTree/OperatorDictionary.ts +++ b/ts/core/MmlTree/OperatorDictionary.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,19 @@ */ /** - * @fileoverview Defines the operator dictionary structure + * @file Defines the operator dictionary structure * * @author dpvc@mathjax.org (Davide Cervone) */ -import {PropertyList} from '../Tree/Node.js'; -import {TEXCLASS} from './MmlNode.js'; +import { PropertyList } from '../Tree/Node.js'; +import { TEXCLASS } from './MmlNode.js'; /** * Types needed for the operator dictionary */ export type OperatorDef = [number, number, number, PropertyList]; -export type OperatorList = {[name: string]: OperatorDef}; +export type OperatorList = { [name: string]: OperatorDef }; export type RangeDef = [number, number, number, string, string?]; /** @@ -36,110 +36,131 @@ export type RangeDef = [number, number, number, string, string?]; * @param {number} rspace The operator's MathML right-hand spacing * @param {number} texClass The default TeX class for the operator * @param {PropertyList} properties Any default properties from the operator dictionary - * @return {OperatorDef} The operator definition array + * @returns {OperatorDef} The operator definition array */ -export function OPDEF(lspace: number, rspace: number, texClass: number = TEXCLASS.BIN, - properties: PropertyList = null): OperatorDef { - return [lspace, rspace, texClass, properties] as OperatorDef; - } +export function OPDEF( + lspace: number, + rspace: number, + texClass: number = TEXCLASS.BIN, + properties: PropertyList = null +): OperatorDef { + return [lspace, rspace, texClass, properties] as OperatorDef; +} /** * The various kinds of operators in the dictionary */ export const MO = { - ORD: OPDEF(0, 0, TEXCLASS.ORD), - ORD11: OPDEF(1, 1, TEXCLASS.ORD), - ORD21: OPDEF(2, 1, TEXCLASS.ORD), - ORD02: OPDEF(0, 2, TEXCLASS.ORD), - ORD55: OPDEF(5, 5, TEXCLASS.ORD), - NONE: OPDEF(0, 0, TEXCLASS.NONE), - OP: OPDEF(1, 2, TEXCLASS.OP, {largeop: true, movablelimits: true, symmetric: true}), - OPFIXED: OPDEF(1, 2, TEXCLASS.OP, {largeop: true, movablelimits: true}), - INTEGRAL: OPDEF(0, 1, TEXCLASS.OP, {largeop: true, symmetric: true}), - INTEGRAL2: OPDEF(1, 2, TEXCLASS.OP, {largeop: true, symmetric: true}), - BIN3: OPDEF(3, 3, TEXCLASS.BIN), - BIN4: OPDEF(4, 4, TEXCLASS.BIN), - BIN01: OPDEF(0, 1, TEXCLASS.BIN), - BIN5: OPDEF(5, 5, TEXCLASS.BIN), - TALLBIN: OPDEF(4, 4, TEXCLASS.BIN, {stretchy: true}), - BINOP: OPDEF(4, 4, TEXCLASS.BIN, {largeop: true, movablelimits: true}), - REL: OPDEF(5, 5, TEXCLASS.REL), - REL1: OPDEF(1, 1, TEXCLASS.REL, {stretchy: true}), - REL4: OPDEF(4, 4, TEXCLASS.REL), - RELSTRETCH: OPDEF(5, 5, TEXCLASS.REL, {stretchy: true}), - RELACCENT: OPDEF(5, 5, TEXCLASS.REL, {accent: true}), - WIDEREL: OPDEF(5, 5, TEXCLASS.REL, {accent: true, stretchy: true}), - OPEN: OPDEF(0, 0, TEXCLASS.OPEN, {fence: true, stretchy: true, symmetric: true}), - CLOSE: OPDEF(0, 0, TEXCLASS.CLOSE, {fence: true, stretchy: true, symmetric: true}), - INNER: OPDEF(0, 0, TEXCLASS.INNER), - PUNCT: OPDEF(0, 3, TEXCLASS.PUNCT), - ACCENT: OPDEF(0, 0, TEXCLASS.ORD, {accent: true}), - WIDEACCENT: OPDEF(0, 0, TEXCLASS.ORD, {accent: true, stretchy: true}) + ORD: OPDEF(0, 0, TEXCLASS.ORD), + ORD11: OPDEF(1, 1, TEXCLASS.ORD), + ORD21: OPDEF(2, 1, TEXCLASS.ORD), + ORD02: OPDEF(0, 2, TEXCLASS.ORD), + ORD55: OPDEF(5, 5, TEXCLASS.ORD), + NONE: OPDEF(0, 0, TEXCLASS.NONE), + OP: OPDEF(1, 2, TEXCLASS.OP, { + largeop: true, + movablelimits: true, + symmetric: true, + }), + OPFIXED: OPDEF(1, 2, TEXCLASS.OP, { largeop: true, movablelimits: true }), + INTEGRAL: OPDEF(0, 1, TEXCLASS.OP, { largeop: true, symmetric: true }), + INTEGRAL2: OPDEF(1, 2, TEXCLASS.OP, { largeop: true, symmetric: true }), + BIN3: OPDEF(3, 3, TEXCLASS.BIN), + BIN4: OPDEF(4, 4, TEXCLASS.BIN), + BIN01: OPDEF(0, 1, TEXCLASS.BIN), + BIN5: OPDEF(5, 5, TEXCLASS.BIN), + TALLBIN: OPDEF(4, 4, TEXCLASS.BIN, { stretchy: true }), + BINOP: OPDEF(4, 4, TEXCLASS.BIN, { largeop: true, movablelimits: true }), + REL: OPDEF(5, 5, TEXCLASS.REL), + REL1: OPDEF(1, 1, TEXCLASS.REL, { stretchy: true }), + REL4: OPDEF(4, 4, TEXCLASS.REL), + RELSTRETCH: OPDEF(5, 5, TEXCLASS.REL, { stretchy: true }), + RELACCENT: OPDEF(5, 5, TEXCLASS.REL, { accent: true }), + WIDEREL: OPDEF(5, 5, TEXCLASS.REL, { accent: true, stretchy: true }), + OPEN: OPDEF(0, 0, TEXCLASS.OPEN, { + fence: true, + stretchy: true, + symmetric: true, + }), + CLOSE: OPDEF(0, 0, TEXCLASS.CLOSE, { + fence: true, + stretchy: true, + symmetric: true, + }), + INNER: OPDEF(0, 0, TEXCLASS.INNER), + PUNCT: OPDEF(0, 3, TEXCLASS.PUNCT), + ACCENT: OPDEF(0, 0, TEXCLASS.ORD, { accent: true }), + WIDEACCENT: OPDEF(0, 0, TEXCLASS.ORD, { accent: true, stretchy: true }), }; /** * The default TeX classes for the various unicode blocks, and their names */ export const RANGES: RangeDef[] = [ - [0x0020, 0x007F, TEXCLASS.REL, 'mo'], // Basic Latin - [0x00A0, 0x00BF, TEXCLASS.ORD, 'mo'], // Latin-1 Supplement symbols - [0x00C0, 0x024F, TEXCLASS.ORD, 'mi'], // Latin-1 Supplement, Latin Extended-A, Latin Extended-B - [0x02B0, 0x036F, TEXCLASS.ORD, 'mo'], // Spacing modifier letters, Combining Diacritical Marks - [0x0370, 0x1A20, TEXCLASS.ORD, 'mi'], // Greek and Coptic (through) Tai Tham - [0x1AB0, 0x1AFF, TEXCLASS.ORD, 'mo'], // Combining Diacritical Marks Extended - [0x1B00, 0x1DBF, TEXCLASS.ORD, 'mi'], // Balinese (through) Phonetic Extensions Supplement - [0x1DC0, 0x1DFF, TEXCLASS.ORD, 'mo'], // Combining Diacritical Marks Supplement - [0x1E00, 0x1FFF, TEXCLASS.ORD, 'mi'], // Latin Extended Additional, Greek Extended - [0x2000, 0x206F, TEXCLASS.ORD, 'mo'], // General Punctuation - [0x2070, 0x209F, TEXCLASS.ORD, 'mo'], // Superscript and Subscripts (through) Combining Diacritical Marks for Symbols - [0x2100, 0x214F, TEXCLASS.ORD, 'mi'], // Letterlike Symbols - [0x2150, 0x218F, TEXCLASS.ORD, 'mn'], // Number Forms - [0x2190, 0x21FF, TEXCLASS.REL, 'mo'], // Arrows - [0x2200, 0x22FF, TEXCLASS.BIN, 'mo'], // Mathematical Operators - [0x2300, 0x23FF, TEXCLASS.ORD, 'mo'], // Miscellaneous Technical - [0x2460, 0x24FF, TEXCLASS.ORD, 'mn'], // Enclosed Alphanumerics - [0x2500, 0x27EF, TEXCLASS.ORD, 'mo'], // Box Drawing (though) Miscellaneous Math Symbols-A - [0x27F0, 0x27FF, TEXCLASS.REL, 'mo'], // Supplemental Arrows-A - [0x2800, 0x28FF, TEXCLASS.ORD, 'mtext'], // Braille Patterns - [0x2900, 0x297F, TEXCLASS.REL, 'mo'], // Supplemental Arrows-B - [0x2980, 0x29FF, TEXCLASS.ORD, 'mo'], // Miscellaneous Math Symbols-B - [0x2A00, 0x2AFF, TEXCLASS.BIN, 'mo'], // Supplemental Math Operators - [0x2B00, 0x2B2F, TEXCLASS.ORD, 'mo'], // Miscellaneous Symbols and Arrows - [0x2B30, 0x2B4F, TEXCLASS.REL, 'mo'], // Arrows from above - [0x2B50, 0x2BFF, TEXCLASS.ORD, 'mo'], // Rest of above - [0x2C00, 0x2DE0, TEXCLASS.ORD, 'mi'], // Glagolitic (through) Ethipoc Extended - [0x2E00, 0x2E7F, TEXCLASS.ORD, 'mo'], // Supplemental Punctuation - [0x2E80, 0x2FDF, TEXCLASS.ORD, 'mi', 'normal'], // CJK Radicals Supplement (through) Kangxi Radicals - [0x2FF0, 0x303F, TEXCLASS.ORD, 'mo'], // Ideographic Desc. Characters, CJK Symbols and Punctuation - [0x3040, 0xA49F, TEXCLASS.ORD, 'mi', 'normal'], // Hiragana (through) Yi Radicals - [0xA4D0, 0xA82F, TEXCLASS.ORD, 'mi'], // Lisu (through) Syloti Nagri - [0xA830, 0xA83F, TEXCLASS.ORD, 'mn'], // Common Indic Number FormsArabic Presentation Forms-A - [0xA840, 0xD7FF, TEXCLASS.ORD, 'mi'], // Phags-pa (though) Hangul Jamo Extended-B - [0xF900, 0xFAFF, TEXCLASS.ORD, 'mi', 'normal'], // CJK Compatibility Ideographs - [0xFB00, 0xFDFF, TEXCLASS.ORD, 'mi'], // Alphabetic Presentation Forms (though) Arabic Presentation Forms-A - [0xFE00, 0xFE6F, TEXCLASS.ORD, 'mo'], // Variation Selector (through) Small Form Variants - [0xFE70, 0x100FF, TEXCLASS.ORD, 'mi'], // Arabic Presentation Forms-B (through) Linear B Ideograms - [0x10100, 0x1018F, TEXCLASS.ORD, 'mn'], // Aegean Numbers, Ancient Greek Numbers - [0x10190, 0x123FF, TEXCLASS.ORD, 'mi', 'normal'], // Ancient Symbols (through) Cuneiform - [0x12400, 0x1247F, TEXCLASS.ORD, 'mn'], // Cuneiform Numbers and Punctuation - [0x12480, 0x1BC9F, TEXCLASS.ORD, 'mi', 'normal'], // Early Dynastic Cuneiform (through) Duployan - [0x1BCA0, 0x1D25F, TEXCLASS.ORD, 'mo'], // Shorthand Format Controls (through) TaiXuan Jing Symbols - [0x1D360, 0x1D37F, TEXCLASS.ORD, 'mn'], // Counting Rod Numerals - [0x1D400, 0x1D7CD, TEXCLASS.ORD, 'mi'], // Math Alphanumeric Symbols - [0x1D7CE, 0x1D7FF, TEXCLASS.ORD, 'mn'], // Numerals from above - [0x1DF00, 0x1F7FF, TEXCLASS.ORD, 'mo'], // Mahjong Tiles (through) Geometric Shapes Extended - [0x1F800, 0x1F8FF, TEXCLASS.REL, 'mo'], // Supplemental Arrows-C - [0x1F900, 0x1F9FF, TEXCLASS.ORD, 'mo'], // Supplemental Symbols and Pictographs - [0x20000, 0x2FA1F, TEXCLASS.ORD, 'mi', 'normnal'], // CJK Unified Ideographs Ext. B (through) CJK Sompatibility Ideographs Supp. + [0x0020, 0x007f, TEXCLASS.REL, 'mo'], // Basic Latin + [0x00a0, 0x00bf, TEXCLASS.ORD, 'mo'], // Latin-1 Supplement symbols + [0x00c0, 0x024f, TEXCLASS.ORD, 'mi'], // Latin-1 Supplement, Latin Extended-A, Latin Extended-B + [0x02b0, 0x036f, TEXCLASS.ORD, 'mo'], // Spacing modifier letters, Combining Diacritical Marks + [0x0370, 0x1a20, TEXCLASS.ORD, 'mi'], // Greek and Coptic (through) Tai Tham + [0x1ab0, 0x1aff, TEXCLASS.ORD, 'mo'], // Combining Diacritical Marks Extended + [0x1b00, 0x1dbf, TEXCLASS.ORD, 'mi'], // Balinese (through) Phonetic Extensions Supplement + [0x1dc0, 0x1dff, TEXCLASS.ORD, 'mo'], // Combining Diacritical Marks Supplement + [0x1e00, 0x1fff, TEXCLASS.ORD, 'mi'], // Latin Extended Additional, Greek Extended + [0x2000, 0x206f, TEXCLASS.ORD, 'mo'], // General Punctuation + [0x2070, 0x209f, TEXCLASS.ORD, 'mo'], // Superscript and Subscripts (through) Combining Diacritical Marks for Symbols + [0x2100, 0x214f, TEXCLASS.ORD, 'mi'], // Letterlike Symbols + [0x2150, 0x218f, TEXCLASS.ORD, 'mn'], // Number Forms + [0x2190, 0x21ff, TEXCLASS.REL, 'mo'], // Arrows + [0x2200, 0x22ff, TEXCLASS.BIN, 'mo'], // Mathematical Operators + [0x2300, 0x23ff, TEXCLASS.ORD, 'mo'], // Miscellaneous Technical + [0x2460, 0x24ff, TEXCLASS.ORD, 'mn'], // Enclosed Alphanumerics + [0x2500, 0x27ef, TEXCLASS.ORD, 'mo'], // Box Drawing (though) Miscellaneous Math Symbols-A + [0x27f0, 0x27ff, TEXCLASS.REL, 'mo'], // Supplemental Arrows-A + [0x2800, 0x28ff, TEXCLASS.ORD, 'mtext'], // Braille Patterns + [0x2900, 0x297f, TEXCLASS.REL, 'mo'], // Supplemental Arrows-B + [0x2980, 0x29ff, TEXCLASS.ORD, 'mo'], // Miscellaneous Math Symbols-B + [0x2a00, 0x2aff, TEXCLASS.BIN, 'mo'], // Supplemental Math Operators + [0x2b00, 0x2b2f, TEXCLASS.ORD, 'mo'], // Miscellaneous Symbols and Arrows + [0x2b30, 0x2b4f, TEXCLASS.REL, 'mo'], // Arrows from above + [0x2b50, 0x2bff, TEXCLASS.ORD, 'mo'], // Rest of above + [0x2c00, 0x2de0, TEXCLASS.ORD, 'mi'], // Glagolitic (through) Ethipoc Extended + [0x2e00, 0x2e7f, TEXCLASS.ORD, 'mo'], // Supplemental Punctuation + [0x2e80, 0x2fdf, TEXCLASS.ORD, 'mi', 'normal'], // CJK Radicals Supplement (through) Kangxi Radicals + [0x2ff0, 0x303f, TEXCLASS.ORD, 'mo'], // Ideographic Desc. Characters, CJK Symbols and Punctuation + [0x3040, 0xa49f, TEXCLASS.ORD, 'mi', 'normal'], // Hiragana (through) Yi Radicals + [0xa4d0, 0xa82f, TEXCLASS.ORD, 'mi'], // Lisu (through) Syloti Nagri + [0xa830, 0xa83f, TEXCLASS.ORD, 'mn'], // Common Indic Number FormsArabic Presentation Forms-A + [0xa840, 0xd7ff, TEXCLASS.ORD, 'mi'], // Phags-pa (though) Hangul Jamo Extended-B + [0xf900, 0xfaff, TEXCLASS.ORD, 'mi', 'normal'], // CJK Compatibility Ideographs + [0xfb00, 0xfdff, TEXCLASS.ORD, 'mi'], // Alphabetic Presentation Forms (though) Arabic Presentation Forms-A + [0xfe00, 0xfe6f, TEXCLASS.ORD, 'mo'], // Variation Selector (through) Small Form Variants + [0xfe70, 0x100ff, TEXCLASS.ORD, 'mi'], // Arabic Presentation Forms-B (through) Linear B Ideograms + [0x10100, 0x1018f, TEXCLASS.ORD, 'mn'], // Aegean Numbers, Ancient Greek Numbers + [0x10190, 0x123ff, TEXCLASS.ORD, 'mi', 'normal'], // Ancient Symbols (through) Cuneiform + [0x12400, 0x1247f, TEXCLASS.ORD, 'mn'], // Cuneiform Numbers and Punctuation + [0x12480, 0x1bc9f, TEXCLASS.ORD, 'mi', 'normal'], // Early Dynastic Cuneiform (through) Duployan + [0x1bca0, 0x1d25f, TEXCLASS.ORD, 'mo'], // Shorthand Format Controls (through) TaiXuan Jing Symbols + [0x1d360, 0x1d37f, TEXCLASS.ORD, 'mn'], // Counting Rod Numerals + [0x1d400, 0x1d7cd, TEXCLASS.ORD, 'mi'], // Math Alphanumeric Symbols + [0x1d7ce, 0x1d7ff, TEXCLASS.ORD, 'mn'], // Numerals from above + [0x1df00, 0x1f7ff, TEXCLASS.ORD, 'mo'], // Mahjong Tiles (through) Geometric Shapes Extended + [0x1f800, 0x1f8ff, TEXCLASS.REL, 'mo'], // Supplemental Arrows-C + [0x1f900, 0x1f9ff, TEXCLASS.ORD, 'mo'], // Supplemental Symbols and Pictographs + [0x20000, 0x2fa1f, TEXCLASS.ORD, 'mi', 'normal'], // CJK Unified Ideographs Ext. B (through) CJK Sompatibility Ideographs Supp. ]; /** * Get the Unicode range for the first character of a string * - * @param {string} text The character to check - * @return {RangeDef|null} The range containing that character, or null + * @param {string} text The character to check + * @returns {RangeDef} The range containing that character, or null */ -export function getRange(text: string): RangeDef | null { +export function getRange(text: string): RangeDef { + const def = + OPTABLE.infix[text] || OPTABLE.prefix[text] || OPTABLE.postfix[text]; + if (def) { + return [0, 0, def[2], 'mo']; + } const n = text.codePointAt(0); for (const range of RANGES) { if (n <= range[1]) { @@ -149,25 +170,26 @@ export function getRange(text: string): RangeDef | null { break; } } - return null; + return [0, 0, TEXCLASS.REL, 'mo']; } /** * The default MathML spacing for the various TeX classes. */ export const MMLSPACING = [ - [0, 0], // ORD - [1, 2], // OP - [3, 3], // BIN - [4, 4], // REL - [0, 0], // OPEN - [0, 0], // CLOSE - [0, 3] // PUNCT + [0, 0], // ORD + [1, 2], // OP + [3, 3], // BIN + [4, 4], // REL + [0, 0], // OPEN + [0, 0], // CLOSE + [0, 3], // PUNCT ]; /** * The operator dictionary, with sections for the three forms: prefix, postfix, and infix */ +/* prettier-ignore */ export const OPTABLE: {[form: string]: OperatorList} = { prefix: { '(': MO.OPEN, // left parenthesis @@ -321,13 +343,13 @@ export const OPTABLE: {[form: string]: OperatorList} = { '\u201E': MO.ACCENT, // double low-9 quotation mark '\u201F': MO.ACCENT, // double high-reversed-9 quotation mark '\u2032': MO.ORD, // prime - '\u2033': MO.ACCENT, // double prime - '\u2034': MO.ACCENT, // triple prime - '\u2035': MO.ACCENT, // reversed prime - '\u2036': MO.ACCENT, // reversed double prime - '\u2037': MO.ACCENT, // reversed triple prime + '\u2033': MO.ORD, // double prime + '\u2034': MO.ORD, // triple prime + '\u2035': MO.ORD, // reversed prime + '\u2036': MO.ORD, // reversed double prime + '\u2037': MO.ORD, // reversed triple prime '\u203E': MO.WIDEACCENT, // overline - '\u2057': MO.ACCENT, // quadruple prime + '\u2057': MO.ORD, // quadruple prime '\u20DB': MO.ACCENT, // combining three dots above '\u20DC': MO.ACCENT, // combining four dots above '\u2309': MO.CLOSE, // right ceiling @@ -412,7 +434,7 @@ export const OPTABLE: {[form: string]: OperatorList} = { '-': MO.BIN4, // hyphen-minus '-=': MO.BIN4, // multiple character operator: -= '->': MO.BIN5, // multiple character operator: -> - '.': [0, 3, TEXCLASS.PUNCT, {separator: true}], // \ldotp + '.': [0, 3, TEXCLASS.PUNCT, {linebreakstyle: 'after', separator: true}], // \ldotp '/': MO.ORD11, // solidus '//': OPDEF(1, 1), // multiple character operator: // '/=': MO.BIN4, // multiple character operator: /= diff --git a/ts/core/MmlTree/SerializedMmlVisitor.ts b/ts/core/MmlTree/SerializedMmlVisitor.ts index 80ec44807..a09add02e 100644 --- a/ts/core/MmlTree/SerializedMmlVisitor.ts +++ b/ts/core/MmlTree/SerializedMmlVisitor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +16,16 @@ */ /** - * @fileoverview A visitor that produces a serilaied MathML string + * @file A visitor that produces a serilaied MathML string * (replacement for toMathML() output from v2) * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MmlVisitor} from './MmlVisitor.js'; -import {MmlNode, TextNode, XMLNode, TEXCLASS, TEXCLASSNAMES} from './MmlNode.js'; -import {MmlMi} from './MmlNodes/mi.js'; - - -export const DATAMJX = 'data-mjx-'; - -export const toEntity = (c: string) => '&#x' + c.codePointAt(0).toString(16).toUpperCase() + ';'; - -type PropertyList = {[name: string]: string}; - +import { MmlVisitor } from './MmlVisitor.js'; +import { MmlNode, TextNode, XMLNode } from './MmlNode.js'; +import { HtmlNode } from './MmlNodes/HtmlNode.js'; +import { toEntity } from '../../util/string.js'; /*****************************************************************/ /** @@ -40,32 +33,11 @@ type PropertyList = {[name: string]: string}; */ export class SerializedMmlVisitor extends MmlVisitor { - - /** - * Translations for the internal mathvariants - */ - public static variants: PropertyList = { - '-tex-calligraphic': 'script', - '-tex-bold-calligraphic': 'bold-script', - '-tex-oldstyle': 'normal', - '-tex-bold-oldstyle': 'bold', - '-tex-mathit': 'italic' - }; - - /** - * Attributes to include on every element of a given kind - */ - public static defaultAttributes: {[kind: string]: PropertyList} = { - math: { - xmlns: 'http://www.w3.org/1998/Math/MathML' - } - }; - /** * Convert the tree rooted at a particular node into a serialized MathML string * * @param {MmlNode} node The node to use as the root of the tree to traverse - * @return {string} The MathML string representing the internal tree + * @returns {string} The MathML string representing the internal tree */ public visitTree(node: MmlNode): string { return this.visitNode(node, ''); @@ -73,8 +45,8 @@ export class SerializedMmlVisitor extends MmlVisitor { /** * @param {TextNode} node The text node to visit - * @param {string} space The amount of indenting for this node - * @return {string} The (HTML-quoted) text of the node + * @param {string} _space The amount of indenting for this node + * @returns {string} The (HTML-quoted) text of the node */ public visitTextNode(node: TextNode, _space: string): string { return this.quoteHTML(node.getText()); @@ -83,52 +55,45 @@ export class SerializedMmlVisitor extends MmlVisitor { /** * @param {XMLNode} node The XML node to visit * @param {string} space The amount of indenting for this node - * @return {string} The serialization of the XML node + * @returns {string} The serialization of the XML node */ public visitXMLNode(node: XMLNode, space: string): string { return space + node.getSerializedXML(); } + /** + * @param {HtmlNode} node The HTML node to visit + * @param {string} _space The amount of indenting for this node + * @returns {string} The serialization of the HTML + */ + public visitHtmlNode(node: HtmlNode, _space: string): string { + return node.getSerializedHTML(); + } + /** * Visit an inferred mrow, but don't add the inferred row itself (since * it is supposed to be inferred). * * @param {MmlNode} node The inferred mrow to visit * @param {string} space The amount of indenting for this node - * @return {string} The serialized contents of the mrow, properly indented + * @returns {string} The serialized contents of the mrow, properly indented */ public visitInferredMrowNode(node: MmlNode, space: string): string { - let mml = []; + const mml = []; for (const child of node.childNodes) { mml.push(this.visitNode(child, space)); } return mml.join('\n'); } - /** - * Visit a TeXAtom node. It is turned into a mrow with the appropriate TeX class - * indicator. - * - * @param {MmlNode} node The TeXAtom to visit. - * @param {string} space The amount of indenting for this node. - * @return {string} The serialized contents of the mrow, properly indented. - */ - public visitTeXAtomNode(node: MmlNode, space: string): string { - let children = this.childNodeMml(node, space + ' ', '\n'); - let mml = space + '' + - (children.match(/\S/) ? '\n' + children + space : '') + ''; - return mml; - } - /** * @param {MmlNode} node The annotation node to visit * @param {string} space The number of spaces to use for indentation - * @return {string} The serializied annotation element + * @returns {string} The serializied annotation element */ public visitAnnotationNode(node: MmlNode, space: string): string { - return space + '' - + this.childNodeMml(node, '', '') - + ''; + const children = this.childNodeMml(node, '', ''); + return `${space}${children}`; } /** @@ -140,22 +105,22 @@ export class SerializedMmlVisitor extends MmlVisitor { * * @param {MmlNode} node The node to visit * @param {string} space The number of spaces to use for indentation - * @return {string} The serialization of the given node + * @returns {string} The serialization of the given node */ public visitDefault(node: MmlNode, space: string): string { - let kind = node.kind; - let [nl, endspace] = (node.isToken || node.childNodes.length === 0 ? ['', ''] : ['\n', space]); + const kind = this.getKind(node); + const [nl, endspace] = + node.isToken || node.childNodes.length === 0 ? ['', ''] : ['\n', space]; const children = this.childNodeMml(node, space + ' ', nl); - return space + '<' + kind + this.getAttributes(node) + '>' - + (children.match(/\S/) ? nl + children + endspace : '') - + ''; + const childNode = children.match(/\S/) ? nl + children + endspace : ''; + return `${space}<${kind}${this.getAttributes(node)}>${childNode}`; } /** * @param {MmlNode} node The node whose children are to be added * @param {string} space The spaces to use for indentation * @param {string} nl The newline character (or empty) - * @return {string} The serializied children + * @returns {string} The serializied children */ protected childNodeMml(node: MmlNode, space: string, nl: string): string { let mml = ''; @@ -167,20 +132,11 @@ export class SerializedMmlVisitor extends MmlVisitor { /** * @param {MmlNode} node The node whose attributes are to be produced - * @return {string} The attribute list as a string + * @returns {string} The attribute list as a string */ protected getAttributes(node: MmlNode): string { const attr = []; - const defaults = (this.constructor as typeof SerializedMmlVisitor).defaultAttributes[node.kind] || {}; - const attributes = Object.assign({}, - defaults, - this.getDataAttributes(node), - node.attributes.getAllAttributes() - ); - const variants = (this.constructor as typeof SerializedMmlVisitor).variants; - if (attributes.hasOwnProperty('mathvariant') && variants.hasOwnProperty(attributes.mathvariant)) { - attributes.mathvariant = variants[attributes.mathvariant]; - } + const attributes = this.getAttributeList(node); for (const name of Object.keys(attributes)) { const value = String(attributes[name]); if (value === undefined) continue; @@ -189,60 +145,31 @@ export class SerializedMmlVisitor extends MmlVisitor { return attr.length ? ' ' + attr.join(' ') : ''; } - /** - * Create the list of data-mjx-* attributes - * - * @param {MmlNode} node The node whose data list is to be generated - * @return {PropertyList} The final class attribute list - */ - protected getDataAttributes(node: MmlNode): PropertyList { - const data = {} as PropertyList; - const variant = node.attributes.getExplicit('mathvariant') as string; - const variants = (this.constructor as typeof SerializedMmlVisitor).variants; - variant && variants.hasOwnProperty(variant) && this.setDataAttribute(data, 'variant', variant); - node.getProperty('variantForm') && this.setDataAttribute(data, 'alternate', '1'); - node.getProperty('pseudoscript') && this.setDataAttribute(data, 'pseudoscript', 'true'); - node.getProperty('autoOP') === false && this.setDataAttribute(data, 'auto-op', 'false'); - const scriptalign = node.getProperty('scriptalign') as string; - scriptalign && this.setDataAttribute(data, 'script-align', scriptalign); - const texclass = node.getProperty('texClass') as number; - if (texclass !== undefined) { - let setclass = true; - if (texclass === TEXCLASS.OP && node.isKind('mi')) { - const name = (node as MmlMi).getText(); - setclass = !(name.length > 1 && name.match(MmlMi.operatorName)); - } - setclass && this.setDataAttribute(data, 'texclass', texclass < 0 ? 'NONE' : TEXCLASSNAMES[texclass]); - } - node.getProperty('scriptlevel') && node.getProperty('useHeight') === false && - this.setDataAttribute(data, 'smallmatrix', 'true'); - return data; - } - - /** - * @param {PropertyList} data The class attribute list - * @param {string} name The name for the data-mjx-name attribute - * @param {string} value The value of the attribute - */ - protected setDataAttribute(data: PropertyList, name: string, value: string) { - data[DATAMJX + name] = value; - } - /** * Convert HTML special characters to entities (&, <, >, ") * Convert multi-character Unicode characters to entities * Convert non-ASCII characters to entities. * * @param {string} value The string to be made HTML escaped - * @return {string} The string with escaping performed + * @returns {string} The string with escaping performed */ protected quoteHTML(value: string): string { return value .replace(/&/g, '&') - .replace(//g, '>') - .replace(/\"/g, '"') - .replace(/[\uD800-\uDBFF]./g, toEntity) - .replace(/[\u0080-\uD7FF\uE000-\uFFFF]/g, toEntity); + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/[\uD800-\uDBFF]./g, this.toEntity) + .replace(/[\u0080-\uD7FF\uE000-\uFFFF]/g, this.toEntity); } + /** + * Access to the toEntity() function that can be overridden in subclasses. + * + * @param {string} c The character to encode. + * @returns {string} The numeric entity for the character. + */ + protected toEntity(c: string): string { + return toEntity(c); + } } diff --git a/ts/core/MmlTree/TestMmlVisitor.ts b/ts/core/MmlTree/TestMmlVisitor.ts index 829c4da4d..ae4a28fa2 100644 --- a/ts/core/MmlTree/TestMmlVisitor.ts +++ b/ts/core/MmlTree/TestMmlVisitor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ */ /** - * @fileoverview A visitor that produces a serilaied MathML string + * @file A visitor that produces a serilaied MathML string * that contains addition information about inherited * attributes and internal properties. * (For testing purposes only.) @@ -24,9 +24,9 @@ * @author dpvc@mathjax.org (Davide Cervone) */ -import {SerializedMmlVisitor} from './SerializedMmlVisitor.js'; -import {MmlNode} from './MmlNode.js'; -import {PropertyList} from '../Tree/Node.js'; +import { SerializedMmlVisitor } from './SerializedMmlVisitor.js'; +import { MmlNode } from './MmlNode.js'; +import { PropertyList } from '../Tree/Node.js'; /*****************************************************************/ /** @@ -34,40 +34,35 @@ import {PropertyList} from '../Tree/Node.js'; */ export class TestMmlVisitor extends SerializedMmlVisitor { - /** - * The generic visiting function: - * Make the string versino of the open tag with it attributes (explicit and - * inherited) and properties - * Increate the indentation level - * Add the childnodes - * Add the end tag with proper spacing (empty tags have the close tag following directly) - * - * @param {MmlNode} node The node to visit - * @param {string} space The number of spaces to use for indentation + * @override */ - public visitDefault(node: MmlNode, space: string) { - let kind = node.kind; - let [nl, endspace] = (node.isToken || node.childNodes.length === 0 ? ['', ''] : ['\n', space]); - let mml = space + '<' + kind + this.getAttributes(node) + - this.getInherited(node) + this.getProperties(node) + '\n' + space + ' ' + - this.attributeString({ + public visitDefault(node: MmlNode, space: string): string { + const kind = node.kind; + const [nl, endspace] = + node.isToken || node.childNodes.length === 0 ? ['', ''] : ['\n', space]; + const attributes = this.attributeString( + { isEmbellished: node.isEmbellished, isSpacelike: node.isSpacelike, - texClass: node.texClass - }, '{', '}') + - '>' + nl; + texClass: node.texClass, + }, + '{', + '}' + ); + let mml = + `${space}<${kind}${this.getAttributes(node)}${this.getInherited(node)}${this.getProperties(node)}\n` + + `${space} ${attributes}>${nl}`; space += ' '; for (const child of node.childNodes) { mml += this.visitNode(child, space) + nl; } - mml += endspace + ''; + mml += `${endspace}`; return mml; } /** - * @param {MmlNode} node The node whose attributes are to be produced - * @return {string} The attribute list as a string + * @override */ protected getAttributes(node: MmlNode): string { return this.attributeString(node.attributes.getAllAttributes(), '', ''); @@ -75,7 +70,7 @@ export class TestMmlVisitor extends SerializedMmlVisitor { /** * @param {MmlNode} node The node whose inherited attributes are to be produced - * @return {string} The inhertited attribute list as a string (with each in [...]) + * @returns {string} The inhertited attribute list as a string (with each in [...]) */ protected getInherited(node: MmlNode): string { return this.attributeString(node.attributes.getAllInherited(), '[', ']'); @@ -83,7 +78,7 @@ export class TestMmlVisitor extends SerializedMmlVisitor { /** * @param {MmlNode} node The node whose properties are to be produced - * @return {string} The property list as a string (with each in [[...]]) + * @returns {string} The property list as a string (with each in [[...]]) */ protected getProperties(node: MmlNode): string { return this.attributeString(node.getAllProperties(), '[[', ']]'); @@ -93,14 +88,17 @@ export class TestMmlVisitor extends SerializedMmlVisitor { * @param {PropertyList} attributes The attributes to be made into a list * @param {string} open The opening delimiter to add before each attribute * @param {string} close The closing delimiter to add after each attribute - * @return {string} The attribute list as a string + * @returns {string} The attribute list as a string */ - protected attributeString(attributes: PropertyList, open: string, close: string): string { + protected attributeString( + attributes: PropertyList, + open: string, + close: string + ): string { let ATTR = ''; for (const name of Object.keys(attributes)) { - ATTR += ' ' + open + name + '="' + this.quoteHTML(String(attributes[name])) + '"' + close; + ATTR += ` ${open}${name}="${this.quoteHTML(String(attributes[name]))}"${close}`; } return ATTR; } - } diff --git a/ts/core/OutputJax.ts b/ts/core/OutputJax.ts index ace5da7d2..843fc8c6b 100644 --- a/ts/core/OutputJax.ts +++ b/ts/core/OutputJax.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,16 +16,16 @@ */ /** - * @fileoverview Implements the interface and abstract class for the OutputJax + * @file Implements the interface and abstract class for the OutputJax * * @author dpvc@mathjax.org (Davide Cervone) */ -import {userOptions, defaultOptions, OptionList} from '../util/Options.js'; -import {MathDocument} from './MathDocument.js'; -import {MathItem} from './MathItem.js'; -import {DOMAdaptor} from '../core/DOMAdaptor.js'; -import {FunctionList} from '../util/FunctionList.js'; +import { userOptions, defaultOptions, OptionList } from '../util/Options.js'; +import { MathDocument } from './MathDocument.js'; +import { MathItem } from './MathItem.js'; +import { DOMAdaptor } from '../core/DOMAdaptor.js'; +import { FunctionList } from '../util/FunctionList.js'; /*****************************************************************/ /** @@ -47,7 +47,12 @@ export interface OutputJax { options: OptionList; /** - * Lists of post-filters to call after typesetting the math + * List of pre-filters to call after typesetting the math + */ + preFilters: FunctionList; + + /** + * List of post-filters to call before typesetting the math */ postFilters: FunctionList; @@ -78,7 +83,7 @@ export interface OutputJax { * * @param {MathItem} math The MathItem to be typeset * @param {MathDocument} document The MathDocument in which the typesetting should occur - * @return {N} The DOM tree for the typeset math + * @returns {N} The DOM tree for the typeset math */ typeset(math: MathItem, document?: MathDocument): N; @@ -87,7 +92,7 @@ export interface OutputJax { * * @param {MathItem} math The MathItem to be escaped * @param {MathDocument} document The MathDocument in which the math occurs - * @return {N} The DOM tree for the escaped item + * @returns {N} The DOM tree for the escaped item */ escaped(math: MathItem, document?: MathDocument): N; @@ -113,7 +118,6 @@ export interface OutputJax { pageElements(document: MathDocument): N; } - /*****************************************************************/ /** * The OutputJax abstract class @@ -123,7 +127,6 @@ export interface OutputJax { * @template D The Document class */ export abstract class AbstractOutputJax implements OutputJax { - /** * The name for the output jax */ @@ -132,13 +135,21 @@ export abstract class AbstractOutputJax implements OutputJax { /** * The default options for the output jax */ - public static OPTIONS: OptionList = {}; + public static OPTIONS: OptionList = { + preFilters: [], + postFilters: [], + }; /** * The actual options supplied to the output jax */ public options: OptionList; + /** + * Filters to run before the output is processed + */ + public preFilters: FunctionList; + /** * Filters to run after the output is processed */ @@ -147,19 +158,20 @@ export abstract class AbstractOutputJax implements OutputJax { /** * The MathDocument's DOMAdaptor */ - public adaptor: DOMAdaptor = null; // set by the handler + public adaptor: DOMAdaptor = null; // set by the handler /** * @param {OptionList} options The options for this instance */ constructor(options: OptionList = {}) { - let CLASS = this.constructor as typeof AbstractOutputJax; + const CLASS = this.constructor as typeof AbstractOutputJax; this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options); - this.postFilters = new FunctionList(); + this.preFilters = new FunctionList(this.options.preFilters); + this.postFilters = new FunctionList(this.options.postFilters); } /** - * @return {string} The name for this output jax class + * @returns {string} The name for this output jax class */ public get name(): string { return (this.constructor as typeof AbstractOutputJax).NAME; @@ -175,30 +187,33 @@ export abstract class AbstractOutputJax implements OutputJax { /** * @override */ - public initialize() { - } + public initialize() {} /** * @override */ - public reset(..._args: any[]) { - } + public reset(..._args: any[]) {} /** * @override */ - public abstract typeset(math: MathItem, document?: MathDocument): N; + public abstract typeset( + math: MathItem, + document?: MathDocument + ): N; /** * @override */ - public abstract escaped(math: MathItem, document?: MathDocument): N; + public abstract escaped( + math: MathItem, + document?: MathDocument + ): N; /** * @override */ - public getMetrics(_document: MathDocument) { - } + public getMetrics(_document: MathDocument) {} /** * @override @@ -222,15 +237,16 @@ export abstract class AbstractOutputJax implements OutputJax { * @param {MathItem} math The math item that is being processed * @param {MathDocument} document The math document contaiing the math item * @param {any} data Whatever other data is needed - * @return {any} The (possibly modified) data + * @returns {any} The (possibly modified) data */ protected executeFilters( - filters: FunctionList, math: MathItem, - document: MathDocument, data: any + filters: FunctionList, + math: MathItem, + document: MathDocument, + data: any ): any { - let args = {math, document, data}; + const args = { math, document, data }; filters.execute(args); return args.data; } - } diff --git a/ts/core/Tree/Factory.ts b/ts/core/Tree/Factory.ts index e8e6a256f..dec2bd2b0 100644 --- a/ts/core/Tree/Factory.ts +++ b/ts/core/Tree/Factory.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,7 +16,7 @@ */ /** - * @fileoverview The generic Factory class for creating arbitrary objects + * @file The generic Factory class for creating arbitrary objects * * @author dpvc@mathjax.org (Davide Cervone) */ @@ -37,9 +37,9 @@ export interface FactoryNodeClass { /** * @param {Factory>} factory The factory for creating more nodes * @param {any[]} args Any additional arguments needed by the node - * @return {N} The newly created node + * @returns {N} The newly created node */ - new(factory: Factory>, ...args: any[]): N; + new (factory: Factory>, ...args: any[]): N; } /*****************************************************************/ @@ -59,7 +59,7 @@ export interface FactoryNodeClass { export interface Factory> { /** * @param {string} kind The kind of node to create - * @return {N} The newly created node of the given kind + * @returns {N} The newly created node of the given kind */ create(kind: string): N; @@ -73,7 +73,7 @@ export interface Factory> { /** * @param {string} kind The kind of node whose class is to be returned - * @return {C} The class object for the given kind + * @returns {C} The class object for the given kind */ getNodeClass(kind: string): C; @@ -85,17 +85,16 @@ export interface Factory> { /** * @param {N} node The node to test if it is of a given kind * @param {string} kind The kind to test for - * @return {boolean} True if the node is of the given kind, false otherwise + * @returns {boolean} True if the node is of the given kind, false otherwise */ nodeIsKind(node: N, kind: string): boolean; /** - * @return {string[]} The names of all the available kinds of nodes + * @returns {string[]} The names of all the available kinds of nodes */ getKinds(): string[]; } - /*****************************************************************/ /** * The generic AbstractFactoryClass interface @@ -104,11 +103,14 @@ export interface Factory> { * @template N The node type created by the factory * @template C The class of the node being constructed (for access to static properties) */ -interface AbstractFactoryClass> extends Function { - defaultNodes: {[kind: string]: C}; +interface AbstractFactoryClass< + N extends FactoryNode, + C extends FactoryNodeClass, + // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type +> extends Function { + defaultNodes: { [kind: string]: C }; } - /*****************************************************************/ /** * The generic AbstractFactory class @@ -116,8 +118,11 @@ interface AbstractFactoryClass> implements Factory { - +export abstract class AbstractFactory< + N extends FactoryNode, + C extends FactoryNodeClass, +> implements Factory +{ /** * The default collection of objects to use for the node map */ @@ -136,12 +141,12 @@ export abstract class AbstractFactory N} = {}; + protected node: { [kind: string]: (...args: any[]) => N } = {}; /** * @override */ - constructor(nodes: {[kind: string]: C} = null) { + constructor(nodes: { [kind: string]: C } = null) { if (nodes === null) { nodes = (this.constructor as AbstractFactoryClass).defaultNodes; } @@ -162,12 +167,12 @@ export abstract class AbstractFactory { - return new KIND(THIS, ...args); + return new KIND(this, ...args); }; } + /** * @override */ @@ -187,7 +192,7 @@ export abstract class AbstractFactory, C extends NodeClass> { readonly kind: string; /** * The NodeFactory to use to create additional nodes, as needed */ - readonly factory: NodeFactory; - parent: Node; - childNodes: Node[]; + readonly factory: NodeFactory; + parent: N; + childNodes: N[]; /** * @param {string} name The name of the property to set @@ -52,17 +55,17 @@ export interface Node { /** * @param {string} name The name of the property to get - * @return {Property} The value of the named property + * @returns {Property} The value of the named property */ getProperty(name: string): Property; /** - * @return {string[]} An array of the names of every property currently defined + * @returns {string[]} An array of the names of every property currently defined */ getPropertyNames(): string[]; /** - * @return {PropertyList} The propery list containing all the properties of the node + * @returns {PropertyList} The propery list containing all the properties of the node */ getAllProperties(): PropertyList; @@ -71,87 +74,97 @@ export interface Node { */ removeProperty(...names: string[]): void; - /** * @param {string} kind The type of node to test for - * @return {boolean} True when the node is of the given type + * @returns {boolean} True when the node is of the given type */ isKind(kind: string): boolean; /** - * @param {Node[]} children The child nodes to add to this node + * @param {N[]} children The child nodes to add to this node */ - setChildren(children: Node[]): void; + setChildren(children: N[]): void; /** - * @param {Node} child A node to add to this node's children - * @return {Node} The child node that was added + * @param {N} child A node to add to this node's children + * @returns {N} The child node that was added */ - appendChild(child: Node): Node; + appendChild(child: N): N; /** - * @param {Node} newChild A child node to be inserted - * @param {Node} oldChild A child node to be replaced - * @return {Node} The old child node that was removed + * @param {N} newChild A child node to be inserted + * @param {N} oldChild A child node to be replaced + * @returns {N} The old child node that was removed */ - replaceChild(newChild: Node, oldChild: Node): Node; + replaceChild(newChild: N, oldChild: N): N; /** - * @param {Node} child Child node to be removed - * @return {Node} The old child node that was removed + * @param {N} child Child node to be removed + * @returns {N} The old child node that was removed */ - removeChild(child: Node): Node; + removeChild(child: N): N; /** - * @param {Node} child A child node whose index in childNodes is desired - * @return {number} The index of the child in childNodes, or null if not found + * @param {N} child A child node whose index in childNodes is desired + * @returns {number} The index of the child in childNodes, or null if not found */ - childIndex(child: Node): number; + childIndex(child: N): number; /** * Make a deep copy of the node (but with no parent). */ - copy(): Node; + copy(): N; /** * @param {string} kind The kind of nodes to be located in the tree - * @return {Node[]} An array of nodes that are children (at any depth) of the given kind + * @returns {N[]} An array of nodes that are children (at any depth) of the given kind */ - findNodes(kind: string): Node[]; + findNodes(kind: string): N[]; /** * @param {Function} func A function to apply to each node in the tree rooted at this node * @param {any} data Data to pass to the function (as state information) */ - walkTree(func: (node: Node, data?: any) => void, data?: any): void; + walkTree(func: (node: N, data?: any) => void, data?: any): void; } /*********************************************************/ /** - * The generic Node class interface + * The generic Node class interface + * + * @template N The node type being created + * @template C The node class for N (the constructor rather than instance of the class) */ - -export interface NodeClass { +export interface NodeClass, C extends NodeClass> { /** * @param {NodeFactory} factory The NodeFactory to use to create new nodes when needed * @param {PropertyList} properties Any properties to be added to the node, if any - * @param {Node[]} children The initial child nodes, if any - * @return {Node} The newly created node - */ - new (factory: NodeFactory, properties?: PropertyList, children?: Node[]): Node; + * @param {N[]} children The initial child nodes, if any + * @returns {N} The newly created node + */ + new ( + factory: NodeFactory, + properties?: PropertyList, + children?: N[] + ): N; } /*********************************************************/ /** - * The abstract Node class + * The abstract Node class + * + * @template N The actual type of node being created + * @template C The node class for N (the constructor rather than instance of the class) */ - -export abstract class AbstractNode implements Node { - +export abstract class AbstractNode< + N extends Node, + C extends NodeClass, +> implements Node +{ /** * The parent node for this one */ - public parent: Node = null; + public parent: N = null; /** * The properties for this node @@ -161,17 +174,21 @@ export abstract class AbstractNode implements Node { /** * The children for this node */ - public childNodes: Node[] = []; + public childNodes: N[] = []; /** * @param {NodeFactory} factory The NodeFactory to use to create new nodes when needed * @param {PropertyList} properties Any properties to be added to the node, if any - * @param {Node[]} children The initial child nodes, if any + * @param {N[]} children The initial child nodes, if any * - * @constructor - * @implements {Node} - */ - constructor(readonly factory: NodeFactory, properties: PropertyList = {}, children: Node[] = []) { + * @class + * @implements {N} + */ + constructor( + readonly factory: NodeFactory, + properties: PropertyList = {}, + children: N[] = [] + ) { for (const name of Object.keys(properties)) { this.setProperty(name, properties[name]); } @@ -224,21 +241,19 @@ export abstract class AbstractNode implements Node { } } - /** * @override */ public isKind(kind: string): boolean { - return this.factory.nodeIsKind(this, kind); + return this.factory.nodeIsKind(this as any, kind); } - /** * @override */ - public setChildren(children: Node[]) { + public setChildren(children: N[]) { this.childNodes = []; - for (let child of children) { + for (const child of children) { this.appendChild(child); } } @@ -246,22 +261,24 @@ export abstract class AbstractNode implements Node { /** * @override */ - public appendChild(child: Node) { + public appendChild(child: N) { this.childNodes.push(child); - child.parent = this; + child.parent = this as any as N; return child; } /** * @override */ - public replaceChild(newChild: Node, oldChild: Node) { - let i = this.childIndex(oldChild); + public replaceChild(newChild: N, oldChild: N) { + const i = this.childIndex(oldChild); // If i === null should we error? return null? silently fail? if (i !== null) { this.childNodes[i] = newChild; - newChild.parent = this; - oldChild.parent = null; + newChild.parent = this as any as N; + if (oldChild.parent === (this as any as N)) { + oldChild.parent = null; + } } return newChild; } @@ -269,7 +286,7 @@ export abstract class AbstractNode implements Node { /** * @override */ - public removeChild(child: Node) { + public removeChild(child: N) { const i = this.childIndex(child); if (i !== null) { this.childNodes.splice(i, 1); @@ -278,36 +295,34 @@ export abstract class AbstractNode implements Node { return child; } - /** * @override */ - public childIndex(node: Node) { - let i = this.childNodes.indexOf(node); - return (i === -1 ? null : i); + public childIndex(node: N) { + const i = this.childNodes.indexOf(node); + return i === -1 ? null : i; } - /** * @override */ public copy() { - const node = (this as AbstractNode).factory.create(this.kind) as AbstractNode; - node.properties = {...this.properties}; + const node = this.factory.create(this.kind) as any as AbstractNode; + node.properties = { ...this.properties }; for (const child of this.childNodes || []) { if (child) { node.appendChild(child.copy()); } } - return node; + return node as any as N; } /** * @override */ public findNodes(kind: string) { - let nodes: Node[] = []; - this.walkTree((node: Node) => { + const nodes: N[] = []; + this.walkTree((node: N) => { if (node.isKind(kind)) { nodes.push(node); } @@ -315,12 +330,11 @@ export abstract class AbstractNode implements Node { return nodes; } - /** * @override */ - public walkTree(func: (node: Node, data?: any) => void, data?: any) { - func(this, data); + public walkTree(func: (node: N, data?: any) => void, data?: any) { + func(this as any as N, data); for (const child of this.childNodes) { if (child) { child.walkTree(func, data); @@ -331,19 +345,25 @@ export abstract class AbstractNode implements Node { /** * Simple string version for debugging, just to get the structure. + * + * @override */ public toString() { return this.kind + '(' + this.childNodes.join(',') + ')'; } - } /*********************************************************/ /** - * The abstract EmptyNode class + * The abstract EmptyNode class + * + * @template N The actual type of node being created + * @template C The node class for N (the constructor rather than instance of the class) */ - -export abstract class AbstractEmptyNode extends AbstractNode { +export abstract class AbstractEmptyNode< + N extends Node, + C extends NodeClass, +> extends AbstractNode { /** * We don't have children, so ignore these methods */ @@ -351,27 +371,26 @@ export abstract class AbstractEmptyNode extends AbstractNode { /** * @override */ - public setChildren(_children: Node[]) { - } + public setChildren(_children: N[]) {} /** * @override */ - public appendChild(child: Node) { + public appendChild(child: N) { return child; } /** * @override */ - public replaceChild(_newChild: Node, oldChild: Node) { + public replaceChild(_newChild: N, oldChild: N) { return oldChild; } /** * @override */ - public childIndex(_node: Node) { + public childIndex(_node: N) { return null as number; } @@ -380,16 +399,17 @@ export abstract class AbstractEmptyNode extends AbstractNode { * * @override */ - public walkTree(func: (node: Node, data?: any) => void, data?: any) { - func(this, data); + public walkTree(func: (node: N, data?: any) => void, data?: any) { + func(this as any as N, data); return data; } /** * Simple string version for debugging, just to get the structure. + * + * @override */ public toString() { return this.kind; } - } diff --git a/ts/core/Tree/NodeFactory.ts b/ts/core/Tree/NodeFactory.ts index a022c0d77..940d3d31f 100644 --- a/ts/core/Tree/NodeFactory.ts +++ b/ts/core/Tree/NodeFactory.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview The generic NodeFactory class for creating Node objects + * @file The generic NodeFactory class for creating Node objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {Node, PropertyList} from './Node.js'; -import {Factory, FactoryNodeClass, AbstractFactory} from './Factory.js'; +import { Node, PropertyList } from './Node.js'; +import { Factory, FactoryNodeClass, AbstractFactory } from './Factory.js'; /*****************************************************************/ /** @@ -31,12 +31,15 @@ import {Factory, FactoryNodeClass, AbstractFactory} from './Factory.js'; * @template N The node type created by the factory * @template C The class of the node being constructed (for access to static properties) */ -export interface NodeFactory> extends Factory { +export interface NodeFactory< + N extends Node, + C extends FactoryNodeClass, +> extends Factory { /** * @param {string} kind The kind of node to create * @param {PropertyList} properties The list of initial properties for the node (if any) * @param {N[]} children The array of initial child nodes (if any) - * @return {N} The newly created node of the given kind + * @returns {N} The newly created node of the given kind */ create(kind: string, properties?: PropertyList, children?: N[]): N; } @@ -48,12 +51,18 @@ export interface NodeFactory> exte * @template N The node type created by the factory * @template C The class of the node being constructed (for access to static properties) */ -export abstract class AbstractNodeFactory> extends AbstractFactory { +export abstract class AbstractNodeFactory< + N extends Node, + C extends FactoryNodeClass, +> extends AbstractFactory { /** * @override */ - public create(kind: string, properties: PropertyList = {}, children: N[] = []) { + public create( + kind: string, + properties: PropertyList = {}, + children: N[] = [] + ) { return this.node[kind](properties, children); } - } diff --git a/ts/core/Tree/Visitor.ts b/ts/core/Tree/Visitor.ts index f6f3ca77b..a4db1d7d8 100644 --- a/ts/core/Tree/Visitor.ts +++ b/ts/core/Tree/Visitor.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,61 +16,78 @@ */ /** - * @fileoverview The generic visitor class for node trees + * @file The generic visitor class for trees * * @author dpvc@mathjax.org (Davide Cervone) */ -import {Node, NodeClass, AbstractNode} from './Node.js'; -import {NodeFactory} from './NodeFactory.js'; +import { Factory, FactoryNode, FactoryNodeClass } from './Factory.js'; + +/*****************************************************************/ /** - * The type for the functions associated with each node class + * Visitor nodes can have childNodes that are traversed by the visitor + * + * @template N The node type being traversed */ -export type VisitorFunction = (visitor: NodeFactory, node: Node, ...args: any[]) => any; +export interface VisitorNode> extends FactoryNode { + childNodes?: N[]; +} -/*****************************************************************/ /** - * Implements the Visitor interface + * The type for the functions associated with each node class + * + * @template N The node type being traversed */ +export type VisitorFunction> = ( + visitor: Factory>, + node: N, + ...args: any[] +) => any; -export interface Visitor { +/*****************************************************************/ +/** + * The Visitor interface + * + * @template N The node type being traversed + */ +export interface Visitor> { /** * Visit the tree rooted at the given node (passing along any needed parameters) * - * @param {Node} tree The node that is the root of the tree + * @param {N} tree The node that is the root of the tree * @param {any[]} args The arguments to pass to the visitNode functions - * @return {any} Whatever the visitNode function returns for the root tree node + * @returns {any} Whatever the visitNode function returns for the root tree node */ - visitTree(tree: Node, ...args: any[]): any; + visitTree(tree: N, ...args: any[]): any; /** * Visit a node by calling the visitor function for the given type of node * (passing along any needed parameters) * - * @param {Node} node The node to visit + * @param {N} node The node to visit * @param {any[]} args The arguments to pass to the visitor function for this node - * @return {any} Whatever the visitor function returns for this node + * @returns {any} Whatever the visitor function returns for this node */ - visitNode(node: Node, ...args: any[]): any; + visitNode(node: N, ...args: any[]): any; /** * The default visitor function for when no node-specific function is defined * - * @param {Node} node The node to visit + * @param {N} node The node to visit * @param {any[]} args The arguments to pass to the visitor function for this node - * @return {any} Whatever the visitor function returns for this node + * @returns {any} Whatever the visitor function returns for this node */ - visitDefault(node: Node, ...args: any[]): any; + visitDefault(node: N, ...args: any[]): any; /** * Define a visitor function for a given node kind * - * @param {string} kind The node kind for which the handler is being defined + * @param {string} kind The node kind for which the handler is being defined * @param {VisitorFunction} handler The function to call to handle nodes of this kind */ - setNodeHandler(kind: string, handler: VisitorFunction): void; + setNodeHandler(kind: string, handler: VisitorFunction): void; /** * Remove the visitor function for a given node kind @@ -88,35 +105,48 @@ export interface Visitor { /*****************************************************************/ /** * Implements the generic Visitor object + * + * @template N The node type being traversed + * @template C The node class for N (the constructor rather than instance of the class) */ - -export abstract class AbstractVisitor implements Visitor { +export abstract class AbstractVisitor> + implements Visitor +{ /** * Holds the mapping from node kinds to visitor funcitons */ - protected nodeHandlers: Map = new Map(); + protected nodeHandlers: Map> = new Map(); /** * Visitor functions are named "visitKindNode" where "Kind" is replaced by * the node kind; e.g., visitTextNode for kind = text. * * @param {string} kind The node kind whose method name is needed - * @return {string} The name of the visitor method for the given node kind + * @returns {string} The name of the visitor method for the given node kind */ protected static methodName(kind: string): string { - return 'visit' + (kind.charAt(0).toUpperCase() + kind.substr(1)).replace(/[^a-z0-9_]/ig, '_') + 'Node'; + return ( + 'visit' + + (kind.charAt(0).toUpperCase() + kind.substring(1)).replace( + /[^a-z0-9_]/gi, + '_' + ) + + 'Node' + ); } /** * Create the node handler map by looking for methods with the correct names * based on the node kinds available from the factory. * - * @constructor - * @param {NodeFactory} factory The node factory for the kinds of nodes this visitor handles + * @class + * @param {Factory} factory The node factory for the kinds of nodes this visitor handles */ - constructor(factory: NodeFactory) { + constructor(factory: Factory>) { for (const kind of factory.getKinds()) { - let method = (this as Visitor)[AbstractVisitor.methodName(kind)] as VisitorFunction; + const method = (this as Visitor)[ + AbstractVisitor.methodName(kind) + ] as VisitorFunction; if (method) { this.nodeHandlers.set(kind, method); } @@ -126,23 +156,23 @@ export abstract class AbstractVisitor implements Visitor { /** * @override */ - public visitTree(tree: Node, ...args: any[]) { + public visitTree(tree: N, ...args: any[]) { return this.visitNode(tree, ...args); } /** * @override */ - public visitNode(node: Node, ...args: any[]) { - let handler = this.nodeHandlers.get(node.kind) || this.visitDefault; + public visitNode(node: N, ...args: any[]) { + const handler = this.nodeHandlers.get(node.kind) || this.visitDefault; return handler.call(this, node, ...args); } /** * @override */ - public visitDefault(node: Node, ...args: any[]) { - if (node instanceof AbstractNode) { + public visitDefault(node: N, ...args: any[]) { + if ('childNodes' in node) { for (const child of node.childNodes) { this.visitNode(child, ...args); } @@ -152,7 +182,7 @@ export abstract class AbstractVisitor implements Visitor { /** * @override */ - public setNodeHandler(kind: string, handler: VisitorFunction) { + public setNodeHandler(kind: string, handler: VisitorFunction) { this.nodeHandlers.set(kind, handler); } @@ -162,5 +192,4 @@ export abstract class AbstractVisitor implements Visitor { public removeNodeHandler(kind: string) { this.nodeHandlers.delete(kind); } - } diff --git a/ts/core/Tree/Wrapper.ts b/ts/core/Tree/Wrapper.ts index 5085429b1..21a2561dd 100644 --- a/ts/core/Tree/Wrapper.ts +++ b/ts/core/Tree/Wrapper.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,13 @@ */ /** - * @fileoverview Generic Wrapper class for adding methods to a Node class for visitors + * @file Generic Wrapper class for adding methods to a Node class for visitors * * @author dpvc@mathjax.org (Davide Cervone) */ -import {Node} from './Node.js'; -import {WrapperFactory} from './WrapperFactory.js'; +import { Node, NodeClass } from './Node.js'; +import { WrapperFactory } from './WrapperFactory.js'; /*********************************************************/ /** @@ -31,18 +31,43 @@ import {WrapperFactory} from './WrapperFactory.js'; * It points to a Node object. Subclasses add methods for the visitor to call. * * @template N The Node type being wrapped + * @template C The NodeClass for the nodes being created * @template W The Wrapper type being produced */ -export interface Wrapper> { - node: N; +export interface Wrapper< + N extends Node, + C extends NodeClass, + W extends Wrapper, +> { + /** + * The kind of this wrapper + */ readonly kind: string; /** - * @param {Node} node A node to be wrapped + * The Node object associated with this instance + */ + node: N; + + /** + * The wrapped child nodes for the wrapped node + */ + childNodes: W[]; + + /** + * @template T The class to use for the wrapped node (defaults to W) + * + * @param {Node} node A node to be wrapped * @param {any[]} args Any additional arguments needed when creating the wrapper - * @return {Wrapper} The wrapped node + * @returns {T} The wrapped node + */ + wrap(node: N, ...args: any[]): T; + + /** + * @param {Function} func A function to apply to each wrapper in the tree rooted at this node + * @param {any} data Data to pass to the function (as state information) */ - wrap(node: N, ...args: any[]): W; + walkTree(func: (node: W, data?: any) => void, data?: any): void; } /*********************************************************/ @@ -50,16 +75,25 @@ export interface Wrapper> { * The Wrapper class interface * * @template N The Node type being wrapped + * @template C The NodeClass for the nodes being created * @template W The Wrapper type being produced */ -export interface WrapperClass> { +export interface WrapperClass< + N extends Node, + C extends NodeClass, + W extends Wrapper, +> { /** * @param {WrapperFactory} factory The factory used to create more wrappers * @param {N} node The node to be wrapped * @param {any[]} args Any additional arguments needed when creating the wrapper - * @return {W} The wrapped node + * @returns {W} The wrapped node */ - new(factory: WrapperFactory>, node: N, ...args: any[]): W; + new ( + factory: WrapperFactory>, + node: N, + ...args: any[] + ): W; } /*********************************************************/ @@ -67,21 +101,32 @@ export interface WrapperClass> { * The abstract Wrapper class * * @template N The Node type being created by the factory + * @template C The NodeClass for the nodes being created * @template W The Wrapper type being produced */ -export class AbstractWrapper> implements Wrapper { +export class AbstractWrapper< + N extends Node, + C extends NodeClass, + W extends Wrapper, +> implements Wrapper +{ /** - * The Node object associated with this instance + * @override */ public node: N; + /** + * @override + */ + public childNodes: W[]; + /** * The WrapperFactory to use to wrap child nodes, as needed */ - protected factory: WrapperFactory>; + protected factory: WrapperFactory>; /** - * The kind of this wrapper + * @override */ get kind() { return this.node.kind; @@ -91,10 +136,13 @@ export class AbstractWrapper> implements * @param {WrapperFactory} factory The WrapperFactory to use to wrap child nodes when needed * @param {Node} node The node to wrap * - * @constructor + * @class * @implements {Wrapper} */ - constructor(factory: WrapperFactory>, node: N) { + constructor( + factory: WrapperFactory>, + node: N + ) { this.factory = factory; this.node = node; } @@ -102,8 +150,22 @@ export class AbstractWrapper> implements /** * @override */ - public wrap(node: N) { - return this.factory.wrap(node); + public wrap(node: N) { + return this.factory.wrap(node) as T; } + /** + * @override + */ + public walkTree(func: (node: W, data?: any) => void, data?: any) { + func(this as any as W, data); + if ('childNodes' in this) { + for (const child of this.childNodes) { + if (child) { + child.walkTree(func, data); + } + } + } + return data; + } } diff --git a/ts/core/Tree/WrapperFactory.ts b/ts/core/Tree/WrapperFactory.ts index 3e00ca67b..6f45eed53 100644 --- a/ts/core/Tree/WrapperFactory.ts +++ b/ts/core/Tree/WrapperFactory.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,49 +16,62 @@ */ /** - * @fileoverview Generic WrapperFactory class for creating Wrapper objects + * @file Generic WrapperFactory class for creating Wrapper objects * * @author dpvc@mathjax.org (Davide Cervone) */ -import {Node} from './Node.js'; -import {Wrapper, WrapperClass} from './Wrapper.js'; -import {Factory, AbstractFactory} from './Factory.js'; +import { Node, NodeClass } from './Node.js'; +import { Wrapper, WrapperClass } from './Wrapper.js'; +import { Factory, AbstractFactory } from './Factory.js'; /*****************************************************************/ /** * The generic WrapperFactory class * - * @template N The Node type being created by the factory - * @template W The Wrapper type being produced (instance type) - * @template C The Wrapper class (for static values) + * @template N The Node type being created by the factory + * @template C The NodeClass for the nodes being created + * @template WW The Wrapper type being produced (instance type) + * @template WC The Wrapper class (for static values) */ -export interface WrapperFactory, C extends WrapperClass> -extends Factory { +export interface WrapperFactory< + N extends Node, + C extends NodeClass, + WW extends Wrapper, + WC extends WrapperClass, +> extends Factory { /** - * @param {N} node The node to be wrapped + * @template TT The type to use for the wrappedd node + * + * @param {N} node The node to be wrapped * @param {any[]} args Any additional arguments needed when wrapping the node - * @return {W} The newly wrapped node + * @returns {TT} The newly wrapped node */ - wrap(node: N, ...args: any[]): W; + wrap(node: N, ...args: any[]): TT; } /*****************************************************************/ /** * The generic WrapperFactory class * - * @template N The Node type being created by the factory - * @template W The Wrapper type being produced (instance type) - * @template C The Wrapper class (for static values) + * @template N The Node type being created by the factory + * @template C The NodeClass for the nodes being created + * @template WW The Wrapper type being produced (instance type) + * @template WC The Wrapper class (for static values) */ -export abstract class AbstractWrapperFactory, C extends WrapperClass> -extends AbstractFactory implements WrapperFactory { +export abstract class AbstractWrapperFactory< + N extends Node, + C extends NodeClass, + WW extends Wrapper, + WC extends WrapperClass, + > + extends AbstractFactory + implements WrapperFactory +{ /** - * @param {N} node The node to be wrapped - * @param {any[]} args Any additional arguments needed when wrapping the node - * @return {W} The newly wrapped node + * @override */ - public wrap(node: N, ...args: any[]): W { - return this.create(node.kind, node, ...args); + public wrap(node: N, ...args: any[]): TT { + return this.create(node.kind, node, ...args) as TT; } } diff --git a/ts/handlers/html.ts b/ts/handlers/html.ts index 0c43663b7..76565be95 100644 --- a/ts/handlers/html.ts +++ b/ts/handlers/html.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,26 +16,28 @@ */ /** - * @fileoverview Registers the HTML document type + * @file Registers the HTML document type * * @author dpvc@mathjax.org (Davide Cervone) */ -import {mathjax} from '../mathjax.js'; -import {HTMLHandler} from './html/HTMLHandler.js'; -import {DOMAdaptor} from '../core/DOMAdaptor.js'; +import { mathjax } from '../mathjax.js'; +import { HTMLHandler } from './html/HTMLHandler.js'; +import { DOMAdaptor } from '../core/DOMAdaptor.js'; /** * Create the HTML handler object and register it with MathJax. * * @param {DOMAdaptor} adaptor The DOM adaptor to use with HTML - * @return {HTMLHandler} The newly created handler + * @returns {HTMLHandler} The newly created handler * * @template N The HTMLElement node class * @template T The Text node class * @template D The Document class */ -export function RegisterHTMLHandler(adaptor: DOMAdaptor): HTMLHandler { +export function RegisterHTMLHandler( + adaptor: DOMAdaptor +): HTMLHandler { const handler = new HTMLHandler(adaptor); mathjax.handlers.register(handler); return handler; diff --git a/ts/handlers/html/HTMLDocument.ts b/ts/handlers/html/HTMLDocument.ts index 2791d6bcf..e5d0ff9cc 100644 --- a/ts/handlers/html/HTMLDocument.ts +++ b/ts/handlers/html/HTMLDocument.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,25 @@ */ /** - * @fileoverview Implements the HTMLDocument class + * @file Implements the HTMLDocument class * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractMathDocument} from '../../core/MathDocument.js'; -import {userOptions, separateOptions, OptionList, expandable} from '../../util/Options.js'; -import {HTMLMathItem} from './HTMLMathItem.js'; -import {HTMLMathList} from './HTMLMathList.js'; -import {HTMLDomStrings} from './HTMLDomStrings.js'; -import {DOMAdaptor} from '../../core/DOMAdaptor.js'; -import {InputJax} from '../../core/InputJax.js'; -import {STATE, ProtoItem, Location} from '../../core/MathItem.js'; -import {StyleList} from '../../util/StyleList.js'; +import { AbstractMathDocument } from '../../core/MathDocument.js'; +import { + userOptions, + separateOptions, + OptionList, + expandable, +} from '../../util/Options.js'; +import { HTMLMathItem } from './HTMLMathItem.js'; +import { HTMLMathList } from './HTMLMathList.js'; +import { HTMLDomStrings } from './HTMLDomStrings.js'; +import { DOMAdaptor } from '../../core/DOMAdaptor.js'; +import { InputJax } from '../../core/InputJax.js'; +import { STATE, newState, ProtoItem, Location } from '../../core/MathItem.js'; +import { StyleJson } from '../../util/StyleJson.js'; /*****************************************************************/ /** @@ -44,6 +49,11 @@ import {StyleList} from '../../util/StyleList.js'; */ export type HTMLNodeArray = [N | T, number][][]; +/** + * Add STATE value for adding the stylesheets (after INSERTED) + */ +newState('STYLES', STATE.INSERTED + 1); + /*****************************************************************/ /** * The HTMLDocument class (extends AbstractMathDocument) @@ -53,7 +63,6 @@ export type HTMLNodeArray = [N | T, number][][]; * @template D The Document class */ export class HTMLDocument extends AbstractMathDocument { - /** * The kind of document */ @@ -62,11 +71,12 @@ export class HTMLDocument extends AbstractMathDocument { /** * The default options for HTMLDocument */ + /* prettier-ignore */ public static OPTIONS: OptionList = { ...AbstractMathDocument.OPTIONS, renderActions: expandable({ ...AbstractMathDocument.OPTIONS.renderActions, - styles: [STATE.INSERTED + 1, '', 'updateStyleSheet', false] // update styles on a rerender() call + styles: [STATE.STYLES, '', 'updateStyleSheet', false] // update styles on a rerender() call }), MathList: HTMLMathList, // Use the HTMLMathList for MathLists MathItem: HTMLMathItem, // Use the HTMLMathItem for MathItem @@ -76,7 +86,7 @@ export class HTMLDocument extends AbstractMathDocument { /** * Extra styles to be included in the document's stylesheet (added by extensions) */ - protected styles: StyleList[]; + protected styles: StyleJson[]; /** * The DomString parser for locating the text in DOM trees @@ -85,13 +95,18 @@ export class HTMLDocument extends AbstractMathDocument { /** * @override - * @constructor - * @extends {AbstractMathDocument} + * @class + * @augments {AbstractMathDocument} */ - constructor(document: any, adaptor: DOMAdaptor, options: OptionList) { - let [html, dom] = separateOptions(options, HTMLDomStrings.OPTIONS); + constructor( + document: any, + adaptor: DOMAdaptor, + options: OptionList + ) { + const [html, dom] = separateOptions(options, HTMLDomStrings.OPTIONS); super(document, adaptor, html); - this.domStrings = this.options['DomStrings'] || new HTMLDomStrings(dom); + this.domStrings = + this.options['DomStrings'] || new HTMLDomStrings(dom); this.domStrings.adaptor = adaptor; this.styles = []; } @@ -105,18 +120,25 @@ export class HTMLDocument extends AbstractMathDocument { * @param {number} index The position within the N's string that needs to be found * @param {string} delim The delimiter for this position * @param {HTMLNodeArray} nodes The list of node lists representing the string array - * @return {Location} The Location object for the position of the delimiter in the document + * @returns {Location} The Location object for the position of the delimiter in the document */ - protected findPosition(N: number, index: number, delim: string, nodes: HTMLNodeArray): Location { + protected findPosition( + N: number, + index: number, + delim: string, + nodes: HTMLNodeArray + ): Location { const adaptor = this.adaptor; - for (const list of nodes[N]) { - let [node, n] = list; + const inc = 1 / (nodes[N].length || 1); + let i = N; + for (const [node, n] of nodes[N]) { if (index <= n && adaptor.kind(node) === '#text') { - return {node: node, n: Math.max(index, 0), delim: delim}; + return { i, node, n: Math.max(index, 0), delim }; } index -= n; + i += inc; } - return {node: null, n: 0, delim: delim}; + return { node: null, n: 0, delim }; } /** @@ -126,15 +148,24 @@ export class HTMLDocument extends AbstractMathDocument { * @param {ProtoItem} item The proto math item to turn into an actual MathItem * @param {InputJax} jax The input jax to use for the MathItem * @param {HTMLNodeArray} nodes The array of node lists that produced the string array - * @return {HTMLMathItem} The MathItem for the given proto item + * @returns {HTMLMathItem} The MathItem for the given proto item */ - protected mathItem(item: ProtoItem, jax: InputJax, - nodes: HTMLNodeArray): HTMLMathItem { - let math = item.math; - let start = this.findPosition(item.n, item.start.n, item.open, nodes); - let end = this.findPosition(item.n, item.end.n, item.close, nodes); - return new this.options.MathItem(math, jax, item.display, start, end) as HTMLMathItem; - } + protected mathItem( + item: ProtoItem, + jax: InputJax, + nodes: HTMLNodeArray + ): HTMLMathItem { + const math = item.math; + const start = this.findPosition(item.n, item.start.n, item.open, nodes); + const end = this.findPosition(item.n, item.end.n, item.close, nodes); + return new this.options.MathItem( + math, + jax, + item.display, + start, + end + ) as HTMLMathItem; + } /** * Find math within the document: @@ -156,33 +187,80 @@ export class HTMLDocument extends AbstractMathDocument { public findMath(options: OptionList) { if (!this.processed.isSet('findMath')) { this.adaptor.document = this.document; - options = userOptions({elements: this.options.elements || [this.adaptor.body(this.document)]}, options); - for (const container of this.adaptor.getElements(options['elements'], this.document)) { - let [strings, nodes] = [null, null] as [string[], HTMLNodeArray]; - for (const jax of this.inputJax) { - let list = new (this.options['MathList'])(); - if (jax.processStrings) { - if (strings === null) { - [strings, nodes] = this.domStrings.find(container); - } - for (const math of jax.findMath(strings)) { - list.push(this.mathItem(math, jax, nodes)); - } - } else { - for (const math of jax.findMath(container)) { - let item: HTMLMathItem = - new this.options.MathItem(math.math, jax, math.display, math.start, math.end); - list.push(item); - } - } - this.math.merge(list); - } + options = userOptions( + { + elements: this.options.elements || [this.adaptor.body(this.document)], + }, + options + ); + const containers = this.adaptor.getElements( + options.elements, + this.document + ); + for (const jax of this.inputJax) { + const list = jax.processStrings + ? this.findMathFromStrings(jax, containers) + : this.findMathFromDOM(jax, containers); + this.math.merge(list); } this.processed.set('findMath'); } return this; } + /** + * Get the MathItems from the containers by searching DOM strings + * + * @param {InputJax} jax The jax being used + * @param {N[]} containers The containers to be searched in order + * @returns {HTMLMathList} The list of MathItems found + */ + protected findMathFromStrings( + jax: InputJax, + containers: N[] + ): HTMLMathList { + const strings = [] as string[]; + const nodes = [] as HTMLNodeArray; + for (const container of containers) { + const [slist, nlist] = this.domStrings.find(container); + strings.push(...slist); + nodes.push(...nlist); + } + const list = new this.options.MathList() as HTMLMathList; + for (const math of jax.findMath(strings)) { + list.push(this.mathItem(math, jax, nodes)); + } + return list; + } + + /** + * Get the MathItems from the containers by searching DOM elements themselves + * + * @param {InputJax} jax The jax being used + * @param {N[]} containers The containers to be searched in order + * @returns {HTMLMathList} The list of MathItems found + */ + protected findMathFromDOM( + jax: InputJax, + containers: N[] + ): HTMLMathList { + const items = [] as HTMLMathItem[]; + for (const container of containers) { + for (const math of jax.findMath(container)) { + items.push( + new this.options.MathItem( + math.math, + jax, + math.display, + math.start, + math.end + ) + ); + } + } + return new this.options.MathList(...items) as HTMLMathList; + } + /** * @override */ @@ -200,10 +278,16 @@ export class HTMLDocument extends AbstractMathDocument { * Add any elements needed for the document */ protected addPageElements() { - const body = this.adaptor.body(this.document); + const adaptor = this.adaptor; + const body = adaptor.body(this.document); const node = this.documentPageElements(); if (node) { - this.adaptor.append(body, node); + const child = adaptor.firstChild(body); + if (child) { + adaptor.insert(node, child); + } else { + adaptor.append(body, node); + } } } @@ -215,7 +299,7 @@ export class HTMLDocument extends AbstractMathDocument { const adaptor = this.adaptor; if (sheet && !adaptor.parent(sheet)) { const head = adaptor.head(this.document); - let styles = this.findSheet(head, adaptor.getAttribute(sheet, 'id')); + const styles = this.findSheet(head, adaptor.getAttribute(sheet, 'id')); if (styles) { adaptor.replace(sheet, styles); } else { @@ -227,9 +311,9 @@ export class HTMLDocument extends AbstractMathDocument { /** * @param {N} head The document * @param {string} id The id of the stylesheet to find - * @param {N|null} The stylesheet with the given ID + * @returns {N|null} The stylesheet with the given ID */ - protected findSheet(head: N, id: string) { + protected findSheet(head: N, id: string): N { if (id) { for (const sheet of this.adaptor.tags(head, 'style')) { if (this.adaptor.getAttribute(sheet, 'id') === id) { @@ -272,17 +356,19 @@ export class HTMLDocument extends AbstractMathDocument { /** * Add styles to be included in the document's stylesheet * - * @param {StyleList} styles The styles to include + * @param {StyleJson} styles The styles to include */ - public addStyles(styles: StyleList) { + public addStyles(styles: StyleJson) { this.styles.push(styles); + if ('insertStyles' in this.outputJax) { + (this.outputJax as any).insertStyles(styles); + } } /** - * Get the array of document-specific styles + * @returns {StyleJson[]} The array of document-specific styles */ - public getStyles() { + public getStyles(): StyleJson[] { return this.styles; } - } diff --git a/ts/handlers/html/HTMLDomStrings.ts b/ts/handlers/html/HTMLDomStrings.ts index 6fe771b99..678b62742 100644 --- a/ts/handlers/html/HTMLDomStrings.ts +++ b/ts/handlers/html/HTMLDomStrings.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,19 @@ */ /** - * @fileoverview Implements the HTMLDomStrings class + * @file Implements the HTMLDomStrings class * * @author dpvc@mathjax.org (Davide Cervone) */ -import {userOptions, defaultOptions, OptionList, makeArray} from '../../util/Options.js'; -import {DOMAdaptor} from '../../core/DOMAdaptor.js'; +import { + userOptions, + defaultOptions, + OptionList, + makeArray, + expandable, +} from '../../util/Options.js'; +import { DOMAdaptor } from '../../core/DOMAdaptor.js'; /** * List of consecutive text nodes and their text lengths @@ -43,16 +49,17 @@ export type HTMLNodeList = [N | T, number][]; * @template D The Document class */ export class HTMLDomStrings { - /** * The default options for string processing */ + /* prettier-ignore */ public static OPTIONS: OptionList = { - skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code', 'annotation', 'annotation-xml'], + skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code', + 'math', 'select', 'option', 'mjx-container'], // The names of the tags whose contents will not be // scanned for math delimiters - includeHtmlTags: {br: '\n', wbr: '', '#comment': ''}, + includeHtmlTags: expandable({br: '\n', wbr: '', '#comment': ''}), // tags to be included in the text (and what // text to replace them with) @@ -70,7 +77,7 @@ export class HTMLDomStrings { /** * The options for this instance */ - protected options: OptionList; + public options: OptionList; /** * The array of strings found in the DOM @@ -119,10 +126,10 @@ export class HTMLDomStrings { /** * @param {OptionList} options The user-supplied options - * @constructor + * @class */ constructor(options: OptionList = null) { - let CLASS = this.constructor as typeof HTMLDomStrings; + const CLASS = this.constructor as typeof HTMLDomStrings; this.options = userOptions(defaultOptions({}, CLASS.OPTIONS), options); this.init(); this.getPatterns(); @@ -143,11 +150,13 @@ export class HTMLDomStrings { * Create the search patterns for skipHtmlTags, ignoreHtmlClass, and processHtmlClass */ protected getPatterns() { - let skip = makeArray(this.options['skipHtmlTags']); - let ignore = makeArray(this.options['ignoreHtmlClass']); - let process = makeArray(this.options['processHtmlClass']); + const skip = makeArray(this.options['skipHtmlTags']); + const ignore = makeArray(this.options['ignoreHtmlClass']); + const process = makeArray(this.options['processHtmlClass']); this.skipHtmlTags = new RegExp('^(?:' + skip.join('|') + ')$', 'i'); - this.ignoreHtmlClass = new RegExp('(?:^| )(?:' + ignore.join('|') + ')(?: |$)'); + this.ignoreHtmlClass = new RegExp( + '(?:^| )(?:' + ignore.join('|') + ')(?: |$)' + ); this.processHtmlClass = new RegExp('(?:^| )(?:' + process + ')(?: |$)'); } @@ -182,7 +191,7 @@ export class HTMLDomStrings { * * @param {T} node The Text node to process * @param {boolean} ignore Whether we are currently ignoring content - * @return {N | T} The next element to process + * @returns {N | T} The next element to process */ protected handleText(node: T, ignore: boolean): N | T { if (!ignore) { @@ -196,12 +205,16 @@ export class HTMLDomStrings { * * @param {N} node The node to process * @param {boolean} ignore Whether we are currently ignoring content - * @return {N | T} The next element to process + * @returns {N | T} The next element to process */ protected handleTag(node: N, ignore: boolean): N | T { if (!ignore) { - let text = this.options['includeHtmlTags'][this.adaptor.kind(node)]; - this.extendString(node, text); + const text = this.options['includeHtmlTags'][this.adaptor.kind(node)]; + if (text instanceof Function) { + this.extendString(node, text(node, this.adaptor)); + } else { + this.extendString(node, text); + } } return this.adaptor.next(node); } @@ -220,7 +233,7 @@ export class HTMLDomStrings { * * @param {N} node The node to process * @param {boolean} ignore Whether we are currently ignoring content - * @return {[N|T, boolean]} The next element to process and whether to ignore its content + * @returns {[N|T, boolean]} The next element to process and whether to ignore its content */ protected handleContainer(node: N, ignore: boolean): [N | T, boolean] { this.pushString(); @@ -228,8 +241,11 @@ export class HTMLDomStrings { const tname = this.adaptor.kind(node) || ''; const process = this.processHtmlClass.exec(cname); let next = node as N | T; - if (this.adaptor.firstChild(node) && !this.adaptor.getAttribute(node, 'data-MJX') && - (process || !this.skipHtmlTags.exec(tname))) { + if ( + this.adaptor.firstChild(node) && + !this.adaptor.getAttribute(node, 'data-MJX') && + (process || !this.skipHtmlTags.exec(tname)) + ) { if (this.adaptor.next(node)) { this.stack.push([this.adaptor.next(node), ignore]); } @@ -245,8 +261,8 @@ export class HTMLDomStrings { * Handle an unknown node type (nodeType other than 1, 3, 8) * * @param {N} node The node to process - * @param {boolean} ignore Whether we are currently ignoring content - * @return {N|T} The next element to process + * @param {boolean} _ignore Whether we are currently ignoring content + * @returns {N|T} The next element to process */ protected handleOther(node: N, _ignore: boolean): N | T { this.pushString(); @@ -269,19 +285,19 @@ export class HTMLDomStrings { * Return the strings and node lists * * @param {N} node The node to search - * @return {[string[], HTMLNodeList[]]} The array of strings and their associated lists of nodes + * @returns {[string[], HTMLNodeList[]]} The array of strings and their associated lists of nodes */ public find(node: N | T): [string[], HTMLNodeList[]] { this.init(); - let stop = this.adaptor.next(node); + const stop = this.adaptor.next(node); let ignore = false; - let include = this.options['includeHtmlTags']; + const include = this.options['includeHtmlTags']; while (node && node !== stop) { const kind = this.adaptor.kind(node); if (kind === '#text') { node = this.handleText(node as T, ignore); - } else if (include.hasOwnProperty(kind)) { + } else if (Object.hasOwn(include, kind)) { node = this.handleTag(node as N, ignore); } else if (kind) { [node, ignore] = this.handleContainer(node as N, ignore); @@ -295,9 +311,11 @@ export class HTMLDomStrings { } this.pushString(); - let result = [this.strings, this.nodes] as [string[], HTMLNodeList[]]; + const result = [this.strings, this.nodes] as [ + string[], + HTMLNodeList[], + ]; this.init(); // free up memory return result; } - } diff --git a/ts/handlers/html/HTMLHandler.ts b/ts/handlers/html/HTMLHandler.ts index ab7d4d826..6a14a8eb9 100644 --- a/ts/handlers/html/HTMLHandler.ts +++ b/ts/handlers/html/HTMLHandler.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ */ /** - * @fileoverview Implements the HTMLHandler class + * @file Implements the HTMLHandler class * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractHandler} from '../../core/Handler.js'; -import {MinHTMLAdaptor} from '../../adaptors/HTMLAdaptor.js'; -import {HTMLDocument} from './HTMLDocument.js'; -import {OptionList} from '../../util/Options.js'; +import { AbstractHandler } from '../../core/Handler.js'; +import { MinHTMLAdaptor } from '../../adaptors/HTMLAdaptor.js'; +import { HTMLDocument } from './HTMLDocument.js'; +import { OptionList } from '../../util/Options.js'; /*****************************************************************/ /** @@ -35,11 +35,10 @@ import {OptionList} from '../../util/Options.js'; * @template D The Document class */ export class HTMLHandler extends AbstractHandler { - /** * The DOMAdaptor for the document being handled */ - public adaptor: MinHTMLAdaptor; // declare a more specific adaptor type + public adaptor: MinHTMLAdaptor; // declare a more specific adaptor type /** * @override @@ -51,14 +50,18 @@ export class HTMLHandler extends AbstractHandler { */ public handlesDocument(document: any) { const adaptor = this.adaptor; - if (typeof(document) === 'string') { + if (typeof document === 'string') { try { document = adaptor.parse(document, 'text/html'); - } catch (err) {} + } catch (_err) { + // continue regardless of error + } } - if (document instanceof adaptor.window.Document || - document instanceof adaptor.window.HTMLElement || - document instanceof adaptor.window.DocumentFragment) { + if ( + document instanceof adaptor.window.Document || + document instanceof adaptor.window.HTMLElement || + document instanceof adaptor.window.DocumentFragment + ) { return true; } return false; @@ -72,15 +75,16 @@ export class HTMLHandler extends AbstractHandler { */ public create(document: any, options: OptionList) { const adaptor = this.adaptor; - if (typeof(document) === 'string') { + if (typeof document === 'string') { document = adaptor.parse(document, 'text/html'); - } else if (document instanceof adaptor.window.HTMLElement || - document instanceof adaptor.window.DocumentFragment) { - let child = document as N; + } else if ( + document instanceof adaptor.window.HTMLElement || + document instanceof adaptor.window.DocumentFragment + ) { + const child = document as N; document = adaptor.parse('', 'text/html'); adaptor.append(adaptor.body(document), child); } return super.create(document, options) as HTMLDocument; } - } diff --git a/ts/handlers/html/HTMLMathItem.ts b/ts/handlers/html/HTMLMathItem.ts index 8351f773e..6e8f96b6c 100644 --- a/ts/handlers/html/HTMLMathItem.ts +++ b/ts/handlers/html/HTMLMathItem.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,14 +16,15 @@ */ /** - * @fileoverview Implements the HTMLMathItem class + * @file Implements the HTMLMathItem class * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractMathItem, Location, STATE} from '../../core/MathItem.js'; -import {InputJax} from '../../core/InputJax.js'; -import {HTMLDocument} from './HTMLDocument.js'; +import { AbstractMathItem, Location, STATE } from '../../core/MathItem.js'; +import { DOMAdaptor } from '../../core/DOMAdaptor.js'; +import { InputJax } from '../../core/InputJax.js'; +import { HTMLDocument } from './HTMLDocument.js'; /*****************************************************************/ /** @@ -34,20 +35,23 @@ import {HTMLDocument} from './HTMLDocument.js'; * @template D The Document class */ export class HTMLMathItem extends AbstractMathItem { - /** - * Easy access to DOM adaptor + * @returns {DOMAdaptor} Easy access to DOM adaptor */ - get adaptor() { + get adaptor(): DOMAdaptor { return this.inputJax.adaptor; } /** * @override */ - constructor(math: string, jax: InputJax, display: boolean = true, - start: Location = {node: null, n: 0, delim: ''}, - end: Location = {node: null, n: 0, delim: ''}) { + constructor( + math: string, + jax: InputJax, + display: boolean = true, + start: Location = { node: null, n: 0, delim: '' }, + end: Location = { node: null, n: 0, delim: '' } + ) { super(math, jax, display, start, end); } @@ -70,7 +74,10 @@ export class HTMLMathItem extends AbstractMathItem { if (this.inputJax.processStrings) { let node = this.start.node as T; if (node === this.end.node) { - if (this.end.n && this.end.n < this.adaptor.value(this.end.node).length) { + if ( + this.end.n && + this.end.n < this.adaptor.value(this.end.node).length + ) { this.adaptor.split(this.end.node, this.end.n); } if (this.start.n) { @@ -82,7 +89,7 @@ export class HTMLMathItem extends AbstractMathItem { node = this.adaptor.split(node, this.start.n); } while (node !== this.end.node) { - let next = this.adaptor.next(node) as T; + const next = this.adaptor.next(node) as T; this.adaptor.remove(node); node = next; } @@ -117,12 +124,13 @@ export class HTMLMathItem extends AbstractMathItem { * @override */ public removeFromDocument(restore: boolean = false) { + super.removeFromDocument(restore); if (this.state() >= STATE.TYPESET) { const adaptor = this.adaptor; - let node = this.start.node; + const node = this.start.node; let math: N | T = adaptor.text(''); if (restore) { - let text = this.start.delim + this.math + this.end.delim; + const text = this.start.delim + this.math + this.end.delim; if (this.inputJax.processStrings) { math = adaptor.text(text); } else { @@ -137,5 +145,4 @@ export class HTMLMathItem extends AbstractMathItem { this.start.n = this.end.n = 0; } } - } diff --git a/ts/handlers/html/HTMLMathList.ts b/ts/handlers/html/HTMLMathList.ts index 4e26fbbcb..3c2ca836d 100644 --- a/ts/handlers/html/HTMLMathList.ts +++ b/ts/handlers/html/HTMLMathList.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,12 +16,12 @@ */ /** - * @fileoverview Implements the HTMLMathList object + * @file Implements the HTMLMathList object * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractMathList} from '../../core/MathList.js'; +import { AbstractMathList } from '../../core/MathList.js'; /*****************************************************************/ /** @@ -31,5 +31,4 @@ import {AbstractMathList} from '../../core/MathList.js'; * @template T The Text node class * @template D The Document class */ -export class HTMLMathList extends AbstractMathList { -} +export class HTMLMathList extends AbstractMathList {} diff --git a/ts/input/asciimath.ts b/ts/input/asciimath.ts index b14222661..1493a3226 100644 --- a/ts/input/asciimath.ts +++ b/ts/input/asciimath.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,18 +16,18 @@ */ /** - * @fileoverview Implements the AsciiMath InputJax object + * @file Implements the AsciiMath InputJax object * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractInputJax} from '../core/InputJax.js'; -import {LegacyAsciiMath} from './asciimath/mathjax2/input/AsciiMath.js'; -import {separateOptions, OptionList} from '../util/Options.js'; -import {MathDocument} from '../core/MathDocument.js'; -import {MathItem} from '../core/MathItem.js'; +import { AbstractInputJax } from '../core/InputJax.js'; +import { LegacyAsciiMath } from './asciimath/legacy.js'; +import { separateOptions, OptionList } from '../util/Options.js'; +import { MathDocument } from '../core/MathDocument.js'; +import { MathItem } from '../core/MathItem.js'; -import {FindAsciiMath} from './asciimath/FindAsciiMath.js'; +import { FindAsciiMath } from './asciimath/FindAsciiMath.js'; /*****************************************************************/ /** @@ -38,7 +38,6 @@ import {FindAsciiMath} from './asciimath/FindAsciiMath.js'; * @template D The Document class */ export class AsciiMath extends AbstractInputJax { - /** * The name of the input jax */ @@ -49,7 +48,7 @@ export class AsciiMath extends AbstractInputJax { */ public static OPTIONS: OptionList = { ...AbstractInputJax.OPTIONS, - FindAsciiMath: null + FindAsciiMath: null, }; /** @@ -61,9 +60,14 @@ export class AsciiMath extends AbstractInputJax { * @override */ constructor(options: OptionList) { - let [ , find, am] = separateOptions(options, FindAsciiMath.OPTIONS, AsciiMath.OPTIONS); + const [, find, am] = separateOptions( + options, + FindAsciiMath.OPTIONS, + AsciiMath.OPTIONS + ); super(am); - this.findAsciiMath = this.options['FindAsciiMath'] || new FindAsciiMath(find); + this.findAsciiMath = + this.options['FindAsciiMath'] || new FindAsciiMath(find); } /** @@ -81,5 +85,4 @@ export class AsciiMath extends AbstractInputJax { public findMath(strings: string[]) { return this.findAsciiMath.findMath(strings); } - } diff --git a/ts/input/asciimath/FindAsciiMath.ts b/ts/input/asciimath/FindAsciiMath.ts index 0cb4f667e..847b94f8c 100644 --- a/ts/input/asciimath/FindAsciiMath.ts +++ b/ts/input/asciimath/FindAsciiMath.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ */ /** - * @fileoverview Implements the AsciiMath version of the FindMath object + * @file Implements the AsciiMath version of the FindMath object * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractFindMath} from '../../core/FindMath.js'; -import {OptionList} from '../../util/Options.js'; -import {quotePattern} from '../../util/string.js'; -import {ProtoItem, protoItem} from '../../core/MathItem.js'; +import { AbstractFindMath } from '../../core/FindMath.js'; +import { OptionList } from '../../util/Options.js'; +import { quotePattern } from '../../util/string.js'; +import { ProtoItem, protoItem } from '../../core/MathItem.js'; /** * Shorthand types for data about end delimiters and delimiter pairs @@ -43,12 +43,11 @@ export type Delims = [string, string]; * @template D The Document class */ export class FindAsciiMath extends AbstractFindMath { - /** * @override */ public static OPTIONS: OptionList = { - delimiters: [['`', '`']], // The start/end delimiter pairs for asciimath code + delimiters: [['`', '`']], // The start/end delimiter pairs for asciimath code }; /** @@ -59,7 +58,7 @@ export class FindAsciiMath extends AbstractFindMath { /** * The end-delimiter data keyed to the opening delimiter string */ - protected end: {[name: string]: EndItem}; + protected end: { [name: string]: EndItem }; /** * False if the configuration has no delimiters (so search can be skipped), true otherwise @@ -79,12 +78,14 @@ export class FindAsciiMath extends AbstractFindMath { * based on the configuration options */ protected getPatterns() { - let options = this.options; - let starts: string[] = []; + const options = this.options; + const starts: string[] = []; this.end = {}; - options['delimiters'].forEach((delims: Delims) => this.addPattern(starts, delims, false)); + options['delimiters'].forEach((delims: Delims) => + this.addPattern(starts, delims, false) + ); this.start = new RegExp(starts.join('|'), 'g'); - this.hasPatterns = (starts.length > 0); + this.hasPatterns = starts.length > 0; } /** @@ -95,7 +96,7 @@ export class FindAsciiMath extends AbstractFindMath { * @param {boolean} display True if the delimiters are for display mode */ protected addPattern(starts: string[], delims: Delims, display: boolean) { - let [open, close] = delims; + const [open, close] = delims; starts.push(quotePattern(open)); this.end[open] = [close, display, new RegExp(quotePattern(close), 'g')]; } @@ -107,14 +108,28 @@ export class FindAsciiMath extends AbstractFindMath { * @param {number} n The index of the string being searched * @param {RegExpExecArray} start The result array from the start-delimiter search * @param {EndItem} end The end-delimiter data corresponding to the start delimiter - * @return {ProtoItem} The proto math item for the math, if found + * @returns {ProtoItem} The proto math item for the math, if found */ - protected findEnd(text: string, n: number, start: RegExpExecArray, end: EndItem): ProtoItem { - let [ , display, pattern] = end; - let i = pattern.lastIndex = start.index + start[0].length; - let match = pattern.exec(text); - return (!match ? null : protoItem(start[0], text.substr(i, match.index - i), match[0], - n, start.index, match.index + match[0].length, display)); + protected findEnd( + text: string, + n: number, + start: RegExpExecArray, + end: EndItem + ): ProtoItem { + const [, display, pattern] = end; + const i = (pattern.lastIndex = start.index + start[0].length); + const match = pattern.exec(text); + return !match + ? null + : protoItem( + start[0], + match.index < i ? '' : text.substring(i, match.index), + match[0], + n, + start.index, + match.index + match[0].length, + display + ); } /** @@ -142,7 +157,7 @@ export class FindAsciiMath extends AbstractFindMath { * @override */ public findMath(strings: string[]) { - let math: ProtoItem[] = []; + const math: ProtoItem[] = []; if (this.hasPatterns) { for (let i = 0, m = strings.length; i < m; i++) { this.findMathInString(math, i, strings[i]); @@ -150,5 +165,4 @@ export class FindAsciiMath extends AbstractFindMath { } return math; } - } diff --git a/ts/input/asciimath/legacy.ts b/ts/input/asciimath/legacy.ts new file mode 100644 index 000000000..79101c0af --- /dev/null +++ b/ts/input/asciimath/legacy.ts @@ -0,0 +1,20 @@ +import { AsciiMath } from './legacy/shim.js'; +import { MmlFactory } from '../../core/MmlTree/MmlFactory.js'; + +const factory = new MmlFactory(); + +export const LegacyAsciiMath = { + Compile: function (am: any, display: boolean) { + const script = { + type: 'math/asciimath', + innerText: am, + MathJax: {}, + }; + const node = AsciiMath.Translate(script).root.toMmlNode(factory); + node.setInheritedAttributes({}, display, 0, false); + return node; + }, + Translate: function (am: any, display: boolean) { + return this.Compile(am, display); + }, +}; diff --git a/ts/input/asciimath/mathjax2/legacy/MathJax.js b/ts/input/asciimath/legacy/MathJax.js similarity index 99% rename from ts/input/asciimath/mathjax2/legacy/MathJax.js rename to ts/input/asciimath/legacy/MathJax.js index 903ede297..853b0a0e9 100644 --- a/ts/input/asciimath/mathjax2/legacy/MathJax.js +++ b/ts/input/asciimath/legacy/MathJax.js @@ -1562,7 +1562,7 @@ MathJax.Message = { MathJax.Hub = { config: { - root: "./mathjax2/legacy", + root: "./legacy", config: [], // list of configuration files to load jax: [], // list of input and output jax to load extensions: [], // list of extensions to load diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/JSON.js b/ts/input/asciimath/legacy/jax/element/JSON.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/JSON.js rename to ts/input/asciimath/legacy/jax/element/JSON.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/MmlNode.js b/ts/input/asciimath/legacy/jax/element/MmlNode.js similarity index 98% rename from ts/input/asciimath/mathjax2/legacy/jax/element/MmlNode.js rename to ts/input/asciimath/legacy/jax/element/MmlNode.js index cab6e13b0..78f14685d 100644 --- a/ts/input/asciimath/mathjax2/legacy/jax/element/MmlNode.js +++ b/ts/input/asciimath/legacy/jax/element/MmlNode.js @@ -24,6 +24,7 @@ toMmlNode: function (factory) { var kind = this.type; if (kind === 'texatom') kind = 'TeXAtom'; + if (kind === 'text') kind = '#text'; var node = this.nodeMake(factory, kind); if ("texClass" in this) node.texClass = this.texClass; return node; diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/jax.js b/ts/input/asciimath/legacy/jax/element/mml/jax.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/jax.js rename to ts/input/asciimath/legacy/jax/element/mml/jax.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/Arrows.js b/ts/input/asciimath/legacy/jax/element/mml/optable/Arrows.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/Arrows.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/Arrows.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/BasicLatin.js b/ts/input/asciimath/legacy/jax/element/mml/optable/BasicLatin.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/BasicLatin.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/BasicLatin.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/CombDiacritMarks.js b/ts/input/asciimath/legacy/jax/element/mml/optable/CombDiacritMarks.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/CombDiacritMarks.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/CombDiacritMarks.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/CombDiactForSymbols.js b/ts/input/asciimath/legacy/jax/element/mml/optable/CombDiactForSymbols.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/CombDiactForSymbols.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/CombDiactForSymbols.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/Dingbats.js b/ts/input/asciimath/legacy/jax/element/mml/optable/Dingbats.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/Dingbats.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/Dingbats.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/GeneralPunctuation.js b/ts/input/asciimath/legacy/jax/element/mml/optable/GeneralPunctuation.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/GeneralPunctuation.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/GeneralPunctuation.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/GeometricShapes.js b/ts/input/asciimath/legacy/jax/element/mml/optable/GeometricShapes.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/GeometricShapes.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/GeometricShapes.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/GreekAndCoptic.js b/ts/input/asciimath/legacy/jax/element/mml/optable/GreekAndCoptic.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/GreekAndCoptic.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/GreekAndCoptic.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/Latin1Supplement.js b/ts/input/asciimath/legacy/jax/element/mml/optable/Latin1Supplement.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/Latin1Supplement.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/Latin1Supplement.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/LetterlikeSymbols.js b/ts/input/asciimath/legacy/jax/element/mml/optable/LetterlikeSymbols.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/LetterlikeSymbols.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/LetterlikeSymbols.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MathOperators.js b/ts/input/asciimath/legacy/jax/element/mml/optable/MathOperators.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MathOperators.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/MathOperators.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MiscMathSymbolsA.js b/ts/input/asciimath/legacy/jax/element/mml/optable/MiscMathSymbolsA.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MiscMathSymbolsA.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/MiscMathSymbolsA.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MiscMathSymbolsB.js b/ts/input/asciimath/legacy/jax/element/mml/optable/MiscMathSymbolsB.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MiscMathSymbolsB.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/MiscMathSymbolsB.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MiscSymbolsAndArrows.js b/ts/input/asciimath/legacy/jax/element/mml/optable/MiscSymbolsAndArrows.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MiscSymbolsAndArrows.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/MiscSymbolsAndArrows.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MiscTechnical.js b/ts/input/asciimath/legacy/jax/element/mml/optable/MiscTechnical.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/MiscTechnical.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/MiscTechnical.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/SpacingModLetters.js b/ts/input/asciimath/legacy/jax/element/mml/optable/SpacingModLetters.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/SpacingModLetters.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/SpacingModLetters.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/SuppMathOperators.js b/ts/input/asciimath/legacy/jax/element/mml/optable/SuppMathOperators.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/SuppMathOperators.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/SuppMathOperators.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/SupplementalArrowsA.js b/ts/input/asciimath/legacy/jax/element/mml/optable/SupplementalArrowsA.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/SupplementalArrowsA.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/SupplementalArrowsA.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/SupplementalArrowsB.js b/ts/input/asciimath/legacy/jax/element/mml/optable/SupplementalArrowsB.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/element/mml/optable/SupplementalArrowsB.js rename to ts/input/asciimath/legacy/jax/element/mml/optable/SupplementalArrowsB.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/input/AsciiMath/config.js b/ts/input/asciimath/legacy/jax/input/AsciiMath/config.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/input/AsciiMath/config.js rename to ts/input/asciimath/legacy/jax/input/AsciiMath/config.js diff --git a/ts/input/asciimath/mathjax2/legacy/jax/input/AsciiMath/jax.js b/ts/input/asciimath/legacy/jax/input/AsciiMath/jax.js similarity index 100% rename from ts/input/asciimath/mathjax2/legacy/jax/input/AsciiMath/jax.js rename to ts/input/asciimath/legacy/jax/input/AsciiMath/jax.js diff --git a/ts/input/asciimath/legacy/package.json b/ts/input/asciimath/legacy/package.json new file mode 100644 index 000000000..5bbefffba --- /dev/null +++ b/ts/input/asciimath/legacy/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/ts/input/asciimath/legacy/shim.d.ts b/ts/input/asciimath/legacy/shim.d.ts new file mode 100644 index 000000000..b8689f4f0 --- /dev/null +++ b/ts/input/asciimath/legacy/shim.d.ts @@ -0,0 +1 @@ +export const AsciiMath: any; diff --git a/ts/input/asciimath/legacy/shim.js b/ts/input/asciimath/legacy/shim.js new file mode 100644 index 000000000..3b228bb9e --- /dev/null +++ b/ts/input/asciimath/legacy/shim.js @@ -0,0 +1,22 @@ +MathJax = Object.assign(global.MathJax || {}, require("./MathJax.js").MathJax); + +// +// Load component-based configuration, if any +// +if (MathJax.config && MathJax.config.asciimath) { + MathJax.Hub.Config({AsciiMath: MathJax.config.asciimath}); +} + +MathJax.Ajax.Preloading( + "[MathJax]/jax/input/AsciiMath/config.js", + "[MathJax]/jax/input/AsciiMath/jax.js", + "[MathJax]/jax/element/mml/jax.js" +); + +require("./jax/element/mml/jax.js"); +require("./jax/input/AsciiMath/config.js"); +require("./jax/input/AsciiMath/jax.js"); + +require("./jax/element/MmlNode.js"); + +module.exports.AsciiMath = MathJax.InputJax.AsciiMath; diff --git a/ts/input/asciimath/mathjax2/input/AsciiMath.d.ts b/ts/input/asciimath/mathjax2/input/AsciiMath.d.ts deleted file mode 100644 index b90804356..000000000 --- a/ts/input/asciimath/mathjax2/input/AsciiMath.d.ts +++ /dev/null @@ -1 +0,0 @@ -export var LegacyAsciiMath: any; diff --git a/ts/input/asciimath/mathjax2/input/AsciiMath.js b/ts/input/asciimath/mathjax2/input/AsciiMath.js deleted file mode 100644 index 41f6a1faa..000000000 --- a/ts/input/asciimath/mathjax2/input/AsciiMath.js +++ /dev/null @@ -1,39 +0,0 @@ -MathJax = Object.assign(global.MathJax || {}, require("../legacy/MathJax.js").MathJax); - -// -// Load component-based configuration, if any -// -if (MathJax.config && MathJax.config.asciimath) { - MathJax.Hub.Config({AsciiMath: MathJax.config.asciimath}); -} - -MathJax.Ajax.Preloading( - "[MathJax]/jax/input/AsciiMath/config.js", - "[MathJax]/jax/input/AsciiMath/jax.js", - "[MathJax]/jax/element/mml/jax.js" -); - -require("../legacy/jax/element/mml/jax.js"); -require("../legacy/jax/input/AsciiMath/config.js"); -require("../legacy/jax/input/AsciiMath/jax.js"); - -require("../legacy/jax/element/MmlNode.js"); - -var MmlFactory = require("../../../../core/MmlTree/MmlFactory.js").MmlFactory; -var factory = new MmlFactory(); - -exports.LegacyAsciiMath = { - Compile: function (am,display) { - var script = { - type: "math/asciimath", - innerText: am, - MathJax: {} - }; - var node = MathJax.InputJax.AsciiMath.Translate(script).root.toMmlNode(factory); - node.setInheritedAttributes({}, display, 0, false); - return node; - }, - Translate: function (am,display) { - return this.Compile(am,display); - } -}; diff --git a/ts/input/mathml.ts b/ts/input/mathml.ts index 600ec4358..e796da765 100644 --- a/ts/input/mathml.ts +++ b/ts/input/mathml.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,21 +16,25 @@ */ /** - * @fileoverview Implements the MathML InputJax object + * @file Implements the MathML InputJax object * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractInputJax} from '../core/InputJax.js'; -import {defaultOptions, separateOptions, OptionList} from '../util/Options.js'; -import {FunctionList} from '../util/FunctionList.js'; -import {MathDocument} from '../core/MathDocument.js'; -import {MathItem} from '../core/MathItem.js'; -import {DOMAdaptor} from '../core/DOMAdaptor.js'; -import {MmlFactory} from '../core/MmlTree/MmlFactory.js'; - -import {FindMathML} from './mathml/FindMathML.js'; -import {MathMLCompile} from './mathml/MathMLCompile.js'; +import { AbstractInputJax } from '../core/InputJax.js'; +import { + defaultOptions, + separateOptions, + OptionList, +} from '../util/Options.js'; +import { FunctionList } from '../util/FunctionList.js'; +import { MathDocument } from '../core/MathDocument.js'; +import { MathItem } from '../core/MathItem.js'; +import { DOMAdaptor } from '../core/DOMAdaptor.js'; +import { MmlFactory } from '../core/MmlTree/MmlFactory.js'; + +import { FindMathML } from './mathml/FindMathML.js'; +import { MathMLCompile } from './mathml/MathMLCompile.js'; /*****************************************************************/ /** @@ -41,7 +45,6 @@ import {MathMLCompile} from './mathml/MathMLCompile.js'; * @template D The Document class */ export class MathML extends AbstractInputJax { - /** * The name of this input jax */ @@ -50,9 +53,11 @@ export class MathML extends AbstractInputJax { /** * @override */ + /* prettier-ignore */ public static OPTIONS: OptionList = defaultOptions({ parseAs: 'html', // Whether to use HTML or XML parsing for the MathML string forceReparse: false, // Whether to force the string to be reparsed, or use the one from the document DOM + mmlFilters: [], // Filters to add to the mmlFilters lost FindMathML: null, // The FindMathML instance to override the default one MathMLCompile: null, // The MathMLCompile instance to override the default one /* @@ -82,11 +87,16 @@ export class MathML extends AbstractInputJax { * @override */ constructor(options: OptionList = {}) { - let [mml, find, compile] = separateOptions(options, FindMathML.OPTIONS, MathMLCompile.OPTIONS); + const [mml, find, compile] = separateOptions( + options, + FindMathML.OPTIONS, + MathMLCompile.OPTIONS + ); super(mml); - this.findMathML = this.options['FindMathML'] || new FindMathML(find); - this.mathml = this.options['MathMLCompile'] || new MathMLCompile(compile); - this.mmlFilters = new FunctionList(); + this.findMathML = this.options.FindMathML || new FindMathML(find); + this.mathml = + this.options.MathMLCompile || new MathMLCompile(compile); + this.mmlFilters = new FunctionList(this.options.mmlFilters); } /** @@ -135,30 +145,52 @@ export class MathML extends AbstractInputJax { */ public compile(math: MathItem, document: MathDocument) { let mml = math.start.node; - if (!mml || !math.end.node || this.options['forceReparse'] || this.adaptor.kind(mml) === '#text') { - let mathml = this.executeFilters(this.preFilters, math, document, (math.math || '').trim()); - let doc = this.checkForErrors(this.adaptor.parse(mathml, 'text/' + this.options['parseAs'])); - let body = this.adaptor.body(doc); + if ( + !mml || + !math.end.node || + this.options['forceReparse'] || + this.adaptor.kind(mml) === '#text' + ) { + let mathml = this.executeFilters( + this.preFilters, + math, + document, + (math.math || '').trim() + ); + if (this.options['parseAs'] === 'html') { + mathml = `${mathml}`; + } + const doc = this.checkForErrors( + this.adaptor.parse(mathml, 'text/' + this.options['parseAs']) + ); + const body = this.adaptor.body(doc); if (this.adaptor.childNodes(body).length !== 1) { this.error('MathML must consist of a single element'); } mml = this.adaptor.remove(this.adaptor.firstChild(body)) as N; if (this.adaptor.kind(mml).replace(/^[a-z]+:/, '') !== 'math') { - this.error('MathML must be formed by a element, not <' + this.adaptor.kind(mml) + '>'); + this.error( + 'MathML must be formed by a element, not <' + + this.adaptor.kind(mml) + + '>' + ); } } mml = this.executeFilters(this.mmlFilters, math, document, mml); - return this.executeFilters(this.postFilters, math, document, this.mathml.compile(mml as N)); + let root = this.mathml.compile(mml as N); + root = this.executeFilters(this.postFilters, math, document, root); + math.display = root.attributes.get('display') === 'block'; + return root; } /** * Check a parsed MathML string for errors. * * @param {D} doc The document returns from the DOMParser - * @return {D} The document + * @returns {D} The document */ protected checkForErrors(doc: D): D { - let err = this.adaptor.tags(this.adaptor.body(doc), 'parsererror')[0]; + const err = this.adaptor.tags(this.adaptor.body(doc), 'parsererror')[0]; if (err) { if (this.adaptor.textContent(err) === '') { this.error('Error processing MathML'); @@ -183,5 +215,4 @@ export class MathML extends AbstractInputJax { public findMath(node: N) { return this.findMathML.findMath(node); } - } diff --git a/ts/input/mathml/FindMathML.ts b/ts/input/mathml/FindMathML.ts index af366689d..46c928f64 100644 --- a/ts/input/mathml/FindMathML.ts +++ b/ts/input/mathml/FindMathML.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,22 +16,21 @@ */ /** - * @fileoverview Implements the MathML version of the FindMath object + * @file Implements the MathML version of the FindMath object * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractFindMath} from '../../core/FindMath.js'; -import {DOMAdaptor} from '../../core/DOMAdaptor.js'; -import {OptionList} from '../../util/Options.js'; -import {ProtoItem} from '../../core/MathItem.js'; +import { AbstractFindMath } from '../../core/FindMath.js'; +import { DOMAdaptor } from '../../core/DOMAdaptor.js'; +import { OptionList } from '../../util/Options.js'; +import { ProtoItem } from '../../core/MathItem.js'; /** * The MathML namespace */ const NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; - /*****************************************************************/ /** * Implements the FindMathML object (extends AbstractFindMath) @@ -41,7 +40,6 @@ const NAMESPACE = 'http://www.w3.org/1998/Math/MathML'; * @template D The Document class */ export class FindMathML extends AbstractFindMath { - /** * @override */ @@ -60,11 +58,11 @@ export class FindMathML extends AbstractFindMath { * @override */ public findMath(node: N) { - let set = new Set(); + const set = new Set(); this.findMathNodes(node, set); this.findMathPrefixed(node, set); const html = this.adaptor.root(this.adaptor.document); - if (this.adaptor.kind(html) === 'html' && set.size === 0) { + if (this.adaptor.kind(html) === 'html' && set.size === 0) { this.findMathNS(node, set); } return this.processMath(set); @@ -86,13 +84,13 @@ export class FindMathML extends AbstractFindMath { * Find tags (or whatever prefixes there are) * * @param {N} node The container to seaerch for math - * @param {NodeSet} set The set in which to store the math nodes + * @param {Set} set The set in which to store the math nodes */ protected findMathPrefixed(node: N, set: Set) { - let html = this.adaptor.root(this.adaptor.document); + const html = this.adaptor.root(this.adaptor.document); for (const attr of this.adaptor.allAttributes(html)) { - if (attr.name.substr(0, 6) === 'xmlns:' && attr.value === NAMESPACE) { - let prefix = attr.name.substr(6); + if (attr.name.substring(0, 6) === 'xmlns:' && attr.value === NAMESPACE) { + const prefix = attr.name.substring(6); for (const math of this.adaptor.tags(node, prefix + ':math')) { set.add(math); } @@ -103,8 +101,8 @@ export class FindMathML extends AbstractFindMath { /** * Find namespaced math in XHTML documents (is this really needed?) * - * @param {N} node The container to seaerch for math - * @param {NodeSet} set The set in which to store the math nodes + * @param {N} node The container to search for math + * @param {Set} set The set in which to store the math nodes */ protected findMathNS(node: N, set: Set) { for (const math of this.adaptor.tags(node, 'math', NAMESPACE)) { @@ -114,17 +112,22 @@ export class FindMathML extends AbstractFindMath { /** * Produce the array of proto math items from the node set + * + * @param {Set} set The original node set + * @returns {ProtoItem[]} The set of proto math items */ - protected processMath(set: Set) { - let math: ProtoItem[] = []; - for (const mml of Array.from(set)) { - let display = (this.adaptor.getAttribute(mml, 'display') === 'block' || - this.adaptor.getAttribute(mml, 'mode') === 'display'); - let start = {node: mml, n: 0, delim: ''}; - let end = {node: mml, n: 0, delim: ''}; - math.push({math: this.adaptor.outerHTML(mml), start, end, display}); + protected processMath(set: Set): ProtoItem[] { + const adaptor = this.adaptor; + const math: ProtoItem[] = []; + for (const mml of set.values()) { + if (adaptor.kind(adaptor.parent(mml)) === 'mjx-assistive-mml') continue; + const display = + adaptor.getAttribute(mml, 'display') === 'block' || + adaptor.getAttribute(mml, 'mode') === 'display'; + const start = { node: mml, n: 0, delim: '' }; + const end = { node: mml, n: 0, delim: '' }; + math.push({ math: adaptor.outerHTML(mml), start, end, display }); } return math; } - } diff --git a/ts/input/mathml/MathMLCompile.ts b/ts/input/mathml/MathMLCompile.ts index 373c924d7..21645a32e 100644 --- a/ts/input/mathml/MathMLCompile.ts +++ b/ts/input/mathml/MathMLCompile.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,17 +16,24 @@ */ /** - * @fileoverview Implementation of the Compile function for the MathML input jax + * @file Implementation of the Compile function for the MathML input jax * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MmlFactory} from '../../core/MmlTree/MmlFactory.js'; -import {MmlNode, TextNode, XMLNode, AbstractMmlNode, AbstractMmlTokenNode, TEXCLASS} -from '../../core/MmlTree/MmlNode.js'; -import {userOptions, defaultOptions, OptionList} from '../../util/Options.js'; +import { MmlFactory } from '../../core/MmlTree/MmlFactory.js'; +import { + MmlNode, + TextNode, + XMLNode, + AbstractMmlNode, + AbstractMmlTokenNode, + TEXCLASS, +} from '../../core/MmlTree/MmlNode.js'; +import { HtmlNode } from '../../core/MmlTree/MmlNodes/HtmlNode.js'; +import { userOptions, defaultOptions, OptionList } from '../../util/Options.js'; import * as Entities from '../../util/Entities.js'; -import {DOMAdaptor} from '../../core/DOMAdaptor.js'; +import { DOMAdaptor } from '../../core/DOMAdaptor.js'; /********************************************************************/ /** @@ -38,12 +45,13 @@ import {DOMAdaptor} from '../../core/DOMAdaptor.js'; * @template D The Document class */ export class MathMLCompile { - /** * The default options for this object */ + /* prettier-ignore */ public static OPTIONS: OptionList = { MmlFactory: null, // The MmlFactory to use (defaults to a new MmlFactory) + allowHtmlInTokenNodes: false, // True if HTML is allowed in token nodes fixMisplacedChildren: true, // True if we want to use heuristics to try to fix // problems with the tree based on HTML not handling // self-closing tags properly @@ -61,11 +69,11 @@ export class MathMLCompile { /** * The instance of the MmlFactory object and */ - protected factory: MmlFactory; + public factory: MmlFactory; /** * The options (the defaults with the user options merged in) */ - protected options: OptionList; + public options: OptionList; /** * Merge the user options into the defaults, and save them @@ -79,7 +87,7 @@ export class MathMLCompile { } /** - * @param{MmlFactory} mmlFactory The MathML factory to use for new nodes + * @param {MmlFactory} mmlFactory The MathML factory to use for new nodes */ public setMmlFactory(mmlFactory: MmlFactory) { this.factory = mmlFactory; @@ -89,10 +97,10 @@ export class MathMLCompile { * Convert a MathML DOM tree to internal MmlNodes * * @param {N} node The node to convert to MmlNodes - * @return {MmlNode} The MmlNode at the root of the converted tree + * @returns {MmlNode} The MmlNode at the root of the converted tree */ public compile(node: N): MmlNode { - let mml = this.makeNode(node); + const mml = this.makeNode(node); mml.verifyTree(this.options['verify']); mml.setInheritedAttributes({}, false, 0, false); mml.walkTree(this.markMrows); @@ -106,12 +114,12 @@ export class MathMLCompile { * FIXME: we should use data-* attributes rather than classes for these * * @param {N} node The node to convert to an MmlNode - * @return {MmlNode} The converted MmlNode + * @returns {MmlNode} The converted MmlNode */ public makeNode(node: N): MmlNode { const adaptor = this.adaptor; let limits = false; - let kind = adaptor.kind(node).replace(/^.*:/, ''); + const kind = adaptor.kind(node).replace(/^.*:/, ''); let texClass = adaptor.getAttribute(node, 'data-mjx-texclass') || ''; if (texClass) { texClass = this.filterAttribute('data-mjx-texclass', texClass) || ''; @@ -119,20 +127,40 @@ export class MathMLCompile { let type = texClass && kind === 'mrow' ? 'TeXAtom' : kind; for (const name of this.filterClassList(adaptor.allClasses(node))) { if (name.match(/^MJX-TeXAtom-/) && kind === 'mrow') { - texClass = name.substr(12); + texClass = name.substring(12); type = 'TeXAtom'; } else if (name === 'MJX-fixedlimits') { limits = true; } } - this.factory.getNodeClass(type) || this.error('Unknown node type "' + type + '"'); - let mml = this.factory.create(type); + if (!this.factory.getNodeClass(type)) { + return this.unknownNode(type, node); + } + return this.createMml(type, node, texClass, limits); + } + + /** + * Create an actual MmlNode tree from a given DOM node. + * + * @param {string} type The type of MmlNode to create + * @param {N} node The original DOM node that is being transcribed + * @param {string} texClass The texClass specified on the node, if any + * @param {boolean} limits True if fixed limits are to be used + * @returns {MmlNode} The final MmlNode tree + */ + protected createMml( + type: string, + node: N, + texClass: string, + limits: boolean + ): MmlNode { + const mml = this.factory.create(type); if (type === 'TeXAtom' && texClass === 'OP' && !limits) { mml.setProperty('movesupsub', true); mml.attributes.setInherited('movablelimits', true); } if (texClass) { - mml.texClass = (TEXCLASS as {[name: string]: number})[texClass]; + mml.texClass = (TEXCLASS as { [name: string]: number })[texClass]; mml.setProperty('texClass', mml.texClass); } this.addAttributes(mml, node); @@ -141,6 +169,27 @@ export class MathMLCompile { return mml; } + /** + * Handle unknown node by either creating an HTML node, or throwing an error. + * + * @param {string} type The type of node being requested + * @param {N} node The HTML node used to create it. + * @returns {MmlNode} The HtmlNode holding the node (or null) + */ + protected unknownNode(type: string, node: N): MmlNode { + if ( + this.factory.getNodeClass('html') && + this.options.allowHtmlInTokenNodes + ) { + return (this.factory.create('html') as HtmlNode).setHTML( + node, + this.adaptor + ); + } + this.error('Unknown node type "' + type + '"'); + return null; + } + /** * Copy the attributes from a MathML node to an MmlNode. * @@ -150,36 +199,43 @@ export class MathMLCompile { protected addAttributes(mml: MmlNode, node: N) { let ignoreVariant = false; for (const attr of this.adaptor.allAttributes(node)) { - let name = attr.name; - let value = this.filterAttribute(name, attr.value); + const name = attr.name; + const value = this.filterAttribute(name, attr.value); if (value === null || name === 'xmlns') { continue; } - if (name.substr(0, 9) === 'data-mjx-') { - switch (name.substr(9)) { - case 'alternate': - mml.setProperty('variantForm', true); - break; - case 'variant': - mml.attributes.set('mathvariant', value); - ignoreVariant = true; - break; - case 'smallmatrix': - mml.setProperty('scriptlevel', 1); - mml.setProperty('useHeight', false); - break; - case 'accent': - mml.setProperty('mathaccent', value === 'true'); - break; - case 'auto-op': - mml.setProperty('autoOP', value === 'true'); - break; - case 'script-align': - mml.setProperty('scriptalign', value); - break; + if (name.substring(0, 9) === 'data-mjx-') { + switch (name.substring(9)) { + case 'alternate': + mml.setProperty('variantForm', true); + break; + case 'variant': + mml.attributes.set('mathvariant', value); + mml.setProperty('ignore-variant', true); + ignoreVariant = true; + break; + case 'smallmatrix': + mml.setProperty('smallmatrix', true); + mml.setProperty('useHeight', false); + break; + case 'mathaccent': + mml.setProperty('mathaccent', value === 'true'); + break; + case 'auto-op': + mml.setProperty('autoOP', value === 'true'); + break; + case 'script-align': + mml.setProperty('scriptalign', value); + break; + case 'vbox': + mml.setProperty('vbox', value); + break; + default: + mml.attributes.set(name, value); + break; } } else if (name !== 'class') { - let val = value.toLowerCase(); + const val = value.toLowerCase(); if (val === 'true' || val === 'false') { mml.attributes.set(name, val === 'true'); } else if (!ignoreVariant || name !== 'mathvariant') { @@ -192,10 +248,11 @@ export class MathMLCompile { /** * Provide a hook for the Safe extension to filter attribute values. * - * @param {string} name The name of an attribute to filter + * @param {string} _name The name of an attribute to filter * @param {string} value The value to filter + * @returns {string} The filtered value. */ - protected filterAttribute(_name: string, value: string) { + protected filterAttribute(_name: string, value: string): string { return value; } @@ -203,6 +260,7 @@ export class MathMLCompile { * Provide a hook for the Safe extension to filter class names. * * @param {string[]} list The list of class names to filter + * @returns {string[]} The list of filtered class names */ protected filterClassList(list: string[]) { return list; @@ -227,19 +285,31 @@ export class MathMLCompile { if (name === '#text') { this.addText(mml, child); } else if (mml.isKind('annotation-xml')) { - mml.appendChild((this.factory.create('XML') as XMLNode).setXML(child, adaptor)); + mml.appendChild( + (this.factory.create('XML') as XMLNode).setXML(child, adaptor) + ); } else { - let childMml = mml.appendChild(this.makeNode(child)) as MmlNode; - if (childMml.arity === 0 && adaptor.childNodes(child).length) { + const childMml = mml.appendChild(this.makeNode(child)); + if ( + childMml.arity === 0 && + adaptor.childNodes(child).length && + !childMml.isKind('html') + ) { if (this.options['fixMisplacedChildren']) { this.addChildren(mml, child); } else { - childMml.mError('There should not be children for ' + childMml.kind + ' nodes', - this.options['verify'], true); + childMml.mError( + 'There should not be children for ' + childMml.kind + ' nodes', + this.options['verify'], + true + ); } } } } + if (mml.isToken) { + this.trimSpace(mml); + } } /** @@ -253,7 +323,7 @@ export class MathMLCompile { if ((mml.isToken || mml.getProperty('isChars')) && mml.arity) { if (mml.isToken) { text = Entities.translate(text); - text = this.trimSpace(text); + text = this.normalizeSpace(text); } mml.appendChild((this.factory.create('text') as TextNode).setText(text)); } else if (text.match(/\S/)) { @@ -268,13 +338,16 @@ export class MathMLCompile { * @param {N} node The MathML node whose class is to be processed */ protected checkClass(mml: MmlNode, node: N) { - let classList = []; + const classList = []; for (const name of this.filterClassList(this.adaptor.allClasses(node))) { - if (name.substr(0, 4) === 'MJX-') { + if (name.substring(0, 4) === 'MJX-') { if (name === 'MJX-variant') { mml.setProperty('variantForm', true); - } else if (name.substr(0, 11) !== 'MJX-TeXAtom') { - mml.attributes.set('mathvariant', this.fixCalligraphic(name.substr(3))); + } else if (name.substring(0, 11) !== 'MJX-TeXAtom') { + mml.attributes.set( + 'mathvariant', + this.fixCalligraphic(name.substring(3)) + ); } } else { classList.push(name); @@ -289,7 +362,7 @@ export class MathMLCompile { * Fix the old incorrect spelling of calligraphic. * * @param {string} variant The mathvariant name - * @return {string} The corrected variant + * @returns {string} The corrected variant */ protected fixCalligraphic(variant: string): string { return variant.replace(/caligraphic/, 'calligraphic'); @@ -302,10 +375,16 @@ export class MathMLCompile { */ protected markMrows(mml: MmlNode) { if (mml.isKind('mrow') && !mml.isInferred && mml.childNodes.length >= 2) { - let first = mml.childNodes[0] as MmlNode; - let last = mml.childNodes[mml.childNodes.length - 1] as MmlNode; - if (first.isKind('mo') && first.attributes.get('fence') && first.attributes.get('stretchy') && - last.isKind('mo') && last.attributes.get('fence') && last.attributes.get('stretchy')) { + const first = mml.childNodes[0]; + const last = mml.childNodes[mml.childNodes.length - 1]; + if ( + first.isKind('mo') && + first.attributes.get('fence') && + first.attributes.get('stretchy') && + last.isKind('mo') && + last.attributes.get('fence') && + last.attributes.get('stretchy') + ) { if (first.childNodes.length) { mml.setProperty('open', (first as AbstractMmlTokenNode).getText()); } @@ -317,16 +396,29 @@ export class MathMLCompile { } /** - * @param {string} text The text to have leading/trailing spaced removed - * @return {string} The trimmed text + * @param {string} text The text to have spacing normalized + * @returns {string} The trimmed text */ - protected trimSpace(text: string): string { - return text.replace(/[\t\n\r]/g, ' ') // whitespace to spaces - .replace(/^ +/, '') // initial whitespace - .replace(/ +$/, '') // trailing whitespace - .replace(/ +/g, ' '); // internal multiple whitespace + protected normalizeSpace(text: string): string { + return text + .replace(/[\t\n\r]/g, ' ') // whitespace to spaces + .replace(/ +/g, ' '); // internal multiple whitespace } + /** + * @param {MmlNode} mml The token node whose leading/trailing spaces should be removed + */ + protected trimSpace(mml: MmlNode) { + let child = mml.childNodes[0] as TextNode; + if (!child) return; + if (child.isKind('text')) { + child.setText(child.getText().replace(/^ +/, '')); + } + child = mml.childNodes[mml.childNodes.length - 1] as TextNode; + if (child.isKind('text')) { + child.setText(child.getText().replace(/ +$/, '')); + } + } /** * @param {string} message The error message to produce */ diff --git a/ts/input/mathml/mml3/mml3-node.ts b/ts/input/mathml/mml3/mml3-node.ts index 26dc47d5b..b310fff3d 100644 --- a/ts/input/mathml/mml3/mml3-node.ts +++ b/ts/input/mathml/mml3/mml3-node.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2021-2022 The MathJax Consortium + * Copyright (c) 2021-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,13 +16,14 @@ */ /** - * @fileoverview Auxiliary function for elementary MathML3 support (experimental) + * @file Auxiliary function for elementary MathML3 support (experimental) * using David Carlisle's XLST transform. * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MathDocument} from '../../../core/MathDocument.js'; +import { MathDocument } from '../../../core/MathDocument.js'; +import { mjxRoot } from '#root/root.js'; /** * Create the transform function that uses Saxon-js to perform the @@ -32,23 +33,32 @@ import {MathDocument} from '../../../core/MathDocument.js'; * @template T The Text node class * @template D The Document class * - * @return {(node: N, doc: MathDocument) => N)} The transformation function + * @returns {(node: N, doc: MathDocument) => N} The transformation function */ -export function createTransform(): (node: N, doc: MathDocument) => N { - /* tslint:disable-next-line:no-eval */ - const nodeRequire = eval('require'); // get the actual require from node. - /* tslint:disable-next-line:no-eval */ - const dirname = eval('__dirname'); // get the actual __dirname +export function createTransform(): ( + node: N, + doc: MathDocument +) => N { + // get the actual require from node. + const nodeRequire = eval('require'); try { - nodeRequire.resolve('saxon-js'); // check if saxon-js is installed. - } catch (err) { - throw Error('Saxon-js not found. Run the command:\n npm install saxon-js\nand try again.'); + // check if saxon-js is installed. + nodeRequire.resolve('saxon-js'); + } catch (_err) { + throw Error( + 'Saxon-js not found. Run the command:\n npm install saxon-js\nand try again.' + ); } - const Saxon = nodeRequire('saxon-js'); // dynamically load Saxon-JS. - const path = nodeRequire('path'); // use the real version from node. - const fs = nodeRequire('fs'); // use the real version from node. - const xsltFile = path.resolve(dirname, 'mml3.sef.json'); // load the preprocessed stylesheet. - const xslt = JSON.parse(fs.readFileSync(xsltFile)); // and parse it. + // dynamically load Saxon-JS. + const Saxon = nodeRequire('saxon-js'); + // use the real version from node. + const path = nodeRequire('path'); + // + // Load the XSLT stylesheet + // + const xslt = nodeRequire( + path.resolve(mjxRoot(), 'input', 'mml', 'extensions', 'mml3.sef.json') + ); return (node: N, doc: MathDocument) => { const adaptor = doc.adaptor; let mml = adaptor.outerHTML(node); @@ -56,19 +66,28 @@ export function createTransform(): (node: N, doc: MathDocument // Make sure the namespace is present // if (!mml.match(/ xmlns[=:]/)) { - mml = mml.replace(/<(?:(\w+)(:))?math/, '<$1$2math xmlns$2$1="http://www.w3.org/1998/Math/MathML"'); + mml = mml.replace( + /<(?:(\w+)(:))?math/, + '<$1$2math xmlns$2$1="http://www.w3.org/1998/Math/MathML"' + ); } // // Try to run the transform, and if it fails, return the original MathML // let result; try { - result = adaptor.firstChild(adaptor.body(adaptor.parse(Saxon.transform({ - stylesheetInternal: xslt, - sourceText: mml, - destination: 'serialized' - }).principalResult))) as N; - } catch (err) { + result = adaptor.firstChild( + adaptor.body( + adaptor.parse( + Saxon.transform({ + stylesheetInternal: xslt, + sourceText: mml, + destination: 'serialized', + }).principalResult + ) + ) + ) as N; + } catch (_err) { result = node; } return result; diff --git a/ts/input/mathml/mml3/mml3.sef.json b/ts/input/mathml/mml3/mml3.sef.json index eeb147d3d..a10a0cf13 100644 --- a/ts/input/mathml/mml3/mml3.sef.json +++ b/ts/input/mathml/mml3/mml3.sef.json @@ -1 +1 @@ -{"N":"package","version":"10","packageVersion":"1","saxonVersion":"Saxon-JS 2.3","target":"JS","targetVersion":"2","name":"TOP-LEVEL","relocatable":"true","buildDateTime":"2022-02-18T15:46:36.585-05:00","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","C":[{"N":"co","id":"0","binds":"0 3 2 1","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"52","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"524","module":"mml3.xsl","expand-text":"false","match":"m:mlongdiv","prio":"11","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"let","var":"Q{}ms","slot":"0","sType":"* ","line":"525","role":"action","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"elem","name":"m:mstack","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstack ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"526","C":[{"N":"sequence","sType":"*N ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"527","sType":"?NA nQ{}decimalpoint","C":[{"N":"lastOf","sType":"?NA nQ{}decimalpoint","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"527","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"fn","name":"reverse","C":[{"N":"axis","name":"ancestor-or-self","nodeTest":"*NE"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}decimalpoint"}]}]}]}]},{"N":"choose","sType":"*N ","type":"item()*","line":"528","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"529","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"left)(right"}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"530","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"531","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"532","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":")"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"533","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"533","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"534","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"("}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"535","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"535","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"538","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"left/\\right"}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"539","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"540","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"17","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"541","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"/"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"542","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"542","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"543","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"\\"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"544","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"544","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"547","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":":right=right"}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"548","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"549","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"549","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"550","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":":"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"551","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"551","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"552","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"="}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"553","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"553","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]},{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"560","C":[{"N":"or","C":[{"N":"or","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedrightright"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"mediumstackedrightright"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"shortstackedrightright"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedleftleft"}]}]},{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","sType":"1NA ","line":"561","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"top"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"562","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"562","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"564","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedleftlinetop"}]},{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"565","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"565","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"elem","name":"m:msline","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msline ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"566","C":[{"N":"att","name":"length","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1ADI","C":[{"N":"fn","name":"string-length","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"566","C":[{"N":"fn","name":"string","C":[{"N":"subscript","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"567","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"568","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"569","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom right"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"570","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"570","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"573","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"573","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"576","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"righttop"}]},{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"577","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"577","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"elem","name":"m:msline","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msline ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"578","C":[{"N":"att","name":"length","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1ADI","C":[{"N":"fn","name":"string-length","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"578","C":[{"N":"fn","name":"string","C":[{"N":"subscript","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"579","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"580","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"580","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"581","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top left bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"582","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"582","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"true"},{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"586","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"586","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"elem","name":"m:msline","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msline ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"587","C":[{"N":"att","name":"length","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"587","C":[{"N":"fn","name":"string-length","C":[{"N":"fn","name":"string","C":[{"N":"subscript","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]},{"N":"int","val":"1"}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"588","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"589","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"52","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".2em"}]}]}]}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"590","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"voffset","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".1em"}]},{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-.15em"}]},{"N":"att","name":"depth","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-.2em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-.2em"}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"591","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"minsize","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"1.2em"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":")"}]}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"593","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"593","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"597","sType":"*NE","C":[{"N":"filter","flags":"p","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"597","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"gc10","op":">","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"int","val":"3"}]}]}]}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"600","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"601","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedrightright"}]},{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"602","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"right"}]},{"N":"applyT","sType":"* ","line":"603","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"603"}]}]}]},{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"605","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"606","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"607","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"608","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"608","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"611","C":[{"N":"elem","name":"mtd","sType":"1NE nQ{}mtd ","nsuri":"","namespaces":"","line":"612","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"68","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"616","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"mediumstackedrightright"}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"617","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"617"}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"618","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"left"}]},{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"619","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"620","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"621","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"622","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"622","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"625","C":[{"N":"elem","name":"mtd","sType":"1NE nQ{}mtd ","nsuri":"","namespaces":"","line":"626","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"78","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"631","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"shortstackedrightright"}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"632","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"632"}]},{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"633","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"634","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"635","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"left bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"636","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"636","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"639","C":[{"N":"elem","name":"mtd","sType":"1NE nQ{}mtd ","nsuri":"","namespaces":"","line":"640","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"87","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"644","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedleftleft"}]},{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"645","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"646","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"647","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"648","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"648","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"651","C":[{"N":"elem","name":"mtd","sType":"1NE nQ{}mtd ","nsuri":"","namespaces":"","line":"652","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"95","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"655","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"left"}]},{"N":"applyT","sType":"* ","line":"656","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"656"}]}]}]}]},{"N":"true"},{"N":"applyT","sType":"* ","line":"660","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"660"}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"38","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"171","module":"mml3.xsl","expand-text":"false","match":"m:mstack","prio":"11","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mstack","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mstack","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstack","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"let","var":"Q{}m","slot":"0","sType":"* ","line":"172","role":"action","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"173","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"columnspacing","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"rowspacing","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"174","sType":"*NA nQ{}align","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}align","sType":"*NA nQ{}align","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"174"}]},{"N":"let","var":"Q{}t","slot":"0","sType":"*N ","line":"175","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"applyT","sType":"* ","line":"176","mode":"Q{}mstack1","bSlot":"1","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"176"},{"N":"withParam","name":"Q{}p","slot":"0","sType":"1ADI","C":[{"N":"int","val":"0","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"177"}]}]}]},{"N":"let","var":"Q{}maxl","slot":"1","sType":"*N ","line":"180","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"forEach","sType":"* ","line":"181","C":[{"N":"sort","sType":"*NA nQ{}l","C":[{"N":"docOrder","sType":"*NA nQ{}l","role":"select","line":"181","C":[{"N":"docOrder","sType":"*NA nQ{}l","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}t","slot":"0"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]},{"N":"sortKey","sType":"*A ","C":[{"N":"data","sType":"*A ","role":"select","C":[{"N":"dot","sType":"1NA nQ{}l ","role":"select"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"choose","sType":"? ","line":"183","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"183","C":[{"N":"fn","name":"position"},{"N":"int","val":"1"}]},{"N":"valueOf","flags":"l","sType":"1NT ","line":"184","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"dot","sType":"1NA nQ{}l","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"184"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]}]}]},{"N":"forEach","sType":"*N ","line":"188","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"188","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}t","slot":"0"}]},{"N":"filter","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"or","C":[{"N":"fn","name":"not","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"},{"N":"str","val":"mscarries"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"slash","op":"/","C":[{"N":"first","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"}]},{"N":"str","val":"mscarries"}]}]}]}]}]}]},{"N":"let","var":"Q{}c","slot":"2","sType":"*N ","line":"189","C":[{"N":"fn","name":"reverse","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"189","C":[{"N":"filter","C":[{"N":"first","C":[{"N":"axis","name":"preceding-sibling","nodeTest":"*NE"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"},{"N":"str","val":"mscarries"}]}]}]},{"N":"sequence","sType":"?N ","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"\n"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"191","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"192","sType":"*NA nQ{}class","C":[{"N":"filter","sType":"*NA nQ{}class","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"192","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"dot"},{"N":"str","val":"msline"}]}]}]},{"N":"let","var":"Q{}offset","slot":"3","sType":"* ","line":"193","C":[{"N":"arith10","op":"-","calc":"d-d","sType":"?AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"193","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}maxl","slot":"1"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"194","C":[{"N":"and","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"195","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"},{"N":"str","val":"msline"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"},{"N":"str","val":"*"}]}]},{"N":"let","var":"Q{}msl","slot":"4","sType":"* ","line":"196","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"196","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]},{"N":"forEach","sType":"*","line":"197","C":[{"N":"filter","flags":"p","sType":"*N","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"197","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*N u[NT,NP,NC,NE]"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}maxl","slot":"1"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"198","sType":"*","C":[{"N":"varRef","name":"Q{}msl","slot":"4","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"198"}]}]}]},{"N":"varRef","name":"Q{}c","slot":"2","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"201"},{"N":"let","var":"Q{}ldiff","slot":"4","sType":"*NE ","line":"202","C":[{"N":"arith10","op":"-","calc":"d-d","sType":"?AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"202","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}c","slot":"2"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]},{"N":"let","var":"Q{}loffset","slot":"5","sType":"*NE ","line":"203","C":[{"N":"arith10","op":"-","calc":"d-d","sType":"?AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"203","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}maxl","slot":"1"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}c","slot":"2"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]}]}]},{"N":"sequence","sType":"*NE ","C":[{"N":"forEach","sType":"*NE ","line":"204","C":[{"N":"filter","flags":"p","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"204","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*NE"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}offset","slot":"3"}]}]},{"N":"let","var":"Q{}pn","slot":"6","sType":"*NE ","line":"205","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"205"},{"N":"let","var":"Q{}cy","slot":"7","sType":"*NE ","line":"206","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"206","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}c","slot":"2"}]},{"N":"filter","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"arith10","op":"-","calc":"d-d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}pn","slot":"6"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}loffset","slot":"5"}]}]}]}]}]}]}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"207","C":[{"N":"choose","sType":"? ","line":"208","C":[{"N":"docOrder","sType":"*NE","line":"208","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]},{"N":"elem","name":"m:mover","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mover ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"209","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mphantom","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mphantom ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"elem","name":"m:mn","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mn ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0"}]}]}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.5width"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"210","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"210","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]}]}]}]}]},{"N":"forEach","sType":"*NE ","line":"214","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"214"},{"N":"let","var":"Q{}pn","slot":"6","sType":"*NE ","line":"215","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"215"},{"N":"let","var":"Q{}cy","slot":"7","sType":"*NE ","line":"216","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"216","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}c","slot":"2"}]},{"N":"filter","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}pn","slot":"6"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}ldiff","slot":"4"}]}]}]}]}]}]}]}]},{"N":"copy","sType":"1NE ","flags":"cin","line":"217","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"218","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"218"}]},{"N":"let","var":"Q{}b","slot":"8","sType":"* ","line":"219","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"choose","sType":"*NE ","type":"item()*","line":"220","C":[{"N":"fn","name":"not","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"221","C":[{"N":"or","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]},{"N":"str","val":"none"}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"45"}]},{"N":"true"},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"223","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"*NA nQ{}crossout","C":[{"N":"docOrder","sType":"*NA nQ{}crossout","line":"223","C":[{"N":"docOrder","sType":"*NA nQ{}crossout","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"48"}]}]}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"227","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"228","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}none"}]}]},{"N":"fn","name":"not","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"51"}]},{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"229","C":[{"N":"fn","name":"not","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"n"}]}]},{"N":"elem","name":"m:mover","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mover ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"230","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"231","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"231"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"231","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.5width"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"232","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"232","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"236","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"nw"}]},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"237","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"59"}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-1width"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"63","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"239","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"s"}]},{"N":"elem","name":"m:munder","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}munder ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"240","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"66"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.5width"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"68","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"242","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"sw"}]},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"243","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"71"}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-1width"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"74","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]},{"N":"elem","name":"m:none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"245","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"ne"}]},{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"246","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"78"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"80","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"248","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"se"}]},{"N":"elem","name":"m:msub","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msub ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"249","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"83"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"85","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"251","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"w"}]},{"N":"sequence","sType":"* ","C":[{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"252","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-1width"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"90","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"253","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"253"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"255","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"e"}]},{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"256","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"256"}]},{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"257","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"97","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]}]},{"N":"true"},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"260","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"260"}]}]}]}]}]}]}]}]}]}]}]},{"N":"true"},{"N":"sequence","sType":"*NE ","C":[{"N":"forEach","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","line":"267","C":[{"N":"filter","flags":"p","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"267","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*NE"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}offset","slot":"3"}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"268","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"268"}]}]}]}]}]}]}]}]}]}]}]}]}]}]},{"N":"applyT","sType":"* ","line":"275","mode":"Q{}ml","bSlot":"2","C":[{"N":"varRef","name":"Q{}m","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"275"}]}]}]},{"N":"templateRule","rank":"2","prec":"0","seq":"1","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"13","module":"mml3.xsl","expand-text":"false","match":"m:*[@dir='rtl']","prio":"10","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}*","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}*"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}dir"},{"N":"str","val":"rtl"}]}]},{"N":"applyT","sType":"* ","line":"14","mode":"Q{}rtl","role":"action","bSlot":"3","C":[{"N":"dot","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"14"}]}]},{"N":"templateRule","rank":"3","prec":"0","seq":"0","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"7","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"copy","sType":"1NE ","flags":"cin","role":"action","line":"8","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"9","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9"}]},{"N":"applyT","sType":"* ","line":"10","mode":"#unnamed","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"10"}]}]}]}]}]}]},{"N":"co","id":"1","binds":"1 0","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","name":"Q{}rtl","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"27","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"144","module":"mml3.xsl","expand-text":"false","match":"m:mmultiscripts[not(m:mprescripts)]","prio":"3","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts"},{"N":"fn","name":"not","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts"}]}]},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"145","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"146","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"146","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"147","C":[{"N":"empty","sType":"0 "}]},{"N":"forEach","sType":"* ","line":"148","C":[{"N":"sort","sType":"*NE","C":[{"N":"filter","flags":"p","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"148","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"arith10","op":"mod","calc":"d%d","C":[{"N":"fn","name":"position"},{"N":"int","val":"2"}]},{"N":"int","val":"0"}]}]},{"N":"sortKey","sType":"?ADI ","C":[{"N":"first","role":"select","sType":"?ADI ","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"149"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"150","mode":"Q{}rtl","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"150"}]},{"N":"applyT","sType":"* ","line":"151","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"151","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"26","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"128","module":"mml3.xsl","expand-text":"false","match":"m:mmultiscripts","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"129","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"130","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"130","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"forEach","sType":"* ","line":"131","C":[{"N":"sort","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"131","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts"},{"N":"filter","flags":"p","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"arith10","op":"mod","calc":"d%d","C":[{"N":"fn","name":"position"},{"N":"int","val":"2"}]},{"N":"int","val":"1"}]}]}]}]}]},{"N":"sortKey","sType":"?ADI ","C":[{"N":"first","role":"select","sType":"?ADI ","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"132"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"133","mode":"Q{}rtl","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"133"}]},{"N":"applyT","sType":"* ","line":"134","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"134","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]}]}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"136","C":[{"N":"empty","sType":"0 "}]},{"N":"forEach","sType":"* ","line":"137","C":[{"N":"sort","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"137","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts"},{"N":"fn","name":"reverse","C":[{"N":"filter","flags":"p","C":[{"N":"filter","flags":"p","C":[{"N":"axis","name":"preceding-sibling","nodeTest":"*NE"},{"N":"gc10","op":"!=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"fn","name":"last"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"arith10","op":"mod","calc":"d%d","C":[{"N":"fn","name":"position"},{"N":"int","val":"2"}]},{"N":"int","val":"0"}]}]}]}]}]}]},{"N":"sortKey","sType":"?ADI ","C":[{"N":"first","role":"select","sType":"?ADI ","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"138"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"139","mode":"Q{}rtl","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"139"}]},{"N":"applyT","sType":"* ","line":"140","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"140","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"2","prec":"0","seq":"25","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"120","module":"mml3.xsl","expand-text":"false","match":"m:msubsup","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msubsup","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msubsup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msubsup","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"121","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"122","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"122","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"123","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","line":"124","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"124","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"applyT","sType":"* ","line":"125","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"125","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]},{"N":"templateRule","rank":"3","prec":"0","seq":"24","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"112","module":"mml3.xsl","expand-text":"false","match":"m:msub","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msub","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msub","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msub","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"113","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"114","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"114","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"115","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","line":"116","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"116","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"elem","name":"m:none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"117","C":[{"N":"empty","sType":"0 "}]}]}]}]},{"N":"templateRule","rank":"4","prec":"0","seq":"23","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"104","module":"mml3.xsl","expand-text":"false","match":"m:msup","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msup","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"105","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"106","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"106","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"107","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"108","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","line":"109","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"109","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]},{"N":"templateRule","rank":"5","prec":"0","seq":"22","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"97","module":"mml3.xsl","expand-text":"false","match":"m:mtable|m:munder|m:mover|m:munderover","prio":"2","matches":"NE u[NE u[NE u[NE nQ{http://www.w3.org/1998/Math/MathML}mtable,NE nQ{http://www.w3.org/1998/Math/MathML}munder],NE nQ{http://www.w3.org/1998/Math/MathML}mover],NE nQ{http://www.w3.org/1998/Math/MathML}munderover]","C":[{"N":"p.venn","role":"match","op":"union","sType":"1NE u[NE u[NE u[NE nQ{http://www.w3.org/1998/Math/MathML}mtable,NE nQ{http://www.w3.org/1998/Math/MathML}munder],NE nQ{http://www.w3.org/1998/Math/MathML}mover],NE nQ{http://www.w3.org/1998/Math/MathML}munderover]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.venn","op":"union","C":[{"N":"p.venn","op":"union","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mtable"},{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}munder"}]},{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mover"}]},{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}munderover"}]},{"N":"copy","sType":"1NE u[1NE u[1NE u[1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ,1NE nQ{http://www.w3.org/1998/Math/MathML}munder ] ,1NE nQ{http://www.w3.org/1998/Math/MathML}mover ] ,1NE nQ{http://www.w3.org/1998/Math/MathML}munderover ] ","flags":"cin","role":"action","line":"98","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"99","mode":"Q{}rtl","bSlot":"0","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"99"}]},{"N":"applyT","sType":"* ","line":"100","mode":"Q{}rtl","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"100"}]}]}]}]},{"N":"templateRule","rank":"6","prec":"0","seq":"53","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"664","module":"mml3.xsl","expand-text":"false","match":"m:menclose[@notation='madruwb']","prio":"0.5","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}menclose","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}menclose"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}notation"},{"N":"str","val":"madruwb"}]}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"665","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom right"}]},{"N":"applyT","sType":"* ","line":"666","mode":"Q{}rtl","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"666"}]}]}]}]},{"N":"templateRule","rank":"7","prec":"0","seq":"36","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"163","module":"mml3.xsl","expand-text":"false","match":"@notation[.='radical']","prio":"0.5","matches":"NA nQ{}notation","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}notation","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}notation"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"radical"}]}]},{"N":"att","name":"notation","sType":"1NA ","role":"action","line":"164","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"top right"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"8","prec":"0","seq":"35","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"162","module":"mml3.xsl","expand-text":"false","match":"text()[.='∋']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"∋"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"∈"}]}]},{"N":"templateRule","rank":"9","prec":"0","seq":"34","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"161","module":"mml3.xsl","expand-text":"false","match":"text()[.='∈']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"∈"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"∋"}]}]},{"N":"templateRule","rank":"10","prec":"0","seq":"33","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"160","module":"mml3.xsl","expand-text":"false","match":"text()[.='>']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":">"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"<"}]}]},{"N":"templateRule","rank":"11","prec":"0","seq":"32","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"159","module":"mml3.xsl","expand-text":"false","match":"text()[.='<']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"<"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":">"}]}]},{"N":"templateRule","rank":"12","prec":"0","seq":"31","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"158","module":"mml3.xsl","expand-text":"false","match":"text()[.='}']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"}"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"{"}]}]},{"N":"templateRule","rank":"13","prec":"0","seq":"30","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"157","module":"mml3.xsl","expand-text":"false","match":"text()[.='{']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"{"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"}"}]}]},{"N":"templateRule","rank":"14","prec":"0","seq":"29","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"156","module":"mml3.xsl","expand-text":"false","match":"text()[.=')']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":")"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"("}]}]},{"N":"templateRule","rank":"15","prec":"0","seq":"28","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"155","module":"mml3.xsl","expand-text":"false","match":"text()[.='(']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"("}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":")"}]}]},{"N":"templateRule","rank":"16","prec":"0","seq":"18","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"72","module":"mml3.xsl","expand-text":"false","match":"m:mfrac[@bevelled='true']","prio":"0.5","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mfrac"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}bevelled"},{"N":"str","val":"true"}]}]},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"73","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:msub","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msub ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"74","C":[{"N":"sequence","sType":"* ","C":[{"N":"elem","name":"m:mi","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mi ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"5","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"75","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"\\"}]}]},{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"76","C":[{"N":"sequence","sType":"* ","C":[{"N":"elem","name":"m:mi","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mi ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"17","prec":"0","seq":"17","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"69","module":"mml3.xsl","expand-text":"false","match":"@close[.='}']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"}"}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"70","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"{"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"18","prec":"0","seq":"16","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"66","module":"mml3.xsl","expand-text":"false","match":"@close[.='{']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"{"}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"67","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"}"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"19","prec":"0","seq":"15","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"63","module":"mml3.xsl","expand-text":"false","match":"@close[.=']']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"]"}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"64","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"["}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"20","prec":"0","seq":"14","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"60","module":"mml3.xsl","expand-text":"false","match":"@close[.='[']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"["}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"61","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"]"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"21","prec":"0","seq":"13","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"57","module":"mml3.xsl","expand-text":"false","match":"@close[.=')']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":")"}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"58","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"("}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"22","prec":"0","seq":"12","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"54","module":"mml3.xsl","expand-text":"false","match":"@close[.='(']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"("}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"55","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":")"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"23","prec":"0","seq":"10","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"48","module":"mml3.xsl","expand-text":"false","match":"@open[.='}']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"}"}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"49","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"{"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"24","prec":"0","seq":"9","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"45","module":"mml3.xsl","expand-text":"false","match":"@open[.='{']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"{"}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"46","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"}"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"25","prec":"0","seq":"8","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"42","module":"mml3.xsl","expand-text":"false","match":"@open[.=']']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"]"}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"43","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"["}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"26","prec":"0","seq":"7","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"39","module":"mml3.xsl","expand-text":"false","match":"@open[.='[']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"["}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"40","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"]"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"27","prec":"0","seq":"6","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"36","module":"mml3.xsl","expand-text":"false","match":"@open[.=')']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":")"}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"37","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"("}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"28","prec":"0","seq":"5","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"33","module":"mml3.xsl","expand-text":"false","match":"@open[.='(']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"("}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"34","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":")"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"29","prec":"0","seq":"37","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"166","module":"mml3.xsl","expand-text":"false","match":"m:mlongdiv|m:mstack","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv"},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"167","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"dir","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"ltr"}]},{"N":"applyT","sType":"* ","line":"168","mode":"#unnamed","bSlot":"1","C":[{"N":"dot","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"168"}]}]}]}]},{"N":"templateRule","rank":"30","prec":"0","seq":"37","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"166","module":"mml3.xsl","expand-text":"false","match":"m:mlongdiv|m:mstack","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mstack","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mstack","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstack"},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"167","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"dir","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"ltr"}]},{"N":"applyT","sType":"* ","line":"168","mode":"#unnamed","bSlot":"1","C":[{"N":"dot","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstack","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"168"}]}]}]}]},{"N":"templateRule","rank":"31","prec":"0","seq":"21","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"92","module":"mml3.xsl","expand-text":"false","match":"m:msqrt","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msqrt","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msqrt","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msqrt","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"93","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top right"}]},{"N":"applyT","sType":"* ","line":"94","mode":"Q{}rtl","bSlot":"0","C":[{"N":"docOrder","sType":"*N u[NA,NE]","role":"select","line":"94","C":[{"N":"union","op":"|","sType":"*N u[NA,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"attribute","nodeTest":"*NA"},{"N":"first","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"32","prec":"0","seq":"20","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"84","module":"mml3.xsl","expand-text":"false","match":"m:mroot","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mroot","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mroot","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mroot","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"85","C":[{"N":"sequence","sType":"* ","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"86","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top right"}]},{"N":"applyT","sType":"* ","line":"87","mode":"Q{}rtl","bSlot":"0","C":[{"N":"docOrder","sType":"*N u[NA,NE]","role":"select","line":"87","C":[{"N":"union","op":"|","sType":"*N u[NA,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"attribute","nodeTest":"*NA"},{"N":"first","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]},{"N":"applyT","sType":"* ","line":"89","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"89","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]},{"N":"templateRule","rank":"33","prec":"0","seq":"19","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"79","module":"mml3.xsl","expand-text":"false","match":"m:mfrac","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"copy","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac ","flags":"cin","role":"action","line":"80","C":[{"N":"applyT","sType":"* ","line":"81","mode":"Q{}rtl","bSlot":"0","C":[{"N":"docOrder","sType":"*N u[NA,NE]","role":"select","line":"81","C":[{"N":"union","op":"|","sType":"*N u[NA,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"attribute","nodeTest":"*NA"},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"templateRule","rank":"34","prec":"0","seq":"11","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"51","module":"mml3.xsl","expand-text":"false","match":"@close","prio":"0","matches":"NA nQ{}close","C":[{"N":"p.nodeTest","role":"match","test":"NA nQ{}close","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"52","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"dot","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"3"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"35","prec":"0","seq":"4","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"30","module":"mml3.xsl","expand-text":"false","match":"@open","prio":"0","matches":"NA nQ{}open","C":[{"N":"p.nodeTest","role":"match","test":"NA nQ{}open","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"31","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"dot","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"3"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"36","prec":"0","seq":"3","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"20","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"copy","sType":"1NE ","flags":"cin","role":"action","line":"21","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"22","mode":"Q{}rtl","bSlot":"0","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"22"}]},{"N":"forEach","sType":"* ","line":"23","C":[{"N":"sort","sType":"*N u[NT,NP,NC,NE]","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"23"},{"N":"sortKey","sType":"?ADI ","C":[{"N":"first","role":"select","sType":"?ADI ","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"24"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"sequence","sType":"* ","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":" "}]},{"N":"applyT","sType":"* ","line":"26","mode":"Q{}rtl","bSlot":"0","C":[{"N":"dot","sType":"1N u[N u[N u[NT,NP],NC],NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"26"}]}]}]}]}]}]},{"N":"templateRule","rank":"37","prec":"0","seq":"2","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"16","module":"mml3.xsl","expand-text":"false","match":"@*","prio":"-0.5","matches":"NA","C":[{"N":"p.nodeTest","role":"match","test":"NA","sType":"1NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"*NA ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"17","sType":"1NA","C":[{"N":"dot","sType":"1NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"17"}]},{"N":"att","name":"dir","sType":"1NA ","line":"18","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"ltr"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]}]}]}]},{"N":"co","id":"2","binds":"2","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","name":"Q{}ml","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"42","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"313","module":"mml3.xsl","expand-text":"false","match":"m:mtr[not(preceding-sibling::*)][@class='msline']","prio":"3","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.withPredicate","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr"},{"N":"fn","name":"not","C":[{"N":"fn","name":"reverse","C":[{"N":"axis","name":"preceding-sibling","nodeTest":"*NE"}]}]}]},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}class"},{"N":"str","val":"msline"}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"314","C":[{"N":"sequence","sType":"*N ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"315","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"315"}]},{"N":"forEach","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","line":"316","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"316"},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"317","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"318","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"318"}]},{"N":"choose","sType":"? ","line":"319","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"319"},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"320","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"321","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"depth","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".1em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"1em"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".5em"}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"322","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".2em"}]}]}]}]}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]}]}]}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"43","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"330","module":"mml3.xsl","expand-text":"false","match":"m:mtr[@class='msline']","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}class"},{"N":"str","val":"msline"}]}]},{"N":"empty","sType":"0 ","role":"action"}]},{"N":"templateRule","rank":"2","prec":"0","seq":"41","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"286","module":"mml3.xsl","expand-text":"false","match":"m:mtr[following-sibling::*[1][@class='msline']]","prio":"0.5","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr"},{"N":"filter","C":[{"N":"first","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}class"},{"N":"str","val":"msline"}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"287","C":[{"N":"sequence","sType":"*N ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"288","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"288"}]},{"N":"let","var":"Q{}m","slot":"0","sType":"*NE ","line":"289","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","role":"select","line":"289","C":[{"N":"slash","op":"/","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"first","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd"}]}]},{"N":"forEach","sType":"*NE ","line":"290","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"290"},{"N":"let","var":"Q{}p","slot":"1","sType":"*NE ","line":"291","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"291"},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"292","C":[{"N":"sequence","sType":"*N ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"293","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"293"}]},{"N":"choose","sType":"*NE ","type":"item()*","line":"294","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded","line":"295","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"filter","flags":"i","C":[{"N":"varRef","name":"Q{}m","slot":"0"},{"N":"varRef","name":"Q{}p","slot":"1"}]}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded"}]}]}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"296","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"depth","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"+.2em"}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"297","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"298","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"depth","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".1em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".8em"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".8em"}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"299","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".15em"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"300","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"300"}]}]}]}]}]}]}]},{"N":"true"},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"306","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"306"}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"3","prec":"0","seq":"39","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"277","module":"mml3.xsl","expand-text":"false","match":"m:none","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}none","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"278","C":[{"N":"empty","sType":"0 "}]}]},{"N":"templateRule","rank":"4","prec":"0","seq":"40","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"280","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"copy","sType":"1NE ","flags":"cin","role":"action","line":"281","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"282","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"282"}]},{"N":"applyT","sType":"* ","line":"283","mode":"Q{}ml","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"283"}]}]}]}]}]}]},{"N":"co","id":"3","binds":"4 3 0","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","name":"Q{}mstack1","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"49","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"481","module":"mml3.xsl","expand-text":"false","match":"m:mscarries","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mscarries","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mscarries","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mscarries","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"482","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"let","var":"Q{}align1","slot":"1","sType":"*NE ","line":"483","C":[{"N":"docOrder","sType":"*NA nQ{}stackalign","role":"select","line":"483","C":[{"N":"slash","op":"/","sType":"*NA nQ{}stackalign","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]}]},{"N":"let","var":"Q{}l1","slot":"2","sType":"*NE ","line":"484","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"485","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"486","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align1","slot":"1"}]}]},{"N":"str","val":"left"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0"}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"fn","sType":"1ADI","name":"count","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"8","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"490","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"mscarries"}]},{"N":"att","name":"l","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"?AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"?AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"490","C":[{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}l1","slot":"2"}]}]}]},{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}position"}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"applyT","sType":"* ","line":"491","mode":"Q{}msc","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"491"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"48","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"428","module":"mml3.xsl","expand-text":"false","match":"m:msline","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msline","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msline","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msline","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"429","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"let","var":"Q{}align1","slot":"1","sType":"*NE ","line":"430","C":[{"N":"docOrder","sType":"*NA nQ{}stackalign","role":"select","line":"430","C":[{"N":"slash","op":"/","sType":"*NA nQ{}stackalign","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]}]},{"N":"let","var":"Q{}align","slot":"2","sType":"*NE ","line":"431","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"432","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"433","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align1","slot":"1"}]}]},{"N":"str","val":""}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"decimalpoint"}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}align1","slot":"1","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"8"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"437","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"msline"}]},{"N":"att","name":"l","sType":"1NA ","line":"438","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"439","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"440","C":[{"N":"fn","name":"not","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"},{"N":"int","val":"0"}]}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"*"}]},{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"441","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align","slot":"2"}]}]},{"N":"str","val":"right"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align","slot":"2"}]}]},{"N":"str","val":"decimalpoint"}]}]},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"arith10","sType":"?AO","op":"+","calc":"d+d","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"14","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}p","slot":"0","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"16"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"let","var":"Q{}w","slot":"3","sType":"*NE ","line":"445","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"446","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"447","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}mslinethickness"},{"N":"str","val":"thin"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0.1em"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"448","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}mslinethickness"},{"N":"str","val":"medium"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0.15em"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"449","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}mslinethickness"},{"N":"str","val":"thick"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0.2em"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}mslinethickness","sType":"*NA nQ{}mslinethickness","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"450"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"axis","sType":"*NA nQ{}mslinethickness","name":"attribute","nodeTest":"*NA nQ{}mslinethickness","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"23"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"true"},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0.15em"}]}]}]},{"N":"choose","sType":"*NE ","type":"item()*","line":"454","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"455","C":[{"N":"fn","name":"not","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"},{"N":"int","val":"0"}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"456","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"mslinemax"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"457","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.2em"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"elem","name":"m:mfrac","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"458","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"linethickness","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"*","C":[{"N":"varRef","name":"Q{}w","slot":"3","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"458"}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"459","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".5em"}]}]},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"460","C":[{"N":"empty","sType":"0 "}]}]}]}]}]}]}]},{"N":"true"},{"N":"let","var":"Q{}l","slot":"4","sType":"*NE ","line":"466","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length","sType":"*NA nQ{}length","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"466"},{"N":"forEach","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","line":"467","C":[{"N":"filter","flags":"p","sType":"*N","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"467","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*N u[NT,NP,NC,NE]"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}l","slot":"4"}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"468","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"msline"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"469","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.2em"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"elem","name":"m:mfrac","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"470","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"linethickness","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"*","C":[{"N":"varRef","name":"Q{}w","slot":"3","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"470"}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"471","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".5em"}]}]},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"472","C":[{"N":"empty","sType":"0 "}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"2","prec":"0","seq":"47","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"418","module":"mml3.xsl","expand-text":"false","match":"m:msgroup","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msgroup","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msgroup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msgroup","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"419","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"let","var":"Q{}s","slot":"1","sType":"* ","line":"420","C":[{"N":"fn","name":"number","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"420","C":[{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}shift"}]}]},{"N":"let","var":"Q{}thisp","slot":"2","sType":"* ","line":"421","C":[{"N":"fn","name":"number","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"421","C":[{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}position"}]}]},{"N":"forEach","sType":"* ","line":"422","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"422"},{"N":"applyT","sType":"* ","line":"423","mode":"Q{}mstack1","bSlot":"1","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"423"},{"N":"withParam","name":"Q{}p","slot":"0","sType":"1AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"424","C":[{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"fn","name":"number","C":[{"N":"atomSing","diag":"0|0||number","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}thisp","slot":"2"}]}]}]},{"N":"arith10","op":"*","calc":"d*d","C":[{"N":"arith10","op":"-","calc":"d-d","C":[{"N":"fn","name":"position"},{"N":"int","val":"1"}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}s","slot":"1"}]}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"3","prec":"0","seq":"46","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"376","module":"mml3.xsl","expand-text":"false","match":"m:mn","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mn","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mn","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mn","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"377","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"let","var":"Q{}align1","slot":"1","sType":"*NE ","line":"378","C":[{"N":"docOrder","sType":"*NA nQ{}stackalign","role":"select","line":"378","C":[{"N":"slash","op":"/","sType":"*NA nQ{}stackalign","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]}]},{"N":"let","var":"Q{}dp1","slot":"2","sType":"*NE ","line":"379","C":[{"N":"docOrder","sType":"*NA nQ{}decimalpoint","role":"select","line":"379","C":[{"N":"slash","op":"/","sType":"*NA nQ{}decimalpoint","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"filter","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}decimalpoint"}]}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}decimalpoint"}]}]},{"N":"let","var":"Q{}align","slot":"3","sType":"*NE ","line":"380","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"381","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"382","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align1","slot":"1"}]}]},{"N":"str","val":""}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"decimalpoint"}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}align1","slot":"1","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"let","var":"Q{}dp","slot":"4","sType":"*NE ","line":"386","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"387","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"388","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}dp1","slot":"2"}]}]},{"N":"str","val":""}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"."}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}dp1","slot":"2","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"14"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"392","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"l","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"$p"}]},{"N":"let","var":"Q{}mn","slot":"5","sType":"* ","line":"393","C":[{"N":"fn","name":"normalize-space","sType":"1AS","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"393","C":[{"N":"fn","name":"string","C":[{"N":"dot"}]}]},{"N":"let","var":"Q{}len","slot":"6","sType":"* ","line":"394","C":[{"N":"fn","name":"string-length","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"394","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}mn","slot":"5"}]}]}]},{"N":"sequence","sType":"* ","C":[{"N":"choose","sType":"? ","type":"item()*","line":"395","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"396","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"right"}]},{"N":"and","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"decimalpoint"}]},{"N":"fn","name":"not","C":[{"N":"fn","name":"contains","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}mn","slot":"5"}]}]},{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}dp","slot":"4"}]}]},{"N":"str","val":"http://www.w3.org/2005/xpath-functions/collation/codepoint"}]}]}]}]},{"N":"att","name":"l","sType":"1NA ","line":"397","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"arith10","sType":"?AO","op":"+","calc":"d+d","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"21","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}len","slot":"6"}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"399","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"center"}]},{"N":"att","name":"l","sType":"1NA ","line":"400","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"fn","sType":"?A m[AO,AD,AF]","name":"round","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"24","C":[{"N":"arith10","op":"div","calc":"d/d","C":[{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}len","slot":"6"}]}]}]},{"N":"int","val":"2"}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"402","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"decimalpoint"}]},{"N":"att","name":"l","sType":"1NA ","line":"403","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"arith10","sType":"?AO","op":"+","calc":"d+d","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"27","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"fn","name":"string-length","C":[{"N":"fn","name":"substring-before","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}mn","slot":"5"}]}]},{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}dp","slot":"4"}]}]},{"N":"str","val":"http://www.w3.org/2005/xpath-functions/collation/codepoint"}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]},{"N":"forEach","sType":"*NE ","line":"406","C":[{"N":"filter","flags":"p","sType":"*N","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"406","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*N u[NT,NP,NC,NE]"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}len","slot":"6"}]}]},{"N":"let","var":"Q{}pos","slot":"7","sType":"*NE ","line":"407","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"407"},{"N":"let","var":"Q{}digit","slot":"8","sType":"*NE ","line":"408","C":[{"N":"fn","name":"substring","sType":"1AS","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"408","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}mn","slot":"5"}]}]},{"N":"fn","name":"number","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}pos","slot":"7"}]}]},{"N":"fn","name":"number","C":[{"N":"int","val":"1"}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"409","C":[{"N":"sequence","sType":"* ","C":[{"N":"choose","sType":"? ","line":"410","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"410","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}digit","slot":"8"},{"N":"str","val":"."}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}digit","slot":"8"},{"N":"str","val":","}]}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"411","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".15em"}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mn","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mn ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"413","C":[{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}digit","slot":"8","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"35"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"4","prec":"0","seq":"45","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"341","module":"mml3.xsl","expand-text":"false","match":"m:msrow","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msrow","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"342","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"param","name":"Q{}maxl","slot":"1","sType":"* ","as":"* ","flags":"","line":"343","C":[{"N":"int","val":"0","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"343"},{"N":"supplied","role":"conversion","slot":"1","sType":"* "}]},{"N":"let","var":"Q{}align1","slot":"2","sType":"*N ","line":"344","C":[{"N":"docOrder","sType":"*NA nQ{}stackalign","role":"select","line":"344","C":[{"N":"slash","op":"/","sType":"*NA nQ{}stackalign","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]}]},{"N":"let","var":"Q{}align","slot":"3","sType":"*N ","line":"345","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"346","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"347","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align1","slot":"2"}]}]},{"N":"str","val":""}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"decimalpoint"}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}align1","slot":"2","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"let","var":"Q{}row","slot":"4","sType":"*N ","line":"351","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"applyT","sType":"* ","line":"352","mode":"Q{}mstack1","bSlot":"1","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"352"},{"N":"withParam","name":"Q{}p","slot":"0","sType":"1ADI","C":[{"N":"int","val":"0","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"353"}]}]}]},{"N":"sequence","sType":"*N ","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"\n"}]},{"N":"let","var":"Q{}l1","slot":"5","sType":"*NE ","line":"357","C":[{"N":"doc","sType":"1ND ","base":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","role":"select","C":[{"N":"choose","sType":"*NT ","type":"item()*","line":"358","C":[{"N":"and","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"359","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"decimalpoint"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mn"}]},{"N":"forEach","sType":"*NT ","line":"360","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr","role":"select","line":"360","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}row","slot":"4"}]},{"N":"first","C":[{"N":"filter","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr"},{"N":"slash","op":"/","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd"},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mn"}]}]}]}]}]}]},{"N":"valueOf","flags":"l","sType":"1NT ","line":"361","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"arith10","sType":"1AO","op":"+","calc":"d+d","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"361","C":[{"N":"fn","name":"number","C":[{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}l"}]}]},{"N":"fn","name":"count","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"fn","name":"reverse","C":[{"N":"axis","name":"preceding-sibling","nodeTest":"*NE"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]},{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"364","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"right"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"decimalpoint"}]}]},{"N":"valueOf","flags":"l","sType":"1NT ","line":"365","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"fn","sType":"1ADI","name":"count","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"365","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}row","slot":"4"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd"}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","line":"368","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"int","sType":"1ADI","val":"0","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"368"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"372","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"msrow"}]},{"N":"att","name":"l","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"372","C":[{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"fn","name":"number","C":[{"N":"atomSing","diag":"0|0||number","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}l1","slot":"5"}]}]}]},{"N":"fn","name":"number","C":[{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}position"}]}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"373","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"373","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}row","slot":"4"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"5","prec":"0","seq":"44","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"331","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"332","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"param","name":"Q{}maxl","slot":"1","sType":"* ","as":"* ","flags":"","line":"333","C":[{"N":"int","val":"0","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"333"},{"N":"supplied","role":"conversion","slot":"1","sType":"* "}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"334","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"l","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"334","C":[{"N":"int","val":"1"},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"choose","sType":"? ","line":"335","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"335","C":[{"N":"slash","op":"/","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]},{"N":"str","val":"left"}]},{"N":"att","name":"l","sType":"1NA ","line":"336","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}p","slot":"0","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"7"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"338","C":[{"N":"applyT","sType":"* ","mode":"#unnamed","bSlot":"2","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9"}]}]}]}]}]}]}]}]},{"N":"co","id":"4","binds":"0","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","name":"Q{}msc","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"51","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"509","module":"mml3.xsl","expand-text":"false","match":"m:mscarry","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mscarry","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mscarry","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mscarry","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"510","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"511","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","C":[{"N":"docOrder","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","role":"select","line":"511","C":[{"N":"union","op":"|","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"512","C":[{"N":"docOrder","sType":"*NA nQ{}scriptsizemultiplier","line":"513","C":[{"N":"slash","op":"/","sType":"*NA nQ{}scriptsizemultiplier","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}scriptsizemultiplier"}]}]},{"N":"elem","name":"m:mstyle","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstyle ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"514","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"mathsize","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"concat","sType":"1AS ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"?A m[AO,AD,AF]","C":[{"N":"fn","name":"round","sType":"?A m[AO,AD,AF]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"514","C":[{"N":"arith10","op":"div","calc":"d/d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}scriptsizemultiplier"}]}]}]},{"N":"dec","val":"0.007"}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]},{"N":"str","sType":"1AS ","val":"%"},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"applyT","sType":"* ","line":"515","mode":"#unnamed","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"515"}]}]}]},{"N":"true"},{"N":"applyT","sType":"* ","line":"519","mode":"#unnamed","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"519"}]}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"50","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","baseUri":"file:///Users/dpvc/Desktop/Folders/Tumlook/Data/Code/JavaScript/MathJax/Code/Git/mathjax/MathJax-src/ts/input/mathml/mml3/mml3.xsl","slots":"200","line":"494","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"495","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"496","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","C":[{"N":"docOrder","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","role":"select","line":"496","C":[{"N":"union","op":"|","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]},{"N":"slash","op":"/","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"497","C":[{"N":"docOrder","sType":"*NA nQ{}scriptsizemultiplier","line":"498","C":[{"N":"slash","op":"/","sType":"*NA nQ{}scriptsizemultiplier","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}scriptsizemultiplier"}]}]},{"N":"elem","name":"m:mstyle","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstyle ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"499","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"mathsize","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"concat","sType":"1AS ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"?A m[AO,AD,AF]","C":[{"N":"fn","name":"round","sType":"?A m[AO,AD,AF]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"499","C":[{"N":"arith10","op":"div","calc":"d/d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}scriptsizemultiplier"}]}]}]},{"N":"dec","val":"0.007"}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]},{"N":"str","sType":"1AS ","val":"%"},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"applyT","sType":"* ","line":"500","mode":"#unnamed","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"500"}]}]}]},{"N":"true"},{"N":"applyT","sType":"* ","line":"504","mode":"#unnamed","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"504"}]}]}]}]}]}]}]},{"N":"overridden"},{"N":"output","C":[{"N":"property","name":"Q{http://saxon.sf.net/}stylesheet-version","value":"10"},{"N":"property","name":"indent","value":"yes"},{"N":"property","name":"omit-xml-declaration","value":"yes"}]},{"N":"decimalFormat"}],"Σ":"9a493c8"} \ No newline at end of file +{"N":"package","version":"10","packageVersion":"1","saxonVersion":"SaxonJS 2.5","target":"JS","targetVersion":"2","name":"TOP-LEVEL","relocatable":"false","buildDateTime":"2023-08-22T12:09:25.408-04:00","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","C":[{"N":"co","id":"0","binds":"0 3 2 1","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"52","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"524","module":"mml3.xsl","expand-text":"false","match":"m:mlongdiv","prio":"11","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"let","var":"Q{}ms","slot":"0","sType":"* ","line":"525","role":"action","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"elem","name":"m:mstack","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstack ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"526","C":[{"N":"sequence","sType":"*N ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"527","sType":"?NA nQ{}decimalpoint","C":[{"N":"lastOf","sType":"?NA nQ{}decimalpoint","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"527","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"fn","name":"reverse","C":[{"N":"axis","name":"ancestor-or-self","nodeTest":"*NE"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}decimalpoint"}]}]}]}]},{"N":"choose","sType":"*N ","type":"item()*","line":"528","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"529","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"left)(right"}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"530","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"531","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"532","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":")"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"533","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"533","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"534","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"("}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"535","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"535","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"538","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"left/\\right"}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"539","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"540","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"17","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"541","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"/"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"542","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"542","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"543","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"\\"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"544","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"544","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"547","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":":right=right"}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"548","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"549","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"549","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"550","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":":"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"551","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"551","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"552","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"="}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"553","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"553","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]},{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"560","C":[{"N":"or","C":[{"N":"or","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedrightright"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"mediumstackedrightright"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"shortstackedrightright"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedleftleft"}]}]},{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","sType":"1NA ","line":"561","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"top"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"562","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"562","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"564","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedleftlinetop"}]},{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"565","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"565","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"elem","name":"m:msline","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msline ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"566","C":[{"N":"att","name":"length","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1ADI","C":[{"N":"fn","name":"string-length","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"566","C":[{"N":"fn","name":"string","C":[{"N":"subscript","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"567","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"568","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"569","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom right"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"570","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"570","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"573","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"573","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"576","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"righttop"}]},{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"577","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"577","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"elem","name":"m:msline","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msline ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"578","C":[{"N":"att","name":"length","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1ADI","C":[{"N":"fn","name":"string-length","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"578","C":[{"N":"fn","name":"string","C":[{"N":"subscript","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"579","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"580","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"580","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"581","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top left bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"582","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"582","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"true"},{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"586","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"586","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"elem","name":"m:msline","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msline ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"587","C":[{"N":"att","name":"length","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"587","C":[{"N":"fn","name":"string-length","C":[{"N":"fn","name":"string","C":[{"N":"subscript","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]},{"N":"int","val":"1"}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]},{"N":"elem","name":"m:msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"588","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"589","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"52","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".2em"}]}]}]}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"590","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"voffset","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".1em"}]},{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-.15em"}]},{"N":"att","name":"depth","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-.2em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-.2em"}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"591","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"minsize","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"1.2em"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":")"}]}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"593","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"593","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"597","sType":"*NE","C":[{"N":"filter","flags":"p","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"597","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"gc10","op":">","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"int","val":"3"}]}]}]}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"600","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"601","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedrightright"}]},{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"602","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"right"}]},{"N":"applyT","sType":"* ","line":"603","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"603"}]}]}]},{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"605","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"606","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"607","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"608","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"608","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"611","C":[{"N":"elem","name":"mtd","sType":"1NE nQ{}mtd ","nsuri":"","namespaces":"","line":"612","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"68","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"616","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"mediumstackedrightright"}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"617","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"617"}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"618","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"left"}]},{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"619","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"620","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"621","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"622","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"622","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"625","C":[{"N":"elem","name":"mtd","sType":"1NE nQ{}mtd ","nsuri":"","namespaces":"","line":"626","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"78","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"631","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"shortstackedrightright"}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"632","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"632"}]},{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"633","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"634","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"635","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"left bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"636","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"636","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"639","C":[{"N":"elem","name":"mtd","sType":"1NE nQ{}mtd ","nsuri":"","namespaces":"","line":"640","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"87","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"644","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}longdivstyle"},{"N":"str","val":"stackedleftleft"}]},{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"645","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"align","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"646","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"647","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"648","sType":"?NE","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"648","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"651","C":[{"N":"elem","name":"mtd","sType":"1NE nQ{}mtd ","nsuri":"","namespaces":"","line":"652","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"?NE","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"95","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"655","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"left"}]},{"N":"applyT","sType":"* ","line":"656","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"656"}]}]}]}]},{"N":"true"},{"N":"applyT","sType":"* ","line":"660","mode":"#unnamed","bSlot":"0","C":[{"N":"varRef","name":"Q{}ms","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"660"}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"38","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"171","module":"mml3.xsl","expand-text":"false","match":"m:mstack","prio":"11","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mstack","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mstack","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstack","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"let","var":"Q{}m","slot":"0","sType":"* ","line":"172","role":"action","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"elem","name":"m:mtable","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"173","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"columnspacing","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"rowspacing","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"174","sType":"*NA nQ{}align","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}align","sType":"*NA nQ{}align","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"174"}]},{"N":"let","var":"Q{}t","slot":"0","sType":"*N ","line":"175","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"applyT","sType":"* ","line":"176","mode":"Q{}mstack1","bSlot":"1","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"176"},{"N":"withParam","name":"Q{}p","slot":"0","sType":"1ADI","C":[{"N":"int","val":"0","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"177"}]}]}]},{"N":"let","var":"Q{}maxl","slot":"1","sType":"*N ","line":"180","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"forEach","sType":"* ","line":"181","C":[{"N":"sort","sType":"*NA nQ{}l","C":[{"N":"docOrder","sType":"*NA nQ{}l","role":"select","line":"181","C":[{"N":"docOrder","sType":"*NA nQ{}l","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}t","slot":"0"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]},{"N":"sortKey","sType":"*A ","C":[{"N":"data","sType":"*A ","role":"select","C":[{"N":"dot","sType":"1NA nQ{}l ","role":"select"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"choose","sType":"? ","line":"183","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"183","C":[{"N":"fn","name":"position"},{"N":"int","val":"1"}]},{"N":"valueOf","flags":"l","sType":"1NT ","line":"184","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"dot","sType":"1NA nQ{}l","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"184"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]}]}]},{"N":"forEach","sType":"*N ","line":"188","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"188","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}t","slot":"0"}]},{"N":"filter","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"or","C":[{"N":"fn","name":"not","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"},{"N":"str","val":"mscarries"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"slash","op":"/","C":[{"N":"first","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"}]},{"N":"str","val":"mscarries"}]}]}]}]}]}]},{"N":"let","var":"Q{}c","slot":"2","sType":"*N ","line":"189","C":[{"N":"fn","name":"reverse","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"189","C":[{"N":"filter","C":[{"N":"first","C":[{"N":"axis","name":"preceding-sibling","nodeTest":"*NE"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"},{"N":"str","val":"mscarries"}]}]}]},{"N":"sequence","sType":"?N ","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"\n"}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"191","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"192","sType":"*NA nQ{}class","C":[{"N":"filter","sType":"*NA nQ{}class","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"192","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"dot"},{"N":"str","val":"msline"}]}]}]},{"N":"let","var":"Q{}offset","slot":"3","sType":"* ","line":"193","C":[{"N":"arith10","op":"-","calc":"d-d","sType":"?AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"193","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}maxl","slot":"1"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"194","C":[{"N":"and","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"195","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}class"},{"N":"str","val":"msline"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"},{"N":"str","val":"*"}]}]},{"N":"let","var":"Q{}msl","slot":"4","sType":"* ","line":"196","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"196","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]},{"N":"forEach","sType":"*","line":"197","C":[{"N":"filter","flags":"p","sType":"*N","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"197","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*N u[NT,NP,NC,NE]"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}maxl","slot":"1"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"198","sType":"*","C":[{"N":"varRef","name":"Q{}msl","slot":"4","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"198"}]}]}]},{"N":"varRef","name":"Q{}c","slot":"2","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"201"},{"N":"let","var":"Q{}ldiff","slot":"4","sType":"*NE ","line":"202","C":[{"N":"arith10","op":"-","calc":"d-d","sType":"?AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"202","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}c","slot":"2"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]},{"N":"let","var":"Q{}loffset","slot":"5","sType":"*NE ","line":"203","C":[{"N":"arith10","op":"-","calc":"d-d","sType":"?AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"203","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}maxl","slot":"1"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}c","slot":"2"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]}]}]},{"N":"sequence","sType":"*NE ","C":[{"N":"forEach","sType":"*NE ","line":"204","C":[{"N":"filter","flags":"p","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"204","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*NE"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}offset","slot":"3"}]}]},{"N":"let","var":"Q{}pn","slot":"6","sType":"*NE ","line":"205","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"205"},{"N":"let","var":"Q{}cy","slot":"7","sType":"*NE ","line":"206","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"206","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}c","slot":"2"}]},{"N":"filter","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"arith10","op":"-","calc":"d-d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}pn","slot":"6"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}loffset","slot":"5"}]}]}]}]}]}]}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"207","C":[{"N":"choose","sType":"? ","line":"208","C":[{"N":"docOrder","sType":"*NE","line":"208","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]},{"N":"elem","name":"m:mover","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mover ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"209","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mphantom","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mphantom ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"elem","name":"m:mn","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mn ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0"}]}]}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.5width"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"210","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"210","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]}]}]}]}]},{"N":"forEach","sType":"*NE ","line":"214","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"214"},{"N":"let","var":"Q{}pn","slot":"6","sType":"*NE ","line":"215","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"215"},{"N":"let","var":"Q{}cy","slot":"7","sType":"*NE ","line":"216","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"216","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}c","slot":"2"}]},{"N":"filter","flags":"p","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}pn","slot":"6"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}ldiff","slot":"4"}]}]}]}]}]}]}]}]},{"N":"copy","sType":"1NE ","flags":"cin","line":"217","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"218","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"218"}]},{"N":"let","var":"Q{}b","slot":"8","sType":"* ","line":"219","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"choose","sType":"*NE ","type":"item()*","line":"220","C":[{"N":"fn","name":"not","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"221","C":[{"N":"or","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]},{"N":"str","val":"none"}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"45"}]},{"N":"true"},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"223","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"*NA nQ{}crossout","C":[{"N":"docOrder","sType":"*NA nQ{}crossout","line":"223","C":[{"N":"docOrder","sType":"*NA nQ{}crossout","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"48"}]}]}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"227","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"228","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}none"}]}]},{"N":"fn","name":"not","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"51"}]},{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"229","C":[{"N":"fn","name":"not","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"n"}]}]},{"N":"elem","name":"m:mover","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mover ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"230","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"231","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"231"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"231","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.5width"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"232","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"232","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"236","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"nw"}]},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"237","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"59"}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-1width"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"63","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"239","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"s"}]},{"N":"elem","name":"m:munder","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}munder ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"240","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"66"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.5width"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"68","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"242","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"sw"}]},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"243","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"71"}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-1width"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"74","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]},{"N":"elem","name":"m:none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"245","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"ne"}]},{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"246","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"78"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"80","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"248","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"se"}]},{"N":"elem","name":"m:msub","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msub ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"249","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"83"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"85","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"251","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"w"}]},{"N":"sequence","sType":"* ","C":[{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"252","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-1width"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"90","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"253","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"253"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"255","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]}]},{"N":"str","val":"e"}]},{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"256","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"256"}]},{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"257","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"97","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}cy","slot":"7"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]}]},{"N":"true"},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"260","sType":"*","C":[{"N":"varRef","name":"Q{}b","slot":"8","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"260"}]}]}]}]}]}]}]}]}]}]}]},{"N":"true"},{"N":"sequence","sType":"*NE ","C":[{"N":"forEach","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","line":"267","C":[{"N":"filter","flags":"p","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"267","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*NE"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}offset","slot":"3"}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"268","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"268"}]}]}]}]}]}]}]}]}]}]}]}]}]}]},{"N":"applyT","sType":"* ","line":"275","mode":"Q{}ml","bSlot":"2","C":[{"N":"varRef","name":"Q{}m","slot":"0","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"275"}]}]}]},{"N":"templateRule","rank":"2","prec":"0","seq":"1","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"13","module":"mml3.xsl","expand-text":"false","match":"m:*[@dir='rtl']","prio":"10","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}*","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}*"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}dir"},{"N":"str","val":"rtl"}]}]},{"N":"applyT","sType":"* ","line":"14","mode":"Q{}rtl","role":"action","bSlot":"3","C":[{"N":"dot","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"14"}]}]},{"N":"templateRule","rank":"3","prec":"0","seq":"0","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"7","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"copy","sType":"1NE ","flags":"cin","role":"action","line":"8","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"9","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9"}]},{"N":"applyT","sType":"* ","line":"10","mode":"#unnamed","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"10"}]}]}]}]}]}]},{"N":"co","id":"1","binds":"1 0","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","name":"Q{}rtl","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"27","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"144","module":"mml3.xsl","expand-text":"false","match":"m:mmultiscripts[not(m:mprescripts)]","prio":"3","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts"},{"N":"fn","name":"not","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts"}]}]},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"145","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"146","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"146","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"147","C":[{"N":"empty","sType":"0 "}]},{"N":"forEach","sType":"* ","line":"148","C":[{"N":"sort","sType":"*NE","C":[{"N":"filter","flags":"p","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"148","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"arith10","op":"mod","calc":"d%d","C":[{"N":"fn","name":"position"},{"N":"int","val":"2"}]},{"N":"int","val":"0"}]}]},{"N":"sortKey","sType":"?ADI ","C":[{"N":"first","role":"select","sType":"?ADI ","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"149"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"150","mode":"Q{}rtl","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"150"}]},{"N":"applyT","sType":"* ","line":"151","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"151","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"26","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"128","module":"mml3.xsl","expand-text":"false","match":"m:mmultiscripts","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"129","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"130","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"130","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"forEach","sType":"* ","line":"131","C":[{"N":"sort","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"131","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts"},{"N":"filter","flags":"p","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"arith10","op":"mod","calc":"d%d","C":[{"N":"fn","name":"position"},{"N":"int","val":"2"}]},{"N":"int","val":"1"}]}]}]}]}]},{"N":"sortKey","sType":"?ADI ","C":[{"N":"first","role":"select","sType":"?ADI ","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"132"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"133","mode":"Q{}rtl","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"133"}]},{"N":"applyT","sType":"* ","line":"134","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"134","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]}]}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"136","C":[{"N":"empty","sType":"0 "}]},{"N":"forEach","sType":"* ","line":"137","C":[{"N":"sort","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"137","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts"},{"N":"fn","name":"reverse","C":[{"N":"filter","flags":"p","C":[{"N":"filter","flags":"p","C":[{"N":"axis","name":"preceding-sibling","nodeTest":"*NE"},{"N":"gc10","op":"!=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"fn","name":"last"}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"arith10","op":"mod","calc":"d%d","C":[{"N":"fn","name":"position"},{"N":"int","val":"2"}]},{"N":"int","val":"0"}]}]}]}]}]}]},{"N":"sortKey","sType":"?ADI ","C":[{"N":"first","role":"select","sType":"?ADI ","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"138"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"139","mode":"Q{}rtl","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"139"}]},{"N":"applyT","sType":"* ","line":"140","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"140","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"2","prec":"0","seq":"25","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"120","module":"mml3.xsl","expand-text":"false","match":"m:msubsup","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msubsup","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msubsup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msubsup","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"121","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"122","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"122","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"123","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","line":"124","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"124","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"applyT","sType":"* ","line":"125","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"125","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"3"}]}]}]}]}]},{"N":"templateRule","rank":"3","prec":"0","seq":"24","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"112","module":"mml3.xsl","expand-text":"false","match":"m:msub","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msub","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msub","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msub","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"113","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"114","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"114","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"115","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","line":"116","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"116","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]},{"N":"elem","name":"m:none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"117","C":[{"N":"empty","sType":"0 "}]}]}]}]},{"N":"templateRule","rank":"4","prec":"0","seq":"23","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"104","module":"mml3.xsl","expand-text":"false","match":"m:msup","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msup","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mmultiscripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mmultiscripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"105","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"106","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"106","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]},{"N":"elem","name":"m:mprescripts","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mprescripts ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"107","C":[{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"108","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","line":"109","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"109","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]},{"N":"templateRule","rank":"5","prec":"0","seq":"22","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"97","module":"mml3.xsl","expand-text":"false","match":"m:mtable|m:munder|m:mover|m:munderover","prio":"2","matches":"NE u[NE u[NE u[NE nQ{http://www.w3.org/1998/Math/MathML}mtable,NE nQ{http://www.w3.org/1998/Math/MathML}munder],NE nQ{http://www.w3.org/1998/Math/MathML}mover],NE nQ{http://www.w3.org/1998/Math/MathML}munderover]","C":[{"N":"p.venn","role":"match","op":"union","sType":"1NE u[NE u[NE u[NE nQ{http://www.w3.org/1998/Math/MathML}mtable,NE nQ{http://www.w3.org/1998/Math/MathML}munder],NE nQ{http://www.w3.org/1998/Math/MathML}mover],NE nQ{http://www.w3.org/1998/Math/MathML}munderover]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.venn","op":"union","C":[{"N":"p.venn","op":"union","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mtable"},{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}munder"}]},{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mover"}]},{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}munderover"}]},{"N":"copy","sType":"1NE u[1NE u[1NE u[1NE nQ{http://www.w3.org/1998/Math/MathML}mtable ,1NE nQ{http://www.w3.org/1998/Math/MathML}munder ] ,1NE nQ{http://www.w3.org/1998/Math/MathML}mover ] ,1NE nQ{http://www.w3.org/1998/Math/MathML}munderover ] ","flags":"cin","role":"action","line":"98","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"99","mode":"Q{}rtl","bSlot":"0","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"99"}]},{"N":"applyT","sType":"* ","line":"100","mode":"Q{}rtl","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"100"}]}]}]}]},{"N":"templateRule","rank":"6","prec":"0","seq":"53","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"664","module":"mml3.xsl","expand-text":"false","match":"m:menclose[@notation='madruwb']","prio":"0.5","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}menclose","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}menclose"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}notation"},{"N":"str","val":"madruwb"}]}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"665","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom right"}]},{"N":"applyT","sType":"* ","line":"666","mode":"Q{}rtl","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"666"}]}]}]}]},{"N":"templateRule","rank":"7","prec":"0","seq":"36","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"163","module":"mml3.xsl","expand-text":"false","match":"@notation[.='radical']","prio":"0.5","matches":"NA nQ{}notation","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}notation","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}notation"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"radical"}]}]},{"N":"att","name":"notation","sType":"1NA ","role":"action","line":"164","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"top right"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"8","prec":"0","seq":"35","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"162","module":"mml3.xsl","expand-text":"false","match":"text()[.='∋']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"∋"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"∈"}]}]},{"N":"templateRule","rank":"9","prec":"0","seq":"34","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"161","module":"mml3.xsl","expand-text":"false","match":"text()[.='∈']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"∈"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"∋"}]}]},{"N":"templateRule","rank":"10","prec":"0","seq":"33","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"160","module":"mml3.xsl","expand-text":"false","match":"text()[.='>']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":">"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"<"}]}]},{"N":"templateRule","rank":"11","prec":"0","seq":"32","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"159","module":"mml3.xsl","expand-text":"false","match":"text()[.='<']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"<"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":">"}]}]},{"N":"templateRule","rank":"12","prec":"0","seq":"31","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"158","module":"mml3.xsl","expand-text":"false","match":"text()[.='}']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"}"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"{"}]}]},{"N":"templateRule","rank":"13","prec":"0","seq":"30","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"157","module":"mml3.xsl","expand-text":"false","match":"text()[.='{']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"{"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"}"}]}]},{"N":"templateRule","rank":"14","prec":"0","seq":"29","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"156","module":"mml3.xsl","expand-text":"false","match":"text()[.=')']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":")"}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":"("}]}]},{"N":"templateRule","rank":"15","prec":"0","seq":"28","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"155","module":"mml3.xsl","expand-text":"false","match":"text()[.='(']","prio":"0.5","matches":"NT","C":[{"N":"p.withPredicate","role":"match","sType":"1NT","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NT"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"("}]}]},{"N":"valueOf","sType":"1NT ","role":"action","C":[{"N":"str","sType":"1AS ","val":")"}]}]},{"N":"templateRule","rank":"16","prec":"0","seq":"18","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"72","module":"mml3.xsl","expand-text":"false","match":"m:mfrac[@bevelled='true']","prio":"0.5","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mfrac"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}bevelled"},{"N":"str","val":"true"}]}]},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"73","C":[{"N":"sequence","sType":"*NE ","C":[{"N":"elem","name":"m:msub","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msub ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"74","C":[{"N":"sequence","sType":"* ","C":[{"N":"elem","name":"m:mi","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mi ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"5","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]},{"N":"elem","name":"m:mo","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mo ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"75","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"\\"}]}]},{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"76","C":[{"N":"sequence","sType":"* ","C":[{"N":"elem","name":"m:mi","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mi ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","C":[{"N":"empty","sType":"0 "}]},{"N":"applyT","sType":"* ","mode":"Q{}rtl","bSlot":"0","C":[{"N":"first","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"17","prec":"0","seq":"17","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"69","module":"mml3.xsl","expand-text":"false","match":"@close[.='}']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"}"}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"70","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"{"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"18","prec":"0","seq":"16","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"66","module":"mml3.xsl","expand-text":"false","match":"@close[.='{']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"{"}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"67","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"}"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"19","prec":"0","seq":"15","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"63","module":"mml3.xsl","expand-text":"false","match":"@close[.=']']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"]"}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"64","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"["}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"20","prec":"0","seq":"14","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"60","module":"mml3.xsl","expand-text":"false","match":"@close[.='[']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"["}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"61","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"]"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"21","prec":"0","seq":"13","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"57","module":"mml3.xsl","expand-text":"false","match":"@close[.=')']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":")"}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"58","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"("}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"22","prec":"0","seq":"12","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"54","module":"mml3.xsl","expand-text":"false","match":"@close[.='(']","prio":"0.5","matches":"NA nQ{}close","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}close"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"("}]}]},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"55","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":")"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"23","prec":"0","seq":"10","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"48","module":"mml3.xsl","expand-text":"false","match":"@open[.='}']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"}"}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"49","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"{"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"24","prec":"0","seq":"9","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"45","module":"mml3.xsl","expand-text":"false","match":"@open[.='{']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"{"}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"46","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"}"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"25","prec":"0","seq":"8","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"42","module":"mml3.xsl","expand-text":"false","match":"@open[.=']']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"]"}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"43","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"["}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"26","prec":"0","seq":"7","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"39","module":"mml3.xsl","expand-text":"false","match":"@open[.='[']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"["}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"40","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"]"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"27","prec":"0","seq":"6","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"36","module":"mml3.xsl","expand-text":"false","match":"@open[.=')']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":")"}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"37","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"("}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"28","prec":"0","seq":"5","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"33","module":"mml3.xsl","expand-text":"false","match":"@open[.='(']","prio":"0.5","matches":"NA nQ{}open","C":[{"N":"p.withPredicate","role":"match","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NA nQ{}open"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"atomSing","diag":"1|0||gc","card":"?","C":[{"N":"dot"}]},{"N":"str","val":"("}]}]},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"34","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":")"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"29","prec":"0","seq":"37","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"166","module":"mml3.xsl","expand-text":"false","match":"m:mlongdiv|m:mstack","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv"},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"167","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"dir","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"ltr"}]},{"N":"applyT","sType":"* ","line":"168","mode":"#unnamed","bSlot":"1","C":[{"N":"dot","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mlongdiv","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"168"}]}]}]}]},{"N":"templateRule","rank":"30","prec":"0","seq":"37","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"166","module":"mml3.xsl","expand-text":"false","match":"m:mlongdiv|m:mstack","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mstack","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mstack","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstack"},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"167","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"dir","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"ltr"}]},{"N":"applyT","sType":"* ","line":"168","mode":"#unnamed","bSlot":"1","C":[{"N":"dot","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstack","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"168"}]}]}]}]},{"N":"templateRule","rank":"31","prec":"0","seq":"21","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"92","module":"mml3.xsl","expand-text":"false","match":"m:msqrt","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msqrt","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msqrt","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msqrt","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"93","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top right"}]},{"N":"applyT","sType":"* ","line":"94","mode":"Q{}rtl","bSlot":"0","C":[{"N":"docOrder","sType":"*N u[NA,NE]","role":"select","line":"94","C":[{"N":"union","op":"|","sType":"*N u[NA,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"attribute","nodeTest":"*NA"},{"N":"first","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"32","prec":"0","seq":"20","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"84","module":"mml3.xsl","expand-text":"false","match":"m:mroot","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mroot","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mroot","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mroot","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:msup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msup ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"85","C":[{"N":"sequence","sType":"* ","C":[{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"86","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"top right"}]},{"N":"applyT","sType":"* ","line":"87","mode":"Q{}rtl","bSlot":"0","C":[{"N":"docOrder","sType":"*N u[NA,NE]","role":"select","line":"87","C":[{"N":"union","op":"|","sType":"*N u[NA,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"attribute","nodeTest":"*NA"},{"N":"first","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]},{"N":"applyT","sType":"* ","line":"89","mode":"Q{}rtl","bSlot":"0","C":[{"N":"subscript","flags":"p","sType":"?NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"89","C":[{"N":"axis","name":"child","nodeTest":"*NE"},{"N":"int","val":"2"}]}]}]}]}]},{"N":"templateRule","rank":"33","prec":"0","seq":"19","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"79","module":"mml3.xsl","expand-text":"false","match":"m:mfrac","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"copy","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac ","flags":"cin","role":"action","line":"80","C":[{"N":"applyT","sType":"* ","line":"81","mode":"Q{}rtl","bSlot":"0","C":[{"N":"docOrder","sType":"*N u[NA,NE]","role":"select","line":"81","C":[{"N":"union","op":"|","sType":"*N u[NA,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"attribute","nodeTest":"*NA"},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]},{"N":"templateRule","rank":"34","prec":"0","seq":"11","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"51","module":"mml3.xsl","expand-text":"false","match":"@close","prio":"0","matches":"NA nQ{}close","C":[{"N":"p.nodeTest","role":"match","test":"NA nQ{}close","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"att","name":"open","sType":"1NA ","role":"action","line":"52","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"dot","sType":"1NA nQ{}close","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"3"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"35","prec":"0","seq":"4","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"30","module":"mml3.xsl","expand-text":"false","match":"@open","prio":"0","matches":"NA nQ{}open","C":[{"N":"p.nodeTest","role":"match","test":"NA nQ{}open","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"att","name":"close","sType":"1NA ","role":"action","line":"31","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"dot","sType":"1NA nQ{}open","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"3"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]},{"N":"templateRule","rank":"36","prec":"0","seq":"3","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"20","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"copy","sType":"1NE ","flags":"cin","role":"action","line":"21","C":[{"N":"sequence","sType":"* ","C":[{"N":"applyT","sType":"* ","line":"22","mode":"Q{}rtl","bSlot":"0","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"22"}]},{"N":"forEach","sType":"* ","line":"23","C":[{"N":"sort","sType":"*N u[NT,NP,NC,NE]","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"23"},{"N":"sortKey","sType":"?ADI ","C":[{"N":"first","role":"select","sType":"?ADI ","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"24"}]},{"N":"str","sType":"1AS ","val":"descending","role":"order"},{"N":"str","sType":"1AS ","val":"en","role":"lang"},{"N":"str","sType":"1AS ","val":"#default","role":"caseOrder"},{"N":"str","sType":"1AS ","val":"true","role":"stable"},{"N":"str","sType":"1AS ","val":"number","role":"dataType"}]}]},{"N":"sequence","sType":"* ","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":" "}]},{"N":"applyT","sType":"* ","line":"26","mode":"Q{}rtl","bSlot":"0","C":[{"N":"dot","sType":"1N u[N u[N u[NT,NP],NC],NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"26"}]}]}]}]}]}]},{"N":"templateRule","rank":"37","prec":"0","seq":"2","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"16","module":"mml3.xsl","expand-text":"false","match":"@*","prio":"-0.5","matches":"NA","C":[{"N":"p.nodeTest","role":"match","test":"NA","sType":"1NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"*NA ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"17","sType":"1NA","C":[{"N":"dot","sType":"1NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"17"}]},{"N":"att","name":"dir","sType":"1NA ","line":"18","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"ltr"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]}]}]}]}]},{"N":"co","id":"2","binds":"2","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","name":"Q{}ml","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"42","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"313","module":"mml3.xsl","expand-text":"false","match":"m:mtr[not(preceding-sibling::*)][@class='msline']","prio":"3","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.withPredicate","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr"},{"N":"fn","name":"not","C":[{"N":"fn","name":"reverse","C":[{"N":"axis","name":"preceding-sibling","nodeTest":"*NE"}]}]}]},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}class"},{"N":"str","val":"msline"}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"314","C":[{"N":"sequence","sType":"*N ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"315","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"315"}]},{"N":"forEach","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","line":"316","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"316"},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"317","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"318","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"318"}]},{"N":"choose","sType":"? ","line":"319","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"319"},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"320","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"321","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"depth","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".1em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"1em"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".5em"}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"322","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".2em"}]}]}]}]}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]}]}]}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"43","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"330","module":"mml3.xsl","expand-text":"false","match":"m:mtr[@class='msline']","prio":"2","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr"},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}class"},{"N":"str","val":"msline"}]}]},{"N":"empty","sType":"0 ","role":"action"}]},{"N":"templateRule","rank":"2","prec":"0","seq":"41","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"286","module":"mml3.xsl","expand-text":"false","match":"m:mtr[following-sibling::*[1][@class='msline']]","prio":"0.5","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr","C":[{"N":"p.withPredicate","role":"match","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"p.nodeTest","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mtr"},{"N":"filter","C":[{"N":"first","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]},{"N":"gc","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"attVal","name":"Q{}class"},{"N":"str","val":"msline"}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"287","C":[{"N":"sequence","sType":"*N ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"288","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"288"}]},{"N":"let","var":"Q{}m","slot":"0","sType":"*NE ","line":"289","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","role":"select","line":"289","C":[{"N":"slash","op":"/","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"first","C":[{"N":"axis","name":"following-sibling","nodeTest":"*NE"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd"}]}]},{"N":"forEach","sType":"*NE ","line":"290","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"290"},{"N":"let","var":"Q{}p","slot":"1","sType":"*NE ","line":"291","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"291"},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"292","C":[{"N":"sequence","sType":"*N ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"293","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"293"}]},{"N":"choose","sType":"*NE ","type":"item()*","line":"294","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded","line":"295","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"filter","flags":"i","C":[{"N":"varRef","name":"Q{}m","slot":"0"},{"N":"varRef","name":"Q{}p","slot":"1"}]}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mpadded"}]}]}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"296","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"depth","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"+.2em"}]},{"N":"elem","name":"m:menclose","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}menclose ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"297","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"notation","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"bottom"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"298","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"depth","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".1em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".8em"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".8em"}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"299","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".15em"}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"300","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"300"}]}]}]}]}]}]}]},{"N":"true"},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"306","sType":"*NE","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"306"}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"3","prec":"0","seq":"39","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"277","module":"mml3.xsl","expand-text":"false","match":"m:none","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}none","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}none","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}none","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"278","C":[{"N":"empty","sType":"0 "}]}]},{"N":"templateRule","rank":"4","prec":"0","seq":"40","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"280","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"copy","sType":"1NE ","flags":"cin","role":"action","line":"281","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"282","sType":"*NA","C":[{"N":"axis","name":"attribute","nodeTest":"*NA","sType":"*NA","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"282"}]},{"N":"applyT","sType":"* ","line":"283","mode":"Q{}ml","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"283"}]}]}]}]}]}]},{"N":"co","id":"3","binds":"4 3 0","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","name":"Q{}mstack1","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"49","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"481","module":"mml3.xsl","expand-text":"false","match":"m:mscarries","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mscarries","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mscarries","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mscarries","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"482","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"let","var":"Q{}align1","slot":"1","sType":"*NE ","line":"483","C":[{"N":"docOrder","sType":"*NA nQ{}stackalign","role":"select","line":"483","C":[{"N":"slash","op":"/","sType":"*NA nQ{}stackalign","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]}]},{"N":"let","var":"Q{}l1","slot":"2","sType":"*NE ","line":"484","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"485","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"486","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align1","slot":"1"}]}]},{"N":"str","val":"left"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0"}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"fn","sType":"1ADI","name":"count","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"8","C":[{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"490","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"mscarries"}]},{"N":"att","name":"l","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"?AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"?AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"490","C":[{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}l1","slot":"2"}]}]}]},{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}position"}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"applyT","sType":"* ","line":"491","mode":"Q{}msc","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"491"}]}]}]}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"48","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"428","module":"mml3.xsl","expand-text":"false","match":"m:msline","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msline","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msline","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msline","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"429","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"let","var":"Q{}align1","slot":"1","sType":"*NE ","line":"430","C":[{"N":"docOrder","sType":"*NA nQ{}stackalign","role":"select","line":"430","C":[{"N":"slash","op":"/","sType":"*NA nQ{}stackalign","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]}]},{"N":"let","var":"Q{}align","slot":"2","sType":"*NE ","line":"431","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"432","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"433","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align1","slot":"1"}]}]},{"N":"str","val":""}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"decimalpoint"}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}align1","slot":"1","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"8"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"437","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"msline"}]},{"N":"att","name":"l","sType":"1NA ","line":"438","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"439","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"440","C":[{"N":"fn","name":"not","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"},{"N":"int","val":"0"}]}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"*"}]},{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"441","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align","slot":"2"}]}]},{"N":"str","val":"right"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align","slot":"2"}]}]},{"N":"str","val":"decimalpoint"}]}]},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"arith10","sType":"?AO","op":"+","calc":"d+d","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"14","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}p","slot":"0","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"16"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"let","var":"Q{}w","slot":"3","sType":"*NE ","line":"445","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"446","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"447","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}mslinethickness"},{"N":"str","val":"thin"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0.1em"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"448","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}mslinethickness"},{"N":"str","val":"medium"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0.15em"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"449","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}mslinethickness"},{"N":"str","val":"thick"}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0.2em"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}mslinethickness","sType":"*NA nQ{}mslinethickness","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"450"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"axis","sType":"*NA nQ{}mslinethickness","name":"attribute","nodeTest":"*NA nQ{}mslinethickness","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"23"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"true"},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"0.15em"}]}]}]},{"N":"choose","sType":"*NE ","type":"item()*","line":"454","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"455","C":[{"N":"fn","name":"not","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"}]}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length"},{"N":"int","val":"0"}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"456","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"mslinemax"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"457","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.2em"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"elem","name":"m:mfrac","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"458","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"linethickness","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"*","C":[{"N":"varRef","name":"Q{}w","slot":"3","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"458"}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"459","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".5em"}]}]},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"460","C":[{"N":"empty","sType":"0 "}]}]}]}]}]}]}]},{"N":"true"},{"N":"let","var":"Q{}l","slot":"4","sType":"*NE ","line":"466","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}length","sType":"*NA nQ{}length","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"466"},{"N":"forEach","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","line":"467","C":[{"N":"filter","flags":"p","sType":"*N","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"467","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*N u[NT,NP,NC,NE]"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}l","slot":"4"}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"468","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"msline"}]},{"N":"elem","name":"m:mpadded","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mpadded ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"469","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"lspace","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"-0.2em"}]},{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"att","name":"height","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"0em"}]},{"N":"elem","name":"m:mfrac","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mfrac ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"470","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"linethickness","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"*","C":[{"N":"varRef","name":"Q{}w","slot":"3","sType":"*","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"470"}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"471","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".5em"}]}]},{"N":"elem","name":"m:mrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mrow ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"472","C":[{"N":"empty","sType":"0 "}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"2","prec":"0","seq":"47","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"418","module":"mml3.xsl","expand-text":"false","match":"m:msgroup","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msgroup","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msgroup","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msgroup","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"419","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"let","var":"Q{}s","slot":"1","sType":"* ","line":"420","C":[{"N":"fn","name":"number","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"420","C":[{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}shift"}]}]},{"N":"let","var":"Q{}thisp","slot":"2","sType":"* ","line":"421","C":[{"N":"fn","name":"number","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"421","C":[{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}position"}]}]},{"N":"forEach","sType":"* ","line":"422","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"422"},{"N":"applyT","sType":"* ","line":"423","mode":"Q{}mstack1","bSlot":"1","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"423"},{"N":"withParam","name":"Q{}p","slot":"0","sType":"1AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"424","C":[{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"fn","name":"number","C":[{"N":"atomSing","diag":"0|0||number","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}thisp","slot":"2"}]}]}]},{"N":"arith10","op":"*","calc":"d*d","C":[{"N":"arith10","op":"-","calc":"d-d","C":[{"N":"fn","name":"position"},{"N":"int","val":"1"}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}s","slot":"1"}]}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"3","prec":"0","seq":"46","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"376","module":"mml3.xsl","expand-text":"false","match":"m:mn","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mn","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mn","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mn","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"377","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"let","var":"Q{}align1","slot":"1","sType":"*NE ","line":"378","C":[{"N":"docOrder","sType":"*NA nQ{}stackalign","role":"select","line":"378","C":[{"N":"slash","op":"/","sType":"*NA nQ{}stackalign","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]}]},{"N":"let","var":"Q{}dp1","slot":"2","sType":"*NE ","line":"379","C":[{"N":"docOrder","sType":"*NA nQ{}decimalpoint","role":"select","line":"379","C":[{"N":"slash","op":"/","sType":"*NA nQ{}decimalpoint","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"filter","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}decimalpoint"}]}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}decimalpoint"}]}]},{"N":"let","var":"Q{}align","slot":"3","sType":"*NE ","line":"380","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"381","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"382","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align1","slot":"1"}]}]},{"N":"str","val":""}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"decimalpoint"}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}align1","slot":"1","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"let","var":"Q{}dp","slot":"4","sType":"*NE ","line":"386","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"387","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"388","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}dp1","slot":"2"}]}]},{"N":"str","val":""}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"."}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}dp1","slot":"2","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"14"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"392","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"l","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"$p"}]},{"N":"let","var":"Q{}mn","slot":"5","sType":"* ","line":"393","C":[{"N":"fn","name":"normalize-space","sType":"1AS","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"393","C":[{"N":"fn","name":"string","C":[{"N":"dot"}]}]},{"N":"let","var":"Q{}len","slot":"6","sType":"* ","line":"394","C":[{"N":"fn","name":"string-length","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"394","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}mn","slot":"5"}]}]}]},{"N":"sequence","sType":"* ","C":[{"N":"choose","sType":"? ","type":"item()*","line":"395","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"396","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"right"}]},{"N":"and","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"decimalpoint"}]},{"N":"fn","name":"not","C":[{"N":"fn","name":"contains","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}mn","slot":"5"}]}]},{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}dp","slot":"4"}]}]},{"N":"str","val":"http://www.w3.org/2005/xpath-functions/collation/codepoint"}]}]}]}]},{"N":"att","name":"l","sType":"1NA ","line":"397","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"arith10","sType":"?AO","op":"+","calc":"d+d","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"21","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}len","slot":"6"}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"399","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"center"}]},{"N":"att","name":"l","sType":"1NA ","line":"400","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"fn","sType":"?A m[AO,AD,AF]","name":"round","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"24","C":[{"N":"arith10","op":"div","calc":"d/d","C":[{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}len","slot":"6"}]}]}]},{"N":"int","val":"2"}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"402","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"decimalpoint"}]},{"N":"att","name":"l","sType":"1NA ","line":"403","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"arith10","sType":"?AO","op":"+","calc":"d+d","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"27","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]},{"N":"fn","name":"string-length","C":[{"N":"fn","name":"substring-before","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}mn","slot":"5"}]}]},{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}dp","slot":"4"}]}]},{"N":"str","val":"http://www.w3.org/2005/xpath-functions/collation/codepoint"}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]},{"N":"forEach","sType":"*NE ","line":"406","C":[{"N":"filter","flags":"p","sType":"*N","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"406","C":[{"N":"slash","op":"/","C":[{"N":"root"},{"N":"axis","name":"descendant","nodeTest":"*N u[NT,NP,NC,NE]"}]},{"N":"gc10","op":"<=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"fn","name":"position"},{"N":"varRef","name":"Q{}len","slot":"6"}]}]},{"N":"let","var":"Q{}pos","slot":"7","sType":"*NE ","line":"407","C":[{"N":"fn","name":"position","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"407"},{"N":"let","var":"Q{}digit","slot":"8","sType":"*NE ","line":"408","C":[{"N":"fn","name":"substring","sType":"1AS","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"408","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}mn","slot":"5"}]}]},{"N":"fn","name":"number","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}pos","slot":"7"}]}]},{"N":"fn","name":"number","C":[{"N":"int","val":"1"}]}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"409","C":[{"N":"sequence","sType":"* ","C":[{"N":"choose","sType":"? ","line":"410","C":[{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"410","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}digit","slot":"8"},{"N":"str","val":"."}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}digit","slot":"8"},{"N":"str","val":","}]}]},{"N":"elem","name":"m:mspace","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mspace ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"411","C":[{"N":"att","name":"width","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":".15em"}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mn","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mn ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"413","C":[{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}digit","slot":"8","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"35"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"4","prec":"0","seq":"45","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"341","module":"mml3.xsl","expand-text":"false","match":"m:msrow","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}msrow","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}msrow","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}msrow","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"342","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"param","name":"Q{}maxl","slot":"1","sType":"* ","as":"* ","flags":"","line":"343","C":[{"N":"int","val":"0","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"343"},{"N":"supplied","role":"conversion","slot":"1","sType":"* "}]},{"N":"let","var":"Q{}align1","slot":"2","sType":"*N ","line":"344","C":[{"N":"docOrder","sType":"*NA nQ{}stackalign","role":"select","line":"344","C":[{"N":"slash","op":"/","sType":"*NA nQ{}stackalign","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]}]},{"N":"let","var":"Q{}align","slot":"3","sType":"*N ","line":"345","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"choose","sType":"?NT ","type":"item()*","line":"346","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"347","C":[{"N":"fn","name":"string","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}align1","slot":"2"}]}]},{"N":"str","val":""}]},{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"decimalpoint"}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}align1","slot":"2","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"let","var":"Q{}row","slot":"4","sType":"*N ","line":"351","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"applyT","sType":"* ","line":"352","mode":"Q{}mstack1","bSlot":"1","C":[{"N":"axis","name":"child","nodeTest":"*NE","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"352"},{"N":"withParam","name":"Q{}p","slot":"0","sType":"1ADI","C":[{"N":"int","val":"0","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"353"}]}]}]},{"N":"sequence","sType":"*N ","C":[{"N":"valueOf","sType":"1NT ","C":[{"N":"str","sType":"1AS ","val":"\n"}]},{"N":"let","var":"Q{}l1","slot":"5","sType":"*NE ","line":"357","C":[{"N":"doc","sType":"1ND ","base":"file:///private/tmp/mml3.xsl","role":"select","C":[{"N":"choose","sType":"*NT ","type":"item()*","line":"358","C":[{"N":"and","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"359","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"decimalpoint"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mn"}]},{"N":"forEach","sType":"*NT ","line":"360","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr","role":"select","line":"360","C":[{"N":"docOrder","sType":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}row","slot":"4"}]},{"N":"first","C":[{"N":"filter","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr"},{"N":"slash","op":"/","C":[{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd"},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mn"}]}]}]}]}]}]},{"N":"valueOf","flags":"l","sType":"1NT ","line":"361","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"arith10","sType":"1AO","op":"+","calc":"d+d","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"361","C":[{"N":"fn","name":"number","C":[{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}l"}]}]},{"N":"fn","name":"count","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"fn","name":"reverse","C":[{"N":"axis","name":"preceding-sibling","nodeTest":"*NE"}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}l"}]}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]},{"N":"or","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"364","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"right"}]},{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","C":[{"N":"varRef","name":"Q{}align","slot":"3"},{"N":"str","val":"decimalpoint"}]}]},{"N":"valueOf","flags":"l","sType":"1NT ","line":"365","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"fn","sType":"1ADI","name":"count","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"365","C":[{"N":"docOrder","C":[{"N":"slash","op":"/","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}row","slot":"4"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtd"}]}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"true"},{"N":"valueOf","flags":"l","sType":"1NT ","line":"368","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"int","sType":"1ADI","val":"0","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"368"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"372","C":[{"N":"sequence","sType":"*N ","C":[{"N":"att","name":"class","nsuri":"","sType":"1NA ","C":[{"N":"str","sType":"1AS ","val":"msrow"}]},{"N":"att","name":"l","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"372","C":[{"N":"arith10","op":"+","calc":"d+d","C":[{"N":"fn","name":"number","C":[{"N":"atomSing","diag":"0|0||number","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}l1","slot":"5"}]}]}]},{"N":"fn","name":"number","C":[{"N":"fn","name":"sum","C":[{"N":"attVal","name":"Q{}position"}]}]}]},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"373","sType":"*NE","C":[{"N":"docOrder","sType":"*NE","role":"select","line":"373","C":[{"N":"docOrder","sType":"*NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"slash","op":"/","C":[{"N":"treat","as":"N","diag":"1|0|XPTY0019|slash","C":[{"N":"varRef","name":"Q{}row","slot":"4"}]},{"N":"axis","name":"child","nodeTest":"*NE nQ{http://www.w3.org/1998/Math/MathML}mtr"}]},{"N":"axis","name":"child","nodeTest":"*NE"}]}]}]}]}]}]}]}]}]}]}]}]}]},{"N":"templateRule","rank":"5","prec":"0","seq":"44","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"331","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"sequence","role":"action","sType":"* ","C":[{"N":"param","name":"Q{}p","slot":"0","sType":"* ","as":"* ","flags":"","line":"332","C":[{"N":"str","sType":"1AS ","val":"","role":"select"},{"N":"supplied","role":"conversion","slot":"0","sType":"* "}]},{"N":"param","name":"Q{}maxl","slot":"1","sType":"* ","as":"* ","flags":"","line":"333","C":[{"N":"int","val":"0","sType":"1ADI","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"333"},{"N":"supplied","role":"conversion","slot":"1","sType":"* "}]},{"N":"elem","name":"m:mtr","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtr ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"334","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"l","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"1AO","C":[{"N":"arith10","op":"+","calc":"d+d","sType":"1AO","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"334","C":[{"N":"int","val":"1"},{"N":"atomSing","diag":"1|1||arith","card":"?","C":[{"N":"first","C":[{"N":"varRef","name":"Q{}p","slot":"0"}]}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]},{"N":"choose","sType":"? ","line":"335","C":[{"N":"gc10","op":"=","comp":"GAC|http://www.w3.org/2005/xpath-functions/collation/codepoint","card":"1:1","sType":"1AB","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"335","C":[{"N":"slash","op":"/","C":[{"N":"fn","name":"reverse","C":[{"N":"first","C":[{"N":"axis","name":"ancestor","nodeTest":"*NE nQ{}mstack"}]}]},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}stackalign"}]},{"N":"str","val":"left"}]},{"N":"att","name":"l","sType":"1NA ","line":"336","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"valueOf","sType":"1NT ","flags":"l","C":[{"N":"fn","name":"string-join","role":"select","C":[{"N":"first","C":[{"N":"forEach","sType":"*AS ","C":[{"N":"data","sType":"*A ","C":[{"N":"mergeAdj","C":[{"N":"varRef","sType":"*","name":"Q{}p","slot":"0","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"7"}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":" "}]}]}]}]},{"N":"fn","name":"string","sType":"1AS ","C":[{"N":"dot"}]}]}]},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"true"},{"N":"empty","sType":"0 "}]},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"338","C":[{"N":"applyT","sType":"* ","mode":"#unnamed","bSlot":"2","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"9"}]}]}]}]}]}]}]}]},{"N":"co","id":"4","binds":"0","C":[{"N":"mode","onNo":"TC","flags":"","patternSlots":"0","name":"Q{}msc","prec":"","C":[{"N":"templateRule","rank":"0","prec":"0","seq":"51","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"509","module":"mml3.xsl","expand-text":"false","match":"m:mscarry","prio":"0","matches":"NE nQ{http://www.w3.org/1998/Math/MathML}mscarry","C":[{"N":"p.nodeTest","role":"match","test":"NE nQ{http://www.w3.org/1998/Math/MathML}mscarry","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mscarry","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"510","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"511","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","C":[{"N":"docOrder","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","role":"select","line":"511","C":[{"N":"union","op":"|","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"512","C":[{"N":"docOrder","sType":"*NA nQ{}scriptsizemultiplier","line":"513","C":[{"N":"slash","op":"/","sType":"*NA nQ{}scriptsizemultiplier","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}scriptsizemultiplier"}]}]},{"N":"elem","name":"m:mstyle","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstyle ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"514","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"mathsize","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"concat","sType":"1AS ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"?A m[AO,AD,AF]","C":[{"N":"fn","name":"round","sType":"?A m[AO,AD,AF]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"514","C":[{"N":"arith10","op":"div","calc":"d/d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}scriptsizemultiplier"}]}]}]},{"N":"dec","val":"0.007"}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]},{"N":"str","sType":"1AS ","val":"%"},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"applyT","sType":"* ","line":"515","mode":"#unnamed","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"515"}]}]}]},{"N":"true"},{"N":"applyT","sType":"* ","line":"519","mode":"#unnamed","bSlot":"0","C":[{"N":"axis","name":"child","nodeTest":"*N u[NT,NP,NC,NE]","sType":"*N u[NT,NP,NC,NE]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"519"}]}]}]}]}]},{"N":"templateRule","rank":"1","prec":"0","seq":"50","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common","minImp":"0","flags":"s","slots":"200","baseUri":"file:///private/tmp/mml3.xsl","line":"494","module":"mml3.xsl","expand-text":"false","match":"*","prio":"-0.5","matches":"NE","C":[{"N":"p.nodeTest","role":"match","test":"NE","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common "},{"N":"elem","name":"m:mtd","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mtd ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","role":"action","line":"495","C":[{"N":"sequence","sType":"* ","C":[{"N":"copyOf","flags":"c","ns":"xml=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ex=http://ns.saxonica.com/xslt/export","line":"496","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","C":[{"N":"docOrder","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","role":"select","line":"496","C":[{"N":"union","op":"|","sType":"*NA u[NA nQ{}location,NA nQ{}crossout]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}location"}]},{"N":"slash","op":"/","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}crossout"}]}]}]}]},{"N":"choose","sType":"* ","type":"item()*","line":"497","C":[{"N":"docOrder","sType":"*NA nQ{}scriptsizemultiplier","line":"498","C":[{"N":"slash","op":"/","sType":"*NA nQ{}scriptsizemultiplier","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}scriptsizemultiplier"}]}]},{"N":"elem","name":"m:mstyle","sType":"1NE nQ{http://www.w3.org/1998/Math/MathML}mstyle ","nsuri":"http://www.w3.org/1998/Math/MathML","namespaces":"","line":"499","C":[{"N":"sequence","sType":"* ","C":[{"N":"att","name":"mathsize","nsuri":"","sType":"1NA ","C":[{"N":"fn","name":"concat","sType":"1AS ","C":[{"N":"fn","name":"string-join","sType":"1AS ","C":[{"N":"first","C":[{"N":"convert","type":"AS*","from":"AZ","to":"AS","C":[{"N":"data","C":[{"N":"mergeAdj","sType":"?A m[AO,AD,AF]","C":[{"N":"fn","name":"round","sType":"?A m[AO,AD,AF]","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","line":"499","C":[{"N":"arith10","op":"div","calc":"d/d","C":[{"N":"atomSing","diag":"1|0||arith","card":"?","C":[{"N":"first","C":[{"N":"slash","op":"/","C":[{"N":"axis","name":"parent","nodeTest":"?N"},{"N":"axis","name":"attribute","nodeTest":"*NA nQ{}scriptsizemultiplier"}]}]}]},{"N":"dec","val":"0.007"}]}]}]}]}]}]},{"N":"str","sType":"1AS ","val":" "}]},{"N":"str","sType":"1AS ","val":"%"},{"N":"str","sType":"1AS ","val":""}]}]},{"N":"applyT","sType":"* ","line":"500","mode":"#unnamed","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"500"}]}]}]},{"N":"true"},{"N":"applyT","sType":"* ","line":"504","mode":"#unnamed","bSlot":"0","C":[{"N":"dot","sType":"1NE","ns":"= xml=~ fn=~ xsl=~ m=http://www.w3.org/1998/Math/MathML c=http://exslt.org/common ","role":"select","line":"504"}]}]}]}]}]}]}]},{"N":"overridden"},{"N":"output","C":[{"N":"property","name":"Q{http://saxon.sf.net/}stylesheet-version","value":"10"},{"N":"property","name":"indent","value":"yes"},{"N":"property","name":"omit-xml-declaration","value":"yes"}]},{"N":"decimalFormat"}],"Σ":"edffd6a"} \ No newline at end of file diff --git a/ts/input/mathml/mml3/mml3.ts b/ts/input/mathml/mml3/mml3.ts index 42f2be359..31789d3bd 100644 --- a/ts/input/mathml/mml3/mml3.ts +++ b/ts/input/mathml/mml3/mml3.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2021-2022 The MathJax Consortium + * Copyright (c) 2021-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,19 +16,18 @@ */ /** - * @fileoverview Implements the elementary MathML3 support (experimental) + * @file Implements the elementary MathML3 support (experimental) * using David Carlisle's XLST transform. * * @author dpvc@mathjax.org (Davide Cervone) */ -import {MathItem} from '../../../core/MathItem.js'; -import {MathDocument} from '../../../core/MathDocument.js'; -import {Handler} from '../../../core/Handler.js'; -import {OptionList} from '../../../util/Options.js'; -import {createTransform} from './mml3-node.js'; -import {MathML} from '../../mathml.js'; - +import { MathItem } from '../../../core/MathItem.js'; +import { MathDocument } from '../../../core/MathDocument.js'; +import { Handler } from '../../../core/Handler.js'; +import { OptionList } from '../../../util/Options.js'; +import { createTransform } from './mml3-node.js'; +import { MathML } from '../../mathml.js'; /** * The data for a MathML prefilter. @@ -37,17 +36,20 @@ import {MathML} from '../../mathml.js'; * @template T The Text node class * @template D The Document class */ -export type FILTERDATA = {math: MathItem, document: MathDocument, data: N}; +export type FILTERDATA = { + math: MathItem; + document: MathDocument; + data: N; +}; /** * Class that handles XSLT transform for MathML3 elementary math tags. */ export class Mml3 { - /** * The XSLT transform as a string; */ - public static XSLT: string; // added below (it is huge) + public static XSLT: string; // added below (it is huge) /** * The function to convert serialized MathML using the XSLT. @@ -57,7 +59,7 @@ export class Mml3 { /** * @param {MathDocument} document The MathDocument for the transformation - * @constructor + * @class */ constructor(document: MathDocument) { if (typeof XSLTProcessor === 'undefined') { @@ -70,13 +72,19 @@ export class Mml3 { // For in-browser use, use the browser's XSLTProcessor // const processor = new XSLTProcessor(); - const parsed = document.adaptor.parse(Mml3.XSLT, 'text/xml') as any as Node; + const parsed = document.adaptor.parse( + Mml3.XSLT, + 'text/xml' + ) as any as Node; processor.importStylesheet(parsed); this.transform = (node: N) => { const adaptor = document.adaptor; const div = adaptor.node('div', {}, [adaptor.clone(node)]); - const mml = processor.transformToDocument(div as any as Node) as any as N; - return adaptor.tags(mml, 'math')[0]; + const dom = adaptor.parse(adaptor.serializeXML(div), 'text/xml'); + const mml = processor.transformToDocument( + dom as any as Node + ) as any as N; + return mml ? adaptor.tags(mml, 'math')[0] : node; }; } } @@ -91,15 +99,18 @@ export class Mml3 { args.data = this.transform(args.data, args.document); } } - } /** * Add Mml3 support into the handler. + * + * @param {Handler} handler The current handler. + * @returns {Handler} The provided handler for pipelining. */ -export function Mml3Handler(handler: Handler): Handler { +export function Mml3Handler( + handler: Handler +): Handler { handler.documentClass = class extends handler.documentClass { - /** * @override */ @@ -112,13 +123,14 @@ export function Mml3Handler(handler: Handler): Handler).mmlFilters.add(mml3.mmlFilter.bind(mml3)); jax.options._mml3 = true; @@ -672,12 +684,12 @@ Mml3.XSLT = ` - + / - \ + \\ diff --git a/ts/input/tex.ts b/ts/input/tex.ts index 98d9dfc46..54d4658a1 100644 --- a/ts/input/tex.ts +++ b/ts/input/tex.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,31 +16,31 @@ */ /** - * @fileoverview Implements the TeX InputJax object + * @file Implements the TeX InputJax object * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractInputJax} from '../core/InputJax.js'; -import {userOptions, separateOptions, OptionList} from '../util/Options.js'; -import {MathDocument} from '../core/MathDocument.js'; -import {MathItem} from '../core/MathItem.js'; -import {MmlNode} from '../core/MmlTree/MmlNode.js'; -import {MmlFactory} from '../core/MmlTree/MmlFactory.js'; +import { AbstractInputJax } from '../core/InputJax.js'; +import { userOptions, separateOptions, OptionList } from '../util/Options.js'; +import { MathDocument } from '../core/MathDocument.js'; +import { MathItem } from '../core/MathItem.js'; +import { MmlNode } from '../core/MmlTree/MmlNode.js'; +import { MmlFactory } from '../core/MmlTree/MmlFactory.js'; -import {FindTeX} from './tex/FindTeX.js'; +import { FindTeX } from './tex/FindTeX.js'; import FilterUtil from './tex/FilterUtil.js'; import NodeUtil from './tex/NodeUtil.js'; import TexParser from './tex/TexParser.js'; import TexError from './tex/TexError.js'; import ParseOptions from './tex/ParseOptions.js'; -import {TagsFactory} from './tex/Tags.js'; -import {ParserConfiguration} from './tex/Configuration.js'; +import { TagsFactory } from './tex/Tags.js'; +import { ParserConfiguration } from './tex/Configuration.js'; +import { TexConstant } from './tex/TexConstants.js'; // Import base as it is the default package loaded. import './tex/base/BaseConfiguration.js'; - /*****************************************************************/ /* * Implements the TeX class (extends AbstractInputJax) @@ -52,26 +52,30 @@ import './tex/base/BaseConfiguration.js'; * @template D The Document class */ export class TeX extends AbstractInputJax { - /** * Name of input jax. + * * @type {string} */ public static NAME: string = 'TeX'; /** * Default options for the jax. + * * @type {OptionList} */ public static OPTIONS: OptionList = { ...AbstractInputJax.OPTIONS, FindTeX: null, packages: ['base'], - // Digit pattern to match numbers. - digits: /^(?:[0-9]+(?:\{,\}[0-9]{3})*(?:\.[0-9]*)?|\.[0-9]+)/, // Maximum size of TeX string to process. maxBuffer: 5 * 1024, - formatError: (jax: TeX, err: TexError) => jax.formatError(err) + // Maximum number of array template substitutions (avoids infinite loop from @{\\} for example) + maxTemplateSubtitutions: 10000, + // math-style to use for Latin and Greek letters + mathStyle: 'TeX', // one of TeX, ISO, French, or upright + formatError: (jax: TeX, err: TexError) => + jax.formatError(err), }; /** @@ -81,18 +85,21 @@ export class TeX extends AbstractInputJax { /** * The configuration of the TeX jax. + * * @type {ParserConfiguration} */ protected configuration: ParserConfiguration; /** * The LaTeX code that is parsed. + * * @type {string} */ protected latex: string; /** * The Math node that results from parsing. + * * @type {MmlNode} */ protected mathNode: MmlNode; @@ -101,50 +108,64 @@ export class TeX extends AbstractInputJax { /** * Initialises the configurations. + * * @param {string[]} packages Names of packages. - * @return {Configuration} The configuration object. + * @returns {ParserConfiguration} The configuration object. */ - protected static configure(packages: (string | [string, number])[]): ParserConfiguration { - let configuration = new ParserConfiguration(packages, ['tex']); + protected static configure( + packages: (string | [string, number])[] + ): ParserConfiguration { + const configuration = new ParserConfiguration(packages, ['tex']); configuration.init(); return configuration; } - /** * Initialises the Tags factory. Add tagging structures from packages and set * tagging to given default. + * * @param {ParseOptions} options The parse options. - * @param {Configuration} configuration The configuration. + * @param {ParserConfiguration} configuration The configuration. */ - protected static tags(options: ParseOptions, configuration: ParserConfiguration) { + protected static tags( + options: ParseOptions, + configuration: ParserConfiguration + ) { TagsFactory.addTags(configuration.tags); TagsFactory.setDefault(options.options.tags); options.tags = TagsFactory.getDefault(); options.tags.configuration = options; } - /** * @override */ constructor(options: OptionList = {}) { - const [rest, tex, find] = separateOptions(options, TeX.OPTIONS, FindTeX.OPTIONS); + const [rest, tex, find] = separateOptions( + options, + TeX.OPTIONS, + FindTeX.OPTIONS + ); super(tex); this.findTeX = this.options['FindTeX'] || new FindTeX(find); const packages = this.options.packages; - const configuration = this.configuration = TeX.configure(packages); - const parseOptions = this._parseOptions = - new ParseOptions(configuration, [this.options, TagsFactory.OPTIONS]); + const configuration = (this.configuration = TeX.configure(packages)); + const parseOptions = (this._parseOptions = new ParseOptions(configuration, [ + this.options, + TagsFactory.OPTIONS, + ])); userOptions(parseOptions.options, rest); configuration.config(this); TeX.tags(parseOptions, configuration); - this.postFilters.add(FilterUtil.cleanSubSup, -6); - this.postFilters.add(FilterUtil.setInherited, -5); - this.postFilters.add(FilterUtil.moveLimits, -4); - this.postFilters.add(FilterUtil.cleanStretchy, -3); - this.postFilters.add(FilterUtil.cleanAttributes, -2); - this.postFilters.add(FilterUtil.combineRelations, -1); + this.postFilters.addList([ + [FilterUtil.cleanSubSup, -7], + [FilterUtil.setInherited, -6], + [FilterUtil.checkScriptlevel, -5], + [FilterUtil.moveLimits, -4], + [FilterUtil.cleanStretchy, -3], + [FilterUtil.cleanAttributes, -2], + [FilterUtil.combineRelations, -1], + ]); } /** @@ -155,9 +176,8 @@ export class TeX extends AbstractInputJax { this._parseOptions.nodeFactory.setMmlFactory(mmlFactory); } - /** - * @return {ParseOptions} The parse options that configure this JaX instance. + * @returns {ParseOptions} The parse options that configure this JaX instance. */ public get parseOptions(): ParseOptions { return this._parseOptions; @@ -170,24 +190,27 @@ export class TeX extends AbstractInputJax { this.parseOptions.tags.reset(tag); } - /** * @override */ - public compile(math: MathItem, document: MathDocument): MmlNode { + public compile( + math: MathItem, + document: MathDocument + ): MmlNode { this.parseOptions.clear(); + this.parseOptions.mathItem = math; this.executeFilters(this.preFilters, math, document, this.parseOptions); - let display = math.display; this.latex = math.math; let node: MmlNode; this.parseOptions.tags.startEquation(math); - let globalEnv; + let parser; try { - let parser = new TexParser(this.latex, - {display: display, isInner: false}, - this.parseOptions); + parser = new TexParser( + this.latex, + { display: math.display, isInner: false }, + this.parseOptions + ); node = parser.mml(); - globalEnv = parser.stack.global; } catch (err) { if (!(err instanceof TexError)) { throw err; @@ -196,20 +219,24 @@ export class TeX extends AbstractInputJax { node = this.options.formatError(this, err); } node = this.parseOptions.nodeFactory.create('node', 'math', [node]); - if (globalEnv?.indentalign) { - NodeUtil.setAttribute(node, 'indentalign', globalEnv.indentalign); - } - if (display) { + node.attributes.set(TexConstant.Attr.LATEX, this.latex); + if (math.display) { NodeUtil.setAttribute(node, 'display', 'block'); } this.parseOptions.tags.finishEquation(math); this.parseOptions.root = node; this.executeFilters(this.postFilters, math, document, this.parseOptions); + // + // Add these here to not lose overflow during filtering attributes in postFilters + // + if (parser && parser.stack.env.hsize) { + NodeUtil.setAttribute(node, 'maxwidth', parser.stack.env.hsize); + NodeUtil.setAttribute(node, 'overflow', 'linebreak'); + } this.mathNode = this.parseOptions.root; return this.mathNode; } - /** * @override */ @@ -219,14 +246,18 @@ export class TeX extends AbstractInputJax { /** * Default formatter for error messages: - * wrap an error into a node for output. - * @param {TeXError} err The TexError. - * @return {Node} The merror node. + * wrap an error into a node for output. + * + * @param {TexError} err The TexError. + * @returns {Node} The merror node. */ public formatError(err: TexError): MmlNode { - let message = err.message.replace(/\n.*/, ''); + const message = err.message.replace(/\n.*/, ''); return this.parseOptions.nodeFactory.create( - 'error', message, err.id, this.latex); + 'error', + message, + err.id, + this.latex + ); } - } diff --git a/ts/input/tex/AllPackages.ts b/ts/input/tex/AllPackages.ts deleted file mode 100644 index a934869f3..000000000 --- a/ts/input/tex/AllPackages.ts +++ /dev/null @@ -1,127 +0,0 @@ -/************************************************************* - * - * Copyright (c) 2018-2022 The MathJax Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/** - * @fileoverview Loads all the TeX extensions - * - * @author dpvc@mathjax.org (Davide Cervone) - */ - -import './base/BaseConfiguration.js'; -import './action/ActionConfiguration.js'; -import './ams/AmsConfiguration.js'; -import './amscd/AmsCdConfiguration.js'; -import './bbox/BboxConfiguration.js'; -import './boldsymbol/BoldsymbolConfiguration.js'; -import './braket/BraketConfiguration.js'; -import './bussproofs/BussproofsConfiguration.js'; -import './cancel/CancelConfiguration.js'; -import './cases/CasesConfiguration.js'; -import './centernot/CenternotConfiguration.js'; -import './color/ColorConfiguration.js'; -import './colorv2/ColorV2Configuration.js'; -import './colortbl/ColortblConfiguration.js'; -import './configmacros/ConfigMacrosConfiguration.js'; -import './empheq/EmpheqConfiguration.js'; -import './enclose/EncloseConfiguration.js'; -import './extpfeil/ExtpfeilConfiguration.js'; -import './gensymb/GensymbConfiguration.js'; -import './html/HtmlConfiguration.js'; -import './mathtools/MathtoolsConfiguration.js'; -import './mhchem/MhchemConfiguration.js'; -import './newcommand/NewcommandConfiguration.js'; -import './noerrors/NoErrorsConfiguration.js'; -import './noundefined/NoUndefinedConfiguration.js'; -import './physics/PhysicsConfiguration.js'; -import './setoptions/SetOptionsConfiguration.js'; -import './tagformat/TagFormatConfiguration.js'; -import './textcomp/TextcompConfiguration.js'; -import './textmacros/TextMacrosConfiguration.js'; -import './upgreek/UpgreekConfiguration.js'; -import './unicode/UnicodeConfiguration.js'; -import './verb/VerbConfiguration.js'; - -declare const MathJax: any; -if (typeof MathJax !== 'undefined' && MathJax.loader) { - MathJax.loader.preLoad( - '[tex]/action', - '[tex]/ams', - '[tex]/amscd', - '[tex]/bbox', - '[tex]/boldsymbol', - '[tex]/braket', - '[tex]/bussproofs', - '[tex]/cancel', - '[tex]/cases', - '[tex]/centernot', - '[tex]/color', - '[tex]/colorv2', - '[tex]/colortbl', - '[tex]/empheq', - '[tex]/enclose', - '[tex]/extpfeil', - '[tex]/gensymb', - '[tex]/html', - '[tex]/mathtools', - '[tex]/mhchem', - '[tex]/newcommand', - '[tex]/noerrors', - '[tex]/noundefined', - '[tex]/physics', - '[tex]/upgreek', - '[tex]/unicode', - '[tex]/verb', - '[tex]/configmacros', - '[tex]/tagformat', - '[tex]/textcomp', - '[tex]/textmacros', - '[tex]/setoptions', - ); -} - -export const AllPackages: string[] = [ - 'base', - 'action', - 'ams', - 'amscd', - 'bbox', - 'boldsymbol', - 'braket', - 'bussproofs', - 'cancel', - 'cases', - 'centernot', - 'color', - 'colortbl', - 'empheq', - 'enclose', - 'extpfeil', - 'gensymb', - 'html', - 'mathtools', - 'mhchem', - 'newcommand', - 'noerrors', - 'noundefined', - 'upgreek', - 'unicode', - 'verb', - 'configmacros', - 'tagformat', - 'textcomp', - 'textmacros' -]; diff --git a/ts/input/tex/ColumnParser.ts b/ts/input/tex/ColumnParser.ts new file mode 100644 index 000000000..04ffe602b --- /dev/null +++ b/ts/input/tex/ColumnParser.ts @@ -0,0 +1,423 @@ +/************************************************************* + * + * Copyright (c) 2022-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Implements a parser for array column declarations. + * + * @author dpvc@mathjax.org (Davide Cervone) + */ + +import { ArrayItem } from './base/BaseItems.js'; +import TexParser from './TexParser.js'; +import TexError from './TexError.js'; +import { lookup } from '../../util/Options.js'; +import { ParseUtil } from './ParseUtil.js'; +import { UnitUtil } from './UnitUtil.js'; + +/***********************************************************************/ + +/** + * The state of the columns analyzed so far. + */ +/* prettier-ignore */ +export type ColumnState = { + parser: TexParser, // the current TexParser + template: string; // the template string for the columns + i: number; // the current location in the template + c: string; // the current column identifier + j: number; // the current column number + calign: string[]; // the column alignments + cwidth: string[]; // the explicit column widths + cspace: string[]; // the column spacing + clines: string[]; // the column lines + cstart: string[]; // the '>' declarations + cend: string[]; // the '<' declarations + cextra: boolean[]; // the extra columns from '@' and '!' declarations + ralign: [string, string, string][]; // the row alignment and column width/align when specified +} + +/** + * A function to handle a column declaration + */ +export type ColumnHandler = (state: ColumnState) => void; + +/***********************************************************************/ + +/** + * The ColumnParser class for processing array environment column templates. + */ +export class ColumnParser { + /** + * The handlers for each column character type (future: can be augmented by \newcolumntype) + */ + public columnHandler: { [c: string]: ColumnHandler } = { + l: (state) => (state.calign[state.j++] = 'left'), + c: (state) => (state.calign[state.j++] = 'center'), + r: (state) => (state.calign[state.j++] = 'right'), + p: (state) => this.getColumn(state, 'top'), + m: (state) => this.getColumn(state, 'middle'), + b: (state) => this.getColumn(state, 'bottom'), + w: (state) => this.getColumn(state, 'top', ''), + W: (state) => this.getColumn(state, 'top', ''), + '|': (state) => this.addRule(state, 'solid'), + ':': (state) => this.addRule(state, 'dashed'), + '>': (state) => + (state.cstart[state.j] = + (state.cstart[state.j] || '') + this.getBraces(state)), + '<': (state) => + (state.cend[state.j - 1] = + (state.cend[state.j - 1] || '') + this.getBraces(state)), + '@': (state) => this.addAt(state, this.getBraces(state)), + '!': (state) => this.addBang(state, this.getBraces(state)), + '*': (state) => this.repeat(state), + // + // Non-standard for math-mode versions + // + P: (state) => this.macroColumn(state, '>{$}p{#1}<{$}', 1), + M: (state) => this.macroColumn(state, '>{$}m{#1}<{$}', 1), + B: (state) => this.macroColumn(state, '>{$}b{#1}<{$}', 1), + // + // Ignored + // + ' ': (_state) => {}, + }; + + /** + * The maximum number of column specifiers to process (prevents loops from \newcolumntype). + */ + public MAXCOLUMNS: number = 10000; + + /** + * Process an array column template + * + * @param {TexParser} parser The active TexParser + * @param {string} template The alignment template + * @param {ArrayItem} array The ArrayItem for the template + */ + public process(parser: TexParser, template: string, array: ArrayItem) { + // + // Initialize the state + // + const state: ColumnState = { + parser, + template, + i: 0, + j: 0, + c: '', + cwidth: [], + calign: [], + cspace: [], + clines: [], + cstart: array.cstart, + cend: array.cend, + ralign: array.ralign, + cextra: array.cextra, + }; + // + // Loop through the template to process the column specifiers + // + let n = 0; + while (state.i < state.template.length) { + if (n++ > this.MAXCOLUMNS) { + throw new TexError( + 'MaxColumns', + 'Too many column specifiers (perhaps looping column definitions?)' + ); + } + const code = state.template.codePointAt(state.i); + const c = (state.c = String.fromCodePoint(code)); + state.i += c.length; + if (!Object.hasOwn(this.columnHandler, c)) { + throw new TexError('BadPreamToken', 'Illegal pream-token (%1)', c); + } + this.columnHandler[c](state); + } + // + // Set array definition values + // + this.setColumnAlign(state, array); + this.setColumnWidths(state, array); + this.setColumnSpacing(state, array); + this.setColumnLines(state, array); + this.setPadding(state, array); + } + + /** + * @param {ColumnState} state The current state of the parser + * @param {ArrayItem} array The array stack item to adjust + */ + protected setColumnAlign(state: ColumnState, array: ArrayItem) { + array.arraydef.columnalign = state.calign.join(' '); + } + + /** + * @param {ColumnState} state The current state of the parser + * @param {ArrayItem} array The array stack item to adjust + */ + protected setColumnWidths(state: ColumnState, array: ArrayItem) { + if (!state.cwidth.length) return; + const cwidth = [...state.cwidth]; + if (cwidth.length < state.calign.length) { + cwidth.push('auto'); + } + array.arraydef.columnwidth = cwidth.map((w) => w || 'auto').join(' '); + } + + /** + * @param {ColumnState} state The current state of the parser + * @param {ArrayItem} array The array stack item to adjust + */ + protected setColumnSpacing(state: ColumnState, array: ArrayItem) { + if (!state.cspace.length) return; + const cspace = [...state.cspace]; + if (cspace.length < state.calign.length) { + cspace.push('1em'); + } + array.arraydef.columnspacing = cspace + .slice(1) + .map((d) => d || '1em') + .join(' '); + } + + /** + * @param {ColumnState} state The current state of the parser + * @param {ArrayItem} array The array stack item to adjust + */ + protected setColumnLines(state: ColumnState, array: ArrayItem) { + if (!state.clines.length) return; + const clines = [...state.clines]; + if (clines[0]) { + // @test Enclosed left right, Enclosed left + array.frame.push(['left', clines[0]]); + } + if (clines.length > state.calign.length) { + // @test Enclosed left right, Enclosed right + array.frame.push(['right', clines.pop()]); + } else if (clines.length < state.calign.length) { + clines.push('none'); + } + if (clines.length > 1) { + // @test Enclosed left right + array.arraydef.columnlines = clines + .slice(1) + .map((l) => l || 'none') + .join(' '); + } + } + + /** + * @param {ColumnState} state The current state of the parser + * @param {ArrayItem} array The array stack item to adjust + */ + protected setPadding(state: ColumnState, array: ArrayItem) { + if (!state.cextra[0] && !state.cextra[state.calign.length - 1]) return; + const i = state.calign.length - 1; + const cspace = state.cspace; + const space = !state.cextra[i] ? null : cspace[i]; + array.arraydef['data-array-padding'] = + `${cspace[0] || '.5em'} ${space || '.5em'}`; + } + + /** + * Read a p/m/b/w/W column declaration + * + * @param {ColumnState} state The current state of the parser + * @param {number} ralign The vertical alignment for the column + * @param {string=} calign The column alignment ('' means get it as an argument) + */ + public getColumn( + state: ColumnState, + ralign: string, + calign: string = 'left' + ) { + state.calign[state.j] = calign || this.getAlign(state); + state.cwidth[state.j] = this.getDimen(state); + state.ralign[state.j] = [ + ralign, + state.cwidth[state.j], + state.calign[state.j], + ]; + state.j++; + } + + /** + * Get a dimension argument + * + * @param {ColumnState} state The current state of the parser + * + * @returns {string} The dimension string + */ + public getDimen(state: ColumnState): string { + const dim = this.getBraces(state); + if (!UnitUtil.matchDimen(dim)[0]) { + throw new TexError( + 'MissingColumnDimOrUnits', + 'Missing dimension or its units for %1 column declaration', + state.c + ); + } + return dim; + } + + /** + * Get an alignment argument + * + * @param {ColumnState} state The current state of the parser + * + * @returns {string} The alignment string + */ + public getAlign(state: ColumnState): string { + const align = this.getBraces(state); + return lookup( + align.toLowerCase(), + { l: 'left', c: 'center', r: 'right' }, + '' + ); + } + + /** + * Get a braced argument + * + * @param {ColumnState} state The current state of the parser + * + * @returns {string} The argument string + */ + public getBraces(state: ColumnState): string { + while (state.template[state.i] === ' ') state.i++; + if (state.i >= state.template.length) { + throw new TexError( + 'MissingArgForColumn', + 'Missing argument for %1 column declaration', + state.c + ); + } + if (state.template[state.i] !== '{') { + return state.template[state.i++]; + } + const i = ++state.i; + let braces = 1; + while (state.i < state.template.length) { + switch (state.template.charAt(state.i++)) { + case '\\': + state.i++; + break; + case '{': + braces++; + break; + case '}': + if (--braces === 0) { + return state.template.slice(i, state.i - 1); + } + break; + } + } + throw new TexError('MissingCloseBrace', 'Missing close brace'); + } + + /** + * Handle \newcolumntype declarations + * + * @param {ColumnState} state The current state of the parser + * @param {string} macro The replacement string for the column type + * @param {number} n The number of arguments for the column type + */ + public macroColumn(state: ColumnState, macro: string, n: number) { + const args: string[] = []; + while (n > 0 && n--) { + args.push(this.getBraces(state)); + } + state.template = + ParseUtil.substituteArgs(state.parser, args, macro) + + state.template.slice(state.i); + state.i = 0; + } + + /** + * @param {ColumnState} state The current state of the parser + * @param {string} rule The type of rule to add (solid or dashed) + */ + public addRule(state: ColumnState, rule: string) { + if (state.clines[state.j]) { + this.addAt(state, '\\,'); + } + state.clines[state.j] = rule; + if (state.cspace[state.j] === '0') { + state.cstart[state.j] = '\\hspace{.5em}'; + } + } + + /** + * Add an @{...} entry + * + * @param {ColumnState} state The current state of the parser + * @param {string} macro The replacement string for the column type + */ + public addAt(state: ColumnState, macro: string) { + const { cstart, cspace, j } = state; + state.cextra[j] = true; + state.calign[j] = 'center'; + if (state.clines[j]) { + if (cspace[j] === '.5em') { + cstart[j - 1] += '\\hspace{.25em}'; + } else if (!cspace[j]) { + state.cend[j - 1] = (state.cend[j - 1] || '') + '\\hspace{.5em}'; + } + } + cstart[j] = macro; + cspace[j] = '0'; + cspace[++state.j] = '0'; + } + + /** + * Add a !{...} entry + * + * @param {ColumnState} state The current state of the parser + * @param {string} macro The replacement string for the column type + */ + public addBang(state: ColumnState, macro: string) { + const { cstart, cspace, j } = state; + state.cextra[j] = true; + state.calign[j] = 'center'; + cstart[j] = + (cspace[j] === '0' && state.clines[j] ? '\\hspace{.25em}' : '') + macro; + if (!cspace[j]) { + cspace[j] = '.5em'; + } + cspace[++state.j] = '.5em'; + } + + /** + * Add a *{n}{...} entry + * + * @param {ColumnState} state The current state of the parser + */ + public repeat(state: ColumnState) { + const num = this.getBraces(state); + const cols = this.getBraces(state); + const n = parseInt(num); + if (String(n) !== num) { + throw new TexError( + 'ColArgNotNum', + 'First argument to %1 column specifier must be a number', + '*' + ); + } + state.template = + new Array(n).fill(cols).join('') + state.template.substring(state.i); + state.i = 0; + } +} diff --git a/ts/input/tex/Configuration.ts b/ts/input/tex/Configuration.ts index 5eb3c23d2..c4187d21e 100644 --- a/ts/input/tex/Configuration.ts +++ b/ts/input/tex/Configuration.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,84 +15,100 @@ * limitations under the License. */ - /** - * @fileoverview Configuration options for the TexParser. + * @file Configuration options for the TexParser. * * @author v.sorge@mathjax.org (Volker Sorge) */ -import {HandlerConfig, FallbackConfig} from './MapHandler.js'; -import {StackItemClass} from './StackItem.js'; -import {TagsClass} from './Tags.js'; -import {userOptions, defaultOptions, OptionList} from '../../util/Options.js'; -import {SubHandlers} from './MapHandler.js'; -import {FunctionList} from '../../util/FunctionList.js'; -import {TeX} from '../tex.js'; -import {PrioritizedList} from '../../util/PrioritizedList.js'; -import {TagsFactory} from './Tags.js'; - - -export type StackItemConfig = {[kind: string]: StackItemClass}; -export type TagsConfig = {[kind: string]: TagsClass}; +import { HandlerType, ConfigurationType } from './HandlerTypes.js'; +import { HandlerConfig, FallbackConfig } from './MapHandler.js'; +import { StackItemClass } from './StackItem.js'; +import { TagsClass } from './Tags.js'; +import { userOptions, defaultOptions, OptionList } from '../../util/Options.js'; +import { SubHandlers } from './MapHandler.js'; +import { FunctionList } from '../../util/FunctionList.js'; +import { TeX } from '../tex.js'; +import { PrioritizedList } from '../../util/PrioritizedList.js'; +import { TagsFactory } from './Tags.js'; + +export type StackItemConfig = { [kind: string]: StackItemClass }; +export type TagsConfig = { [kind: string]: TagsClass }; export type Processor = [T, number]; export type ProtoProcessor = Processor | T; -export type ProcessorList = Processor[]; -export type ConfigMethod = (c: ParserConfiguration, j: TeX) => void; +type ProcessorMethod = (data: any) => void; +export type ProcessorList = Processor[]; +export type ConfigMethod = ( + c: ParserConfiguration, + j: TeX +) => void; export type InitMethod = (c: ParserConfiguration) => void; - - export class Configuration { - /** * Creates a function priority pair. + * * @param {ProtoProcessor} func The function or processor. * @param {number} priority The default priority. - * @return {Processor} The processor pair. + * @returns {Processor} The processor pair. * @template T */ - private static makeProcessor(func: ProtoProcessor, priority: number): Processor { + private static makeProcessor( + func: ProtoProcessor, + priority: number + ): Processor { return Array.isArray(func) ? func : [func, priority]; } /** * Creates a configuration for a package. + * * @param {string} name The package name or empty string. - * @param {Object} config See `create` method. - * @return {Configuration} The newly generated configuration. + * @param {object} config See `create` method. + * @returns {Configuration} The newly generated configuration. */ - private static _create(name: string, - config: {handler?: HandlerConfig, - fallback?: FallbackConfig, - items?: StackItemConfig, - tags?: TagsConfig, - options?: OptionList, - nodes?: {[key: string]: any}, - preprocessors?: ProtoProcessor[], - postprocessors?: ProtoProcessor[], - init?: ProtoProcessor, - config?: ProtoProcessor, - priority?: number, - parser?: string, - } = {}): Configuration { - let priority = config.priority || PrioritizedList.DEFAULTPRIORITY; - let init = config.init ? this.makeProcessor(config.init, priority) : null; - let conf = config.config ? this.makeProcessor(config.config, priority) : null; - let preprocessors = (config.preprocessors || []).map( - pre => this.makeProcessor(pre, priority)); - let postprocessors = (config.postprocessors || []).map( - post => this.makeProcessor(post, priority)); - let parser = config.parser || 'tex'; + private static _create( + name: string, + config: { + [ConfigurationType.HANDLER]?: HandlerConfig; + [ConfigurationType.FALLBACK]?: FallbackConfig; + [ConfigurationType.ITEMS]?: StackItemConfig; + [ConfigurationType.TAGS]?: TagsConfig; + [ConfigurationType.OPTIONS]?: OptionList; + [ConfigurationType.NODES]?: { [key: string]: any }; + [ConfigurationType.PREPROCESSORS]?: ProtoProcessor[]; + [ConfigurationType.POSTPROCESSORS]?: ProtoProcessor[]; + [ConfigurationType.INIT]?: ProtoProcessor; + [ConfigurationType.CONFIG]?: ProtoProcessor; + [ConfigurationType.PRIORITY]?: number; + [ConfigurationType.PARSER]?: string; + } = {} + ): Configuration { + const priority = config.priority ?? PrioritizedList.DEFAULTPRIORITY; + const init = config.init ? this.makeProcessor(config.init, priority) : null; + const conf = config.config + ? this.makeProcessor(config.config, priority) + : null; + const preprocessors = (config.preprocessors || []).map((pre) => + this.makeProcessor(pre, priority) + ); + const postprocessors = (config.postprocessors || []).map((post) => + this.makeProcessor(post, priority) + ); + const parser = config.parser || 'tex'; return new Configuration( name, - config.handler || {}, - config.fallback || {}, - config.items || {}, - config.tags || {}, - config.options || {}, - config.nodes || {}, - preprocessors, postprocessors, init, conf, priority, + config[ConfigurationType.HANDLER] || {}, + config[ConfigurationType.FALLBACK] || {}, + config[ConfigurationType.ITEMS] || {}, + config[ConfigurationType.TAGS] || {}, + config[ConfigurationType.OPTIONS] || {}, + config[ConfigurationType.NODES] || {}, + preprocessors, + postprocessors, + init, + conf, + priority, parser ); } @@ -100,40 +116,44 @@ export class Configuration { /** * Creator pattern for creating a named package configuration. This will be * administered in the configuration handler and can be retrieved again. + * * @param {string} name The package name. - * @param {Object} config The configuration parameters: + * @param {object} config The configuration parameters: * Configuration for the TexParser consist of the following: - * * _handler_ configuration mapping handler types to lists of symbol mappings. - * * _fallback_ configuration mapping handler types to fallback methods. - * * _items_ for the StackItem factory. - * * _tags_ mapping tagging configurations to tagging objects. - * * _options_ parse options for the packages. - * * _nodes_ for the Node factory. - * * _preprocessors_ list of functions for preprocessing the LaTeX + * _handler_ configuration mapping handler types to lists of token mappings. + * _fallback_ configuration mapping handler types to fallback methods. + * _items_ for the StackItem factory. + * _tags_ mapping tagging configurations to tagging objects. + * _options_ parse options for the packages. + * _nodes_ for the Node factory. + * _preprocessors_ list of functions for preprocessing the LaTeX * string wrt. to given parse options. Can contain a priority. - * * _postprocessors_ list of functions for postprocessing the MmlNode + * _postprocessors_ list of functions for postprocessing the MmlNode * wrt. to given parse options. Can contain a priority. - * * _init_ init method and optionally its priority. - * * _config_ config method and optionally its priority. - * * _priority_ default priority of the configuration. - * * _parser_ the name of the parser that this configuration targets. - * @return {Configuration} The newly generated configuration. + * _init_ init method and optionally its priority. + * _config_ config method and optionally its priority. + * _priority_ default priority of the configuration. + * _parser_ the name of the parser that this configuration targets. + * @returns {Configuration} The newly generated configuration. */ - public static create(name: string, - config: {handler?: HandlerConfig, - fallback?: FallbackConfig, - items?: StackItemConfig, - tags?: TagsConfig, - options?: OptionList, - nodes?: {[key: string]: any}, - preprocessors?: ProtoProcessor[], - postprocessors?: ProtoProcessor[], - init?: ProtoProcessor, - config?: ProtoProcessor, - priority?: number, - parser?: string, - } = {}): Configuration { - let configuration = Configuration._create(name, config); + public static create( + name: string, + config: { + [ConfigurationType.HANDLER]?: HandlerConfig; + [ConfigurationType.FALLBACK]?: FallbackConfig; + [ConfigurationType.ITEMS]?: StackItemConfig; + [ConfigurationType.TAGS]?: TagsConfig; + [ConfigurationType.OPTIONS]?: OptionList; + [ConfigurationType.NODES]?: { [key: string]: any }; + [ConfigurationType.PREPROCESSORS]?: ProtoProcessor[]; + [ConfigurationType.POSTPROCESSORS]?: ProtoProcessor[]; + [ConfigurationType.INIT]?: ProtoProcessor; + [ConfigurationType.CONFIG]?: ProtoProcessor; + [ConfigurationType.PRIORITY]?: number; + [ConfigurationType.PARSER]?: string; + } = {} + ): Configuration { + const configuration = Configuration._create(name, config); ConfigurationHandler.set(name, configuration); return configuration; } @@ -141,50 +161,77 @@ export class Configuration { /** * Creates an unnamed, ephemeral package configuration. It will not added to * the configuration handler. - * @param {Object} config See `create` method. - * @return {Configuration} The ephemeral package configuration. + * + * @param {object} config See `create` method. + * @returns {Configuration} The ephemeral package configuration. */ - public static local(config: {handler?: HandlerConfig, - fallback?: FallbackConfig, - items?: StackItemConfig, - tags?: TagsConfig, - options?: OptionList, - nodes?: {[key: string]: any}, - preprocessors?: ProtoProcessor[], - postprocessors?: ProtoProcessor[], - init?: ProtoProcessor, - config?: ProtoProcessor, - priority?: number, - parser?: string, - } = {}): Configuration { + public static local( + config: { + [ConfigurationType.HANDLER]?: HandlerConfig; + [ConfigurationType.FALLBACK]?: FallbackConfig; + [ConfigurationType.ITEMS]?: StackItemConfig; + [ConfigurationType.TAGS]?: TagsConfig; + [ConfigurationType.OPTIONS]?: OptionList; + [ConfigurationType.NODES]?: { [key: string]: any }; + [ConfigurationType.PREPROCESSORS]?: ProtoProcessor[]; + [ConfigurationType.POSTPROCESSORS]?: ProtoProcessor[]; + [ConfigurationType.INIT]?: ProtoProcessor; + [ConfigurationType.CONFIG]?: ProtoProcessor; + [ConfigurationType.PRIORITY]?: number; + [ConfigurationType.PARSER]?: string; + } = {} + ): Configuration { return Configuration._create('', config); } - /** - * @constructor + * @param {string} name package name for the configuration + * @param {HandlerConfig} handler configuration mapping handler types to lists of token mappings. + * @param {FallbackConfig} fallback configuration mapping handler types to fallback methods. + * @param {StackItemConfig} items for the StackItem factory. + * @param {TagsConfig} tags mapping tagging configurations to tagging objects. + * @param {OptionList} options parse options for the packages. + * @param {{ [key: string]: any }} nodes for the Node factory. + * @param {ProcessorList} preprocessors list of functions for preprocessing the LaTeX + * string wrt. to given parse options. Can contain a priority. + * @param {ProcessorList} postprocessors list of functions for postprocessing the MmlNode + * wrt. to given parse options. Can contain a priority. + * @param {Processor} initMethod init method and optionally its priority. + * @param {Processor} configMethod config method and optionally its priority. + * @param {number} priority default priority of the configuration. + * @param {string} parser the name of the parser that this configuration targets. + * @class */ - private constructor(readonly name: string, - readonly handler: HandlerConfig = {}, - readonly fallback: FallbackConfig = {}, - readonly items: StackItemConfig = {}, - readonly tags: TagsConfig = {}, - readonly options: OptionList = {}, - readonly nodes: {[key: string]: any} = {}, - readonly preprocessors: ProcessorList = [], - readonly postprocessors: ProcessorList = [], - readonly initMethod: Processor = null, - readonly configMethod: Processor = null, - public priority: number, - readonly parser: string - ) { + private constructor( + readonly name: string, + readonly handler: HandlerConfig = {}, + readonly fallback: FallbackConfig = {}, + readonly items: StackItemConfig = {}, + readonly tags: TagsConfig = {}, + readonly options: OptionList = {}, + readonly nodes: { [key: string]: any } = {}, + readonly preprocessors: ProcessorList = [], + readonly postprocessors: ProcessorList = [], + readonly initMethod: Processor = null, + readonly configMethod: Processor = null, + public priority: number, + readonly parser: string + ) { this.handler = Object.assign( - {character: [], delimiter: [], macro: [], environment: []}, handler); + { + [HandlerType.CHARACTER]: [], + [HandlerType.DELIMITER]: [], + [HandlerType.MACRO]: [], + [HandlerType.ENVIRONMENT]: [], + }, + handler + ); } /** * The init method. - * @type {Function} + * + * @type {ProcessorMethod} */ public get init(): InitMethod { return this.initMethod ? this.initMethod[0] : null; @@ -192,74 +239,73 @@ export class Configuration { /** * The config method to call once jax is ready. + * * @type {FunctionList} */ public get config(): ConfigMethod { return this.configMethod ? this.configMethod[0] : null; } - } +const maps: Map = new Map(); -export namespace ConfigurationHandler { - - let maps: Map = new Map(); - +export const ConfigurationHandler = { /** * Adds a new configuration to the handler overwriting old ones. * * @param {string} name The name of the configuration. * @param {Configuration} map The configuration mapping. */ - export let set = function(name: string, map: Configuration): void { + set(name: string, map: Configuration): void { maps.set(name, map); - }; - + }, /** * Looks up a configuration. * * @param {string} name The name of the configuration. - * @return {Configuration} The configuration with the given name or null. + * @returns {Configuration} The configuration with the given name or null. */ - export let get = function(name: string): Configuration { + get(name: string): Configuration { return maps.get(name); - }; + }, /** - * @return {string[]} All configurations in the handler. + * @returns {string[]} All configurations in the handler. */ - export let keys = function(): IterableIterator { + keys(): IterableIterator { return maps.keys(); - }; - -} - + }, +}; /** * Parser configuration combines the configurations of the currently selected * packages. - * @constructor + * + * @class */ export class ParserConfiguration { - /** * Priority list of init methods. + * * @type {FunctionList} */ protected initMethod: FunctionList = new FunctionList(); /** * Priority list of init methods to call once jax is ready. + * * @type {FunctionList} */ protected configMethod: FunctionList = new FunctionList(); /** * An ordered list of cofigurations. + * * @type {PrioritizedList} */ - protected configurations: PrioritizedList = new PrioritizedList(); + protected configurations: PrioritizedList = + new PrioritizedList(); /** * The list of parsers this configuration targets @@ -268,46 +314,54 @@ export class ParserConfiguration { /** * The subhandlers for this configuration. + * * @type {SubHandlers} */ public handlers: SubHandlers = new SubHandlers(); /** * The collated stack items. + * * @type {StackItemConfig} */ public items: StackItemConfig = {}; /** * The collated tag configurations. + * * @type {TagsConfig} */ public tags: TagsConfig = {}; /** * The collated options. + * * @type {OptionList} */ public options: OptionList = {}; /** * The collated node creators. + * * @type {{[key: string]: any}} */ - public nodes: {[key: string]: any} = {}; + public nodes: { [key: string]: any } = {}; /** - * @constructor + * @class * @param {(string|[string,number])[]} packages A list of packages with * optional priorities. - * @parm {string[]} parsers The names of the parsers this package targets + * @param {string[]} parsers The names of the parsers this package targets */ - constructor(packages: (string | [string, number])[], parsers: string[] = ['tex']) { + constructor( + packages: (string | [string, number])[], + parsers: string[] = ['tex'] + ) { this.parsers = parsers; for (const pkg of packages.slice().reverse()) { this.addPackage(pkg); } - for (let {item: config, priority: priority} of this.configurations) { + for (const { item: config, priority: priority } of this.configurations) { this.append(config, priority); } } @@ -321,6 +375,7 @@ export class ParserConfiguration { /** * Init method for when the jax is ready + * * @param {TeX} jax The TeX jax for this configuration */ public config(jax: TeX) { @@ -332,12 +387,18 @@ export class ParserConfiguration { /** * Retrieves and adds configuration for a package with priority. - * @param {(string | [string, number]} pkg Package with priority. + * + * @param {string | [string, number]} pkg Package with priority. */ - public addPackage(pkg: (string | [string, number])) { + public addPackage(pkg: string | [string, number]) { const name = typeof pkg === 'string' ? pkg : pkg[0]; const conf = this.getPackage(name); - conf && this.configurations.add(conf, typeof pkg === 'string' ? conf.priority : pkg[1]); + if (conf) { + this.configurations.add( + conf, + typeof pkg === 'string' ? conf.priority : pkg[1] + ); + } } /** @@ -367,22 +428,26 @@ export class ParserConfiguration { } } - /** - * Find a package and check that it is for the targeted parser - * - * @param {string} name The name of the package to check - * @return {Configuration} The configuration for the package - */ + /** + * Find a package and check that it is for the targeted parser + * + * @param {string} name The name of the package to check + * @returns {Configuration} The configuration for the package + */ protected getPackage(name: string): Configuration { const config = ConfigurationHandler.get(name); - if (config && this.parsers.indexOf(config.parser) < 0) { - throw Error(`Package ${name} doesn't target the proper parser`); + if (config && !this.parsers.includes(config.parser)) { + throw Error(`Package '${name}' doesn't target the proper parser`); + } + if (!config) { + this.warn(`Package '${name}' not found. Omitted.`); } return config; } /** * Appends a configuration to the overall configuration object. + * * @param {Configuration} config A configuration. * @param {number} priority The configurations optional priority. */ @@ -392,8 +457,8 @@ export class ParserConfiguration { this.initMethod.add(config.initMethod[0], config.initMethod[1]); } if (config.configMethod) { - this.configMethod.add(config.configMethod[0], config.configMethod[1]); - } + this.configMethod.add(config.configMethod[0], config.configMethod[1]); + } this.handlers.add(config.handler, config.fallback, priority); Object.assign(this.items, config.items); Object.assign(this.tags, config.tags); @@ -403,7 +468,8 @@ export class ParserConfiguration { /** * Adds pre- and postprocessor as filters to the jax. - * @param {TeX, config: Configuration) { @@ -415,4 +481,12 @@ export class ParserConfiguration { } } + /** + * Prints a warning message. + * + * @param {string} message The warning. + */ + private warn(message: string) { + console.warn('MathJax Warning: ' + message); + } } diff --git a/ts/input/tex/FilterUtil.ts b/ts/input/tex/FilterUtil.ts index 7844629bc..6895b4605 100644 --- a/ts/input/tex/FilterUtil.ts +++ b/ts/input/tex/FilterUtil.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,33 +16,151 @@ */ /** - * @fileoverview Utility functions for standard pre and post filters. + * @file Utility functions for standard pre and post filters. * * @author sorge@mathjax.org (Volker Sorge) */ - -import {TEXCLASS, MMLNODE, MmlNode} from '../../core/MmlTree/MmlNode.js'; +import { TEXCLASS, MMLNODE, MmlNode } from '../../core/MmlTree/MmlNode.js'; import NodeUtil from './NodeUtil.js'; import ParseOptions from './ParseOptions.js'; -import {MmlMo} from '../../core/MmlTree/MmlNodes/mo.js'; -import {Attributes} from '../../core/MmlTree/Attributes.js'; +import { MmlMo } from '../../core/MmlTree/MmlNodes/mo.js'; +import { Attributes } from '../../core/MmlTree/Attributes.js'; + +/** + * Copies the specified explicit attributes from node2 to node1. + * + * @param {string[]} attrs List of explicit attribute names. + * @param {MmlNode} node1 The goal node. + * @param {MmlNode} node2 The source node. + */ +function _copyExplicit(attrs: string[], node1: MmlNode, node2: MmlNode) { + const attr1 = node1.attributes; + const attr2 = node2.attributes; + attrs.forEach((x) => { + const attr = attr2.getExplicit(x); + if (attr != null) { + // @test Infix Stretchy Right, Preset Lspace Rspace + attr1.set(x, attr); + } + }); +} +/** + * Compares the explicit attributes of two nodes. Returns true if they + * coincide, with the following exceptions: + * - lspace attribute of node1 is ignored. + * - rspace attribute of node2 is ignored. + * - stretchy=false attributes are ignored. + * - data-latex and -data-latex-item are ignored. + * + * @param {MmlNode} node1 The first node. + * @param {MmlNode} node2 Its next sibling. + * @returns {boolean} The true of attribute equal. + */ +function _compareExplicit(node1: MmlNode, node2: MmlNode): boolean { + const filter = (attr: Attributes, space: string): string[] => { + const exp = attr.getExplicitNames(); + return exp.filter((x) => { + return ( + x !== space && + (x !== 'stretchy' || attr.getExplicit('stretchy')) && + x !== 'data-latex' && + x !== 'data-latex-item' + ); + }); + }; + const attr1 = node1.attributes; + const attr2 = node2.attributes; + const exp1 = filter(attr1, 'lspace'); + const exp2 = filter(attr2, 'rspace'); + if (exp1.length !== exp2.length) { + return false; + } + for (const name of exp1) { + if (attr1.getExplicit(name) !== attr2.getExplicit(name)) { + return false; + } + } + return true; +} -namespace FilterUtil { +/** + * Cleans msubsup and munderover elements. + * + * @param {ParseOptions} options The parse options. + * @param {string} low String representing the lower part of the expression. + * @param {string} up String representing the upper part. + */ +function _cleanSubSup(options: ParseOptions, low: string, up: string) { + const remove: MmlNode[] = []; + for (const mml of options.getList('m' + low + up) as any[]) { + const children = mml.childNodes; + if (children[mml[low]] && children[mml[up]]) { + continue; + } + const parent = mml.parent; + const newNode = children[mml[low]] + ? options.nodeFactory.create('node', 'm' + low, [ + children[mml.base], + children[mml[low]], + ]) + : options.nodeFactory.create('node', 'm' + up, [ + children[mml.base], + children[mml[up]], + ]); + NodeUtil.copyAttributes(mml, newNode); + parent.replaceChild(newNode, mml); + remove.push(mml); + } + options.removeFromList('m' + low + up, remove); +} +/** + * Looks through the list of munderover elements for ones that have + * movablelimits and bases that are not mo's, and creates new msubsup + * elements to replace them if they aren't in displaystyle. + * + * @param {ParseOptions} options The parse options. + * @param {string} underover The name of the under over element. + * @param {string} subsup The name of the sub superscript element. + */ +function _moveLimits(options: ParseOptions, underover: string, subsup: string) { + const remove: MmlNode[] = []; + for (const mml of options.getList(underover)) { + if (mml.attributes.get('displaystyle')) { + continue; + } + const base = mml.childNodes[(mml as any).base]; + const mo = base.coreMO(); + if ( + base.getProperty('movablelimits') && + !mo.attributes.hasExplicit('movablelimits') + ) { + const node = options.nodeFactory.create('node', subsup, mml.childNodes); + NodeUtil.copyAttributes(mml, node); + mml.parent.replaceChild(node, mml); + remove.push(mml); + } + } + options.removeFromList(underover, remove); +} + +const FilterUtil = { /** * Visitor to set stretchy attributes to false on elements, if they are * not used as delimiters. Also wraps non-stretchy infix delimiters into a * TeXAtom. - * @param {MmlNode} math The node to rewrite. - * @param {ParseOptions} data The parse options. + * + * @param {object} arg The argument object. + * @param {MmlNode} arg.math The node to rewrite. + * @param {ParseOptions} arg.data The parse options. */ - export let cleanStretchy = function(arg: {math: any, data: ParseOptions}) { - let options = arg.data; - for (let mo of options.getList('fixStretchy')) { + cleanStretchy(arg: { math: any; data: ParseOptions }) { + const options = arg.data; + for (const mo of options.getList('fixStretchy')) { if (NodeUtil.getProperty(mo, 'fixStretchy')) { - let symbol = NodeUtil.getForm(mo); + const symbol = NodeUtil.getForm(mo); if (symbol && symbol[3] && symbol[3]['stretchy']) { NodeUtil.setAttribute(mo, 'stretchy', false); } @@ -55,57 +173,69 @@ namespace FilterUtil { NodeUtil.removeProperties(mo, 'fixStretchy'); } } - }; - + }, /** * Visitor that removes superfluous attributes from nodes. I.e., if a node has * an attribute, which is also an inherited attribute it will be removed. This * is necessary as attributes are set bottom up in the parser. - * @param {ParseOptions} data The parse options. + * + * @param {object} arg The argument object. + * @param {ParseOptions} arg.data The parse options. */ - export let cleanAttributes = function(arg: {data: ParseOptions}) { - let node = arg.data.root as MmlNode; + cleanAttributes(arg: { data: ParseOptions }) { + const node = arg.data.root; node.walkTree((mml: MmlNode, _d: any) => { - let attribs = mml.attributes as any; - if (!attribs) { - return; - } - const keep = new Set((attribs.get('mjx-keep-attrs') || '').split(/ /)); - delete (attribs.getAllAttributes())['mjx-keep-attrs']; + const attribs = mml.attributes; + const keep = new Set( + ((attribs.get('mjx-keep-attrs') as string) || '').split(/ /) + ); + attribs.unset('mjx-keep-attrs'); for (const key of attribs.getExplicitNames()) { - if (!keep.has(key) && attribs.attributes[key] === mml.attributes.getInherited(key)) { - delete attribs.attributes[key]; + if ( + !keep.has(key) && + attribs.get(key) === mml.attributes.getInherited(key) + ) { + attribs.unset(key); } } }, {}); - }; - + }, /** * Combine adjacent elements that are relations (since MathML treats the * spacing very differently) - * @param {ParseOptions} data The parse options. + * + * @param {object} arg The argument object. + * @param {ParseOptions} arg.data The parse options. */ - export let combineRelations = function(arg: {data: ParseOptions}) { + combineRelations(arg: { data: ParseOptions }) { const remove: MmlNode[] = []; - for (let mo of arg.data.getList('mo')) { - if (mo.getProperty('relationsCombined') || !mo.parent || - (mo.parent && !NodeUtil.isType(mo.parent, 'mrow')) || - NodeUtil.getTexClass(mo) !== TEXCLASS.REL) { + for (const mo of arg.data.getList('mo')) { + if ( + mo.getProperty('relationsCombined') || + !mo.parent || + (mo.parent && !NodeUtil.isType(mo.parent, 'mrow')) || + NodeUtil.getTexClass(mo) !== TEXCLASS.REL + ) { // @test Prime, PrimeSup, Named Function continue; } - let mml = mo.parent; + const mml = mo.parent; let m2: MmlNode; - let children = mml.childNodes as MMLNODE[]; - let next = children.indexOf(mo) + 1; - let variantForm = NodeUtil.getProperty(mo, 'variantForm'); - while (next < children.length && (m2 = children[next]) && - NodeUtil.isType(m2, 'mo') && - NodeUtil.getTexClass(m2) === TEXCLASS.REL) { - if (variantForm === NodeUtil.getProperty(m2, 'variantForm') && - _compareExplicit(mo, m2)) { + const children = mml.childNodes as MMLNODE[]; + const next = children.indexOf(mo) + 1; + const variantForm = NodeUtil.getProperty(mo, 'variantForm'); + while ( + next < children.length && + (m2 = children[next]) && + NodeUtil.isType(m2, 'mo') && + NodeUtil.getTexClass(m2) === TEXCLASS.REL + ) { + if ( + variantForm === NodeUtil.getProperty(m2, 'variantForm') && + _compareExplicit(mo, m2) + ) { // @test Shift Left, Less Equal, // Multirel Font X, Multirel Mathvariant X NodeUtil.appendChildren(mo, NodeUtil.getChildren(m2)); @@ -115,17 +245,25 @@ namespace FilterUtil { for (const name of m2.getPropertyNames()) { mo.setProperty(name, m2.getProperty(name)); } + if (m2.attributes.get('data-latex')) { + mo.attributes.set( + 'data-latex', + (mo.attributes.get('data-latex') as string) + + (m2.attributes.get('data-latex') as string) + ); + } children.splice(next, 1); remove.push(m2); m2.parent = null; m2.setProperty('relationsCombined', true); + mo.setProperty('texClass', TEXCLASS.REL); } else { // @test Preset Rspace Lspace - if (mo.attributes.getExplicit('rspace') == null) { + if (!mo.attributes.hasExplicit('rspace')) { // @test Mulitrel Mathvariant 3, Mulitrel Mathvariant 4 NodeUtil.setAttribute(mo, 'rspace', '0pt'); } - if (m2.attributes.getExplicit('lspace') == null) { + if (!m2.attributes.hasExplicit('lspace')) { // @test Mulitrel Mathvariant 3, Mulitrel Mathvariant 4 NodeUtil.setAttribute(m2, 'lspace', '0pt'); } @@ -135,161 +273,82 @@ namespace FilterUtil { mo.attributes.setInherited('form', (mo as MmlMo).getForms()[0]); } arg.data.removeFromList('mo', remove); - }; - - - /** - * Copies the specified explicit attributes from node2 to node1. - * @param {string[]} attrs List of explicit attribute names. - * @param {MmlNode} node1 The goal node. - * @param {MmlNode} node2 The source node. - */ - let _copyExplicit = function(attrs: string[], - node1: MmlNode, node2: MmlNode) { - let attr1 = node1.attributes; - let attr2 = node2.attributes; - attrs.forEach(x => { - let attr = attr2.getExplicit(x); - if (attr != null) { - // @test Infix Stretchy Right, Preset Lspace Rspace - attr1.set(x, attr); - } - }); - }; - - - /** - * Compares the explicit attributes of two nodes. Returns true if they - * coincide, with the following exceptions: - * - lspace attribute of node1 is ignored. - * - rspace attribute of node2 is ignored. - * - stretchy=false attributes are ignored. - * @param {MmlNode} node1 The first node. - * @param {MmlNode} node2 Its next sibling. - */ - let _compareExplicit = function(node1: MmlNode, node2: MmlNode) { - let filter = (attr: Attributes, space: string): string[] => { - let exp = attr.getExplicitNames(); - return exp.filter(x => { - return x !== space && - (x !== 'stretchy' || - attr.getExplicit('stretchy')); - }); - }; - let attr1 = node1.attributes; - let attr2 = node2.attributes; - let exp1 = filter(attr1, 'lspace'); - let exp2 = filter(attr2, 'rspace'); - if (exp1.length !== exp2.length) { - return false; - } - for (let name of exp1) { - if (attr1.getExplicit(name) !== attr2.getExplicit(name)) { - return false; - } - } - return true; - }; - - /** - * Cleans msubsup and munderover elements. - * @param {ParseOptions} options The parse options. - * @param {string} low String representing the lower part of the expression. - * @param {string} up String representing the upper part. - */ - let _cleanSubSup = function(options: ParseOptions, low: string, up: string) { - const remove: MmlNode[] = []; - for (let mml of options.getList('m' + low + up) as any[]) { - const children = mml.childNodes; - if (children[mml[low]] && children[mml[up]]) { - continue; - } - const parent = mml.parent; - let newNode = (children[mml[low]] ? - options.nodeFactory.create('node', 'm' + low, [children[mml.base], children[mml[low]]]) : - options.nodeFactory.create('node', 'm' + up, [children[mml.base], children[mml[up]]])); - NodeUtil.copyAttributes(mml, newNode); - if (parent) { - parent.replaceChild(newNode, mml); - } else { - options.root = newNode; - } - remove.push(mml); - } - options.removeFromList('m' + low + up, remove); - }; - + }, /** * Visitor that rewrites incomplete msubsup/munderover elements in the given * node into corresponding msub/sup/under/over nodes. - * @param {MmlNode} math The node to rewrite. - * @param {ParseOptions} data The parse options. + * + * @param {object} arg The argument object. + * @param {MmlNode} arg.math The node to rewrite. + * @param {ParseOptions} arg.data The parse options. */ - export let cleanSubSup = function(arg: {math: any, data: ParseOptions}) { - let options = arg.data; + cleanSubSup(arg: { math: any; data: ParseOptions }) { + const options = arg.data; if (options.error) { return; } _cleanSubSup(options, 'sub', 'sup'); _cleanSubSup(options, 'under', 'over'); - }; - - - /** - * Looks through the list of munderover elements for ones that have - * movablelimits and bases that are not mo's, and creates new msubsup - * elements to replace them if they aren't in displaystyle. - * - * @param {MmlNode} ath The node to rewrite. - * @param {ParseOptions} data The parse options. - */ - let _moveLimits = function (options: ParseOptions, underover: string, subsup: string) { - const remove: MmlNode[] = []; - for (const mml of options.getList(underover)) { - if (mml.attributes.get('displaystyle')) { - continue; - } - const base = mml.childNodes[(mml as any).base] as MmlNode; - const mo = base.coreMO(); - if (base.getProperty('movablelimits') && !mo.attributes.getExplicit('movablelimits')) { - let node = options.nodeFactory.create('node', subsup, mml.childNodes); - NodeUtil.copyAttributes(mml, node); - if (mml.parent) { - mml.parent.replaceChild(node, mml); - } else { - options.root = node; - } - remove.push(mml); - } - } - options.removeFromList(underover, remove); - }; + }, /** * Visitor that rewrites in-line munderover elements with movablelimits but bases * that are not mo's into explicit msubsup elements. * - * @param {ParseOptions} data The parse options to use + * @param {object} arg The argument object. + * @param {ParseOptions} arg.data The parse options to use */ - export let moveLimits = function (arg: {data: ParseOptions}) { + moveLimits(arg: { data: ParseOptions }) { const options = arg.data; _moveLimits(options, 'munderover', 'msubsup'); _moveLimits(options, 'munder', 'msub'); _moveLimits(options, 'mover', 'msup'); - }; - + }, /** * Recursively sets the inherited attributes on the math tree. - * @param {MmlNode} math The node to rewrite. - * @param {ParseOptions} data The parse options. + * + * @param {object} arg The argument object. + * @param {MmlNode} arg.math The node to rewrite. + * @param {ParseOptions} arg.data The parse options. */ - export let setInherited = function(arg: {math: any, data: ParseOptions}) { + setInherited(arg: { math: any; data: ParseOptions }) { arg.data.root.setInheritedAttributes({}, arg.math['display'], 0, false); - }; - -} + }, + /** + * Removes unneeded mstyle elements that just set the scriptlevel + * + * @param {object} arg The argument object. + * @param {ParseOptions} arg.data The parse options. + */ + checkScriptlevel(arg: { data: ParseOptions }) { + const options = arg.data; + const remove: MmlNode[] = []; + for (const mml of options.getList('mstyle')) { + if (mml.childNodes[0].childNodes.length !== 1) { + continue; + } + const attributes = mml.attributes; + for (const key of ['displaystyle', 'scriptlevel']) { + if (attributes.getExplicit(key) === attributes.getInherited(key)) { + attributes.unset(key); + } + } + const names = attributes.getExplicitNames(); + if ( + names.filter((key) => key.substring(0, 10) !== 'data-latex').length === + 0 + ) { + const child = mml.childNodes[0].childNodes[0]; + names.forEach((key) => child.attributes.set(key, attributes.get(key))); + mml.parent.replaceChild(child, mml); + remove.push(mml); + } + } + options.removeFromList('mstyle', remove); + }, +}; export default FilterUtil; diff --git a/ts/input/tex/FindTeX.ts b/ts/input/tex/FindTeX.ts index 623604f42..bf2042b66 100644 --- a/ts/input/tex/FindTeX.ts +++ b/ts/input/tex/FindTeX.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,15 +16,15 @@ */ /** - * @fileoverview Implements the TeX version of the FindMath object + * @file Implements the TeX version of the FindMath object * * @author dpvc@mathjax.org (Davide Cervone) */ -import {AbstractFindMath} from '../../core/FindMath.js'; -import {OptionList} from '../../util/Options.js'; -import {sortLength, quotePattern} from '../../util/string.js'; -import {ProtoItem, protoItem} from '../../core/MathItem.js'; +import { AbstractFindMath } from '../../core/FindMath.js'; +import { OptionList } from '../../util/Options.js'; +import { sortLength, quotePattern } from '../../util/string.js'; +import { ProtoItem, protoItem } from '../../core/MathItem.js'; /** * Shorthand types for data about end delimiters and delimiter pairs @@ -39,16 +39,16 @@ export type Delims = [string, string]; * Locates TeX expressions within strings */ -/* +/** * @template N The HTMLElement node class * @template T The Text node class * @template D The Document class */ export class FindTeX extends AbstractFindMath { - /** * @type {OptionList} */ + /* prettier-ignore */ public static OPTIONS: OptionList = { inlineMath: [ // The start/end delimiter pairs for in-line math // ['$', '$'], // (comment out any you don't want, or add your own, but @@ -75,7 +75,7 @@ export class FindTeX extends AbstractFindMath { /** * The end-delimiter data keyed to the opening delimiter string */ - protected end: {[name: string]: EndItem}; + protected end: { [name: string]: EndItem }; /** * False if the configuration has no delimiters (so search can be skipped), true otherwise @@ -105,13 +105,19 @@ export class FindTeX extends AbstractFindMath { * based on the configuration options */ protected getPatterns() { - let options = this.options; - let starts: string[] = [], parts: string[] = [], subparts: string[] = []; + const options = this.options; + const starts: string[] = []; + const parts: string[] = []; + const subparts: string[] = []; this.end = {}; this.env = this.sub = 0; let i = 1; - options['inlineMath'].forEach((delims: Delims) => this.addPattern(starts, delims, false)); - options['displayMath'].forEach((delims: Delims) => this.addPattern(starts, delims, true)); + options['inlineMath'].forEach((delims: Delims) => + this.addPattern(starts, delims, false) + ); + options['displayMath'].forEach((delims: Delims) => + this.addPattern(starts, delims, true) + ); if (starts.length) { parts.push(starts.sort(sortLength).join('|')); } @@ -131,7 +137,7 @@ export class FindTeX extends AbstractFindMath { this.sub = i; } this.start = new RegExp(parts.join('|'), 'g'); - this.hasPatterns = (parts.length > 0); + this.hasPatterns = parts.length > 0; } /** @@ -142,7 +148,7 @@ export class FindTeX extends AbstractFindMath { * @param {boolean} display True if the delimiters are for display mode */ protected addPattern(starts: string[], delims: Delims, display: boolean) { - let [open, close] = delims; + const [open, close] = delims; starts.push(quotePattern(open)); this.end[open] = [close, display, this.endPattern(close)]; } @@ -152,10 +158,13 @@ export class FindTeX extends AbstractFindMath { * * @param {string} end The end delimiter text * @param {string} endp The end delimiter pattern (overrides the literal end pattern) - * @return {RegExp} The regular expression for the end delimiter + * @returns {RegExp} The regular expression for the end delimiter */ protected endPattern(end: string, endp?: string): RegExp { - return new RegExp((endp || quotePattern(end)) + '|\\\\(?:[a-zA-Z]|.)|[{}]', 'g'); + return new RegExp( + (endp || quotePattern(end)) + '|\\\\(?:[a-zA-Z]|.)|[{}]', + 'g' + ); } /** @@ -167,16 +176,29 @@ export class FindTeX extends AbstractFindMath { * @param {number} n The index of the string being searched * @param {RegExpExecArray} start The result array from the start-delimiter search * @param {EndItem} end The end-delimiter data corresponding to the start delimiter - * @return {ProtoItem} The proto math item for the math, if found + * @returns {ProtoItem} The proto math item for the math, if found */ - protected findEnd(text: string, n: number, start: RegExpExecArray, end: EndItem): ProtoItem { - let [close, display, pattern] = end; - let i = pattern.lastIndex = start.index + start[0].length; - let match: RegExpExecArray, braces: number = 0; + protected findEnd( + text: string, + n: number, + start: RegExpExecArray, + end: EndItem + ): ProtoItem { + const [close, display, pattern] = end; + const i = (pattern.lastIndex = start.index + start[0].length); + let match: RegExpExecArray, + braces: number = 0; while ((match = pattern.exec(text))) { if ((match[1] || match[0]) === close && braces === 0) { - return protoItem(start[0], text.substr(i, match.index - i), match[0], - n, start.index, match.index + match[0].length, display); + return protoItem( + start[0], + text.substring(i, match.index), + match[0], + n, + start.index, + match.index + match[0].length, + display + ); } else if (match[0] === '{') { braces++; } else if (match[0] === '}' && braces) { @@ -199,17 +221,28 @@ export class FindTeX extends AbstractFindMath { this.start.lastIndex = 0; while ((start = this.start.exec(text))) { if (start[this.env] !== undefined && this.env) { - let end = '\\\\end\\s*(\\{' + quotePattern(start[this.env]) + '\\})'; - match = this.findEnd(text, n, start, ['{' + start[this.env] + '}', true, this.endPattern(null, end)]); + const end = '\\\\end\\s*(\\{' + quotePattern(start[this.env]) + '\\})'; + match = this.findEnd(text, n, start, [ + '{' + start[this.env] + '}', + true, + this.endPattern(null, end), + ]); if (match) { match.math = match.open + match.math + match.close; match.open = match.close = ''; } } else if (start[this.sub] !== undefined && this.sub) { - let math = start[this.sub]; - let end = start.index + start[this.sub].length; + const math = start[this.sub]; + const end = start.index + start[this.sub].length; if (math.length === 2) { - match = protoItem('', math.substr(1), '', n, start.index, end); + match = protoItem( + '\\', + math.substring(1), + '', + n, + start.index, + end + ); } else { match = protoItem('', math, '', n, start.index, end, false); } @@ -229,7 +262,7 @@ export class FindTeX extends AbstractFindMath { * @override */ public findMath(strings: string[]) { - let math: ProtoItem[] = []; + const math: ProtoItem[] = []; if (this.hasPatterns) { for (let i = 0, m = strings.length; i < m; i++) { this.findMathInString(math, i, strings[i]); @@ -237,5 +270,4 @@ export class FindTeX extends AbstractFindMath { } return math; } - } diff --git a/ts/input/tex/HandlerTypes.ts b/ts/input/tex/HandlerTypes.ts new file mode 100644 index 000000000..bb12293de --- /dev/null +++ b/ts/input/tex/HandlerTypes.ts @@ -0,0 +1,44 @@ +/************************************************************* + * + * Copyright (c) 2017-2025 The MathJax Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * @file Basic enum types for map and configuration handlers. + * + * @author v.sorge@mathjax.org (Volker Sorge) + */ + +export enum ConfigurationType { + HANDLER = 'handler', + FALLBACK = 'fallback', + ITEMS = 'items', + TAGS = 'tags', + OPTIONS = 'options', + NODES = 'nodes', + PREPROCESSORS = 'preprocessors', + POSTPROCESSORS = 'postprocessors', + INIT = 'init', + CONFIG = 'config', + PRIORITY = 'priority', + PARSER = 'parser', +} + +export enum HandlerType { + DELIMITER = 'delimiter', + MACRO = 'macro', + CHARACTER = 'character', + ENVIRONMENT = 'environment', +} diff --git a/ts/input/tex/MapHandler.ts b/ts/input/tex/MapHandler.ts index dcd5567de..618438988 100644 --- a/ts/input/tex/MapHandler.ts +++ b/ts/input/tex/MapHandler.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,74 +15,71 @@ * limitations under the License. */ - /** - * @fileoverview Singleton class for handling symbol maps. + * @file Singleton class for handling symbol maps. * * @author v.sorge@mathjax.org (Volker Sorge) */ -import {AbstractSymbolMap, SymbolMap} from './SymbolMap.js'; -import {ParseInput, ParseResult, ParseMethod} from './Types.js'; -// import {ParserConfiguration} from './Configuration.js'; -import {PrioritizedList} from '../../util/PrioritizedList.js'; -import {FunctionList} from '../../util/FunctionList.js'; - - -export type HandlerType = 'delimiter' | 'macro' | 'character' | 'environment'; - -export type HandlerConfig = {[P in HandlerType]?: string[]}; -export type FallbackConfig = {[P in HandlerType]?: ParseMethod}; +import { HandlerType } from './HandlerTypes.js'; +import { AbstractTokenMap, TokenMap, CharacterMap } from './TokenMap.js'; +import { ParseInput, ParseResult, ParseMethod } from './Types.js'; +import { PrioritizedList } from '../../util/PrioritizedList.js'; +import { FunctionList } from '../../util/FunctionList.js'; +export type HandlerConfig = { [P in HandlerType]?: string[] }; +export type FallbackConfig = { [P in HandlerType]?: ParseMethod }; -export namespace MapHandler { - - let maps: Map = new Map(); +const maps: Map = new Map(); +export const MapHandler = { /** - * Adds a new symbol map to the map handler. Might overwrite an existing - * symbol map of the same name. + * Adds a new token map to the map handler. Might overwrite an existing + * token map of the same name. * - * @param {SymbolMap} map Registers a new symbol map. + * @param {TokenMap} map Registers a new token map. */ - export let register = function(map: SymbolMap): void { + register(map: TokenMap): void { maps.set(map.name, map); - }; - + }, /** - * Looks up a symbol map if it exists. + * Looks up a token map if it exists. * - * @param {string} name The name of the symbol map. - * @return {SymbolMap} The symbol map with the given name or null. + * @param {string} name The name of the token map. + * @returns {TokenMap} The token map with the given name or null. */ - export let getMap = function(name: string): SymbolMap { + getMap(name: string): TokenMap { return maps.get(name); - }; - -} - + }, +}; /** - * Class of symbol mappings that are active in a configuration. + * Class of token mappings that are active in a configuration. */ export class SubHandler { + public static FALLBACK = Symbol('fallback'); - private _configuration: PrioritizedList = new PrioritizedList(); + private _configuration: PrioritizedList = + new PrioritizedList(); private _fallback: FunctionList = new FunctionList(); /** - * Adds a list of symbol maps to the handler. - * @param {string[]} maps The names of the symbol maps to add. + * Adds a list of token maps to the handler. + * + * @param {string[]} maps The names of the token maps to add. * @param {ParseMethod} fallback A fallback method. * @param {number} priority Optionally a priority. */ - public add(maps: string[], fallback: ParseMethod, - priority: number = PrioritizedList.DEFAULTPRIORITY) { + public add( + maps: string[], + fallback: ParseMethod, + priority: number = PrioritizedList.DEFAULTPRIORITY + ) { for (const name of maps.slice().reverse()) { - let map = MapHandler.getMap(name); + const map = MapHandler.getMap(name); if (!map) { - this.warn('Configuration ' + name + ' not found! Omitted.'); + this.warn(`Configuration '${name}' not found! Omitted.`); return; } this._configuration.add(map, priority); @@ -93,80 +90,105 @@ export class SubHandler { } /** - * Parses the given input with the first applicable symbol map. + * Removes a list of token maps from the handler + * + * @param {string[]} maps The names of the token maps to remove. + * @param {ParseMethod} fallback A fallback method to remove. + */ + public remove(maps: string[], fallback: ParseMethod = null) { + for (const name of maps) { + const map = this.retrieve(name); + if (map) { + this._configuration.remove(map); + } + } + if (fallback) { + this._fallback.remove(fallback); + } + } + + /** + * Parses the given input with the first applicable token map. + * * @param {ParseInput} input The input for the parser. - * @return {ParseResult} The output of the parsing function. + * @returns {ParseResult} The output of the parsing function. */ public parse(input: ParseInput): ParseResult { - for (let {item: map} of this._configuration) { + for (const { item: map } of this._configuration) { const result = map.parse(input); + if (result === SubHandler.FALLBACK) { + break; + } if (result) { return result; } } - let [env, symbol] = input; - Array.from(this._fallback)[0].item(env, symbol); + const [env, token] = input; + Array.from(this._fallback)[0].item(env, token); + return; } - /** - * Maps a symbol to its "parse value" if it exists. + * Maps a token to its "parse value" if it exists. + * + * @param {string} token The token to parse. + * @returns {T} A boolean, Character, or Macro. * - * @param {string} symbol The symbol to parse. - * @return {T} A boolean, Character, or Macro. + * @template T */ - public lookup(symbol: string): T { - let map = this.applicable(symbol) as AbstractSymbolMap; - return map ? map.lookup(symbol) : null; + public lookup(token: string): T { + const map = this.applicable(token) as AbstractTokenMap; + return map ? map.lookup(token) : null; } - /** - * Checks if a symbol is contained in one of the symbol mappings of this + * Checks if a token is contained in one of the token mappings of this * configuration. * - * @param {string} symbol The symbol to parse. - * @return {boolean} True if the symbol is contained in the mapping. + * @param {string} token The token to parse. + * @returns {boolean} True if the token is contained in the mapping. */ - public contains(symbol: string): boolean { - return this.applicable(symbol) ? true : false; + public contains(token: string): boolean { + const map = this.applicable(token); + return ( + !!map && !(map instanceof CharacterMap && map.lookup(token).char === null) + ); } - /** * @override */ public toString(): string { - let names = []; - for (let {item: map} of this._configuration) { + const names = []; + for (const { item: map } of this._configuration) { names.push(map.name); } return names.join(', '); } - /** - * Retrieves the first applicable symbol map in the configuration. - * @param {string} symbol The symbol to parse. - * @return {SymbolMap} A map that can parse the symbol. + * Retrieves the first applicable token map in the configuration. + * + * @param {string} token The token to parse. + * @returns {TokenMap} A map that can parse the token. */ - public applicable(symbol: string): SymbolMap { - for (let {item: map} of this._configuration) { - if (map.contains(symbol)) { + public applicable(token: string): TokenMap { + for (const { item: map } of this._configuration) { + if (map.contains(token)) { return map; } } return null; } - /** * Retrieves the map of the given name. - * @param {string} name Name of the symbol map. - * @return {SymbolMap} The map if it exists. + * + * @param {string} name Name of the token map. + * @returns {TokenMap} The map if it exists. */ - public retrieve(name: string): SymbolMap { - for (let {item: map} of this._configuration) { + public retrieve(name: string): TokenMap { + for (const { item: map } of this._configuration) { if (map.name === name) { return map; } @@ -174,30 +196,33 @@ export class SubHandler { return null; } - /** * Prints a warning message. + * * @param {string} message The warning. */ private warn(message: string) { console.log('TexParser Warning: ' + message); } - } - export class SubHandlers { - private map = new Map(); /** - * Adds a symbol map to the configuration if it exists. - * @param {string} name of the symbol map. + * Adds subhandlers and fallbacks to the map. + * + * @param {HandlerConfig} handlers A handler configuration. + * @param {FallbackConfig} fallbacks A configuration of fallback functions. + * @param {number=} priority The priority of the handlers. */ - public add(handlers: HandlerConfig, fallbacks: FallbackConfig, - priority: number = PrioritizedList.DEFAULTPRIORITY): void { + public add( + handlers: HandlerConfig, + fallbacks: FallbackConfig, + priority: number = PrioritizedList.DEFAULTPRIORITY + ): void { for (const key of Object.keys(handlers)) { - let name = key as HandlerType; + const name = key as HandlerType; let subHandler = this.get(name); if (!subHandler) { subHandler = new SubHandler(); @@ -207,9 +232,24 @@ export class SubHandlers { } } + /** + * Removes subhandlers and fallbacks from the map. + * + * @param {HandlerConfig} handlers A handler configuration to remove + * @param {FallbackConfig} fallbacks A configuration of fallback functions to remove + */ + public remove(handlers: HandlerConfig, fallbacks: FallbackConfig) { + for (const name of Object.keys(handlers) as HandlerType[]) { + const subHandler = this.get(name); + if (subHandler) { + subHandler.remove(handlers[name], fallbacks[name]); + } + } + } /** * Setter for subhandlers. + * * @param {HandlerType} name The name of the subhandler. * @param {SubHandler} subHandler The subhandler. */ @@ -217,25 +257,25 @@ export class SubHandlers { this.map.set(name, subHandler); } - /** * Getter for subhandler. + * * @param {HandlerType} name Name of the subhandler. - * @return {SubHandler} The subhandler by that name if it exists. + * @returns {SubHandler} The subhandler by that name if it exists. */ public get(name: HandlerType): SubHandler { return this.map.get(name); } - /** - * Retrieves a symbol map of the given name. - * @param {string} name Name of the symbol map. - * @return {SymbolMap} The map if it exists. O/w null. + * Retrieves a token map of the given name. + * + * @param {string} name Name of the token map. + * @returns {TokenMap} The map if it exists. O/w null. */ - public retrieve(name: string): SymbolMap { + public retrieve(name: string): TokenMap { for (const handler of this.map.values()) { - let map = handler.retrieve(name); + const map = handler.retrieve(name); if (map) { return map; } @@ -243,13 +283,12 @@ export class SubHandlers { return null; } - /** * All names of registered subhandlers. - * @return {IterableIterator} Iterable list of keys. + * + * @returns {IterableIterator} Iterable list of keys. */ public keys(): IterableIterator { return this.map.keys(); } - } diff --git a/ts/input/tex/NodeFactory.ts b/ts/input/tex/NodeFactory.ts index 2a7c203e1..0adc3d76a 100644 --- a/ts/input/tex/NodeFactory.ts +++ b/ts/input/tex/NodeFactory.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,60 +15,66 @@ * limitations under the License. */ - /** - * @fileoverview Node factory for creating MmlNodes. This allows extension + * @file Node factory for creating MmlNodes. This allows extension * packages to add node constructors or overwrite existing ones. * * @author v.sorge@mathjax.org (Volker Sorge) */ -import {TextNode, MmlNode} from '../../core/MmlTree/MmlNode.js'; -import {MmlFactory} from '../../core/MmlTree/MmlFactory.js'; +import { TextNode, MmlNode } from '../../core/MmlTree/MmlNode.js'; +import { MmlFactory } from '../../core/MmlTree/MmlFactory.js'; import ParseOptions from './ParseOptions.js'; import NodeUtil from './NodeUtil.js'; - -export type NodeFactoryMethod = (factory: NodeFactory, kind: string, ...rest: any[]) => MmlNode; +export type NodeFactoryMethod = ( + factory: NodeFactory, + kind: string, + ...rest: any[] +) => MmlNode; export class NodeFactory { - /** * Parser configuration that can be used to pass information between node methods. - * @type {ParseOption} + * + * @type {ParseOptions} */ public configuration: ParseOptions; - /** * The external node factory. + * * @type {MmlFactory} */ protected mmlFactory: MmlFactory = null; - /** * The factory table populated with some default methods. */ - private factory: {[kind: string]: NodeFactoryMethod} = - {'node': NodeFactory.createNode, - 'token': NodeFactory.createToken, - 'text': NodeFactory.createText, - 'error': NodeFactory.createError - }; + private factory: { [kind: string]: NodeFactoryMethod } = { + node: NodeFactory.createNode, + token: NodeFactory.createToken, + text: NodeFactory.createText, + error: NodeFactory.createError, + }; /** * Default node generation function. + * * @param {NodeFactory} factory The current node factory. * @param {string} kind The type of node to create. * @param {MmlNode[]} children Its children. * @param {any=} def Its properties. * @param {TextNode=} text An optional text node if this is a token. - * @return {MmlNode} The newly created Mml node. + * @returns {MmlNode} The newly created Mml node. */ - public static createNode(factory: NodeFactory, kind: string, - children: MmlNode[] = [], def: any = {}, - text?: TextNode): MmlNode { + public static createNode( + factory: NodeFactory, + kind: string, + children: MmlNode[] = [], + def: any = {}, + text?: TextNode + ): MmlNode { const node = factory.mmlFactory.create(kind); node.setChildren(children); if (text) { @@ -78,50 +84,55 @@ export class NodeFactory { return node; } - /** * Default token generation function. + * * @param {NodeFactory} factory The current node factory. * @param {string} kind The type of node to create. * @param {any} def Its properties. * @param {string} text Text of the token. - * @return {MmlNode} The newly created token node. + * @returns {MmlNode} The newly created token node. */ - public static createToken(factory: NodeFactory, kind: string, - def: any = {}, text: string = ''): MmlNode { + public static createToken( + factory: NodeFactory, + kind: string, + def: any = {}, + text: string = '' + ): MmlNode { const textNode = factory.create('text', text); return factory.create('node', kind, [], def, textNode); } - /** * Default text node generation function. + * * @param {NodeFactory} factory The current node factory. * @param {string} text The text for the new node. - * @return {TextNode} The newly created text node. + * @returns {TextNode} The newly created text node. */ - public static createText(factory: NodeFactory, text: string): TextNode { + public static createText(factory: NodeFactory, text: string): TextNode { if (text == null) { return null; } return (factory.mmlFactory.create('text') as TextNode).setText(text); } - /** * Default error node generation function. + * * @param {NodeFactory} factory The current node factory. * @param {string} message The error message. - * @return {MmlNode} The newly created error node. + * @returns {MmlNode} The newly created error node. */ - public static createError(factory: NodeFactory, message: string): MmlNode { - let text = factory.create('text', message); - let mtext = factory.create('node', 'mtext', [], {}, text); - let error = factory.create('node', 'merror', [mtext], {'data-mjx-error': message}); + public static createError(factory: NodeFactory, message: string): MmlNode { + const text = factory.create('text', message); + const mtext = factory.create('node', 'mtext', [], {}, text); + const error = factory.create('node', 'merror', [mtext], { + 'data-mjx-error': message, + }); return error; } - /** * @param {MmlFactory} mmlFactory The MmlFactory for the TeX jax to use */ @@ -131,6 +142,7 @@ export class NodeFactory { /** * Adds a method to the factory. + * * @param {string} kind The type of node the method creates. * @param {NodeFactoryMethod} func The node creator. */ @@ -138,23 +150,23 @@ export class NodeFactory { this.factory[kind] = func; } - /** * Adds a set of node creators to the factory. - * @param {Object.} maps The set of functions. + * + * @param {{ [kind: string]: NodeFactoryMethod }} maps The set of functions. */ - public setCreators(maps: {[kind: string]: NodeFactoryMethod}) { - for (let kind in maps) { + public setCreators(maps: { [kind: string]: NodeFactoryMethod }) { + for (const kind in maps) { this.set(kind, maps[kind]); } } - /** * Creates a node for the internal data structure from the factory. + * * @param {string} kind The type of node to be created. - * @param {any[]} ...rest The arguments for the node. - * @return {MmlNode} The created node. + * @param {any[]} rest The arguments for the node. + * @returns {MmlNode} The created node. */ public create(kind: string, ...rest: any[]): MmlNode { const func = this.factory[kind] || this.factory['node']; @@ -165,12 +177,13 @@ export class NodeFactory { return node; } - /** - * @param {string} kind The method for generating a node of given kind. + * Gets the method for generating a node of given kind. + * + * @param {string} kind The kind of node. + * @returns {NodeFactoryMethod} The method to generate that node type. */ - public get(kind: string) { + public get(kind: string): NodeFactoryMethod { return this.factory[kind]; } - } diff --git a/ts/input/tex/NodeUtil.ts b/ts/input/tex/NodeUtil.ts index b49402d2c..3ccbe01c5 100644 --- a/ts/input/tex/NodeUtil.ts +++ b/ts/input/tex/NodeUtil.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,111 +15,114 @@ * limitations under the License. */ - /** - * @fileoverview Node utility methods. + * @file Node utility methods. * * @author v.sorge@mathjax.org (Volker Sorge) */ -import {TextNode, MMLNODE, MmlNode, AbstractMmlNode, AbstractMmlEmptyNode} from '../../core/MmlTree/MmlNode.js'; -import {MmlMo} from '../../core/MmlTree/MmlNodes/mo.js'; -import {Property, PropertyList} from '../../core/Tree/Node.js'; -import {Args} from './Types.js'; -import {OperatorDef} from '../../core/MmlTree/OperatorDictionary.js'; - - -namespace NodeUtil { - - const attrs: Map = new Map([ - ['autoOP', true], - ['fnOP', true], - ['movesupsub', true], - ['subsupOK', true], - ['texprimestyle', true], - ['useHeight', true], - ['variantForm', true], - ['withDelims', true], - ['mathaccent', true], - ['open', true], - ['close', true] - ]); - +import { + TextNode, + MMLNODE, + MmlNode, + AbstractMmlNode, + AbstractMmlEmptyNode, +} from '../../core/MmlTree/MmlNode.js'; +import { MmlMo } from '../../core/MmlTree/MmlNodes/mo.js'; +import { Property, PropertyList } from '../../core/Tree/Node.js'; +import { Args } from './Types.js'; +import { OperatorDef } from '../../core/MmlTree/OperatorDictionary.js'; + +const NodeUtil = { + attrs: new Set([ + 'autoOP', + 'fnOP', + 'movesupsub', + 'subsupOK', + 'texprimestyle', + 'useHeight', + 'variantForm', + 'withDelims', + 'mathaccent', + 'open', + 'close', + ]), /** * Creates a single character from a unicode hex string. + * * @param {string} code The code. - * @return {string} The newly created entity. + * @returns {string} The newly created entity. */ - export function createEntity(code: string): string { + createEntity(code: string): string { return String.fromCodePoint(parseInt(code, 16)); - } - + }, /** * Get the children of the a node. + * * @param {MmlNode} node The node. - * @return {MMLNODE[]} Its children. + * @returns {MMLNODE[]} Its children. */ - export function getChildren(node: MmlNode): MMLNODE[] { - return (node.childNodes as MMLNODE[]); - } - + getChildren(node: MmlNode): MMLNODE[] { + return node.childNodes as MMLNODE[]; + }, /** * Get text content of a node. + * * @param {TextNode} node The node. - * @return {string} Its text content. + * @returns {string} Its text content. */ - export function getText(node: TextNode): string { + getText(node: TextNode): string { return node.getText(); - } - + }, /** * Append children to a node. + * * @param {MmlNode} node The node. * @param {MMLNODE[]} children A list of new children. */ - export function appendChildren(node: MmlNode, children: MMLNODE[]) { - for (let child of children) { + appendChildren(node: MmlNode, children: MMLNODE[]) { + for (const child of children) { node.appendChild(child); } - } - + }, /** * Sets an attribute of a node. + * * @param {MmlNode} node The node. * @param {string} attribute An attribute. * @param {Args} value The attribute value. */ - export function setAttribute(node: MmlNode, attribute: string, value: Args) { + setAttribute(node: MmlNode, attribute: string, value: Args) { node.attributes.set(attribute, value); - } - + }, /** * Sets a property of a node. + * * @param {MmlNode} node The node. * @param {string} property The property. * @param {Args} value The property value. */ - export function setProperty(node: MmlNode, property: string, value: Args) { + setProperty(node: MmlNode, property: string, value: Args) { node.setProperty(property, value); - } - + }, /** * Sets properties and attributes of a node. + * * @param {MmlNode} node The node. * @param {PropertyList} properties A list of property/attribute value pairs. */ - export function setProperties(node: MmlNode, properties: PropertyList) { + setProperties(node: MmlNode, properties: PropertyList) { for (const name of Object.keys(properties)) { - let value = properties[name]; + const value = properties[name]; if (name === 'texClass') { - node.texClass = (value as number); + node.texClass = value as number; node.setProperty(name, value); } else if (name === 'movablelimits') { node.setProperty('movablelimits', value); @@ -128,179 +131,222 @@ namespace NodeUtil { } } else if (name === 'inferred') { // ignore - } else if (attrs.has(name)) { + } else if (NodeUtil.attrs.has(name)) { node.setProperty(name, value); } else { node.attributes.set(name, value); } } - } - + }, /** * Returns the property of a node. + * * @param {MmlNode} node The node. * @param {string} property A property name. - * @return {Property} Value of the property. + * @returns {Property} Value of the property. */ - export function getProperty(node: MmlNode, property: string): Property { + getProperty(node: MmlNode, property: string): Property { return node.getProperty(property); - } - + }, /** * Returns the attribute of a node. + * * @param {MmlNode} node The node. - * @param {string} attr A attribute name. - * @return {Property} Value of the attribute. + * @param {string} attr An attribute name. + * @returns {Property} Value of the attribute. */ - export function getAttribute(node: MmlNode, attr: string): Property { + getAttribute(node: MmlNode, attr: string): Property { return node.attributes.get(attr); - } + }, + /** + * Removes an attribute of a node. + * + * @param {MmlNode} node The node. + * @param {string} attr An attribute name. + */ + removeAttribute(node: MmlNode, attr: string): void { + node.attributes.unset(attr); + }, /** * Removes a set of properties from a node. + * * @param {MmlNode} node The node. - * @param {string[]} ...properties A list of properties. + * @param {string[]} properties A list of properties. */ - export function removeProperties(node: MmlNode, ...properties: string[]) { + removeProperties(node: MmlNode, ...properties: string[]) { node.removeProperty(...properties); - } - + }, /** * Returns a child node at a given position. + * * @param {MmlNode} node The node. * @param {number} position The position of the child. - * @return {MMLNODE} The child node at position. + * @returns {MMLNODE} The child node at position. */ - export function getChildAt(node: MmlNode, position: number): MMLNODE { - return (node.childNodes[position] as MMLNODE); - } - + getChildAt(node: MmlNode, position: number): MMLNODE { + return node.childNodes[position] as MMLNODE; + }, /** * Set node child at position. + * * @param {MmlNode} node The node. * @param {number} position The position of the new child. * @param {MmlNode} child The new child. */ - export function setChild(node: MmlNode, position: number, child: MmlNode) { - let children = node.childNodes; + setChild(node: MmlNode, position: number, child: MmlNode) { + const children = node.childNodes; children[position] = child; if (child) { child.parent = node; } - } - + }, /** * Copies children between nodes. + * * @param {MmlNode} oldNode The source node. * @param {MmlNode} newNode The target node. */ - export function copyChildren(oldNode: MmlNode, newNode: MmlNode) { - let children = oldNode.childNodes as (TextNode | MmlNode)[]; + copyChildren(oldNode: MmlNode, newNode: MmlNode) { + const children = oldNode.childNodes as (TextNode | MmlNode)[]; for (let i = 0; i < children.length; i++) { - setChild(newNode, i, children[i]); + this.setChild(newNode, i, children[i]); } - } - + }, /** * Copies attributes between nodes. + * * @param {MmlNode} oldNode The source node. * @param {MmlNode} newNode The target node. */ - export function copyAttributes(oldNode: MmlNode, newNode: MmlNode) { + copyAttributes(oldNode: MmlNode, newNode: MmlNode) { newNode.attributes = oldNode.attributes; - setProperties(newNode, oldNode.getAllProperties()); - } - + this.setProperties(newNode, oldNode.getAllProperties()); + }, /** * Checks if node is of a particular type. + * * @param {MmlNode} node The node. * @param {string} kind The type to check. - * @return {boolean} True if node is of the given type. + * @returns {boolean} True if node is of the given type. */ - export function isType(node: MmlNode, kind: string): boolean { + isType(node: MmlNode, kind: string): boolean { return node.isKind(kind); - } - + }, /** * Checks if the node is embellished. + * * @param {MmlNode} node The node. - * @return {boolean} True if node is embellished. + * @returns {boolean} True if node is embellished. */ - export function isEmbellished(node: MmlNode): boolean { + isEmbellished(node: MmlNode): boolean { return node.isEmbellished; - } - + }, /** * Gets the texclass of a node. + * * @param {MmlNode} node The node. - * @return {number} Its texclass. + * @returns {number} Its texclass. */ - export function getTexClass(node: MmlNode): number { + getTexClass(node: MmlNode): number { return node.texClass; - } - + }, /** * Gets the mo element at the core of the node. + * * @param {MmlNode} node The node. - * @return {MmlNode} The MO node at the core. + * @returns {MmlNode} The MO node at the core. */ - export function getCoreMO(node: MmlNode): MmlNode { + getCoreMO(node: MmlNode): MmlNode { return node.coreMO(); - } - + }, /** * Checks if an object is a node. + * * @param {any} item The object. - * @return {boolean} True if it is a node. + * @returns {boolean} True if it is a node. */ - export function isNode(item: any): boolean { - return item instanceof AbstractMmlNode || item instanceof AbstractMmlEmptyNode; - } - + isNode(item: any): boolean { + return ( + item instanceof AbstractMmlNode || item instanceof AbstractMmlEmptyNode + ); + }, /** * Checks if the node is an inferred mrow. + * * @param {MmlNode} node The node. - * @return {boolean} True if the node is an inferred mrow. + * @returns {boolean} True if the node is an inferred mrow. */ - export function isInferred(node: MmlNode): boolean { + isInferred(node: MmlNode): boolean { return node.isInferred; - } - + }, /** * Gets the operator definition of a node. + * * @param {MmlNode} node The node. - * @return {OperatorDef} If node is an MO returns the operator definition. O/w + * @returns {OperatorDef} If node is an MO returns the operator definition. O/w * null. */ - export function getForm(node: MmlNode): OperatorDef { - if (!isType(node, 'mo')) { + getForm(node: MmlNode): OperatorDef { + if (!node.isKind('mo')) { return null; } - let mo = node as MmlMo; - let forms = mo.getForms(); - for (let form of forms) { - let symbol = MmlMo.OPTABLE[form][mo.getText()]; + const mo = node as MmlMo; + const forms = mo.getForms(); + for (const form of forms) { + const symbol = this.getOp(mo, form); if (symbol) { return symbol; } } return null; - } + }, -} + /** + * Gets the operator definition of an mo node of a particular form. + * + * @param {MmlMo} mo The mo node. + * @param {string=} form The form (infix/prefix/postfix) for the mo. + * @returns {OperatorDef} If node is an MO returns the operator definition. O/w + * null. + */ + getOp(mo: MmlMo, form: string = 'infix'): OperatorDef { + return MmlMo.OPTABLE[form][mo.getText()] || null; + }, + + /** + * Gets an explicit or inherited attribute of an mo, or its default from the + * operator dictionary, or the default value + * + * @param {MmlMo} mo The mo node. + * @param {string} attr The attribute to return. + * @returns {Property} The attributes property. + */ + getMoAttribute(mo: MmlNode, attr: string): Property { + if (!mo.attributes.isSet(attr)) { + for (const form of ['infix', 'postfix', 'prefix']) { + const value = this.getOp(mo, form)?.[3]?.[attr]; + if (value !== undefined) { + return value; + } + } + } + return mo.attributes.get(attr); + }, +}; export default NodeUtil; diff --git a/ts/input/tex/ParseMethods.ts b/ts/input/tex/ParseMethods.ts index e5d77b6e9..934423f8c 100644 --- a/ts/input/tex/ParseMethods.ts +++ b/ts/input/tex/ParseMethods.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2017-2022 The MathJax Consortium + * Copyright (c) 2017-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,97 +15,148 @@ * limitations under the License. */ - /** - * @fileoverview Base methods for TeX Parsing. + * @file Base methods for TeX Parsing. * * @author v.sorge@mathjax.org (Volker Sorge) */ -import {Symbol} from './Symbol.js'; +import { HandlerType } from './HandlerTypes.js'; +import { Token } from './Token.js'; import TexParser from './TexParser.js'; import NodeUtil from './NodeUtil.js'; -import {TexConstant} from './TexConstants.js'; -import {MmlNode} from '../../core/MmlTree/MmlNode.js'; -import ParseUtil from './ParseUtil.js'; - +import { TexConstant } from './TexConstants.js'; +import { ParseUtil } from './ParseUtil.js'; +import { ParseMethod, ParseResult } from './Types.js'; +import { StackItem } from './StackItem.js'; -namespace ParseMethods { +const MATHVARIANT = TexConstant.Variant; +const ParseMethods = { /** * Handle a variable (a single letter or multi-letter if allowed). + * * @param {TexParser} parser The current tex parser. * @param {string} c The letter to transform into an mi. */ - export function variable(parser: TexParser, c: string) { + variable(parser: TexParser, c: string) { // @test Identifier Font const def = ParseUtil.getFontDef(parser); const env = parser.stack.env; if (env.multiLetterIdentifiers && env.font !== '') { - c = parser.string.substr(parser.i - 1).match(env.multiLetterIdentifiers as any as RegExp)[0]; + c = + parser.string + .substring(parser.i - 1) + .match(env.multiLetterIdentifiers as any as RegExp)?.[0] || c; parser.i += c.length - 1; - if (def.mathvariant === TexConstant.Variant.NORMAL && env.noAutoOP && c.length > 1) { + if ( + def.mathvariant === MATHVARIANT.NORMAL && + env.noAutoOP && + c.length > 1 + ) { def.autoOP = false; } } + if (!def.mathvariant && ParseUtil.isLatinOrGreekChar(c)) { + const variant = parser.configuration.mathStyle(c); + if (variant) { + def.mathvariant = variant; + } + } // @test Identifier const node = parser.create('token', 'mi', def, c); parser.Push(node); - } - + }, /** * Handle a number (a sequence of digits, with decimal separator, etc.). + * * @param {TexParser} parser The current tex parser. - * @param {string} c The first character of a number than can be parsed with + * @param {string} _c The first character of a number that can be parsed with * the digits pattern. + * @returns {ParseResult} false if the string doesn't match a number + * (e.g., a decimal with no following digit). */ - export function digit(parser: TexParser, c: string) { - let mml: MmlNode; - const pattern = parser.configuration.options['digits']; + digit(parser: TexParser, _c: string): ParseResult { + const pattern = parser.configuration.options['numberPattern']; const n = parser.string.slice(parser.i - 1).match(pattern); // @test Integer Font const def = ParseUtil.getFontDef(parser); - if (n) { - // @test Integer, Number, Decimal (European) - mml = parser.create('token', 'mn', def, n[0].replace(/[{}]/g, '')); - parser.i += n[0].length - 1; - } else { + if (!n) { // @test Decimal Point, Decimal Point European - mml = parser.create('token', 'mo', def, c); + return false; } + // @test Integer, Number, Decimal (European) + const mml = parser.create('token', 'mn', def, n[0].replace(/[{}]/g, '')); + parser.i += n[0].length - 1; parser.Push(mml); - } + return true; + }, /** * Lookup a control-sequence and process it. + * * @param {TexParser} parser The current tex parser. - * @param {string} c The string '\'. + * @param {string} _c The string '\'. */ - export function controlSequence(parser: TexParser, _c: string) { + controlSequence(parser: TexParser, _c: string) { const name = parser.GetCS(); - parser.parse('macro', [parser, name]); - } + parser.parse(HandlerType.MACRO, [parser, name]); + }, + + /** + * Handle lower-case Greek (as an mi). + * + * @param {TexParser} parser The current tex parser. + * @param {Token} mchar The parsed token. + */ + lcGreek(parser: TexParser, mchar: Token) { + const def = { + mathvariant: + parser.configuration.mathStyle(mchar.char) || MATHVARIANT.ITALIC, + }; + // @test Greek + const node = parser.create('token', 'mi', def, mchar.char); + parser.Push(node); + }, + /** + * Handle upper-case Greek in current family. + * + * @param {TexParser} parser The current tex parser. + * @param {Token} mchar The parsed token. + */ + ucGreek(parser: TexParser, mchar: Token) { + const def = { + mathvariant: + parser.stack.env['font'] || + parser.configuration.mathStyle(mchar.char, true) || + MATHVARIANT.NORMAL, + }; + // @test MathChar7 Single, MathChar7 Operator, MathChar7 Multi + const node = parser.create('token', 'mi', def, mchar.char); + parser.Push(node); + }, /** * Handle normal mathchar (as an mi). + * * @param {TexParser} parser The current tex parser. - * @param {Symbol} mchar The parsed symbol. + * @param {Token} mchar The parsed token. */ - export function mathchar0mi(parser: TexParser, mchar: Symbol) { - const def = mchar.attributes || {mathvariant: TexConstant.Variant.ITALIC}; - // @test Greek + mathchar0mi(parser: TexParser, mchar: Token) { + const def = mchar.attributes || { mathvariant: MATHVARIANT.ITALIC }; const node = parser.create('token', 'mi', def, mchar.char); parser.Push(node); - } + }, /** * Handle normal mathchar (as an mo). + * * @param {TexParser} parser The current tex parser. - * @param {Symbol} mchar The parsed symbol. + * @param {Token} mchar The parsed token. */ - export function mathchar0mo(parser: TexParser, mchar: Symbol) { + mathchar0mo(parser: TexParser, mchar: Token) { const def = mchar.attributes || {}; def['stretchy'] = false; // @test Large Set @@ -114,15 +165,16 @@ namespace ParseMethods { parser.configuration.addNode('fixStretchy', node); // PROBLEM: Attributes stop working when Char7 are explicitly set. parser.Push(node); - } + }, /** * Handle mathchar in current family. + * * @param {TexParser} parser The current tex parser. - * @param {Symbol} mchar The parsed symbol. + * @param {Token} mchar The parsed token. */ - export function mathchar7(parser: TexParser, mchar: Symbol) { - const def = mchar.attributes || {mathvariant: TexConstant.Variant.NORMAL}; + mathchar7(parser: TexParser, mchar: Token) { + const def = mchar.attributes || { mathvariant: MATHVARIANT.NORMAL }; if (parser.stack.env['font']) { // @test MathChar7 Single Font def['mathvariant'] = parser.stack.env['font']; @@ -130,36 +182,34 @@ namespace ParseMethods { // @test MathChar7 Single, MathChar7 Operator, MathChar7 Multi const node = parser.create('token', 'mi', def, mchar.char); parser.Push(node); - } + }, /** * Handle delimiter. + * * @param {TexParser} parser The current tex parser. - * @param {Symbol} delim The parsed delimiter symbol. + * @param {Token} delim The parsed delimiter token. */ - export function delimiter(parser: TexParser, delim: Symbol) { + delimiter(parser: TexParser, delim: Token) { let def = delim.attributes || {}; // @test Fenced2, Delimiter (AMS) - def = Object.assign({fence: false, stretchy: false}, def); + def = Object.assign({ fence: false, stretchy: false }, def); const node = parser.create('token', 'mo', def, delim.char); parser.Push(node); - } - + }, /** * Parse an environment. + * * @param {TexParser} parser The current tex parser. * @param {string} env The name of the environment. - * @param {Function} func The parse method for the environment. + * @param {ParseMethod} func The parse method for the environment. * @param {any[]} args A list of additional arguments. */ - export function environment(parser: TexParser, env: string, func: Function, args: any[]) { - const end = args[0]; - let mml = parser.itemFactory.create('begin').setProperties({name: env, end: end}); - mml = func(parser, mml, ...args.slice(1)); - parser.Push(mml); - } - -} + environment(parser: TexParser, env: string, func: ParseMethod, args: any[]) { + const mml = parser.itemFactory.create('begin').setProperty('name', env); + parser.Push(func(parser, mml, ...args.slice(1)) as StackItem); + }, +}; export default ParseMethods; diff --git a/ts/input/tex/ParseOptions.ts b/ts/input/tex/ParseOptions.ts index c90010298..3995d79c6 100644 --- a/ts/input/tex/ParseOptions.ts +++ b/ts/input/tex/ParseOptions.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,61 +15,102 @@ * limitations under the License. */ - /** - * @fileoverview Factory generating maps to keep options for the TeX parser. + * @file Factory generating maps to keep options for the TeX parser. * * @author v.sorge@mathjax.org (Volker Sorge) */ import StackItemFactory from './StackItemFactory.js'; -import {Tags} from './Tags.js'; -import {SubHandlers} from './MapHandler.js'; -import {NodeFactory} from './NodeFactory.js'; +import { Tags } from './Tags.js'; +import { SubHandlers } from './MapHandler.js'; +import { NodeFactory } from './NodeFactory.js'; import NodeUtil from './NodeUtil.js'; -import {MmlNode} from '../../core/MmlTree/MmlNode.js'; +import { MmlNode } from '../../core/MmlTree/MmlNode.js'; +import { MathItem } from '../../core/MathItem.js'; import TexParser from './TexParser.js'; -import {defaultOptions, OptionList} from '../../util/Options.js'; -import {ParserConfiguration} from './Configuration.js'; +import { TexConstant } from './TexConstants.js'; +import { defaultOptions, OptionList } from '../../util/Options.js'; +import { ParserConfiguration } from './Configuration.js'; +import { ColumnParser } from './ColumnParser.js'; +const MATHVARIANT = TexConstant.Variant; /** * @class */ export default class ParseOptions { + // + // Look up math variant for the current math-style + // + public static getVariant = new Map< + string, + (c: string, b?: boolean) => string + >([ + [ + 'TeX', + (c, b) => + b ? (c.match(/^[\u0391-\u03A9\u03F4]/) ? MATHVARIANT.NORMAL : '') : '', + ], + ['ISO', (_c) => MATHVARIANT.ITALIC], + [ + 'French', + (c) => + c.normalize('NFD').match(/^[a-z]/) + ? MATHVARIANT.ITALIC + : MATHVARIANT.NORMAL, + ], + ['upright', (_c) => MATHVARIANT.NORMAL], + ]); /** * A set of sub handlers + * * @type {SubHandlers} */ public handlers: SubHandlers; /** * A set of options, mapping names to string or boolean values. + * * @type {OptionList} */ public options: OptionList = {}; /** * The current item factory. + * * @type {StackItemFactory} */ public itemFactory: StackItemFactory; /** * The current node factory. + * * @type {NodeFactory} */ public nodeFactory: NodeFactory; /** * The current tagging object. + * * @type {Tags} */ public tags: Tags; + /** + * The function returning the math-style variant + */ + public mathStyle: (c: string, b?: boolean) => string; + + /** + * The column parser + */ + public columnParser: ColumnParser = new ColumnParser(); + /** * Storage area for parser-specific package data (indexed by package name) + * * @type {Map} */ public packageData: Map = new Map(); @@ -79,38 +120,47 @@ export default class ParseOptions { /** * Stack of previous tex parsers. This is used to keep track of parser * settings when expressions are recursively parsed. + * * @type {TexParser[]} */ public parsers: TexParser[] = []; + /** + * The current MathItem + */ + public mathItem: MathItem; /** * The current root node. + * * @type {MmlNode} */ public root: MmlNode = null; /** * List of node lists saved with respect to some property or their kind. + * * @type {{[key: string]: MmlNode[]}} */ - public nodeLists: {[key: string]: MmlNode[]} = {}; + public nodeLists: { [key: string]: MmlNode[] } = {}; /** * Error state of the parser. + * * @type {boolean} */ public error: boolean = false; - - /** - * @constructor - * @param {Configuration} configuration Configuration object of the current + * @class + * @param {ParserConfiguration} configuration Configuration object of the current * TeX parser. * @param {OptionList[]} options [TeX options, Tag options, {packages}] */ - public constructor(configuration: ParserConfiguration, options: OptionList[] = []) { + public constructor( + configuration: ParserConfiguration, + options: OptionList[] = [] + ) { this.handlers = configuration.handlers; // Add node factory methods from packages. this.nodeFactory = new NodeFactory(); @@ -122,19 +172,21 @@ export default class ParseOptions { // Set default options for parser from packages and for tags. defaultOptions(this.options, ...options); defaultOptions(this.options, configuration.options); + this.mathStyle = + ParseOptions.getVariant.get(this.options.mathStyle) || + ParseOptions.getVariant.get('TeX'); } - // Methods for dealing with ephemeral fields. /** * Pushes a new tex parser onto the stack. + * * @param {TexParser} parser The new parser. */ public pushParser(parser: TexParser) { this.parsers.unshift(parser); } - /** * Pops a parser of the tex parser stack. */ @@ -142,9 +194,8 @@ export default class ParseOptions { this.parsers.shift(); } - /** - * @return {TexParser} The currently active tex parser. + * @returns {TexParser} The currently active tex parser. */ public get parser(): TexParser { return this.parsers[0]; @@ -161,9 +212,9 @@ export default class ParseOptions { this.tags.resetTag(); } - /** * Saves a tree node to a list of nodes for post processing. + * * @param {string} property The property name that will be used for * postprocessing. * @param {MmlNode} node The node to save. @@ -179,13 +230,14 @@ export default class ParseOptions { // If the list is not just for its kind, record that it is in this list // so that if it is copied, the copy can also be added to the list. // - const inlists = (NodeUtil.getProperty(node, 'in-lists') as string || ''); - const lists = (inlists ? inlists.split(/,/) : []).concat(property).join(','); + const inlists = (NodeUtil.getProperty(node, 'in-lists') as string) || ''; + const lists = (inlists ? inlists.split(/,/) : []) + .concat(property) + .join(','); NodeUtil.setProperty(node, 'in-lists', lists); } } - /** * Gets a saved node list with respect to a given property. It first ensures * that all the nodes are "live", i.e., actually live in the current @@ -194,12 +246,15 @@ export default class ParseOptions { * * NB: Do not use this method before the root field of the options is * set. Otherwise, your node list will always be empty! + * * @param {string} property The property for which to retrieve the node list. + * + * @returns {MmlNode[]} The saved node list. */ - public getList(property: string) { - let list = this.nodeLists[property] || []; - let result = []; - for (let node of list) { + public getList(property: string): MmlNode[] { + const list = this.nodeLists[property] || []; + const result = []; + for (const node of list) { if (this.inTree(node)) { result.push(node); } @@ -208,7 +263,6 @@ export default class ParseOptions { return result; } - /** * Remove a list of nodes from a saved list (e.g., when a filter removes the * node from the DOM, like for munderover => munder). @@ -226,16 +280,17 @@ export default class ParseOptions { } } - /** * Tests if the node is in the tree spanned by the current root node. + * * @param {MmlNode} node The node to test. + * + * @returns {boolean} True if the node is in the tree. */ - private inTree(node: MmlNode) { + private inTree(node: MmlNode): boolean { while (node && node !== this.root) { node = node.parent; } return !!node; } - } diff --git a/ts/input/tex/ParseUtil.ts b/ts/input/tex/ParseUtil.ts index 6f64ab4b5..6f839dbef 100644 --- a/ts/input/tex/ParseUtil.ts +++ b/ts/input/tex/ParseUtil.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,167 +15,333 @@ * limitations under the License. */ - /** - * @fileoverview A namespace for utility functions for the TeX Parser. + * @file A namespace for utility functions for the TeX Parser. * * @author v.sorge@mathjax.org (Volker Sorge) */ -import {TEXCLASS, MmlNode} from '../../core/MmlTree/MmlNode.js'; -import {EnvList} from './StackItem.js'; -import {ArrayItem} from './base/BaseItems.js'; +import { TEXCLASS, MmlNode } from '../../core/MmlTree/MmlNode.js'; +import { EnvList } from './StackItem.js'; +import { ArrayItem } from './base/BaseItems.js'; import ParseOptions from './ParseOptions.js'; import NodeUtil from './NodeUtil.js'; import TexParser from './TexParser.js'; import TexError from './TexError.js'; -import {entities} from '../../util/Entities.js'; -import {MmlMunderover} from '../../core/MmlTree/MmlNodes/munderover.js'; - - -namespace ParseUtil { +import { entities } from '../../util/Entities.js'; +import { MmlMunderover } from '../../core/MmlTree/MmlNodes/munderover.js'; +import { UnitUtil } from './UnitUtil.js'; - // TODO (VS): Combine some of this with lengths in util. - const emPerInch = 7.2; - const pxPerInch = 72; - // Note, the following are TeX CM font values. - const UNIT_CASES: {[key: string]: ((m: number) => number)} = { - 'em': m => m, - 'ex': m => m * .43, - 'pt': m => m / 10, // 10 pt to an em - 'pc': m => m * 1.2, // 12 pt to a pc - 'px': m => m * emPerInch / pxPerInch, - 'in': m => m * emPerInch, - 'cm': m => m * emPerInch / 2.54, // 2.54 cm to an inch - 'mm': m => m * emPerInch / 25.4, // 10 mm to a cm - 'mu': m => m / 18, - }; - const num = '([-+]?([.,]\\d+|\\d+([.,]\\d*)?))'; - const unit = '(pt|em|ex|mu|px|mm|cm|in|pc)'; - const dimenEnd = RegExp('^\\s*' + num + '\\s*' + unit + '\\s*$'); - const dimenRest = RegExp('^\\s*' + num + '\\s*' + unit + ' ?'); +/** + * The data needed for checking the value of a key-value pair. + */ +export class KeyValueDef { + public static oneof(...values: string[]) { + return new this( + 'string', + (value) => values.includes(value), + (value) => value + ); + } + constructor( + public name: string, + public verify: (value: string) => boolean, + public convert: (value: string) => T + ) {} +} - /** - * Matches for a dimension argument. - * @param {string} dim The argument. - * @param {boolean} rest Allow for trailing garbage in the dimension string. - * @return {[string, string, number]} The match result as (Anglosaxon) value, - * unit name, length of matched string. The latter is interesting in the - * case of trailing garbage. - */ - export function matchDimen( - dim: string, rest: boolean = false): [string, string, number] { - let match = dim.match(rest ? dimenRest : dimenEnd); - return match ? - muReplace([match[1].replace(/,/, '.'), match[4], match[0].length]) : - [null, null, 0]; - } +export type KeyValueFn = (...data: any[]) => KeyValueDef; +export type KeyValueType = KeyValueDef; +/** + * Predefined value types that can be used to create the list of allowed types. E.g. + * + * const allowed = { + * compact: KeyValueTypes.boolean, + * direction: KeyValueDef.oneof('up', 'down'), + * 'open-brace': KeyValueTypes.string + * }; + * + * ParseUtil.keyvalOptions(options, allowed, true); + */ +export const KeyValueTypes: { [name: string]: KeyValueType } = { + boolean: new KeyValueDef( + 'boolean', + (value) => value === 'true' || value === 'false', + (value) => value === 'true' + ), + number: new KeyValueDef( + 'number', + (value) => !!value.match(/^[-+]?(?:\d+(?:\.\d*)?|\.\d+)(?:e[-+]?\d+)?$/), + (value) => parseFloat(value) + ), + integer: new KeyValueDef( + 'integer', + (value) => !!value.match(/^[-+]?\d+$/), + (value) => parseInt(value) + ), + string: new KeyValueDef( + 'string', + (_value) => true, + (value) => value + ), + dimen: new KeyValueDef( + 'dimen', + (value) => UnitUtil.matchDimen(value)[0] !== null, + (value) => value + ), +}; - /** - * Transforms mu dimension to em if necessary. - * @param {[string, string, number]} [value, unit, length] The dimension triple. - * @return {[string, string, number]} [value, unit, length] The transformed triple. - */ - function muReplace([value, unit, length]: [string, string, number]): [string, string, number] { - if (unit !== 'mu') { - return [value, unit, length]; +/** + * Implementation of the keyval function from https://www.ctan.org/pkg/keyval + * + * @param {string} text The optional parameter string for a package or + * command. + * @param {boolean?} l3keys If true, use l3key-style parsing (only remove one set of braces) + * @returns {EnvList} Set of options as key/value pairs. + */ +function readKeyval(text: string, l3keys: boolean = false): EnvList { + const options: EnvList = {}; + let rest = text; + let end, key, val; + let dropBrace = true; + while (rest) { + [key, end, rest] = readValue(rest, ['=', ','], l3keys, dropBrace); + dropBrace = false; + if (end === '=') { + [val, end, rest] = readValue(rest, [','], l3keys); + val = val === 'false' || val === 'true' ? JSON.parse(val) : val; + options[key] = val; + } else if (key) { + options[key] = true; } - let em = Em(UNIT_CASES[unit](parseFloat(value || '1'))); - return [em.slice(0, -2), 'em', length]; } + return options; +} - - /** - * Convert a dimension string into standard em dimension. - * @param {string} dim The attribute string. - * @return {number} The numerical value. - */ - export function dimen2em(dim: string): number { - let [value, unit] = matchDimen(dim); - let m = parseFloat(value || '1'); - let func = UNIT_CASES[unit]; - return func ? func(m) : 0; +/** + * Removes pairs of outer braces. + * + * @param {string} text The string to clean. + * @param {number} count The number of outer braces to slice off. + * @returns {string} The cleaned string. + */ +function removeBraces(text: string, count: number): string { + if (count === 0) { + return text + .replace(/^\s+/, '') + .replace(/([^\\\s]|^)((?:\\\\)*(?:\\\s)?)?\s+$/, '$1$2'); } + while (count > 0) { + text = text.trim().slice(1, -1); + count--; + } + return text; +} - - /** - * Turns a number into an em value. - * @param {number} m The number. - * @return {string} The em dimension string. - */ - export function Em(m: number): string { - if (Math.abs(m) < .0006) { - return '0em'; +/** + * Read a value from the given string until an end parameter is reached or + * string is exhausted. + * + * @param {string} text The string to process. + * @param {string[]} end List of possible end characters. + * @param {boolean?} l3keys If true, use l3key-style parsing (only remove one set of braces) + * @param {boolean?} dropBrace True if the outermost braces should be dropped + * @returns {[string, string, string]} The collected value, the actual end + * character, and the rest of the string still to parse. + */ +function readValue( + text: string, + end: string[], + l3keys: boolean = false, + dropBrace: boolean = false +): [string, string, string] { + const length = text.length; + let braces = 0; + let value = ''; + let index = 0; + let start = 0; // Counter for the starting left braces. + let countBraces = true; // Flag for counting starting left braces. + // after starting braces, but no other char yet. + while (index < length) { + const c = text[index++]; + switch (c) { + // Handle control sequences (in particular, \{ and \}) + case '\\': + value += c + (text[index++] || ''); + countBraces = false; + continue; + // Ignore spaces. + case ' ': + break; + // Count open left braces at start. + case '{': + if (countBraces) { + start++; + } + braces++; + break; + // Closing braces. + case '}': + if (!braces) { + throw new TexError( + 'ExtraCloseMissingOpen', + 'Extra close brace or missing open brace' + ); + } + braces--; + countBraces = false; // Stop counting start left braces. + break; + default: + if (!braces && end.includes(c)) { + // End character reached. + return [ + removeBraces(value, l3keys ? Math.min(1, start) : start), + c, + text.slice(index), + ]; + } + if (start > braces) { + // Some start left braces have been closed. + start = braces; + } + countBraces = false; } - return m.toFixed(3).replace(/\.?0+$/, '') + 'em'; + value += c; + } + if (braces) { + throw new TexError( + 'ExtraOpenMissingClose', + 'Extra open brace or missing close brace' + ); } + return dropBrace && start + ? ['', '', removeBraces(value, 1)] + : [ + removeBraces(value, l3keys ? Math.min(1, start) : start), + '', + text.slice(index), + ]; +} +export const ParseUtil = { + // Above will move into lenghts + // + // Remainder: Parse Utililities /** * Takes an array of numbers and returns a space-separated string of em values. + * * @param {number[]} W The widths to be turned into em values - * @return {string} The numbers with em units, separated by spaces. + * @returns {string} The numbers with em units, separated by spaces. */ - export function cols(...W: number[]): string { - return W.map(n => Em(n)).join(' '); - } - + cols(...W: number[]): string { + return W.map((n) => UnitUtil.em(n)).join(' '); + }, /** * Create an mrow that has stretchy delimiters at either end, as needed + * * @param {ParseOptions} configuration Current parse options. * @param {string} open The opening fence. * @param {MmlNode} mml The enclosed node. * @param {string} close The closing fence. * @param {string=} big Bigg command. + * @param {string=} color The color name. + * @returns {MmlNode} The newly created mrow. */ - export function fenced(configuration: ParseOptions, open: string, mml: MmlNode, - close: string, big: string = '', color: string = '') { + fenced( + configuration: ParseOptions, + open: string, + mml: MmlNode, + close: string, + big: string = '', + color: string = '' + ): MmlNode { // @test Fenced, Fenced3 - let nf = configuration.nodeFactory; - let mrow = nf.create('node', 'mrow', [], - {open: open, close: close, texClass: TEXCLASS.INNER}); + const nf = configuration.nodeFactory; + const mrow = nf.create('node', 'mrow', [], { + open: open, + close: close, + texClass: TEXCLASS.INNER, + }); let mo; if (big) { - mo = new TexParser('\\' + big + 'l' + open, configuration.parser.stack.env, configuration).mml(); + mo = new TexParser( + '\\' + big + 'l' + open, + configuration.parser.stack.env, + configuration + ).mml(); } else { - let openNode = nf.create('text', open); - mo = nf.create('node', 'mo', [], - {fence: true, stretchy: true, symmetric: true, texClass: TEXCLASS.OPEN}, - openNode); + const openNode = nf.create('text', open); + mo = nf.create( + 'node', + 'mo', + [], + { + fence: true, + stretchy: true, + symmetric: true, + texClass: TEXCLASS.OPEN, + }, + openNode + ); } NodeUtil.appendChildren(mrow, [mo, mml]); if (big) { - mo = new TexParser('\\' + big + 'r' + close, configuration.parser.stack.env, configuration).mml(); + mo = new TexParser( + '\\' + big + 'r' + close, + configuration.parser.stack.env, + configuration + ).mml(); } else { - let closeNode = nf.create('text', close); - mo = nf.create('node', 'mo', [], - {fence: true, stretchy: true, symmetric: true, texClass: TEXCLASS.CLOSE}, - closeNode); + const closeNode = nf.create('text', close); + mo = nf.create( + 'node', + 'mo', + [], + { + fence: true, + stretchy: true, + symmetric: true, + texClass: TEXCLASS.CLOSE, + }, + closeNode + ); + } + if (color) { + mo.attributes.set('mathcolor', color); } - color && mo.attributes.set('mathcolor', color); NodeUtil.appendChildren(mrow, [mo]); return mrow; - } - + }, /** * Create an mrow that has \\mathchoice using \\bigg and \\big for the delimiters. + * * @param {ParseOptions} configuration The current parse options. * @param {string} open The opening fence. * @param {MmlNode} mml The enclosed node. * @param {string} close The closing fence. - * @return {MmlNode} The mrow node. + * @returns {MmlNode} The mrow node. */ - export function fixedFence(configuration: ParseOptions, open: string, - mml: MmlNode, close: string): MmlNode { + fixedFence( + configuration: ParseOptions, + open: string, + mml: MmlNode, + close: string + ): MmlNode { // @test Choose, Over With Delims, Above with Delims - let mrow = configuration.nodeFactory.create('node', - 'mrow', [], {open: open, close: close, texClass: TEXCLASS.ORD}); + const mrow = configuration.nodeFactory.create('node', 'mrow', [], { + open: open, + close: close, + texClass: TEXCLASS.ORD, + }); if (open) { - NodeUtil.appendChildren(mrow, [mathPalette(configuration, open, 'l')]); + NodeUtil.appendChildren(mrow, [ + ParseUtil.mathPalette(configuration, open, 'l'), + ]); } if (NodeUtil.isType(mml, 'mrow')) { NodeUtil.appendChildren(mrow, NodeUtil.getChildren(mml)); @@ -183,83 +349,118 @@ namespace ParseUtil { NodeUtil.appendChildren(mrow, [mml]); } if (close) { - NodeUtil.appendChildren(mrow, [mathPalette(configuration, close, 'r')]); + NodeUtil.appendChildren(mrow, [ + ParseUtil.mathPalette(configuration, close, 'r'), + ]); } return mrow; - } - + }, /** * Generates a mathchoice element for fences. These will be resolved later, * once the position, and therefore size, of the of the fenced expression is * known. + * * @param {ParseOptions} configuration The current parse otpions. * @param {string} fence The fence. * @param {string} side The side of the fence (l or r). - * @return {MmlNode} The mathchoice node. + * @returns {MmlNode} The mathchoice node. */ - export function mathPalette(configuration: ParseOptions, fence: string, - side: string): MmlNode { + mathPalette( + configuration: ParseOptions, + fence: string, + side: string + ): MmlNode { if (fence === '{' || fence === '}') { fence = '\\' + fence; } - let D = '{\\bigg' + side + ' ' + fence + '}'; - let T = '{\\big' + side + ' ' + fence + '}'; - return new TexParser('\\mathchoice' + D + T + T + T, {}, configuration).mml(); - } - + const D = '{\\bigg' + side + ' ' + fence + '}'; + const T = '{\\big' + side + ' ' + fence + '}'; + return new TexParser( + '\\mathchoice' + D + T + T + T, + {}, + configuration + ).mml(); + }, /** * If the initial child, skipping any initial space or * empty braces (TeXAtom with child being an empty inferred row), * is an , precede it by an empty to force the to * be infix. + * * @param {ParseOptions} configuration The current parse options. * @param {MmlNode[]} nodes The row of nodes to scan for an initial */ - export function fixInitialMO(configuration: ParseOptions, nodes: MmlNode[]) { + fixInitialMO(configuration: ParseOptions, nodes: MmlNode[]) { for (let i = 0, m = nodes.length; i < m; i++) { - let child = nodes[i]; - if (child && (!NodeUtil.isType(child, 'mspace') && - (!NodeUtil.isType(child, 'TeXAtom') || - (NodeUtil.getChildren(child)[0] && - NodeUtil.getChildren(NodeUtil.getChildren(child)[0]).length)))) { - if (NodeUtil.isEmbellished(child) || - (NodeUtil.isType(child, 'TeXAtom') && NodeUtil.getTexClass(child) === TEXCLASS.REL)) { - let mi = configuration.nodeFactory.create('node', 'mi'); + const child = nodes[i]; + if ( + child && + !NodeUtil.isType(child, 'mspace') && + (!NodeUtil.isType(child, 'TeXAtom') || + (NodeUtil.getChildren(child)[0] && + NodeUtil.getChildren(NodeUtil.getChildren(child)[0]).length)) + ) { + if ( + NodeUtil.isEmbellished(child) || + (NodeUtil.isType(child, 'TeXAtom') && + NodeUtil.getTexClass(child) === TEXCLASS.REL) + ) { + const mi = configuration.nodeFactory.create('node', 'mi'); nodes.unshift(mi); } break; } } - } - + }, /** * Break up a string into text and math blocks. + * * @param {TexParser} parser The calling parser. * @param {string} text The text in the math expression to parse. * @param {number|string=} level The scriptlevel. * @param {string} font The mathvariant to use - * @return {MmlNode[]} The nodes corresponding to the internal math expression. + * @returns {MmlNode[]} The nodes corresponding to the internal math expression. */ - export function internalMath(parser: TexParser, text: string, - level?: number | string, font?: string): MmlNode[] { + internalMath( + parser: TexParser, + text: string, + level?: number | string, + font?: string + ): MmlNode[] { + text = text.replace(/ +/g, ' '); if (parser.configuration.options.internalMath) { - return parser.configuration.options.internalMath(parser, text, level, font); + return parser.configuration.options.internalMath( + parser, + text, + level, + font + ); } - let mathvariant = font || parser.stack.env.font; - let def = (mathvariant ? {mathvariant} : {}); - let mml: MmlNode[] = [], i = 0, k = 0, c, node, match = '', braces = 0; - if (text.match(/\\?[${}\\]|\\\(|\\(eq)?ref\s*\{/)) { + const mathvariant = font || parser.stack.env.font; + const def = mathvariant ? { mathvariant } : {}; + let mml: MmlNode[] = [], + i = 0, + k = 0, + c, + node, + match = '', + braces = 0; + if (text.match(/\\?[${}\\]|\\\(|\\(?:eq)?ref\s*\{|\\U/)) { while (i < text.length) { c = text.charAt(i++); if (c === '$') { if (match === '$' && braces === 0) { // @test Interspersed Text - node = parser.create( - 'node', 'TeXAtom', - [(new TexParser(text.slice(k, i - 1), {}, parser.configuration)).mml()]); + node = parser.create('node', 'TeXAtom', [ + new TexParser( + text.slice(k, i - 1), + {}, + parser.configuration + ).mml(), + ]); mml.push(node); match = ''; k = i; @@ -267,7 +468,9 @@ namespace ParseUtil { // @test Interspersed Text if (k < i - 1) { // @test Interspersed Text - mml.push(internalText(parser, text.slice(k, i - 1), def)); + mml.push( + ParseUtil.internalText(parser, text.slice(k, i - 1), def) + ); } match = '$'; k = i; @@ -279,7 +482,11 @@ namespace ParseUtil { // @test Mbox Mbox, Mbox Math if (match === '}' && braces === 0) { // @test Mbox Eqref, Mbox Math - let atom = (new TexParser(text.slice(k, i), {}, parser.configuration)).mml(); + const atom = new TexParser( + text.slice(k, i), + {}, + parser.configuration + ).mml(); node = parser.create('node', 'TeXAtom', [atom], def); mml.push(node); match = ''; @@ -293,12 +500,14 @@ namespace ParseUtil { } } else if (c === '\\') { // @test Mbox Eqref, Mbox CR - if (match === '' && text.substr(i).match(/^(eq)?ref\s*\{/)) { + if (match === '' && text.substring(i).match(/^(eq)?ref\s*\{/)) { // @test Mbox Eqref - let len = ((RegExp as any)['$&'] as string).length; + const len = ((RegExp as any)['$&'] as string).length; if (k < i - 1) { // @test Mbox Eqref - mml.push(internalText(parser, text.slice(k, i - 1), def)); + mml.push( + ParseUtil.internalText(parser, text.slice(k, i - 1), def) + ); } match = '}'; k = i - 1; @@ -310,127 +519,181 @@ namespace ParseUtil { // @test Mbox Internal Display if (k < i - 2) { // @test Mbox Internal Display - mml.push(internalText(parser, text.slice(k, i - 2), def)); + mml.push( + ParseUtil.internalText(parser, text.slice(k, i - 2), def) + ); } - match = ')'; k = i; + match = ')'; + k = i; } else if (c === ')' && match === ')' && braces === 0) { // @test Mbox Internal Display - node = parser.create( - 'node', 'TeXAtom', - [(new TexParser(text.slice(k, i - 2), {}, parser.configuration)).mml()]); + node = parser.create('node', 'TeXAtom', [ + new TexParser( + text.slice(k, i - 2), + {}, + parser.configuration + ).mml(), + ]); mml.push(node); match = ''; k = i; - } else if (c.match(/[${}\\]/) && match === '') { + } else if (c.match(/[${}\\]/) && match === '') { // @test Mbox CR i--; - text = text.substr(0, i - 1) + text.substr(i); // remove \ from \$, \{, \}, or \\ + text = text.substring(0, i - 1) + text.substring(i); // remove \ from \$, \{, \}, or \\ + } else if (c === 'U') { + const arg = text + .substring(i) + .match(/^\s*(?:([0-9A-F])|\{\s*([0-9A-F]+)\s*\})/); + if (!arg) { + throw new TexError( + 'BadRawUnicode', + 'Argument to %1 must a hexadecimal number with 1 to 6 digits', + '\\U' + ); + } + // Replace \U{...} with specified character + const c = String.fromCodePoint(parseInt(arg[1] || arg[2], 16)); + text = + text.substring(0, i - 2) + + c + + text.substring(i + arg[0].length); + i = i - 2 + c.length; } } } } if (match !== '') { // @test Internal Math Error - throw new TexError('MathNotTerminated', 'Math not terminated in text box'); + throw new TexError( + 'MathNotTerminated', + 'Math mode is not properly terminated' + ); } } if (k < text.length) { // @test Interspersed Text, Mbox Mbox - mml.push(internalText(parser, text.slice(k), def)); + mml.push(ParseUtil.internalText(parser, text.slice(k), def)); } if (level != null) { // @test Label, Fbox, Hbox - mml = [parser.create('node', 'mstyle', mml, {displaystyle: false, scriptlevel: level})]; + mml = [ + parser.create('node', 'mstyle', mml, { + displaystyle: false, + scriptlevel: level, + }), + ]; } else if (mml.length > 1) { // @test Interspersed Text mml = [parser.create('node', 'mrow', mml)]; } return mml; - } - + }, /** * Parses text internal to boxes or labels. + * * @param {TexParser} parser The current tex parser. * @param {string} text The text to parse. * @param {EnvList} def The attributes of the text node. - * @return {MmlNode} The text node. + * @returns {MmlNode} The text node. */ - export function internalText(parser: TexParser, text: string, def: EnvList): MmlNode { + internalText(parser: TexParser, text: string, def: EnvList): MmlNode { // @test Label, Fbox, Hbox - text = text.replace(/^\s+/, entities.nbsp).replace(/\s+$/, entities.nbsp); - let textNode = parser.create('text', text); + text = text + .replace(/\n+/g, ' ') + .replace(/^ +/, entities.nbsp) + .replace(/ +$/, entities.nbsp); + const textNode = parser.create('text', text); return parser.create('node', 'mtext', [], def, textNode); - } + }, /** * Create an munderover node with the given script position. + * * @param {TexParser} parser The current TeX parser. * @param {MmlNode} base The base node. * @param {MmlNode} script The under- or over-script. * @param {string} pos Either 'over' or 'under'. * @param {boolean} stack True if super- or sub-scripts should stack. - * @return {MmlNode} The generated node (MmlMunderover or TeXAtom) + * @returns {MmlNode} The generated node (MmlMunderover or TeXAtom) */ - export function underOver(parser: TexParser, base: MmlNode, script: MmlNode, pos: string, stack: boolean): MmlNode { + underOver( + parser: TexParser, + base: MmlNode, + script: MmlNode, + pos: string, + stack: boolean + ): MmlNode { // @test Overline ParseUtil.checkMovableLimits(base); if (NodeUtil.isType(base, 'munderover') && NodeUtil.isEmbellished(base)) { // @test Overline Limits - NodeUtil.setProperties(NodeUtil.getCoreMO(base), {lspace: 0, rspace: 0}); - const mo = parser.create('node', 'mo', [], {rspace: 0}); + NodeUtil.setProperties(NodeUtil.getCoreMO(base), { + lspace: 0, + rspace: 0, + }); + const mo = parser.create('node', 'mo', [], { rspace: 0 }); base = parser.create('node', 'mrow', [mo, base]); // TODO? add an empty so it's not embellished any more } const mml = parser.create('node', 'munderover', [base]) as MmlMunderover; - NodeUtil.setChild(mml, pos === 'over' ? mml.over : mml.under, script); + NodeUtil.setChild(mml, pos === 'over' ? mml.over : mml.under, script); let node: MmlNode = mml; if (stack) { // @test Overbrace 1 2 3, Underbrace, Overbrace Op 1 2 - node = parser.create('node', 'TeXAtom', [mml], {texClass: TEXCLASS.OP, movesupsub: true}); + node = parser.create( + 'node', + 'TeXAtom', + [ + parser.create('node', 'mstyle', [mml], { + displaystyle: true, + scriptlevel: 0, + }), + ], + { + texClass: TEXCLASS.OP, + movesupsub: true, + } + ); } NodeUtil.setProperty(node, 'subsupOK', true); return node; - } + }, /** * Set movablelimits to false if necessary. + * * @param {MmlNode} base The base node being tested. */ - export function checkMovableLimits(base: MmlNode) { - const symbol = (NodeUtil.isType(base, 'mo') ? NodeUtil.getForm(base) : null); - if (NodeUtil.getProperty(base, 'movablelimits') || (symbol && symbol[3] && symbol[3].movablelimits)) { + checkMovableLimits(base: MmlNode) { + const symbol = NodeUtil.isType(base, 'mo') ? NodeUtil.getForm(base) : null; + if ( + NodeUtil.getProperty(base, 'movablelimits') || + (symbol && symbol[3] && symbol[3].movablelimits) + ) { // @test Overline Sum - NodeUtil.setProperties(base, {movablelimits: false}); + NodeUtil.setProperties(base, { movablelimits: false }); } - } - - /** - * Trim spaces from a string. - * @param {string} text The string to clean. - * @return {string} The string with leading and trailing whitespace removed. - */ - export function trimSpaces(text: string): string { - if (typeof(text) !== 'string') { - return text; - } - let TEXT = text.trim(); - if (TEXT.match(/\\$/) && text.match(/ $/)) { - TEXT += ' '; - } - return TEXT; - } - + }, /** * Sets alignment in array definitions. + * * @param {ArrayItem} array The array item. * @param {string} align The alignment string. - * @return {ArrayItem} The altered array item. + * @param {TexParser?} parser The current tex parser. + * @returns {ArrayItem} The altered array item. */ - export function setArrayAlign(array: ArrayItem, align: string): ArrayItem { + setArrayAlign( + array: ArrayItem, + align: string, + parser?: TexParser + ): ArrayItem { // @test Array1, Array2, Array Test - align = ParseUtil.trimSpaces(align || ''); + if (!parser) { + align = UnitUtil.trimSpaces(align || ''); + } if (align === 't') { array.arraydef.align = 'baseline 1'; } else if (align === 'b') { @@ -438,21 +701,25 @@ namespace ParseUtil { } else if (align === 'c') { array.arraydef.align = 'axis'; } else if (align) { - array.arraydef.align = align; - } // FIXME: should be an error? + if (parser) { + parser.string = `[${align}]` + parser.string.slice(parser.i); + parser.i = 0; + } else { + array.arraydef.align = align; + } + } return array; - } - + }, /** * Replace macro parameters with their values. + * * @param {TexParser} parser The current TeX parser. * @param {string[]} args A list of arguments for macro parameters. * @param {string} str The macro parameter string. - * @return {string} The string with all parameters replaced by arguments. + * @returns {string} The string with all parameters replaced by arguments. */ - export function substituteArgs(parser: TexParser, args: string[], - str: string): string { + substituteArgs(parser: TexParser, args: string[], str: string): string { let text = ''; let newstring = ''; let i = 0; @@ -460,142 +727,190 @@ namespace ParseUtil { let c = str.charAt(i++); if (c === '\\') { text += c + str.charAt(i++); - } - else if (c === '#') { + } else if (c === '#') { c = str.charAt(i++); if (c === '#') { text += c; } else { if (!c.match(/[1-9]/) || parseInt(c, 10) > args.length) { - throw new TexError('IllegalMacroParam', - 'Illegal macro parameter reference'); + throw new TexError( + 'IllegalMacroParam', + 'Illegal macro parameter reference' + ); } - newstring = addArgs(parser, addArgs(parser, newstring, text), - args[parseInt(c, 10) - 1]); + newstring = ParseUtil.addArgs( + parser, + ParseUtil.addArgs(parser, newstring, text), + args[parseInt(c, 10) - 1] + ); text = ''; } } else { text += c; } } - return addArgs(parser, newstring, text); - } - + return ParseUtil.addArgs(parser, newstring, text); + }, /** * Adds a new expanded argument to an already macro parameter string. Makes * sure that macros are followed by a space if their names could accidentally * be continued into the following text. + * * @param {TexParser} parser The current TeX parser. * @param {string} s1 The already expanded string. * @param {string} s2 The string to add. - * @return {string} The combined string. + * @returns {string} The combined string. */ - export function addArgs(parser: TexParser, s1: string, s2: string): string { + addArgs(parser: TexParser, s1: string, s2: string): string { if (s2.match(/^[a-z]/i) && s1.match(/(^|[^\\])(\\\\)*\\[a-z]+$/i)) { s1 += ' '; } if (s1.length + s2.length > parser.configuration.options['maxBuffer']) { - throw new TexError('MaxBufferSize', - 'MathJax internal buffer size exceeded; is there a' + - ' recursive macro call?'); + throw new TexError( + 'MaxBufferSize', + 'MathJax internal buffer size exceeded; is there a' + + ' recursive macro call?' + ); } return s1 + s2; - } + }, /** * Report an error if there are too many macro substitutions. + * * @param {TexParser} parser The current TeX parser. * @param {boolean} isMacro True if we are substituting a macro, false for environment. */ - export function checkMaxMacros(parser: TexParser, isMacro: boolean = true) { + checkMaxMacros(parser: TexParser, isMacro: boolean = true) { if (++parser.macroCount <= parser.configuration.options['maxMacros']) { return; } if (isMacro) { - throw new TexError('MaxMacroSub1', - 'MathJax maximum macro substitution count exceeded; ' + - 'is here a recursive macro call?'); + throw new TexError( + 'MaxMacroSub1', + 'MathJax maximum macro substitution count exceeded; ' + + 'is here a recursive macro call?' + ); } else { - throw new TexError('MaxMacroSub2', - 'MathJax maximum substitution count exceeded; ' + - 'is there a recursive latex environment?'); + throw new TexError( + 'MaxMacroSub2', + 'MathJax maximum substitution count exceeded; ' + + 'is there a recursive latex environment?' + ); } - } - + }, /** * Check for bad nesting of equation environments + * + * @param {TexParser} parser The current parser. + * @param {boolean=} nestable Is the environment nestable? */ - export function checkEqnEnv(parser: TexParser) { - if (parser.stack.global.eqnenv) { - // @test ErroneousNestingEq - throw new TexError('ErroneousNestingEq', 'Erroneous nesting of equation structures'); + checkEqnEnv(parser: TexParser, nestable: boolean = true) { + const top = parser.stack.Top(); + const first = top.First; + // + // The gather environment can include align and others, but only one level deep. + // + if ( + (top.getProperty('nestable') && nestable && !first) || + top.getProperty('nestStart') + ) { + return; } - parser.stack.global.eqnenv = true; - } + if (!top.isKind('start') || first) { + throw new TexError( + 'ErroneousNestingEq', + 'Erroneous nesting of equation structures' + ); + } + }, /** * Copy an MmlNode and add it (and its children) to the proper lists. * * @param {MmlNode} node The MmlNode to copy * @param {TexParser} parser The active tex parser - * @return {MmlNode} The duplicate tree + * @returns {MmlNode} The duplicate tree */ - export function copyNode(node: MmlNode, parser: TexParser): MmlNode { - const tree = node.copy() as MmlNode; + copyNode(node: MmlNode, parser: TexParser): MmlNode { + const tree = node.copy(); const options = parser.configuration; tree.walkTree((n: MmlNode) => { options.addNode(n.kind, n); - const lists = (n.getProperty('in-lists') as string || '').split(/,/); + const lists = ((n.getProperty('in-lists') as string) || '').split(/,/); for (const list of lists) { - list && options.addNode(list, n); + if (list) { + options.addNode(list, n); + } } }); return tree; - } + }, /** * This is a placeholder for future security filtering of attributes. - * @param {TexParser} parser The current parser. - * @param {string} name The attribute name. + * + * @param {TexParser} _parser The current parser. + * @param {string} _name The attribute name. * @param {string} value The attribute value to filter. - * @return {string} The filtered value. + * @returns {string} The filtered value. */ - export function MmlFilterAttribute(_parser: TexParser, _name: string, value: string): string { + mmlFilterAttribute(_parser: TexParser, _name: string, value: string): string { // TODO: Implement in security package. return value; - } - + }, /** * Initialises an stack environment with current font definition in the parser. + * * @param {TexParser} parser The current tex parser. - * @return {EnvList} The initialised environment list. + * @returns {EnvList} The initialised environment list. */ - export function getFontDef(parser: TexParser): EnvList { + getFontDef(parser: TexParser): EnvList { const font = parser.stack.env['font']; - return (font ? {mathvariant: font} : {}); - } - + return font ? { mathvariant: font } : {}; + }, /** * Splits a package option list of the form [x=y,z=1] into an attribute list * of the form {x: y, z: 1}. + * * @param {string} attrib The attributes of the package. * @param {{[key: string]: number}?} allowed A list of allowed options. If * given only allowed arguments are returned. * @param {boolean?} error If true, raises an exception if not allowed options * are found. - * @return {EnvList} The attribute list. + * @param {boolean?} l3keys If true, use l3key-style parsing (only remove one set of braces) + * @returns {EnvList} The attribute list. */ - export function keyvalOptions(attrib: string, - allowed: {[key: string]: number} = null, - error: boolean = false): EnvList { - let def: EnvList = readKeyval(attrib); + keyvalOptions( + attrib: string, + allowed: { [key: string]: number | KeyValueType } = null, + error: boolean = false, + l3keys: boolean = false + ): EnvList { + const def: EnvList = readKeyval(attrib, l3keys); if (allowed) { - for (let key of Object.keys(def)) { - if (!allowed.hasOwnProperty(key)) { + for (const key of Object.keys(def)) { + if (Object.hasOwn(allowed, key)) { + // + // If allowed[key] is a type definition, check the key value against that + // + if (allowed[key] instanceof KeyValueDef) { + const type = allowed[key] as KeyValueDef; + const value = String(def[key]); + if (!type.verify(value)) { + throw new TexError( + 'InvalidValue', + "Value for key '%1' is not of the expected type", + key + ); + } + def[key] = type.convert(value); + } + } else { if (error) { throw new TexError('InvalidOption', 'Invalid option: %1', key); } @@ -604,110 +919,13 @@ namespace ParseUtil { } } return def; - } - + }, /** - * Implementation of the keyval function from https://www.ctan.org/pkg/keyval - * @param {string} text The optional parameter string for a package or - * command. - * @return {EnvList} Set of options as key/value pairs. + * @param {string} c The character to test. + * @returns {boolean} True if the character is Latin or Greek */ - function readKeyval(text: string): EnvList { - let options: EnvList = {}; - let rest = text; - let end, key, val; - while (rest) { - [key, end, rest] = readValue(rest, ['=', ',']); - if (end === '=') { - [val, end, rest] = readValue(rest, [',']); - val = (val === 'false' || val === 'true') ? - JSON.parse(val) : val; - options[key] = val; - } else if (key) { - options[key] = true; - } - } - return options; - } - - - /** - * Removes pairs of outer braces. - * @param {string} text The string to clean. - * @param {number} count The number of outer braces to slice off. - * @return {string} The cleaned string. - */ - function removeBraces(text: string, count: number): string { - while (count > 0) { - text = text.trim().slice(1, -1); - count--; - } - return text.trim(); - } - - - /** - * Read a value from the given string until an end parameter is reached or - * string is exhausted. - * @param {string} text The string to process. - * @param {string[]} end List of possible end characters. - * @return {[string, string, string]} The collected value, the actual end - * character, and the rest of the string still to parse. - */ - function readValue(text: string, end: string[]): [string, string, string] { - let length = text.length; - let braces = 0; - let value = ''; - let index = 0; - let start = 0; // Counter for the starting left braces. - let startCount = true; // Flag for counting starting left braces. - let stopCount = false; // If true right braces are found directly - // after starting braces, but no other char yet. - while (index < length) { - let c = text[index++]; - switch (c) { - case ' ': // Ignore spaces. - break; - case '{': - if (startCount) { // Count start left braces at start. - start++; - } else { - stopCount = false; - if (start > braces) { // Some start left braces have been closed. - start = braces; - } - } - braces++; - break; - case '}': - if (braces) { // Closing braces. - braces--; - } - if (startCount || stopCount) { // Closing braces at the start. - start--; - stopCount = true; // Continue to close braces. - } - startCount = false; // Stop counting start left braces. - break; - default: - if (!braces && end.indexOf(c) !== -1) { // End character reached. - return [stopCount ? 'true' : // If Stop count is true we - // have balanced braces, only. - removeBraces(value, start), c, text.slice(index)]; - } - startCount = false; - stopCount = false; - } - value += c; - } - if (braces) { - throw new TexError('ExtraOpenMissingClose', - 'Extra open brace or missing close brace'); - } - return [stopCount ? 'true' : removeBraces(value, start), '', text.slice(index)]; - } - -} - -export default ParseUtil; + isLatinOrGreekChar(c: string): boolean { + return !!c.normalize('NFD').match(/[a-zA-Z\u0370-\u03F0]/); + }, +}; diff --git a/ts/input/tex/Stack.ts b/ts/input/tex/Stack.ts index 599985724..6bc75cd98 100644 --- a/ts/input/tex/Stack.ts +++ b/ts/input/tex/Stack.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,22 +15,18 @@ * limitations under the License. */ - /** - * @fileoverview The Stack for the TeX parser. + * @file The Stack for the TeX parser. * * @author v.sorge@mathjax.org (Volker Sorge) */ - import NodeUtil from './NodeUtil.js'; -import {MmlNode} from '../../core/MmlTree/MmlNode.js'; -import {StackItem, EnvList} from './StackItem.js'; +import { MmlNode } from '../../core/MmlTree/MmlNode.js'; +import { StackItem, EnvList } from './StackItem.js'; import StackItemFactory from './StackItemFactory.js'; - export default class Stack { - /** * @type {EnvList} */ @@ -38,47 +34,51 @@ export default class Stack { /** * The actual stack, a list of stack items. + * * @type {Array.} */ private stack: StackItem[] = []; /** - * @constructor - * @param {StackItemFactory} factory The stack item factory. - * @param {EnvList} env The environment. + * @class + * @param {StackItemFactory} _factory The stack item factory. + * @param {EnvList} _env The environment. * @param {boolean} inner True if parser has been called recursively. */ - constructor(private _factory: StackItemFactory, - private _env: EnvList, inner: boolean) { - this.global = {isInner: inner}; - this.stack = [ this._factory.create('start', this.global) ]; + constructor( + private _factory: StackItemFactory, + private _env: EnvList, + inner: boolean + ) { + this.global = { isInner: inner }; + this.stack = [this._factory.create('start', this.global)]; if (_env) { this.stack[0].env = _env; } this.env = this.stack[0].env; } - /** * Set the environment of the stack. + * * @param {EnvList} env The new environment. */ public set env(env: EnvList) { this._env = env; } - /** * Retrieves the environment of that stack. - * @return {EnvList} The current environment. + * + * @returns {EnvList} The current environment. */ public get env(): EnvList { return this._env; } - /** * Pushes items or nodes onto stack. + * * @param {...StackItem|MmlNode} args A list of items to push. */ public Push(...args: (StackItem | MmlNode)[]) { @@ -86,11 +86,13 @@ export default class Stack { if (!node) { continue; } - const item = NodeUtil.isNode(node) ? - this._factory.create('mml', node) : node as StackItem; + const item = NodeUtil.isNode(node) + ? this._factory.create('mml', node) + : (node as StackItem); item.global = this.global; - const [top, success] = - this.stack.length ? this.Top().checkItem(item) : [null, true]; + const [top, success] = this.stack.length + ? this.Top().checkItem(item) + : [null, true]; if (!success) { continue; } @@ -99,7 +101,9 @@ export default class Stack { this.Push(...top); continue; } - this.stack.push(item); + if (!item.isKind('null')) { + this.stack.push(item); + } if (item.env) { if (item.copyEnv) { Object.assign(item.env, this.env); @@ -111,42 +115,50 @@ export default class Stack { } } - /** * Pop the topmost elements off the stack. - * @return {StackItem} A stack item. + * + * @returns {StackItem} A stack item. */ public Pop(): StackItem { const item = this.stack.pop(); if (!item.isOpen) { delete item.env; } - this.env = (this.stack.length ? this.Top().env : {}); + this.env = this.stack.length ? this.Top().env : {}; return item; } - /** - * Lookup the nth elements on the stack without removing them. + * Look up the nth elements on the stack without removing them. + * * @param {number=} n Position of element that should be returned. Default 1. - * @return {StackItem} Nth item on the stack. + * @returns {StackItem} Nth item on the stack. */ public Top(n: number = 1): StackItem { return this.stack.length < n ? null : this.stack[this.stack.length - n]; } - /** - * Lookup the topmost element on the stack, returning the Mml node in that + * Look up the topmost element on the stack, returning the Mml node in that * item. Optionally pops the Mml node from that stack item. + * * @param {boolean=} noPop Pop top item if true. - * @return {MmlNode} The Mml node in the topmost stack item. + * @returns {MmlNode} The Mml node in the topmost stack item. */ public Prev(noPop?: boolean): MmlNode | void { const top = this.Top(); return noPop ? top.First : top.Pop(); } + /** + * Look up the current number of stack items. + * + * @returns {number} The number of items on the stack. + */ + public get height(): number { + return this.stack.length; + } /** * @override @@ -154,5 +166,4 @@ export default class Stack { public toString() { return 'stack[\n ' + this.stack.join('\n ') + '\n]'; } - } diff --git a/ts/input/tex/StackItem.ts b/ts/input/tex/StackItem.ts index 900979ca2..f230ecbbb 100644 --- a/ts/input/tex/StackItem.ts +++ b/ts/input/tex/StackItem.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,65 +15,66 @@ * limitations under the License. */ - /** - * @fileoverview Stack items hold information on the TexParser stack. + * @file Stack items hold information on the TexParser stack. * * @author v.sorge@mathjax.org (Volker Sorge) */ -import {MmlNode} from '../../core/MmlTree/MmlNode.js'; -import {FactoryNodeClass} from '../../core/Tree/Factory.js'; +import { MmlNode } from '../../core/MmlTree/MmlNode.js'; +import { FactoryNodeClass } from '../../core/Tree/Factory.js'; import TexError from './TexError.js'; import StackItemFactory from './StackItemFactory.js'; // Union types for abbreviation. export type EnvProp = string | number | boolean; -export type EnvList = {[key: string]: EnvProp}; +export type EnvList = { [key: string]: EnvProp }; // This is the type for all fields that used to be set with With. export type Prop = string | number | boolean | MmlNode | PropList; -export type PropList = {[key: string]: Prop}; +export type PropList = { [key: string]: Prop }; export type CheckType = [(MmlNode | StackItem)[], boolean]; - export interface NodeStack { - /** * Get or set the topmost element on the node stack without removing it. - * @return {MmlNode} The topmost node on the stack. + * + * @returns {MmlNode} The topmost node on the stack. */ First: MmlNode; /** * Get or set the last element on the node stack without removing it. - * @return {MmlNode} The last node on the stack. + * + * @returns {MmlNode} The last node on the stack. */ Last: MmlNode; /** - * @return {MmlNode} The topmost node on the item's node stack. + * @returns {MmlNode} The topmost node on the item's node stack. */ Pop(): MmlNode | void; /** * Pushes new nodes onto the items node stack. - * @param {MmlNode[]} ...nodes A list of nodes. + * + * @param {MmlNode[]} nodes A list of nodes. */ Push(...nodes: MmlNode[]): void; /** * Get the top n elements on the node stack without removing them. + * * @param {number=} n Number of elements that should be returned. - * @return {MmlNode[]} List of nodes on top of stack. + * @returns {MmlNode[]} List of nodes on top of stack. */ Peek(n?: number): MmlNode[]; /** - * @return {number} The size of the stack. + * @returns {number} The size of the stack. */ Size(): number; @@ -82,30 +83,58 @@ export interface NodeStack { */ Clear(): void; + /** + * The LaTeX string at the moment item is called. + */ + startStr: string; + + /** + * Parser position in the global LaTeX string when item is called. + */ + startI: number; + + /** + * Parser position in the global LaTeX string when item is pushed. + */ + stopI: number; + /** * Returns nodes on the stack item's node stack as an Mml node. I.e., in case * the item contains more than one node, it creates an mrow. + * * @param {boolean=} inferred If set the mrow will be an inferred mrow. * @param {boolean=} forceRow If set an mrow will be created, regardless of * how many nodes the item contains. - * @return {MmlNode} The topmost Mml node. + * @returns {MmlNode} The topmost Mml node. */ toMml(inferred?: boolean, forceRow?: boolean): MmlNode; - } - export abstract class MmlStack implements NodeStack { + /** + * @override + */ + public startStr: string = ''; + + /** + * @override + */ + public startI: number = 0; + + /** + * @override + */ + public stopI: number = 0; /** - * @constructor - * @extends {NodeStack} - * @param {MmlNode[]} nodes An initial list of nodes to put on the stack. + * @class + * @augments {NodeStack} + * @param {MmlNode[]} _nodes An initial list of nodes to put on the stack. */ - constructor(private _nodes: MmlNode[]) { } + constructor(private _nodes: MmlNode[]) {} /** - * @return {MmlNode[]} The nodes on the stack. + * @returns {MmlNode[]} The nodes on the stack. */ protected get nodes(): MmlNode[] { return this._nodes; @@ -118,7 +147,6 @@ export abstract class MmlStack implements NodeStack { this._nodes.push(...nodes); } - /** * @override */ @@ -126,7 +154,6 @@ export abstract class MmlStack implements NodeStack { return this._nodes.pop(); } - /** * @override */ @@ -134,7 +161,6 @@ export abstract class MmlStack implements NodeStack { return this._nodes[this.Size() - 1]; } - /** * @override */ @@ -142,7 +168,6 @@ export abstract class MmlStack implements NodeStack { this._nodes[this.Size() - 1] = node; } - /** * @override */ @@ -150,7 +175,6 @@ export abstract class MmlStack implements NodeStack { return this._nodes[0]; } - /** * @override */ @@ -158,7 +182,6 @@ export abstract class MmlStack implements NodeStack { this._nodes[0] = node; } - /** * @override */ @@ -169,7 +192,6 @@ export abstract class MmlStack implements NodeStack { return this._nodes.slice(this.Size() - n); } - /** * @override */ @@ -177,7 +199,6 @@ export abstract class MmlStack implements NodeStack { return this._nodes.length; } - /** * @override */ @@ -185,7 +206,6 @@ export abstract class MmlStack implements NodeStack { this._nodes = []; } - protected abstract get factory(): StackItemFactory; /** @@ -197,99 +217,113 @@ export abstract class MmlStack implements NodeStack { } // @test Two Identifiers return this.create( - 'node', inferred ? 'inferredMrow' : 'mrow', this._nodes, {}); + 'node', + inferred ? 'inferredMrow' : 'mrow', + this._nodes, + {} + ); } - /** * Convenience method to create nodes with the node factory on this stack. + * * @param {string} kind The kind of node to create. - * @param {any[]} ...rest The remaining arguments for the creation method. - * @return {MmlNode} The newly created node. + * @param {...any} rest The remaining arguments for the creation method. + * @returns {MmlNode} The newly created node. */ public create(kind: string, ...rest: any[]): MmlNode { return this.factory.configuration.nodeFactory.create(kind, ...rest); } - } export interface StackItem extends NodeStack { - - /** * Type of stack item. + * * @type {string} */ kind: string; /** * Is this a closing item, e.g., end. + * * @type {boolean} */ isClose: boolean; /** * Is this an opening item, e.g., begin. + * * @type {boolean} */ isOpen: boolean; /** * Is this a finalising item, i.e., one that only collects nodes. + * * @type {boolean} */ isFinal: boolean; /** * Global properties of the parser. + * * @type {EnvList} */ - global: EnvList; + global: EnvList; /** * Local properties of the stack item. + * * @type {EnvList} */ - env: EnvList; + env: EnvList; /** * Copy local properties when pushed to stack? + * Default is to copy local environment when pushed on stack. + * * @type {boolean} */ - copyEnv: boolean; + copyEnv: boolean; /** * Tests if item is of the given type. + * * @param {string} kind The type. - * @return {boolean} True if item is of that type. + * @returns {boolean} True if item is of that type. */ isKind(kind: string): boolean; /** * Get a property of the item. + * * @param {string} key Property name. - * @return {Prop} Property value if it exists. + * @returns {Prop} Property value if it exists. */ getProperty(key: string): Prop; /** * Set a property. + * * @param {string} key Property name. * @param {Prop} value Property value. - * @return {StackItem} The item for pipelining. + * @returns {StackItem} The item for pipelining. */ setProperty(key: string, value: Prop): StackItem; /** * Sets a list of properties. + * * @param {PropList} def The properties to set. - * @return {StackItem} Returns the stack item object for pipelining. + * @returns {StackItem} Returns the stack item object for pipelining. */ setProperties(def: PropList): StackItem; /** * Convenience method for returning the string property "name". - * @return {string} The value for the name property. + * + * @returns {string} The value for the name property. */ getName(): string; @@ -314,50 +348,49 @@ export interface StackItem extends NodeStack { * for 'foo' or does not exist an error is thrown. * * @param {StackItem} item The pushed item. - * @return {CheckType} True/false or an item or node. + * @returns {CheckType} True/false or an item or node. */ checkItem(item: StackItem): CheckType; - } export interface StackItemClass extends FactoryNodeClass { // new (factory: StackItemFactory, ...args: any[]): StackItem; } - /** * Abstract basic item class that implements most of the stack item * functionality. In particular, it contains the base method for checkItem. */ export abstract class BaseItem extends MmlStack implements StackItem { - /** * The fail value. + * * @type {CheckType} */ protected static fail: CheckType = [null, false]; /** * The success value. + * * @type {CheckType} */ protected static success: CheckType = [null, true]; /** * A list of basic errors. + * * @type {{[key: string]: string[]}} */ - protected static errors: {[key: string]: string[]} = { + protected static errors: { [key: string]: string[] } = { // @test ExtraOpenMissingClose end: ['MissingBeginExtraEnd', 'Missing \\begin{%1} or extra \\end{%1}'], // @test ExtraCloseMissingOpen close: ['ExtraCloseMissingOpen', 'Extra close brace or missing open brace'], // @test MissingLeftExtraRight right: ['MissingLeftExtraRight', 'Missing \\left or extra \\right'], - middle: ['ExtraMiddle', 'Extra \\middle'] + middle: ['ExtraMiddle', 'Extra \\middle'], }; - /** * @override */ @@ -367,12 +400,16 @@ export abstract class BaseItem extends MmlStack implements StackItem { private _properties: PropList = {}; - /** - * @constructor - * @extends {MmlStack} + * @param {StackItemFactory} factory The factory for stack items. + * @param {MmlNode[]} nodes Initial list of nodes to put on the stack. + * @class + * @augments {MmlStack} */ - constructor(protected factory: StackItemFactory, ...nodes: MmlNode[]) { + constructor( + protected factory: StackItemFactory, + ...nodes: MmlNode[] + ) { super(nodes); if (this.isOpen) { this._env = {}; @@ -380,14 +417,14 @@ export abstract class BaseItem extends MmlStack implements StackItem { } /** - * @return {string} The type of the stack item. + * @returns {string} The type of the stack item. */ - public get kind(): string { + public get kind(): string { return 'base'; } /** - * @return {EnvList} Get the private environment + * @returns {EnvList} Get the private environment */ public get env(): EnvList { return this._env; @@ -395,6 +432,7 @@ export abstract class BaseItem extends MmlStack implements StackItem { /** * Set the private environment + * * @param {EnvList} value New private environemt. */ public set env(value: EnvList) { @@ -402,7 +440,7 @@ export abstract class BaseItem extends MmlStack implements StackItem { } /** - * Default is to copy local environment when pushed on stack + * @override */ public get copyEnv() { return true; @@ -423,9 +461,8 @@ export abstract class BaseItem extends MmlStack implements StackItem { return this; } - /** - * @return {boolean} True if item is an opening entity, i.e., it expects a + * @returns {boolean} True if item is an opening entity, i.e., it expects a * closing counterpart on the stack later. */ get isOpen(): boolean { @@ -433,23 +470,21 @@ export abstract class BaseItem extends MmlStack implements StackItem { } /** - * @return {boolean} True if item is an closing entity, i.e., it needs an + * @returns {boolean} True if item is an closing entity, i.e., it needs an * opening counterpart already on the stack. */ get isClose(): boolean { return false; } - /** - * @return {boolean} True if item is final, i.e., it contains one or multiple + * @returns {boolean} True if item is final, i.e., it contains one or multiple * finished parsed nodes. */ get isFinal(): boolean { return false; } - /** * @override */ @@ -457,7 +492,6 @@ export abstract class BaseItem extends MmlStack implements StackItem { return kind === this.kind; } - /** * @override */ @@ -486,7 +520,6 @@ export abstract class BaseItem extends MmlStack implements StackItem { return BaseItem.fail; } - /** * Clears the item's environment. */ @@ -496,7 +529,6 @@ export abstract class BaseItem extends MmlStack implements StackItem { } } - /** * @override */ @@ -505,7 +537,6 @@ export abstract class BaseItem extends MmlStack implements StackItem { return this; } - /** * @override */ @@ -513,7 +544,6 @@ export abstract class BaseItem extends MmlStack implements StackItem { return this.getProperty('name') as string; } - /** * @override */ @@ -521,17 +551,16 @@ export abstract class BaseItem extends MmlStack implements StackItem { return this.kind + '[' + this.nodes.join('; ') + ']'; } - /** - * Get error messages for a particular types of stack items. This reads error + * Get error messages for a particular types of stack item. This reads error * messages from the static errors object, which can be extended in * subclasses. + * * @param {string} kind The stack item type. - * @return {string[]} The list of arguments for the TeXError. + * @returns {string[]} The list of arguments for the TeXError. */ public getErrors(kind: string): string[] { - const CLASS = (this.constructor as typeof BaseItem); - return (CLASS.errors || {})[kind] || BaseItem.errors[kind]; + const CLASS = this.constructor as typeof BaseItem; + return CLASS.errors[kind] || BaseItem.errors[kind]; } - } diff --git a/ts/input/tex/StackItemFactory.ts b/ts/input/tex/StackItemFactory.ts index ec34ae8c8..8f9a8996f 100644 --- a/ts/input/tex/StackItemFactory.ts +++ b/ts/input/tex/StackItemFactory.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2009-2022 The MathJax Consortium + * Copyright (c) 2009-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,18 +15,16 @@ * limitations under the License. */ - /** - * @fileoverview A factory for stack items. This allows particular items to be + * @file A factory for stack items. This allows particular items to be * overwritten later. * * @author v.sorge@mathjax.org (Volker Sorge) */ -import {StackItemClass, StackItem, BaseItem} from './StackItem.js'; +import { StackItemClass, StackItem, BaseItem } from './StackItem.js'; import ParseOptions from './ParseOptions.js'; -import {AbstractFactory} from '../../core/Tree/Factory.js'; - +import { AbstractFactory } from '../../core/Tree/Factory.js'; class DummyItem extends BaseItem {} @@ -34,29 +32,29 @@ class DummyItem extends BaseItem {} * The StackItemFactory is initially populated with the default stack item * classes. They can be changed, deleted or added to, if and when necessary. * - * @constructor - * @extends {AbstractFactory} + * @class + * @augments {AbstractFactory} */ -export default class StackItemFactory extends AbstractFactory { - +export default class StackItemFactory extends AbstractFactory< + StackItem, + StackItemClass +> { /** * @override */ - public static DefaultStackItems: {[kind: string]: StackItemClass} = { - [DummyItem.prototype.kind]: DummyItem + public static DefaultStackItems: { [kind: string]: StackItemClass } = { + [DummyItem.prototype.kind]: DummyItem, }; - /** * @override */ public defaultKind = 'dummy'; - /** * The parser configuration. + * * @type {ParseOptions} */ public configuration: ParseOptions = null; - } diff --git a/ts/input/tex/SymbolMap.ts b/ts/input/tex/SymbolMap.ts deleted file mode 100644 index 5415496c4..000000000 --- a/ts/input/tex/SymbolMap.ts +++ /dev/null @@ -1,392 +0,0 @@ -/************************************************************* - * - * Copyright (c) 2017-2022 The MathJax Consortium - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -/** - * @fileoverview Symbol map classes. - * - * @author v.sorge@mathjax.org (Volker Sorge) - */ - -import {Attributes, Args, ParseMethod, ParseInput, ParseResult} from './Types.js'; -import {Symbol, Macro} from './Symbol.js'; -import {MapHandler} from './MapHandler.js'; - - -/** - * SymbolMaps are the base components for the input parsers. - * - * They provide a contains method that checks if a map is applicable (contains) - * a particular string. Implementing classes then perform the actual symbol - * parsing, from simple regular expression test, straight forward symbol mapping - * to transformational functionality on the parsed string. - * - * @interface - */ -export interface SymbolMap { - - /** - * @return {string} The name of the map. - */ - name: string; - - /** - * @return {ParseMethod} The default parsing method. - */ - parser: ParseMethod; - - /** - * @param {string} symbol A symbol to parse. - * @return {boolean} True if the symbol map applies to the symbol. - */ - contains(symbol: string): boolean; - - /** - * @param {string} symbol A symbol to parse. - * @return {ParseMethod} A parse method for the symbol. - */ - parserFor(symbol: string): ParseMethod; - - /** - * @param {TexParser} env The current parser. - * @param {string} symbol A symbol to parse. - * @return {ParseResult} The parsed symbol and the rest of the string. - */ - parse([env, symbol]: ParseInput): ParseResult; - -} - -/** - * @param {ParseResult} result The result to check - * @return {ParseResult} True if result was void, result otherwise - */ -export function parseResult(result: ParseResult): ParseResult { - return result === void 0 ? true : result; -} - -/** - * Abstract implementation of symbol maps. - * @template T - */ -export abstract class AbstractSymbolMap implements SymbolMap { - - /** - * @constructor - * @implements {SymbolMap} - * @param {string} name Name of the mapping. - * @param {ParseMethod} parser The parser for the mappiong. - */ - constructor(private _name: string, private _parser: ParseMethod) { - MapHandler.register(this); - } - - - /** - * @override - */ - public get name(): string { - return this._name; - } - - - /** - * @override - */ - public abstract contains(symbol: string): boolean; - - - /** - * @override - */ - public parserFor(symbol: string) { - return this.contains(symbol) ? this.parser : null; - } - - - /** - * @override - */ - public parse([env, symbol]: ParseInput) { - let parser = this.parserFor(symbol); - let mapped = this.lookup(symbol); - return (parser && mapped) ? parseResult(parser(env, mapped as any)) : null; - } - - - public set parser(parser: ParseMethod) { - this._parser = parser; - } - - public get parser(): ParseMethod { - return this._parser; - } - - - /** - * @param {string} symbol - * @return {T} - */ - public abstract lookup(symbol: string): T; - -} - - - -/** - * Regular expressions used for parsing strings. - */ -export class RegExpMap extends AbstractSymbolMap { - - /** - * @constructor - * @extends {AbstractSymbolMap} - * @param {string} name Name of the mapping. - * @param {ParseMethod} parser The parser for the mappiong. - * @param {RegExp} regexp The regular expression. - */ - constructor(name: string, parser: ParseMethod, private _regExp: RegExp) { - super(name, parser); - } - - - /** - * @override - */ - public contains(symbol: string) { - return this._regExp.test(symbol); - } - - - /** - * @override - */ - public lookup(symbol: string): string { - return this.contains(symbol) ? symbol : null; - } - -} - - -/** - * Parse maps associate strings with parsing functionality. - * @constructor - * @extends {AbstractSymbolMap} - * @template K - */ -export abstract class AbstractParseMap extends AbstractSymbolMap { - - private map: Map = new Map(); - - /** - * @override - */ - public lookup(symbol: string): K { - return this.map.get(symbol); - } - - /** - * @override - */ - public contains(symbol: string) { - return this.map.has(symbol); - } - - /** - * Sets mapping for a symbol. - * @param {string} symbol The symbol to map. - * @param {K} object The symbols value in the mapping's codomain. - */ - public add(symbol: string, object: K) { - this.map.set(symbol, object); - } - - /** - * Removes a symbol from the map - * @param {string} symbol The symbol to remove - */ - public remove(symbol: string) { - this.map.delete(symbol); - } - -} - - -/** - * Maps symbols that can all be parsed with the same method. - * - * @constructor - * @extends {AbstractParseMap} - */ -export class CharacterMap extends AbstractParseMap { - - /** - * @constructor - * @param {string} name Name of the mapping. - * @param {ParseMethod} parser The parser for the mapping. - * @param {JSON} json The JSON representation of the character mapping. - */ - constructor(name: string, parser: ParseMethod, - json: {[index: string]: string | [string, Attributes]}) { - super(name, parser); - for (const key of Object.keys(json)) { - let value = json[key]; - let [char, attrs] = (typeof(value) === 'string') ? [value, null] : value; - let character = new Symbol(key, char, attrs); - this.add(key, character); - } - } - -} - - -/** - * Maps symbols that are delimiters, that are all parsed with the same method. - * - * @constructor - * @extends {CharacterMap} - */ -export class DelimiterMap extends CharacterMap { - - /** - * @override - */ - public parse([env, symbol]: ParseInput) { - return super.parse([env, '\\' + symbol]); - } - -} - - -/** - * Maps macros that all bring their own parsing method. - * - * @constructor - * @extends {AbstractParseMap} - */ -export class MacroMap extends AbstractParseMap { - - /** - * @constructor - * @param {string} name Name of the mapping. - * @param {JSON} json The JSON representation of the macro map. - * @param {Record} functionMap Collection of parse - * functions for the single macros. - */ - constructor(name: string, - json: {[index: string]: string | Args[]}, - functionMap: Record) { - super(name, null); - for (const key of Object.keys(json)) { - let value = json[key]; - let [func, ...attrs] = (typeof(value) === 'string') ? [value] : value; - let character = new Macro(key, functionMap[func as string], attrs); - this.add(key, character); - } - } - - - /** - * @override - */ - public parserFor(symbol: string) { - let macro = this.lookup(symbol); - return macro ? macro.func : null; - } - - - /** - * @override - */ - public parse([env, symbol]: ParseInput) { - let macro = this.lookup(symbol); - let parser = this.parserFor(symbol); - if (!macro || !parser) { - return null; - } - return parseResult(parser(env, macro.symbol, ...macro.args)); - } - -} - - -/** - * Maps macros that all bring their own parsing method. - * - * @constructor - * @extends {MacroMap} - */ -export class CommandMap extends MacroMap { - - /** - * @override - */ - public parse([env, symbol]: ParseInput) { - let macro = this.lookup(symbol); - let parser = this.parserFor(symbol); - if (!macro || !parser) { - return null; - } - let saveCommand = env.currentCS; - env.currentCS = '\\' + symbol; - let result = parser(env, '\\' + macro.symbol, ...macro.args); - env.currentCS = saveCommand; - return parseResult(result); - } - -} - - -/** - * Maps macros for environments. It has a general parsing method for - * environments, i.e., one that deals with begin/end, and each environment has - * its own parsing method returning the content. - * - * @constructor - * @extends {MacroMap} - */ -export class EnvironmentMap extends MacroMap { - - /** - * @constructor - * @param {string} name Name of the mapping. - * @param {ParseMethod} parser The parser for the environments. - * @param {JSON} json The JSON representation of the macro map. - * @param {Record} functionMap Collection of parse - * functions for the single macros. - */ - constructor(name: string, - parser: ParseMethod, - json: {[index: string]: string | Args[]}, - functionMap: Record) { - super(name, json, functionMap); - this.parser = parser; - } - - - /** - * @override - */ - public parse([env, symbol]: ParseInput) { - let macro = this.lookup(symbol); - let envParser = this.parserFor(symbol); - if (!macro || !envParser) { - return null; - } - return parseResult(this.parser(env, macro.symbol, envParser, macro.args)); - } - -} diff --git a/ts/input/tex/Tags.ts b/ts/input/tex/Tags.ts index 3f1547da8..aad89bbf7 100644 --- a/ts/input/tex/Tags.ts +++ b/ts/input/tex/Tags.ts @@ -1,6 +1,6 @@ /************************************************************* * - * Copyright (c) 2018-2022 The MathJax Consortium + * Copyright (c) 2018-2025 The MathJax Consortium * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,42 +15,39 @@ * limitations under the License. */ - /** - * @fileoverview Class for generating tags, references, etc. + * @file Class for generating tags, references, etc. * * @author v.sorge@mathjax.org (Volker Sorge) */ import TexParser from './TexParser.js'; -import {MmlNode} from '../../core/MmlTree/MmlNode.js'; -import {MathItem} from '../../core/MathItem.js'; -import {EnvList} from './StackItem.js'; +import { MmlNode } from '../../core/MmlTree/MmlNode.js'; +import { MathItem } from '../../core/MathItem.js'; +import { EnvList } from './StackItem.js'; import ParseOptions from './ParseOptions.js'; -import {OptionList} from '../../util/Options.js'; - /** * Simple class for label objects. */ export class Label { - /** - * @constructor + * @class * @param {string=} tag The tag that's displayed. * @param {string=} id The id that serves as reference. */ - constructor(public tag: string = '???', public id: string = '') {} + constructor( + public tag: string = '???', + public id: string = '' + ) {} } - /** * A simple class for keeping track of tag information. */ export class TagInfo { - /** - * @constructor + * @class * @param {string} env The environment name (e.g., align). * @param {boolean} taggable Environment supports tags (e.g., align* does, but * split does not.) @@ -63,92 +60,111 @@ export class TagInfo { * \nonumber). * @param {string} labelId The label referring to the tag. */ - constructor(readonly env: string = '', - readonly taggable: boolean = false, - readonly defaultTags: boolean = false, - public tag: string = null, - public tagId: string = '', - public tagFormat: string = '', - public noTag: boolean = false, - public labelId: string = '') {} - + constructor( + readonly env: string = '', + readonly taggable: boolean = false, + readonly defaultTags: boolean = false, + public tag: string = null, + public tagId: string = '', + public tagFormat: string = '', + public noTag: boolean = false, + public labelId: string = '' + ) {} } - export interface Tags { - /** * The global configurations in which the parsing takes place. + * * @type {ParseOptions} */ configuration: ParseOptions; /** * IDs used in this equation. - * @type {Object.} + * + * @type {{ [key: string]: boolean }} */ - ids: {[key: string]: boolean}; + ids: { [key: string]: boolean }; /** * IDs used in previous equations. - * @type {Object.} + * + * @type {{ [key: string]: boolean }} */ - allIds: {[key: string]: boolean}; + allIds: { [key: string]: boolean }; /** * Labels in the current equation. - * @type {Object.