]>
Commit | Line | Data |
---|---|---|
ae510306 SR |
1 | #!/usr/bin/env node |
2 | ||
2b5f94fa JD |
3 | const path = require('path'); |
4 | const program = require('commander'); | |
5 | const fs = require('fs'); | |
6 | const fse = require('fs-extra'); | |
0dd439a8 | 7 | const babel = require('@babel/core'); |
ae510306 | 8 | |
ae510306 | 9 | program |
6cae7b58 | 10 | .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) ') |
c4e5a50e | 11 | .option('--clean', 'clear the lib folder before building') |
ae510306 SR |
12 | .parse(process.argv); |
13 | ||
14 | // the various important paths | |
152c3995 SR |
15 | const paths = { |
16 | main: path.resolve(__dirname, '..'), | |
17 | core: path.resolve(__dirname, '..', 'core'), | |
152c3995 | 18 | vendor: path.resolve(__dirname, '..', 'vendor'), |
8b0034ee | 19 | libDirBase: path.resolve(__dirname, '..', 'lib'), |
152c3995 | 20 | }; |
ae510306 | 21 | |
21633268 PO |
22 | // util.promisify requires Node.js 8.x, so we have our own |
23 | function promisify(original) { | |
8b0034ee | 24 | return function promiseWrap() { |
2b5f94fa | 25 | const args = Array.prototype.slice.call(arguments); |
21633268 | 26 | return new Promise((resolve, reject) => { |
651c23ec | 27 | original.apply(this, args.concat((err, value) => { |
21633268 PO |
28 | if (err) return reject(err); |
29 | resolve(value); | |
30 | })); | |
31 | }); | |
0ae5c54a | 32 | }; |
21633268 PO |
33 | } |
34 | ||
21633268 PO |
35 | const writeFile = promisify(fs.writeFile); |
36 | ||
37 | const readdir = promisify(fs.readdir); | |
38 | const lstat = promisify(fs.lstat); | |
39 | ||
21633268 PO |
40 | const ensureDir = promisify(fse.ensureDir); |
41 | ||
42 | const babelTransformFile = promisify(babel.transformFile); | |
43 | ||
6cae7b58 SR |
44 | // walkDir *recursively* walks directories trees, |
45 | // calling the callback for all normal files found. | |
8b0034ee SM |
46 | function walkDir(basePath, cb, filter) { |
47 | return readdir(basePath) | |
7b536961 | 48 | .then((files) => { |
8b0034ee | 49 | const paths = files.map(filename => path.join(basePath, filename)); |
7b536961 PO |
50 | return Promise.all(paths.map(filepath => lstat(filepath) |
51 | .then((stats) => { | |
52 | if (filter !== undefined && !filter(filepath, stats)) return; | |
53 | ||
54 | if (stats.isSymbolicLink()) return; | |
55 | if (stats.isFile()) return cb(filepath); | |
56 | if (stats.isDirectory()) return walkDir(filepath, cb, filter); | |
57 | }))); | |
58 | }); | |
651c23ec | 59 | } |
ae510306 | 60 | |
890cff92 | 61 | function makeLibFiles(sourceMaps) { |
8b0034ee SM |
62 | // NB: we need to make a copy of babelOpts, since babel sets some defaults on it |
63 | const babelOpts = () => ({ | |
0dd439a8 PO |
64 | plugins: [], |
65 | presets: [ | |
66 | [ '@babel/preset-env', | |
890cff92 | 67 | { modules: 'commonjs' } ] |
0dd439a8 | 68 | ], |
6cae7b58 | 69 | ast: false, |
8b0034ee | 70 | sourceMaps: sourceMaps, |
6cae7b58 | 71 | }); |
6cae7b58 | 72 | |
890cff92 | 73 | fse.ensureDirSync(paths.libDirBase); |
a80955ee | 74 | |
be7b4e88 PO |
75 | const outFiles = []; |
76 | ||
890cff92 | 77 | const handleDir = (vendorRewrite, inPathBase, filename) => Promise.resolve() |
7b536961 | 78 | .then(() => { |
890cff92 | 79 | const outPath = path.join(paths.libDirBase, path.relative(inPathBase, filename)); |
4a65d50d | 80 | |
35068204 | 81 | if (path.extname(filename) !== '.js') { |
7b536961 | 82 | return; // skip non-javascript files |
ae510306 | 83 | } |
7b536961 | 84 | return Promise.resolve() |
890cff92 | 85 | .then(() => ensureDir(path.dirname(outPath))) |
7b536961 | 86 | .then(() => { |
8b0034ee | 87 | const opts = babelOpts(); |
1524df89 PO |
88 | // Adjust for the fact that we move the core files relative |
89 | // to the vendor directory | |
8b0034ee | 90 | if (vendorRewrite) { |
7b536961 | 91 | opts.plugins.push(["import-redirect", |
890cff92 | 92 | {"root": paths.libDirBase, |
7b536961 PO |
93 | "redirect": { "vendor/(.+)": "./vendor/$1"}}]); |
94 | } | |
adfc9d3f | 95 | |
7b536961 PO |
96 | return babelTransformFile(filename, opts) |
97 | .then((res) => { | |
890cff92 | 98 | console.log(`Writing ${outPath}`); |
7b536961 PO |
99 | const {map} = res; |
100 | let {code} = res; | |
8b0034ee | 101 | if (sourceMaps === true) { |
6cae7b58 | 102 | // append URL for external source map |
890cff92 | 103 | code += `\n//# sourceMappingURL=${path.basename(outPath)}.map\n`; |
7b536961 | 104 | } |
890cff92 PO |
105 | outFiles.push(`${outPath}`); |
106 | return writeFile(outPath, code) | |
7b536961 | 107 | .then(() => { |
8b0034ee | 108 | if (sourceMaps === true || sourceMaps === 'both') { |
890cff92 PO |
109 | console.log(` and ${outPath}.map`); |
110 | outFiles.push(`${outPath}.map`); | |
111 | return writeFile(`${outPath}.map`, JSON.stringify(map)); | |
7b536961 PO |
112 | } |
113 | }); | |
114 | }); | |
21633268 | 115 | }); |
6cae7b58 | 116 | }); |
6cae7b58 | 117 | |
21633268 | 118 | Promise.resolve() |
7b536961 | 119 | .then(() => { |
890cff92 PO |
120 | const handler = handleDir.bind(null, false, paths.main); |
121 | return walkDir(paths.vendor, handler); | |
4a65d50d | 122 | }) |
be7b4e88 | 123 | .then(() => { |
890cff92 PO |
124 | const handler = handleDir.bind(null, true, paths.core); |
125 | return walkDir(paths.core, handler); | |
7b536961 PO |
126 | }) |
127 | .catch((err) => { | |
128 | console.error(`Failure converting modules: ${err}`); | |
129 | process.exit(1); | |
be7b4e88 | 130 | }); |
651c23ec | 131 | } |
ae510306 | 132 | |
c4e5a50e | 133 | if (program.clean) { |
8b0034ee SM |
134 | console.log(`Removing ${paths.libDirBase}`); |
135 | fse.removeSync(paths.libDirBase); | |
c4e5a50e SR |
136 | } |
137 | ||
890cff92 | 138 | makeLibFiles(program.withSourceMaps); |