spiegel-keyman/common/web/lm-worker/build-wrapper.js
Joshua Horton 6c38e45e91
chore(web): Apply suggestions from code review
Co-authored-by: Marc Durdin <marc@durdin.net>
2024-01-08 11:57:52 +07:00

112 lines
No EOL
3.6 KiB
JavaScript

import fs from 'fs';
import convertSourcemap from 'convert-source-map'; // Transforms sourcemaps among various common formats.
// Base64, stringified-JSON, end-of-file comment...
let INCLUDE_SRCMAPS = false;
let sourceFromArgs;
let destFromArgs;
function doHelp(errMessage) {
if(errMessage) {
console.error(errMessage + '\n');
}
console.log(`
Summary:
Creates a "wrapped" version of the lm-worker for compilation into and inclusion as part
of a different JS bundle for later use as the core of a predictive-text WebWorker.
Usage:
node build-wrapper.js <input-file> [options...]
Parameters:
<input-file>: Fully-bundled and compiled JS file to be wrapped.
Options:
--help Shows this script's documentation
--out <out-file> Specifies the destination path for the wrapped output.
If missing, the output will be placed next to the source and given
the same path, but with '.wrapped.js' replacing the original '.js'
extension.
--sourceMap Includes the script's original sourcemaps within the wrapped output
` );
process.exit(errMessage ? 1 : 0);
}
if(process.argv.length > 2) {
for(let i = 2; i < process.argv.length; i++) {
const arg = process.argv[i];
switch(arg) {
case '--help':
doHelp();
break;
case '--sourceMap': // bc TS uses this exact flag. esbuild... uses sourcemap (in the JS config)
case '--sourcemap':
case '--source-map':
INCLUDE_SRCMAPS = true;
break;
case '--out':
destFromArgs = process.argv[++i];
break;
default:
if(!sourceFromArgs) {
sourceFromArgs = arg;
} else {
doHelp("Input file can only be specified once; aborting");
}
}
}
} else {
// Display help + abort.
doHelp("Required parameters missing");
}
if(!sourceFromArgs || sourceFromArgs.substring(sourceFromArgs.length - 3) != '.js') {
doHelp("No input file has been specified; aborting.");
}
const sourceFile = sourceFromArgs;
const destFile = destFromArgs || sourceFromArgs.substring(0, sourceFromArgs.length - 3) + '.wrapped.js';
// Now, to build the wrapper...
const script = fs.readFileSync(sourceFile);
// Wrapped in a function so we can leverage `const` with the result.
function buildSrcMapString() {
const sourcemapJSON = convertSourcemap.fromJSON(fs.readFileSync(`${sourceFile}.map`)).toObject();
const encodedSrcMap = convertSourcemap.fromObject(sourcemapJSON).toBase64();
return `//# sourceMappingURL=data:application/json;charset=utf-8;base64,${encodedSrcMap}`;
}
// While it IS possible to do partial sourcemaps (without the sources, but with everything else) within the worker...
// the resulting sourcemaps are -surprisingly- large - larger than the code itself!
const srcMapString = INCLUDE_SRCMAPS ? buildSrcMapString() : "";
/*
* It'd be nice to do a 'partial' encodeURIComponent that only gets the important bits...
* but my attempts to do so end up triggering errors when loading.
*/
let rawScript = script.toString();
// Two layers of encoding: one for the raw source (parsed by the JS engine),
// one to 'unwrap' it from a string _within_ that source.
let jsonEncoded = JSON.stringify(rawScript);
let wrapper = `
// Autogenerated code. Do not modify!
// --START:LMLayerWorkerCode--
export var LMLayerWorkerCode = ${jsonEncoded};
${!INCLUDE_SRCMAPS && "// Sourcemaps have been omitted for this release build." || ''}
export var LMLayerWorkerSourcemapComment = "${srcMapString}";
// --END:LMLayerWorkerCode
`;
fs.writeFileSync(destFile, wrapper);