| #!/usr/bin/env node |
| |
| const path = require('path'); |
| const program = require('commander'); |
| const fs = require('fs'); |
| const fse = require('fs-extra'); |
| const babel = require('@babel/core'); |
| |
| program |
| .option('-m, --with-source-maps [type]', 'output source maps when not generating a bundled app (type may be empty for external source maps, inline for inline source maps, or both) ') |
| .option('--clean', 'clear the lib folder before building') |
| .parse(process.argv); |
| |
| // the various important paths |
| const paths = { |
| main: path.resolve(__dirname, '..'), |
| core: path.resolve(__dirname, '..', 'core'), |
| vendor: path.resolve(__dirname, '..', 'vendor'), |
| libDirBase: path.resolve(__dirname, '..', 'lib'), |
| }; |
| |
| // util.promisify requires Node.js 8.x, so we have our own |
| function promisify(original) { |
| return function promiseWrap() { |
| const args = Array.prototype.slice.call(arguments); |
| return new Promise((resolve, reject) => { |
| original.apply(this, args.concat((err, value) => { |
| if (err) return reject(err); |
| resolve(value); |
| })); |
| }); |
| }; |
| } |
| |
| const writeFile = promisify(fs.writeFile); |
| |
| const readdir = promisify(fs.readdir); |
| const lstat = promisify(fs.lstat); |
| |
| const ensureDir = promisify(fse.ensureDir); |
| |
| const babelTransformFile = promisify(babel.transformFile); |
| |
| // walkDir *recursively* walks directories trees, |
| // calling the callback for all normal files found. |
| function walkDir(basePath, cb, filter) { |
| return readdir(basePath) |
| .then((files) => { |
| const paths = files.map(filename => path.join(basePath, filename)); |
| return Promise.all(paths.map(filepath => lstat(filepath) |
| .then((stats) => { |
| if (filter !== undefined && !filter(filepath, stats)) return; |
| |
| if (stats.isSymbolicLink()) return; |
| if (stats.isFile()) return cb(filepath); |
| if (stats.isDirectory()) return walkDir(filepath, cb, filter); |
| }))); |
| }); |
| } |
| |
| function makeLibFiles(sourceMaps) { |
| // NB: we need to make a copy of babelOpts, since babel sets some defaults on it |
| const babelOpts = () => ({ |
| plugins: [], |
| presets: [ |
| [ '@babel/preset-env', |
| { modules: 'commonjs' } ] |
| ], |
| ast: false, |
| sourceMaps: sourceMaps, |
| }); |
| |
| fse.ensureDirSync(paths.libDirBase); |
| |
| const outFiles = []; |
| |
| const handleDir = (vendorRewrite, inPathBase, filename) => Promise.resolve() |
| .then(() => { |
| const outPath = path.join(paths.libDirBase, path.relative(inPathBase, filename)); |
| |
| if (path.extname(filename) !== '.js') { |
| return; // skip non-javascript files |
| } |
| return Promise.resolve() |
| .then(() => ensureDir(path.dirname(outPath))) |
| .then(() => { |
| const opts = babelOpts(); |
| // Adjust for the fact that we move the core files relative |
| // to the vendor directory |
| if (vendorRewrite) { |
| opts.plugins.push(["import-redirect", |
| {"root": paths.libDirBase, |
| "redirect": { "vendor/(.+)": "./vendor/$1"}}]); |
| } |
| |
| return babelTransformFile(filename, opts) |
| .then((res) => { |
| console.log(`Writing ${outPath}`); |
| const {map} = res; |
| let {code} = res; |
| if (sourceMaps === true) { |
| // append URL for external source map |
| code += `\n//# sourceMappingURL=${path.basename(outPath)}.map\n`; |
| } |
| outFiles.push(`${outPath}`); |
| return writeFile(outPath, code) |
| .then(() => { |
| if (sourceMaps === true || sourceMaps === 'both') { |
| console.log(` and ${outPath}.map`); |
| outFiles.push(`${outPath}.map`); |
| return writeFile(`${outPath}.map`, JSON.stringify(map)); |
| } |
| }); |
| }); |
| }); |
| }); |
| |
| Promise.resolve() |
| .then(() => { |
| const handler = handleDir.bind(null, false, paths.main); |
| return walkDir(paths.vendor, handler); |
| }) |
| .then(() => { |
| const handler = handleDir.bind(null, true, paths.core); |
| return walkDir(paths.core, handler); |
| }) |
| .catch((err) => { |
| console.error(`Failure converting modules: ${err}`); |
| process.exit(1); |
| }); |
| } |
| |
| let options = program.opts(); |
| |
| if (options.clean) { |
| console.log(`Removing ${paths.libDirBase}`); |
| fse.removeSync(paths.libDirBase); |
| } |
| |
| makeLibFiles(options.withSourceMaps); |