dragonbones-runtime
Version:
the tools to build dragonbones file for diffrent framework
569 lines (568 loc) • 19.9 kB
JavaScript
/*
* Copyright (c) 2014,egret.com
* 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.com 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-LABS.ORG 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-LABS.ORG 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.
*/
/// <reference path="../types.d.ts" />
var file = require("../FileUtil");
var xml = require("../xml/index");
var CodeUtil = require("./code_util");
var create_manifest = require("./createManifest");
var properties = {};
var stylesMap = {};
var EXMLConfig = (function () {
/**
* 构造函数
*/
function EXMLConfig() {
/**
* 组件清单列表
*/
this.componentDic = {};
this.idMap = {};
this.basicTypes = ["void", "any", "number", "string", "boolean", "Object", "Array", "Function"];
var exmlPath = egret.root + "/tools/lib/exml/";
exmlPath = exmlPath.split("\\").join("/");
var str = file.read(exmlPath + "egret-manifest.xml");
var manifest = xml.parse(str);
this.parseManifest(manifest);
str = file.read(exmlPath + "properties.json");
properties = JSON.parse(str);
this.findStyles(properties);
}
EXMLConfig.getInstance = function () {
if (!exmlConfig) {
exmlConfig = new EXMLConfig();
}
return exmlConfig;
};
EXMLConfig.prototype.findStyles = function (properties) {
var data = properties["styles"];
if (!data) {
return;
}
for (var key in data) {
var classData = properties[key];
if (!classData) {
continue;
}
var list = data[key];
var length = list.length;
for (var i = 0; i < length; i++) {
var prop = list[i];
var type = classData[prop];
if (type) {
stylesMap[prop] = type;
}
}
}
};
Object.defineProperty(EXMLConfig.prototype, "srcPath", {
get: function () {
return this._srcPath;
},
set: function (value) {
this._srcPath = value;
this.classNameToPath = create_manifest.getClassToPathInfo(this.srcPath);
this.parseModules();
},
enumerable: true,
configurable: true
});
EXMLConfig.prototype.parseModules = function () {
this.classNameToModule = {};
for (var className in this.classNameToPath) {
var index = className.lastIndexOf(".");
var ns = "";
if (index != -1) {
ns = className.substring(0, index);
className = className.substring(index + 1);
}
var list = this.classNameToModule[className];
if (!list) {
list = this.classNameToModule[className] = [];
}
if (ns && list.indexOf(ns) == -1) {
list.push(ns);
}
}
};
/**
* 解析框架清单文件
*/
EXMLConfig.prototype.parseManifest = function (manifest) {
var children = manifest.children;
var length = children.length;
for (var i = 0; i < length; i++) {
var item = children[i];
var component = new Component(item);
this.componentDic[component.className] = component;
this.idMap[component.id] = component.className;
}
for (var className in this.componentDic) {
var component = this.componentDic[className];
if (!component.defaultProp)
this.findProp(component);
}
};
/**
* 递归查找默认属性
*/
EXMLConfig.prototype.findProp = function (component) {
if (component.defaultProp)
return component.defaultProp;
var superComp = this.componentDic[component.superClass];
if (superComp) {
var prop = this.findProp(superComp);
if (prop) {
component.defaultProp = prop;
}
}
return component.defaultProp;
};
/**
* @inheritDoc
*/
EXMLConfig.prototype.getClassNameById = function (id, ns) {
var name = "";
if (this.basicTypes.indexOf(id) != -1) {
return id;
}
if (ns == EXMLConfig.W) {
}
else if (!ns || ns == EXMLConfig.E) {
name = this.idMap[id];
}
else {
name = ns.substring(0, ns.length - 1) + id;
if (!this.classNameToPath[name]) {
name = "";
}
}
return name;
};
/**
* 检查一个类名是否存在
*/
EXMLConfig.prototype.checkClassName = function (className) {
if (!className) {
return false;
}
if (this.componentDic[className]) {
return true;
}
if (this.classNameToPath[className]) {
return true;
}
return false;
};
/**
* @inheritDoc
*/
EXMLConfig.prototype.getDefaultPropById = function (id, ns) {
var className = this.getClassNameById(id, ns);
var component = this.componentDic[className];
if (!component && className) {
component = this.findDefaultProp(className);
}
if (!component)
return "";
return component.defaultProp;
};
EXMLConfig.prototype.findDefaultProp = function (className) {
var classData = properties[className];
if (!classData) {
var path = this.classNameToPath[className];
var ext = file.getExtension(path).toLowerCase();
var text = file.read(path);
if (ext == "ts") {
classData = this.getPropertiesFromTs(text, className, "");
}
else if (ext == "exml") {
classData = this.getPropertiesFromExml(text);
}
if (classData) {
properties[className] = classData;
}
else {
return null;
}
}
var superClass = classData["super"];
var component = this.componentDic[superClass];
if (!component) {
component = this.findDefaultProp(superClass);
}
return component;
};
/**
* 指定的属性是否为样式属性
*/
EXMLConfig.prototype.isStyleProperty = function (prop, className) {
var type = this.findType(className, prop);
return !type && this.checkStyleProperty(prop, className);
};
EXMLConfig.prototype.checkStyleProperty = function (prop, className) {
return (this.isInstanceOf(className, "egret.gui.IStyleClient") && stylesMap[prop]);
};
/**
* 获取指定类指定属性的类型
*/
EXMLConfig.prototype.getPropertyType = function (prop, className) {
if (className == "Object") {
return "any";
}
var type = this.findType(className, prop);
if (!type) {
if (this.checkStyleProperty(prop, className)) {
return stylesMap[prop];
}
}
return type;
};
EXMLConfig.prototype.findType = function (className, prop) {
var classData = properties[className];
if (!classData) {
var path = this.classNameToPath[className];
var ext = file.getExtension(path).toLowerCase();
var text = file.read(path);
if (ext == "ts") {
text = CodeUtil.removeComment(text, path);
classData = this.getPropertiesFromTs(text, className, "");
}
else if (ext == "exml") {
classData = this.getPropertiesFromExml(text);
}
if (classData) {
properties[className] = classData;
}
else {
return "";
}
}
var type = classData[prop];
if (!type) {
type = this.findType(classData["super"], prop);
}
return type;
};
/**
* 读取一个exml文件引用的类列表
*/
EXMLConfig.prototype.getPropertiesFromExml = function (text) {
var exml = xml.parse(text);
if (!exml) {
return null;
}
var superClass = this.getClassNameById(exml.localName, exml.namespace);
if (superClass) {
var data = {};
data["super"] = superClass;
return data;
}
return null;
};
/**
* 获取属性列表
*/
EXMLConfig.prototype.getPropertiesFromTs = function (text, className, nsPrefiex) {
index = className.lastIndexOf(".");
var moduleName = "";
if (index != -1) {
moduleName = className.substring(0, index);
className = className.substring(index + 1);
}
var data;
if (moduleName) {
while (text.length > 0) {
var index = CodeUtil.getFirstVariableIndex("module", text);
if (index == -1) {
break;
}
text = text.substring(index + 6);
index = text.indexOf("{");
if (index == -1) {
continue;
}
var ns = text.substring(0, index).trim();
text = text.substring(index);
index = CodeUtil.getBracketEndIndex(text);
if (index == -1) {
break;
}
var block = text.substring(0, index);
text = text.substring(index);
if (ns == moduleName) {
if (nsPrefiex) {
ns = nsPrefiex + "." + moduleName;
}
data = this.getPropFromBlock(block, className, ns);
break;
}
else if (moduleName.indexOf(ns) == 0 && moduleName.charAt(ns.length) == ".") {
var tail = moduleName.substring(ns.length + 1);
var prefix = moduleName.substring(0, ns.length);
if (nsPrefiex) {
prefix = nsPrefiex + "." + prefix;
}
data = this.getPropertiesFromTs(block, tail + "." + className, prefix);
if (data) {
break;
}
}
}
}
else {
data = this.getPropFromBlock(text, className, nsPrefiex);
}
return data;
};
EXMLConfig.prototype.getPropFromBlock = function (block, targetClassName, ns) {
var data;
while (block.length > 0) {
var index = CodeUtil.getFirstVariableIndex("class", block);
if (index == -1) {
break;
}
block = block.substring(index + 5);
index = block.indexOf("{");
var preStr = block.substring(0, index);
block = block.substring(index);
var className = CodeUtil.getFirstVariable(preStr);
if (className != targetClassName) {
continue;
}
data = {};
preStr = CodeUtil.removeFirstVariable(preStr, className);
var word = CodeUtil.getFirstVariable(preStr);
if (word == "extends") {
preStr = CodeUtil.removeFirstVariable(preStr);
word = CodeUtil.getFirstWord(preStr);
if (word) {
word = this.getFullClassName(word, ns);
data["super"] = word;
}
preStr = CodeUtil.removeFirstWord(preStr);
word = CodeUtil.getFirstVariable(preStr);
}
if (word == "implements") {
preStr = CodeUtil.removeFirstVariable(preStr);
var arr = preStr.split(",");
for (var i = arr.length - 1; i >= 0; i--) {
var inter = arr[i];
inter = inter.trim();
if (inter) {
inter = this.getFullClassName(inter, ns);
arr[i] = inter;
}
else {
arr.splice(i, 1);
}
}
data["implements"] = arr;
}
index = CodeUtil.getBracketEndIndex(block);
if (index == -1)
break;
var text = block.substring(0, index + 1);
this.readProps(text, data, ns);
break;
}
return data;
};
/**
* 根据类类短名,和这个类被引用的时所在的module名来获取完整类名。
*/
EXMLConfig.prototype.getFullClassName = function (word, ns) {
if (!ns || !word) {
return word;
}
var prefix = "";
var index = word.lastIndexOf(".");
var nsList;
if (index == -1) {
nsList = this.classNameToModule[word];
}
else {
prefix = word.substring(0, index);
nsList = this.classNameToModule[word.substring(index + 1)];
}
if (!nsList) {
return word;
}
var length = nsList.length;
var targetNs = "";
for (var k = 0; k < length; k++) {
var superNs = nsList[k];
if (prefix) {
var tail = superNs.substring(superNs.length - prefix.length);
if (tail == prefix) {
superNs = superNs.substring(0, superNs.length - prefix.length - 1);
}
else {
continue;
}
}
if (ns.indexOf(superNs) == 0) {
if (superNs.length > targetNs.length) {
targetNs = superNs;
}
}
}
if (targetNs) {
word = targetNs + "." + word;
}
return word;
};
EXMLConfig.prototype.readProps = function (text, data, ns) {
var lines = text.split("\n");
var length = lines.length;
for (var i = 0; i < length; i++) {
var line = lines[i];
var index = CodeUtil.getFirstVariableIndex("public", line);
if (index == -1)
continue;
line = line.substring(index + 7);
var word = CodeUtil.getFirstVariable(line);
if (!word || word.charAt(0) == "_")
continue;
if (word == "get") {
continue;
}
else if (word == "set") {
line = CodeUtil.removeFirstVariable(line);
word = CodeUtil.getFirstVariable(line);
if (!word || word.charAt(0) == "_") {
continue;
}
line = CodeUtil.removeFirstVariable(line);
line = line.trim();
if (line.charAt(0) == "(") {
index = line.indexOf(":");
if (index != -1) {
line = line.substring(index + 1);
index = line.indexOf(")");
type = line.substring(0, index);
index = type.indexOf("<");
if (index != -1) {
type = type.substring(0, index);
}
type = CodeUtil.trimVariable(type);
if (this.basicTypes.indexOf(type) == -1) {
type = this.getFullClassName(type, ns);
}
data[word] = type;
}
else {
data[word] = "any";
}
}
}
else {
line = CodeUtil.removeFirstVariable(line);
line = line.trim();
var firstChar = line.charAt(0);
if (firstChar == ":") {
var type = CodeUtil.getFirstWord(line.substring(1));
index = type.indexOf("=");
if (index != -1) {
type = type.substring(0, index);
}
index = type.indexOf("<");
if (index != -1) {
type = type.substring(0, index);
}
type = CodeUtil.trimVariable(type);
if (this.basicTypes.indexOf(type) == -1) {
type = this.getFullClassName(type, ns);
}
data[word] = type;
}
else if (!line || firstChar == ";" || firstChar == "=") {
data[word] = "any";
}
}
}
};
/**
* 检查classNameA是否是classNameB的子类或classNameA实现了接口classNameB
*/
EXMLConfig.prototype.isInstanceOf = function (classNameA, classNameB) {
if (classNameB == "any" || classNameB == "Class") {
return true;
}
if (classNameA == classNameB) {
return true;
}
var dataA = properties[classNameA];
if (!dataA) {
return false;
}
var list = dataA["implements"];
if (list) {
var length = list.length;
for (var i = 0; i < length; i++) {
if (list[i] == classNameB) {
return true;
}
}
}
return this.isInstanceOf(dataA["super"], classNameB);
};
return EXMLConfig;
}());
/**
* Egret命名空间
*/
EXMLConfig.E = "http://ns.egret-labs.org/egret";
/**
* Wing命名空间
*/
EXMLConfig.W = "http://ns.egret-labs.org/wing";
var Component = (function () {
/**
* 构造函数
*/
function Component(item) {
/**
* 父级类名
*/
this.superClass = "";
/**
* 默认属性
*/
this.defaultProp = "";
if (item) {
this.id = item.$id;
this.className = item["$module"] + "." + this.id;
if (item["$super"])
this.superClass = item.$super;
if (item["$default"])
this.defaultProp = item.$default;
}
}
return Component;
}());
var exmlConfig;
module.exports = EXMLConfig;