closure-builder
Version:
Simple Closure, Soy and JavaScript Build system
347 lines (317 loc) • 10 kB
JavaScript
/**
* @fileoverview Closure Builder - Build tools
*
* @license Copyright 2015 Google Inc. All Rights Reserved.
*
* 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.
*
* @author mbordihn@google.com (Markus Bordihn)
*/
var fs = require('fs-extra');
var os = require('os');
var BuildType = require('./build_types.js');
/**
* Build Tools.
* @constructor
* @struct
* @final
*/
var BuildTools = function() {};
/**
* Detects the needed compiler types.
* @param {BuildConfig} config
*/
BuildTools.detectType = function(config) {
if (config.hasSoyFiles() > 0) {
if (config.hasClosureFiles() === 0) {
return BuildType.SOY;
} else {
return BuildType.SOY_CLOSURE;
}
} else if (config.hasClosureFiles()) {
return BuildType.CLOSURE;
} else if (config.hasNodeFiles()) {
return BuildType.NODEJS;
} else if (config.hasJsFiles()) {
return BuildType.JAVASCRIPT;
} else if (config.hasCssFiles()) {
return BuildType.CSS;
} else if (config.hasMarkdownFiles()) {
return BuildType.MARKDOWN;
} else if (config.hasResourceFiles()) {
return BuildType.RESOURCES;
} else {
return BuildType.UNKNOWN;
}
};
/**
* @param {array} files
* @param {boolean=} opt_all Show all files and folders.
* @param {boolean=} opt_exclude_test Exclude test files.
* @return {array}
*/
BuildTools.sortFiles = function(files, opt_all, opt_exclude_test) {
var fileList = [];
var knownFile = {};
for (var i = files.length - 1; i >= 0; i--) {
var file = files[i];
if (file.constructor === Array) {
for (var i2 = file.length - 1; i2 >= 0; i2--) {
var subFile = file[i2];
if (!knownFile[subFile] &&
(opt_all || subFile.indexOf('.') !== -1)) {
fileList.push(subFile);
knownFile[subFile] = true;
}
}
} else {
if (!knownFile[file] &&
(opt_all || file.indexOf('.') !== -1)) {
fileList.push(file);
knownFile[file] = true;
}
}
}
if (opt_exclude_test) {
return BuildTools.filterTestFiles(fileList);
}
return fileList;
};
/**
* Returns the needed build requirements for the given config.
* @param {BuildConfig} config
* @return {Object} Build requirements
*/
BuildTools.getBuildRequirements = function(config) {
var depsConfig = this.scanFiles(config.deps);
var srcsConfig = this.scanFiles(config.srcs, config.name);
var soyConfig = this.scanFiles(config.soy);
var mdConfig = this.scanFiles(config.markdown);
return {
closureFiles: [].concat(depsConfig.closureFiles, srcsConfig.closureFiles),
cssFiles: [].concat(srcsConfig.cssFiles),
jsFiles: [].concat(depsConfig.jsFiles, srcsConfig.jsFiles),
markdownFiles: [].concat(mdConfig.markdownFiles),
nodeFiles: [].concat(srcsConfig.nodeFiles),
soyFiles: [].concat(depsConfig.soyFiles, soyConfig.soyFiles,
srcsConfig.soyFiles),
entryPoint: (depsConfig.entryPoint || srcsConfig.entryPoint),
requireClosureExport: (srcsConfig.requireClosureExport),
requireClosureLibrary: (depsConfig.requireClosureLibrary ||
srcsConfig.requireClosureLibrary),
requireECMAScript6: (depsConfig.requireECMAScript6 ||
srcsConfig.requireECMAScript6),
requireSoyLibrary: (depsConfig.requireSoyLibrary ||
srcsConfig.requireSoyLibrary || soyConfig.requireSoyLibrary),
requireSoyi18n: (soyConfig.requireSoyi18n || srcsConfig.requireSoyi18n)
};
};
/**
* Scan files for certain file types and return list of files and requirements.
* @param {array} files
* @param {string=} opt_entry_point
* @return {Object}
*/
BuildTools.scanFiles = function(files, opt_entry_point) {
var closureFiles = [];
var cssFiles = [];
var jsFiles = [];
var markdownFiles = [];
var nodeFiles = [];
var soyFiles = [];
var entryPoint = '';
var requireClosureExport = false;
var requireClosureLibrary = false;
var requireECMAScript6 = false;
var requireSoyLibrary = false;
var requireSoyi18n = false;
for (var i = files.length - 1; i >= 0; i--) {
var file = files[i];
if (file.indexOf('.soy') !== -1 && file.indexOf('.soy.js') === -1) {
var soyContent = fs.readFileSync(file, 'utf8');
if (soyContent.indexOf('{i18n}') !== -1 &&
soyContent.indexOf('{/i18n}') !== -1) {
requireSoyi18n = true;
}
requireSoyLibrary = true;
soyFiles.push(file);
} else if (file.indexOf('.js') !== -1) {
var fileContent = fs.readFileSync(file, 'utf8');
if (fileContent.indexOf('goog.provide(') !== -1 ||
fileContent.indexOf('goog.require(') !== -1 ||
fileContent.indexOf('goog.module(') !== -1) {
if (fileContent.indexOf(' * @export') !== -1) {
requireClosureExport = true;
}
closureFiles.push(file);
} else if (fileContent.indexOf('require(' !== -1) &&
fileContent.indexOf('module.exports') !== -1) {
nodeFiles.push(file);
} else {
jsFiles.push(file);
}
if (opt_entry_point && fileContent.indexOf(
'goog.provide(\'' + opt_entry_point + '\'') !== -1) {
entryPoint = opt_entry_point;
}
if (fileContent.indexOf('goog.require(\'goog.') !== -1 ||
fileContent.indexOf('goog.require("goog.') !== -1) {
requireClosureLibrary = true;
}
if (fileContent.indexOf('goog.require(\'soy') !== -1 ||
fileContent.indexOf('goog.require(\'soydata') !== -1) {
requireSoyLibrary = true;
}
if (/(let|const)\s+\w+\s?=/.test(fileContent)) {
requireECMAScript6 = true;
}
} else if (file.indexOf('.css') !== -1) {
cssFiles.push(file);
} else if (file.indexOf('.md') !== -1) {
markdownFiles.push(file);
}
}
return {
closureFiles: closureFiles,
cssFiles: cssFiles,
entryPoint: entryPoint,
jsFiles: jsFiles,
nodeFiles: nodeFiles,
soyFiles: soyFiles,
markdownFiles: markdownFiles,
requireClosureExport: requireClosureExport,
requireClosureLibrary: requireClosureLibrary,
requireSoyLibrary: requireSoyLibrary,
requireSoyi18n: requireSoyi18n,
requireECMAScript6: requireECMAScript6
};
};
/**
* @param {string!} file
* @param {string!} content
* @param {function=} opt_callback
* @param {BuildConfig=} opt_config
* @param {?} opt_warning
*/
BuildTools.saveContent = function(file, content, opt_callback, opt_config,
opt_warning) {
var fileEvent = function(error) {
if (error) {
var errorMessage = 'Was not able to write file ' + file + ':' + error;
if (opt_config) {
opt_config.setMessage(errorMessage);
}
if (opt_callback) {
opt_callback('Was not able to write file ' + file + ':' + error,
opt_warning);
}
} else {
var successMessage = 'Saved file ' +
BuildTools.getTruncateText(file) + ' ( ' + content.length + ' )';
if (opt_config) {
opt_config.setMessage(successMessage);
}
if (opt_callback) {
opt_callback(false, opt_warning, file, content);
}
}
};
fs.outputFile(file, content, fileEvent.bind(this));
};
/**
* @param {array} files
* @return {array}
*/
BuildTools.filterTestFiles = function(files) {
for (var i = files.length - 1; i >= 0; i--) {
var file = files[i];
if (file.indexOf('_test.js') !== -1 ||
file.indexOf('_testhelper.js') !== -1 ||
file.indexOf('/demos/') !== -1 ||
file.indexOf('/deps.js') !== -1) {
files.splice(i, 1);
}
}
return files;
};
/**
* @param {array} files
* @return {array}
*/
BuildTools.getSafeFileList = function(files) {
var result = [];
var cache = {};
for (var file in files) {
var fileEntry = files[file];
var safeFileEntry = '"' + fileEntry + '"';
if (fileEntry && !(fileEntry in cache || safeFileEntry in cache)) {
if ((fileEntry.charAt(0) === '"' && fileEntry.charAt(0) === '"') ||
(fileEntry.charAt(0) === '\'' && fileEntry.charAt(0) === '\'')){
result.push(fileEntry);
} else {
result.push(safeFileEntry);
}
cache[fileEntry] = true;
}
}
return result;
};
/**
* @param {!number} size in megabyte.
* @return {!boolean}
*/
BuildTools.checkAvailableMemory = function(size) {
return size <= BuildTools.getMemory();
};
/**
* @param {boolean=} opt_raw
* @return {!number} Available memory in megabyte.
*/
BuildTools.getMemory = function(opt_raw) {
var memory = os.freemem() / 1000000;
if (memory > 512 && process.env.C9_PROJECT) {
memory = 384;
}
if (opt_raw) {
return memory;
}
return Math.floor(memory);
};
/**
* @return {number} 90% of the available memory in megabyte and max of 1024.
*/
BuildTools.getSafeMemory = function() {
var safeMemory = Math.floor(BuildTools.getMemory(true) * 0.9);
if (safeMemory > 1024) {
return 1024;
}
return safeMemory;
};
/**
* Trucate a text in the middle.
* @param {!string} text
* @param {number=} opt_max_length
* @param {string=} opt_seperator
* @return {!string}
*/
BuildTools.getTruncateText = function(text, opt_max_length, opt_seperator) {
var max_length = opt_max_length || 40;
if (text.length <= max_length) {
return text;
}
var seperator = opt_seperator || '…';
var textFront = text.substr(0, Math.ceil(max_length/2) - seperator.length);
var textEnd = text.substr(text.length - Math.floor(max_length/2));
return textFront + seperator + textEnd;
};
module.exports = BuildTools;