diff options
Diffstat (limited to '')
-rw-r--r-- | src/arrow/js/gulp/util.js | 200 |
1 files changed, 200 insertions, 0 deletions
diff --git a/src/arrow/js/gulp/util.js b/src/arrow/js/gulp/util.js new file mode 100644 index 000000000..d8cde29e8 --- /dev/null +++ b/src/arrow/js/gulp/util.js @@ -0,0 +1,200 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you 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. + +const fs = require('fs'); +const path = require(`path`); +const pump = require(`stream`).pipeline; +const child_process = require(`child_process`); +const { targets, modules } = require('./argv'); +const { + ReplaySubject, + empty: ObservableEmpty, + throwError: ObservableThrow, + fromEvent: ObservableFromEvent +} = require('rxjs'); +const { + share, + flatMap, + takeUntil, + defaultIfEmpty, + mergeWith, +} = require('rxjs/operators'); +const asyncDone = require('util').promisify(require('async-done')); + +const mainExport = `Arrow`; +const npmPkgName = `apache-arrow`; +const npmOrgName = `@${npmPkgName}`; + +const releasesRootDir = `targets`; +const knownTargets = [`es5`, `es2015`, `esnext`]; +const knownModules = [`cjs`, `esm`, `cls`, `umd`]; +const tasksToSkipPerTargetOrFormat = { + src: { clean: true, build: true }, + cls: { test: true, package: true } +}; +const packageJSONFields = [ + `version`, `license`, `description`, + `author`, `homepage`, `repository`, + `bugs`, `keywords`, `dependencies`, + `bin` +]; + +const metadataFiles = [`LICENSE.txt`, `NOTICE.txt`, `README.md`].map((filename) => { + let prefixes = [`./`, `../`]; + let p = prefixes.find((prefix) => { + try { + fs.statSync(path.resolve(path.join(prefix, filename))); + } catch (e) { return false; } + return true; + }); + if (!p) { + throw new Error(`Couldn't find ${filename} in ./ or ../`); + } + return path.join(p, filename); +}); + +// see: https://github.com/google/closure-compiler/blob/c1372b799d94582eaf4b507a4a22558ff26c403c/src/com/google/javascript/jscomp/CompilerOptions.java#L2988 +const gCCLanguageNames = { + es5: `ECMASCRIPT5`, + es2015: `ECMASCRIPT_2015`, + es2016: `ECMASCRIPT_2016`, + es2017: `ECMASCRIPT_2017`, + es2018: `ECMASCRIPT_2018`, + es2019: `ECMASCRIPT_2019`, + esnext: `ECMASCRIPT_NEXT` +}; + +function taskName(target, format) { + return !format ? target : `${target}:${format}`; +} + +function packageName(target, format) { + return !format ? target : `${target}-${format}`; +} + +function tsconfigName(target, format) { + return !format ? target : `${target}.${format}`; +} + +function targetDir(target, format) { + return path.join(releasesRootDir, ...(!format ? [target] : [target, format])); +} + +function shouldRunInChildProcess(target, format) { + // If we're building more than one module/target, then yes run this task in a child process + if (targets.length > 1 || modules.length > 1) { return true; } + // If the target we're building *isn't* the target the gulp command was configured to run, then yes run that in a child process + if (targets[0] !== target || modules[0] !== format) { return true; } + // Otherwise no need -- either gulp was run for just one target, or we've been spawned as the child of a multi-target parent gulp + return false; +} + +const gulp = path.join(path.parse(require.resolve(`gulp`)).dir, `bin/gulp.js`); +function spawnGulpCommandInChildProcess(command, target, format) { + const args = [gulp, command, '-t', target, '-m', format, `--silent`]; + const opts = { + stdio: [`ignore`, `inherit`, `inherit`], + env: { ...process.env, NODE_NO_WARNINGS: `1` } + }; + return asyncDone(() => child_process.spawn(`node`, args, opts)) + .catch((e) => { throw `Error in "${command}:${taskName(target, format)}" task`; }); +} + +const logAndDie = (e) => { if (e) { process.exit(1) } }; +function observableFromStreams(...streams) { + if (streams.length <= 0) { return ObservableEmpty(); } + const pumped = streams.length <= 1 ? streams[0] : pump(...streams, logAndDie); + const fromEvent = ObservableFromEvent.bind(null, pumped); + const streamObs = fromEvent(`data`).pipe( + mergeWith(fromEvent(`error`).pipe(flatMap((e) => ObservableThrow(e)))), + takeUntil(fromEvent(`end`).pipe(mergeWith(fromEvent(`close`)))), + defaultIfEmpty(`empty stream`), + share({ connector: () => new ReplaySubject(), resetOnError: false, resetOnComplete: false, resetOnRefCountZero: false }) + ); + streamObs.stream = pumped; + streamObs.observable = streamObs; + return streamObs; +} + +function* combinations(_targets, _modules) { + const targets = known(knownTargets, _targets || [`all`]); + const modules = known(knownModules, _modules || [`all`]); + + if (_targets.includes(`src`)) { + yield [`src`, ``]; + return; + } + + if (_targets.includes(`all`) && _modules.includes(`all`)) { + yield [`ts`, ``]; + yield [`src`, ``]; + yield [npmPkgName, ``]; + } + + for (const format of modules) { + for (const target of targets) { + yield [target, format]; + } + } + + function known(known, values) { + return values.includes(`all`) ? known + : values.includes(`src`) ? [`src`] + : Object.keys( + values.reduce((map, arg) => (( + (known.includes(arg)) && + (map[arg.toLowerCase()] = true) + || true) && map + ), {}) + ).sort((a, b) => known.indexOf(a) - known.indexOf(b)); + } +} + +const publicModulePaths = (dir) => [ + `${dir}/${mainExport}.dom.js`, + `${dir}/util/int.js`, + `${dir}/compute/predicate.js`, +]; + +const esmRequire = require(`esm`)(module, { + mode: `auto`, + cjs: { + /* A boolean for storing ES modules in require.cache. */ + cache: true, + /* A boolean for respecting require.extensions in ESM. */ + extensions: true, + /* A boolean for __esModule interoperability. */ + interop: true, + /* A boolean for importing named exports of CJS modules. */ + namedExports: true, + /* A boolean for following CJS path rules in ESM. */ + paths: true, + /* A boolean for __dirname, __filename, and require in ESM. */ + vars: true, + } +}); + +module.exports = { + mainExport, npmPkgName, npmOrgName, metadataFiles, packageJSONFields, + + knownTargets, knownModules, tasksToSkipPerTargetOrFormat, gCCLanguageNames, + + taskName, packageName, tsconfigName, targetDir, combinations, observableFromStreams, + publicModulePaths, esmRequire, shouldRunInChildProcess, spawnGulpCommandInChildProcess, + + targetAndModuleCombinations: [...combinations(targets, modules)] +}; |