dragonbones-runtime
Version:
the tools to build dragonbones file for diffrent framework
449 lines (392 loc) • 13.6 kB
text/typescript
//////////////////////////////////////////////////////////////////////////////////////
//
// Copyright (c) 2014-present, Egret Technology.
// All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
// * Neither the name of the Egret nor the
// names of its contributors may be used to endorse or promote products
// derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
// OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA,
// OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////////////////
import cp = require('child_process');
import path = require('path');
import file = require('./FileUtil');
import UglifyJS = require("./uglify-js/uglifyjs");
import net = require('net');
//第三方调用时,可能不支持颜色显示,可通过添加 -nocoloroutput 移除颜色信息
var ColorOutputReplacements = {
"{color_green}": "\033[1;32;1m",
"{color_red}": "\033[0;31m",
"{color_normal}": "\033[0m",
"{color_gray}": "\033[0;37m",
"{color_underline}": "\033[4;36;1m"
};
var NoColorOutputReplacements = {
"{color_green}": "",
"{color_red}": "",
"{color_normal}": "",
"{color_gray}": "",
"{color_underline}": "",
"\n": "\\n",
"\r": ""
};
function formatStdoutString(message) {
var replacements = ColorOutputReplacements;
for (var raw in replacements) {
let replace = (egret.args && egret.args.ide) ? "" : replacements[raw];
message = message.split(raw).join(replace);
}
return message;
}
global["$locale_strings"] = global["$locale_strings"] || {};
var $locale_strings = global["$locale_strings"];
/**
* 全局多语言翻译函数
* @param code 要查询的字符串代码
* @param args 替换字符串中{0}标志的参数列表
* @returns 返回拼接后的字符串
*/
export function tr(code: number, ...args): string {
var text = $locale_strings[code];
if (!text) {
return "{" + code + "}";
}
text = format.apply(this, [text].concat(args));
return text;
}
export function format(text: string, ...args): string {
var length = args.length;
for (var i = 0; i < length || i < 5; i++) {
text = text.replace(new RegExp("\\{" + i + "\\}", "ig"), args[i] || "");
}
text = formatStdoutString(text);
return text;
}
export function ti(code: number, injector?: any): string {
var text = $locale_strings[code];
if (!text) {
return "{" + code + "}";
}
text = inject.call(this, text, injector);
return text;
}
export function inject(text: string, injector?: any): string {
if (injector) {
for (var p in injector) {
text = text.replace(new RegExp("\\{" + p + "\\}", "ig"), injector[p]);
}
}
return text;
}
export function exit(code: number, ...args) {
if (code) {
var text: string = $locale_strings[code];
if (text && text.indexOf("{0}") < 0 || args && args.length > 0) {
var message = tr.apply(this, [code].concat(args));
console.error(message);
}
}
process.exit(code);
}
function _getEnv() {
return process.env;
}
export function getEgretRoot() {
var path = require("path");
var obj = _getEnv();
var egretRoot: string;
var globalpath = module['paths'].concat();
var existsFlag = false;
for (var i = 0; i < globalpath.length; i++) {
var prefix = globalpath[i];
var url = file.joinPath(prefix, '../');
if (file.exists(file.joinPath(url, 'tools/bin/egret'))) {
existsFlag = true;
break;
}
url = prefix;
if (file.exists(file.joinPath(url, 'tools/bin/egret'))) {
existsFlag = true;
break;
}
}
if (!existsFlag) {
throw new Error("can't find Egret");
}
egretRoot = url;
return file.escapePath(file.joinPath(egretRoot, '/'));
}
export function open(target, appName?) {
var command;
switch (process.platform) {
case 'darwin':
if (appName) {
command = 'open -a "' + escape(appName) + '"';
} else {
command = 'open';
}
break;
case 'win32':
// if the first parameter to start is quoted, it uses that as the title
// so we pass a blank title so we can quote the file we are opening
if (appName) {
command = 'start "" "' + escape(appName) + '"';
} else {
command = 'start ""';
}
break;
default:
if (appName) {
command = escape(appName);
} else {
// use Portlands xdg-open everywhere else
command = path.join(__dirname, '../vendor/xdg-open');
}
break;
}
executeCommand(command + ' "' + escape(target) + '"')
}
export async function executeCommand(command: string) {
return new Promise<{ error: Error, stdout: string, stderr: string }>((reslove, reject) => {
cp.exec(command, {}, (error, stdout, stderr) => {
reslove({ error, stdout, stderr })
});
})
}
export function endWith(text: string, match: string) {
return text.lastIndexOf(match) == (text.length - match.length);
}
function escape(s) {
return s.replace(/"/, '\\\"');
}
export function uglify(sourceFile: any) {
const defines = {
DEBUG: false,
RELEASE: true
}
const result = UglifyJS.minify(sourceFile, { compress: { global_defs: defines }, fromString: true, output: { beautify: false } });
const code = result.code;
return code;
}
export function minify(sourceFile: string): string
export function minify(sourceFile: string, output: string): void
export function minify(sourceFile: string, output?: string) {
const defines = {
DEBUG: false,
RELEASE: true
}
//UglifyJS参数参考这个页面:https://github.com/mishoo/UglifyJS2
const result = UglifyJS.minify(sourceFile, { compress: { global_defs: defines }, output: { beautify: false } });
const code = result.code;
if (output) {
file.save(output, code);
}
else {
return code;
}
}
export function clean(path: string, excludes?: string[]) {
var fileList = file.getDirectoryListing(path);
var length = fileList.length;
for (var i = 0; i < length; i++) {
var path = fileList[i];
if (excludes && excludes.indexOf(path) >= 0)
continue;
file.remove(path);
}
}
export function getNetworkAddress(): string[] {
var os = require('os');
var ifaces = os.networkInterfaces();
var ips: string[] = [];
Object.keys(ifaces).forEach(function (ifname) {
var alias = 0;
ifaces[ifname].forEach(function (iface) {
if ('IPv4' !== iface.family || iface.internal !== false) {
// skip over internal (i.e. 127.0.0.1) and non-ipv4 addresses
return;
}
ips.push(iface.address);
});
});
return ips;
}
export function measure(target: any, propertyKey: string, descriptor: TypedPropertyDescriptor<any>) {
const method = descriptor.value;
descriptor.value = function (...arg) {
const timeBuildStart = (new Date()).getTime();
let promise = method.apply(this, arg);
return promise.then((result) => {
const timeBuildEnd = (new Date()).getTime();
const timeBuildUsed = (timeBuildEnd - timeBuildStart) / 1000;
console.log(tr(1108, timeBuildUsed));
return result;
})
}
}
export function getAvailablePort(port = 0) {
return new Promise<number>((resolve, reject) => {
function getPort() {
var server = net.createServer();
server.on('listening', function () {
port = server.address().port
server.close()
})
server.on('close', function () {
resolve(port)
})
server.on('error', function (err) {
port++;
getPort();
})
server.listen(port, '0.0.0.0')
}
getPort();
})
}
export function checkEgret() {
var options = egret.args;
if (file.exists(options.srcDir) == false ||
file.exists(options.templateDir) == false) {
exit(10015, options.projectDir);
}
}
export function isFormatString(text: string): boolean {
if (text) {
if (text.indexOf("\n") != -1) {
return true;
}
}
return false;
}
export function addIndents(times: number, text: string) {
if (times == 0)
return text;
var added = '\t';
for (var i = 0; i < times - 1; i++) {
added += added;
}
//开头
if (text != null) {
text = added + text;
}
//替换\n
return text.replace(new RegExp("\\n", "ig"), '\n' + added);
}
interface MapLike<T> {
[index: string]: T;
}
export interface Map<T> extends MapLike<T> {
__mapBrand: any;
}
export function createMap<T>(template?: MapLike<T>): Map<T> {
const map: Map<T> = Object.create(null); // tslint:disable-line:no-null-keyword
// Using 'delete' on an object causes V8 to put the object in dictionary mode.
// This disables creation of hidden classes, which are expensive when an object is
// constantly changing shape.
map["__"] = undefined;
delete map["__"];
// Copies keys/values from template. Note that for..in will not throw if
// template is undefined, and instead will just exit the loop.
for (const key in template) if (Object.prototype.hasOwnProperty.call(template, key)) {
map[key] = template[key];
}
return map;
}
export function shell(path: string, args: string[], opt?: cp.SpawnOptions, verbase?: boolean): Promise<number> {
let stdout = "";
let stderr = "";
var cmd = `${path} ${args.join(" ")}`;
if (verbase) {
console.log(cmd);
}
let printStdoutBufferMessage = (message) => {
var str = message.toString();
stdout += str;
if (verbase) {
console.log(str);
}
};
let printStderrBufferMessage = (message) => {
var str = message.toString();
stderr += str;
if (verbase) {
console.log(str);
}
};
let callback = (reslove, reject) => {
var shell = cp.spawn(path, args, opt);
shell.on("error", (message) => { console.log(message); });
shell.stderr.on("data", printStderrBufferMessage);
shell.stderr.on("error", printStderrBufferMessage);
shell.stdout.on("data", printStdoutBufferMessage);
shell.stdout.on("error", printStdoutBufferMessage);
shell.on('exit', function (code) {
if (code != 0) {
if (verbase) {
console.log('Failed: ' + code);
}
reject({ code, stdout, stderr });
}
else {
reslove({ code, stdout, stderr });
}
});
};
return new Promise(callback);
};
let error_code_filename = path.join(__dirname, "../error_code.json");
let errorcode = file.readJSONSync(error_code_filename, { "encoding": "utf-8" });
export class CliException extends Error {
public message;
constructor(public errorId, param?: string) {
super();
var message: string = errorcode[this.errorId];
if (message) {
message = message.replace('{0}', param);
}
else {
message = `unkown error : ${errorId}`;
console.error(message);
}
this.message = message;
}
}
export function findValidatePathSync(pathStr: string): string {
if (!pathStr) {
pathStr = process.cwd();
} else {
if (!file.existsSync(pathStr)) {
pathStr = path.join(process.cwd(), pathStr);
}
}
return pathStr;
}
export const cache: MethodDecorator = (target, propertyKey, descriptor: TypedPropertyDescriptor<any>) => {
const method = descriptor.value;
let cacheValue = null;
descriptor.value = function (...arg) {
if (!cacheValue) {
cacheValue = method.apply(this, arg);
}
return cacheValue;
}
}