Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Definitions and utilities to create MathJax components #180

Merged
merged 37 commits into from
Feb 22, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
05aafe4
Add webpack and components to package.json
dpvc Dec 12, 2018
0b91f03
Add initial implementation for webpack components.
dpvc Dec 12, 2018
e0dcd3b
Refactor common webpack functions and make matching more reliable
dpvc Dec 13, 2018
5d3a6ad
Remove .dist.js files and modify .gitignore to ignore them
dpvc Dec 13, 2018
8ef5d0a
Simplify mathjax-global.ts
dpvc Dec 13, 2018
cc6617e
Add loader and startup components, and rename global file.
dpvc Dec 26, 2018
dd29b59
Update build to make js files directy; update webpack.common.js to re…
dpvc Dec 30, 2018
6652e4e
Update .gitignore to not save the component lib and dist files
dpvc Dec 30, 2018
3508d34
Remove unneeded webpack components from package.json
dpvc Dec 30, 2018
5e25f89
Make asynchLoad() configurable so that it will work with component lo…
dpvc Dec 30, 2018
4cce8fc
Add IE11 support via polyfill and charset
dpvc Jan 4, 2019
3fc513c
Add support for IE11 via babel to transpile the component drivers
dpvc Jan 4, 2019
c570d89
Improve error handling (and promise handling in general), break up pa…
dpvc Jan 4, 2019
9d14f05
Split chtml font into separate package; update build to handle it pro…
dpvc Jan 4, 2019
fde4e8b
Add entities package for including all entities
dpvc Jan 4, 2019
6614b54
Add combineDefaults() to global.js to make setting defaults from with…
dpvc Jan 4, 2019
8c0feb9
Update location of tex font in source.js
dpvc Jan 4, 2019
a4221d1
Add force arguments to make forcing startup to use a component easier
dpvc Jan 4, 2019
87f6995
Fix typo in variable name
dpvc Jan 5, 2019
c663234
Don't run babel on components/dist files (since they are already conv…
dpvc Jan 5, 2019
208e4e8
Add ability to mark preloaded packages as loaded (so packages can be …
dpvc Jan 5, 2019
c4e2c5b
Add pagePromise and make typesetting wait for that; synchronize inter…
dpvc Jan 5, 2019
8649691
Add sample for using combined packages and hand-loading packages.
dpvc Jan 5, 2019
f26ac10
Remove the obsolete buildTS file (we build .js files directly now)
dpvc Jan 7, 2019
362b229
Add jsdoc comments, and make some minor improvements identified while…
dpvc Jan 7, 2019
1493a22
Fix typo, and add rmDir to remove library directory before rebuilding it
dpvc Jan 7, 2019
4b12d9a
Add bin/makeAll that creates all the components automatically
dpvc Jan 7, 2019
f5e80c9
Make sure builds are all done first, then webpacks
dpvc Jan 7, 2019
26c63fd
Have makeAll default to current directory as the starting point
dpvc Jan 8, 2019
be337c3
Add a11y, break up svg into main and fonts, improve loader and startu…
dpvc Jan 10, 2019
d2c2a61
Include global.js into core library
dpvc Jan 10, 2019
b5a1b12
Improve semantic-enrich component
dpvc Jan 11, 2019
267fe73
Allow options for creating the MathDocument. Add complexity componen…
dpvc Jan 11, 2019
4d705ce
Updates requested by Volker's review.
dpvc Feb 20, 2019
f26550e
Missed one requested update from Volker...
dpvc Feb 20, 2019
9628d35
Fix return types of several functions.
dpvc Feb 16, 2019
9e483de
Use proper root directory for asyncLoad with System.js
dpvc Feb 16, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
*~
node_modules
mathjax3
components/src/*/lib
components/src/*/*/lib
components/src/*/*/*/lib
components/samples/*/lib
components/samples/*/*.min.js
components/dist
316 changes: 316 additions & 0 deletions components/bin/build
Original file line number Diff line number Diff line change
@@ -0,0 +1,316 @@
#! /usr/bin/env node

/*************************************************************
*
* 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 Builds the lib directory for a component
*
* @author [email protected] (Davide Cervone)
*/


const fs = require('fs');
const path = require('path');

/**
* The amount of space for each level of indentation
*/
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 EXPORT_IGNORE = ['type', 'interface'];
const EXPORT_PROCESS = ['let', 'const', 'var', 'function', 'class', 'namespace'];

/**
* Read the configuration for the component
*/
const config = JSON.parse(fs.readFileSync(process.argv[2] || 'build.json'));

/**
* Extract the configuration values
*/
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 MATHJAX3 = config.mathjax3 || '../../../mathjax3'; // path to the mathjax3 .js files
const LIB = config.lib || './lib'; // path to the lib directory to create
const COMPONENT = config.component || 'part'; // name of the component
const GLOBAL = config.global || `../${MATHJAX3}/components/global.js`; // the location of global.js

/**
* The list of files that need to be added to the lib directory
*/
let PACKAGE = [];

/**
* Process an array of files/directories to be included in the component
*
* @param {string} base The root directory for the .ts files
* @param {string} dir The relative path within the root for the files to process
* @param {string[]} list An array of file/directory names to process
*/
function processList(base, dir, list) {
for (const item of list) {
const file = path.join(dir, item);
if (!EXCLUDE.has(file)) {
const stat = fs.statSync(path.resolve(base, file));
if (stat.isDirectory()) {
processDir(base, file);
} else if (file.match(/\.ts/)) {
processFile(base, file);
}
}
}
}

/**
* Process the contents of the directory
*
* @param {string} base The root directory for the .ts files
* @param {string} dir The relative path within the root for the directory to process
*/
function processDir(base, dir) {
const root = path.resolve(base, dir);
processList(base, dir, fs.readdirSync(root));
}

/**
* Process the contents of a .ts file
*
* Look for export commands within the file, and determine the objects
* that they reference, then produce the library file that defines
* them, and add the file to the package list.
*
* @param {string} base The root directory for the .ts files
* @param {string} name The path of the file relative to the base
*/
function processFile(base, name) {
console.log(' ' + name);
const file = fs.readFileSync(path.resolve(base, name)).toString();
const parts = file.split(EXPORTPATTERN);
const objects = processParts(parts);
const lines = processLines(name, objects);
makeFile(name, lines);
if (objects.length) {
PACKAGE.push(name);
}
}

/**
* Process the export lines to record the ones that need to be added to the
* library file.
*
* @param {string[]} parts The file broken into export lines and the text between them
* @return {string[]} An array of names of exported objects
*/
function processParts(parts) {
const objects = [];
for (let i = 1; i < parts.length; i += 2) {
const words = parts[i].split(/\s+/);
const type = words[words.length - 2];
const name = words[words.length - 1];

if (words[1] === 'default' || type === 'default') {
objects.push('default');
} else if (EXPORT_PROCESS.indexOf(type) >= 0) {
objects.push(name);
} else if (EXPORT_IGNORE.indexOf(type) < 0) {
console.log(" Can't process '" + parts[i] + "'");
}
}
return objects;
}

/**
* 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
* @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 dots = dir.replace(/[^\/]+/g, '..') || '.';
const relative = path.join(dots, '..', MATHJAX3, dir, path.basename(file)).replace(/\.ts$/, '.js');
const name = path.parse(file).name;
const lines = [
'"use strict";',
`Object.defineProperty(exports, '__esModule', {value: true});`
];
let source = (dir.replace(/\//g, '.') + '.' + name).replace(/^\./, '')
.replace(/\.[^.]*/g, (x) => (x.substr(1).match(/[^a-zA-Z_]/) ? '[\'' + x.substr(1) + '\']' : x));
if (exists(path.resolve(MATHJAX3, file.replace(/\.ts$/, '')))) {
source += '_ts';
}
for (const id of objects) {
lines.push(`exports.${id} = MathJax._.${source}.${id};`);
}
return lines;
}

/**
* @param {string} file Path to a file
* @return {boolean} True if the file exists, false if not
*/
function exists(file) {
if (!fs.existsSync(file)) return false;
//
// For case-insensitive file systems (like Mac OS),
// check that the file names match exactly
//
const [dir, name] = [path.dirname(file), path.basename(file)];
return fs.readdirSync(dir).indexOf(name) >= 0;
}

/**
* Recursively make any needed directories
*
* @param {string} dir The directory relative to the library directory
*/
function makeDir(dir) {
const fulldir = path.resolve(LIB, dir);
if (fs.existsSync(fulldir)) return;
makeDir(path.dirname(fulldir));
fs.mkdirSync(fulldir);
dpvc marked this conversation as resolved.
Show resolved Hide resolved
}

/**
* Make a file in the library directory from the given lines of javascript
*
* @param {string} file The name of the file relative to the root .ts directory
* @param {string[]} lines The contents of the file to create
*/
function makeFile(file, lines) {
if (!lines.length) return;
const [dir, name] = [path.dirname(file), path.basename(file)];
makeDir(dir);
fs.writeFileSync(path.resolve(LIB, dir, name.replace(/\.ts$/, '.js')), lines.join('\n') + '\n');
}

/**
* Make the library file that adds all the exported objects into the MathJax global object
*/
function processGlobal() {
console.log(' ' + COMPONENT + '.ts');
const lines = [
'"use strict";',
`Object.defineProperty(exports, '__esModule', {value: true});`,
`require('${GLOBAL}').combineWithMathJax({_: {`
];
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));
}
lines.push(INDENT + packages.join(',\n' + INDENT));
lines.push('}});');
fs.writeFileSync(path.join(LIB, COMPONENT + '.js'), lines.join('\n') + '\n');
}

/**
* Sort file paths alphabetically
*/
function sortDir(a, b) {
const A = a.replace(/\//g, '|'); // Replace directory separator by one that is after the alphnumerics
const B = b.replace(/\//g, '|');
return (A === B ? 0 : A < B ? -1 : 1);
}

/**
* Recursively process packages, collecting them into groups by subdirectory, properly indented
dpvc marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {string[]} lines The array where lines of code defining the packages are to be stored
* @param {string} space The current level of indentation
* @param {string} dir The subdirectory currently being processed
* @return {string} The string to use to load all the objects from the given directory
*/
function processPackage(lines, space, dir) {
const packages = [];
//
// Loop through the lines that are in the current directory
//
while (PACKAGE.length && (PACKAGE[0].substr(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
// Otherwise (its in a subdirectory)
// Get the subdirectory name
// Process the subdirectory using an additional indentation
//
if (path.dirname(PACKAGE[0]) === dir) {
const file = PACKAGE.shift();
const name = path.basename(file);
const relativefile = path.join('..', MATHJAX3, dir, name).replace(/\.ts$/, '.js');
const component = `require('${relativefile}')`;
let property = name.replace(/\.ts$/, '');
if (property !== name && exists(path.resolve(MATHJAX3, file.replace(/\.ts$/, '')))) {
property += '_ts';
}
if (property.match(/[^a-zA-Z0-9_]/)) {
property = `"${property}"`;
}
packages.push(`${property}: ${component}`);
} else {
let subdir = path.dirname(PACKAGE[0]);
while (path.dirname(subdir) !== dir && subdir !== '.') {
subdir = path.dirname(subdir);
}
packages.push(processPackage(lines, space + (dir === '.' ? '' : INDENT), subdir));
}
}
//
// 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 + '}';
}

/**
* @param {string} dir The path to the directory tree to be removed (recursively)
*/
function rmDir(dir) {
dpvc marked this conversation as resolved.
Show resolved Hide resolved
if (!dir) return;
if (fs.existsSync(dir)) {
for (const name of fs.readdirSync(dir)) {
const file = path.join(dir, name);
if (fs.lstatSync(file).isDirectory()) {
rmDir(file);
} else {
fs.unlinkSync(file);
}
}
fs.rmdirSync(dir);
}
}

//
// Remove the existing lib directory contents, if any.
// Load all the target files from the MathJax .ts directory.
// Create the file that loads all the target objects into the MathJax global object.
//
rmDir(LIB);
console.log("Processing:");
processList(MATHJAX3 + '-ts', '', TARGETS);
processGlobal();
Loading