Math/modules/ve-math/tools/makeSvgsAndCss.js

163 lines
3.8 KiB
JavaScript
Executable File

#!/usr/bin/env node
/* jshint node: true */
( function () {
var i, count, group, symbol, symbols, symbolObject,
symbolsData, cssData, cssLines, index,
cssRules = [],
cssClasses = [],
symbolList = [],
symbolsFile = '../symbols.json',
cssFile = '../ve.ui.MWMathSymbols.css',
cssPrefix = '.ve-ui-mwMathSymbol-',
fs = require( 'fs' ),
http = require( 'http' ),
querystring = require( 'querystring' ),
SVGO = require( 'svgo' ),
svgo = new SVGO( {
plugins: [
{ convertTransform: false }
]
} ),
mathoidMaxConnections = 5;
symbolsData = fs.readFileSync( symbolsFile ).toString();
try {
cssData = fs.readFileSync( cssFile ).toString();
} catch ( e ) {}
function encodeURIComponentForCSS( str ) {
return encodeURIComponent( str )
.replace( /[!'\(\)\*]/g, function ( chr ) {
return '%' + chr.charCodeAt( 0 ).toString( 16 );
} );
}
function texToClass( tex ) {
// Make the className, replacing any non-alphanumerics with their character code
return tex.replace( /[^\w]/g, function ( c ) {
return '_' + c.charCodeAt( 0 ) + '_';
} );
}
function makeRequest( symbol ) {
var request,
data = querystring.stringify( {
q: symbol
} ),
// API call to mathoid
options = {
host: 'mathoid.testme.wmflabs.org',
port: '80',
path: '/',
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
'Content-Length': Buffer.byteLength( data )
}
};
// Populate and make the API call
request = http.request( options, function ( res ) {
var body = '';
res.setEncoding( 'utf8' );
res.on( 'data', function ( data ) {
body += data;
} );
res.on( 'end', function () {
var className = texToClass( symbol ),
svg = JSON.parse( body ).svg;
if ( !svg ) {
console.log( symbol + ' FAILED: ' + body );
onEnd();
return;
}
svgo.optimize( svg, function ( result ) {
// write to the css file
cssRules.push(
cssPrefix + className + ' {\n' +
'\tbackground-image: url(data:image/svg+xml,' + encodeURIComponentForCSS( result.data ) + ');\n' +
'}'
);
console.log( symbol + ' -> ' + className );
} );
onEnd();
} );
} );
request.setTimeout( 10000 );
request.write( data );
request.end();
runNext();
}
function onEnd() {
count--;
runNext();
}
function runNext() {
if ( count < mathoidMaxConnections && symbolList.length ) {
count++;
makeRequest( symbolList.shift() );
}
if ( !symbolList.length && !count ) {
cssRules.sort();
fs.writeFileSync(
cssFile,
'/*!\n' +
' * This file is GENERATED by tools/makeSvgsAndCss.js\n' +
' * DO NOT EDIT\n' +
' */\n' +
'\n' +
cssRules.join( '\n\n' ) +
'\n'
);
}
}
if ( cssData ) {
cssLines = cssData.split( '\n' );
for ( i = 0; i < cssLines.length; i++ ) {
if ( cssLines[ i ].indexOf( cssPrefix ) === 0 ) {
cssRules.push( cssLines.slice( i, i + 3 ).join( '\n' ) );
cssClasses.push( cssLines[ i ].slice( cssPrefix.length, -2 ) );
}
}
}
symbolObject = JSON.parse( symbolsData );
for ( group in symbolObject ) {
symbols = symbolObject[ group ];
for ( i = 0; i < symbols.length; i++ ) {
symbol = symbols[ i ];
if ( symbol.duplicate || symbol.notWorking ) {
continue;
}
index = cssClasses.indexOf( texToClass( symbol.tex ) );
if ( index === -1 ) {
symbolList.push( symbol.tex );
} else {
// Remove CSS classes we found in the symbol list so that
// and the end of this loop, cssClasses contains classes
// that have been deleted from the symbol list
cssClasses.splice( index, 1 );
}
}
}
// Remove classes that are no longer in the JSON
cssRules = cssRules.filter( function ( rule ) {
return cssClasses.indexOf( rule.split( '\n' )[ 0 ].slice( cssPrefix.length, -2 ) ) === -1;
} );
count = 0;
runNext();
} )();