UNPKG

google-closure-compiler

Version:

Check, compile, optimize and compress Javascript with Closure-Compiler

149 lines (128 loc) 4.01 kB
/* * Copyright 2015 The Closure Compiler Authors. * * Licensed 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. */ /** * @fileoverview Low level class for calling the closure-compiler jar * from nodejs * * @author Chad Killingsworth (chadkillingsworth@gmail.com) */ import {spawn} from 'node:child_process'; import compilerPath from 'google-closure-compiler-java'; /** * @type {string} */ export const javaPath = 'java'; export default class Compiler { /** * @param {Object<string,string|boolean>|Array<string>} args * @param {Array<String>=} extraCommandArgs */ constructor(args, extraCommandArgs) { this.commandArguments = []; this.extraCommandArgs = extraCommandArgs; this.JAR_PATH = compilerPath; this.javaPath = javaPath; if (Array.isArray(args)) { this.commandArguments.push(...args); } else { for (const [key, val] of Object.entries(args)) { if (Array.isArray(val)) { this.commandArguments.push(...val.map((item) => this.formatArgument(key, item))); } else { this.commandArguments.push(this.formatArgument(key, val)); } } } /** @type {function(...*)|null} */ this.logger = null; /** @type {Object<string, string>} */ this.spawnOptions = undefined; } /** @param {function(number, string, string)=} callback */ run(callback) { if (this.JAR_PATH) { this.commandArguments.unshift( '-XX:+IgnoreUnrecognizedVMOptions', '--sun-misc-unsafe-memory-access=allow', '-jar', this.JAR_PATH, ); if (this.extraCommandArgs) { this.commandArguments.unshift(...this.extraCommandArgs); } } if (this.logger) { this.logger(this.getFullCommand() + '\n'); } let compileProcess = spawn(this.javaPath, this.commandArguments, this.spawnOptions); let stdOutData = ''; let stdErrData = ''; if (callback) { if (compileProcess.stdout) { compileProcess.stdout.setEncoding('utf8'); compileProcess.stdout.on('data', (data) => { stdOutData += data; }); compileProcess.stdout.on('error', (err) => { stdErrData += err.toString(); }); } if (compileProcess.stderr) { compileProcess.stderr.setEncoding('utf8'); compileProcess.stderr.on('data', (data) => { stdErrData += data; }); } compileProcess.on('close', (code) => { if (code !== 0) { stdErrData = this.prependFullCommand(stdErrData); } callback(code, stdOutData, stdErrData); }); compileProcess.on('error', (err) => { callback(1, stdOutData, this.prependFullCommand('Process spawn error. Is java in the path?\n' + err.message)); }); } return compileProcess; } /** * @return {string} */ getFullCommand() { return `${this.javaPath} ${this.commandArguments.join(' ')}`; } /** * @param {string} msg * @return {string} */ prependFullCommand(msg) { return `${this.getFullCommand()}\n\n${msg}\n\n`; } /** * @param {string} key * @param {(string|boolean)=} val * @return {string} */ formatArgument(key, val) { let normalizedKey = key.replace(/[A-Z]/g, (match) => `_${match.toLowerCase()}`); normalizedKey = normalizedKey.replace(/^--/, ''); if (val === undefined || val === null) { return `--${normalizedKey}`; } return `--${normalizedKey}=${val}`; } };