build4code
Version:
The repository supports the NPM build process based on UML models created and managed with the JSONEditor4Code. A JSON file defines the attributes and methods of a class and a JSON editor running in a browser allows the generation of Javascript code. In t
431 lines (390 loc) • 14.6 kB
JavaScript
const codegen = require('../codegen/index.js');
// let default_uml =codegen.load_json('./default_uml.json');
console.log("CALL: require('build4code/src/js2uml/default_uml.json') ");
var default_uml = require('./default_uml');
//console.log("Loaded JSON:\n"+JSON.stringify(default_uml,null,4));
// Main function is js2uml()
function js2uml(pClassname,pObject,pkg) {
// pObject is the parsed object for attributes and methods
console.log("CALL: js2uml('" + pClassname + "',pUML,pObject,pkg)");
var vDefaultUML = null;
if (!pkg.js2uml) {
console.warn("WARNING: package.json - js2uml key/value pairs 'default', 'filename' and 'is_constructor' are not defined");
pkg.js2uml = {
"filename": "./jscc/" + pkg.name + "_uml.json",
"default": "./jscc/" + pkg.name + "_default_uml.json",
"is_constructor": true
};
}
if (pkg.js2uml && pkg.js2uml.default) {
vDefaultUML = codegen.load_json(pkg.js2uml.default);
} else {
console.warn("WARNING: package.json - js2uml.default was not defined");
}
vUML = check_js2uml(pClassname,vDefaultUML,pObject,pkg);
var vString4UML = JSON.stringify(vUML,null,4);
if (pkg.js2uml && pkg.js2uml.filename) {
codegen.save_file(pkg.js2uml.filename,vString4UML);
} else {
console.warn("WARNING: package.json - js2uml.filename was not defined");
}
}
function update_uml(pUML,pkg) {
if (pkg.hasOwnProperty("exportvar")) {
//pUML.data.classname = pkg.exportvar;
} else {
console.log("package.json has no property 'exportvar' e.g. ");
pkg.exportvar = codegen.capitalizeFirstLetter(pkg.name);
}
// Package description as Comment for class
pUML.data.comment = pkg.description;
// Time and Date
if (pUML.data) {
if (pUML.data.reposinfo) {
// set date time for created and modified
console.log("build4code - set date time for modified");
pUML.data.reposinfo.modified = getDateTime();
if (!pUML.data.reposinfo.created) {
console.log("build4code - set date time for created");
pUML.data.reposinfo.created = getDateTime();
}
console.log("build4code - set author");
if (pkg.author) {
pUML.data.reposinfo.author = pkg.author;
}
console.log("build4code - set repository URL");
if (pkg.repository) {
if (pkg.repository.url) {
pUML.data.reposinfo.repository = pkg.repository.url;
}
}
} else {
console.error("build4code - pUML.data.reposinfo is not defined ");
}
} else {
console.error("build4code - pUML.data is not defined ");
}
// update URL to repository
var vRepo = pkg.repository.url;
var vBegin = vRepo.indexOf("https:");
var vEnd = vRepo.lastIndexOf(".git");
var vURL = pkg.repository.url;
if ((vBegin >= 0) && (vEnd > vBegin)) {
vURL = "https:" + vRepo.substring(vBegin,vEnd);
}
}
function outTime(pNr) {
var vOut = pNr;
if (pNr == 0) {
vOut = "00"
} if (pNr<10) {
vOut = "0"+pNr;
};
return vOut
}
function getDateTime() {
var vNow = new Date();
var vSep = "/"; // set separator for date
var vOut = vNow.getFullYear() + vSep +outTime(vNow.getMonth()+1) + vSep + outTime(vNow.getDate());
vOut += " "; // Separator between Date and Time
vSep = ":"; // set separator for time
vOut += vNow.getHours() + vSep + outTime(vNow.getMinutes()) + vSep + outTime(vNow.getSeconds());
return vOut;
}
function cloneJSON(pJSON) {
return JSON.parse(JSON.stringify(pJSON));
}
function extract_body(pFunctionDef) {
var vString = pFunctionDef + " ";
var vBody = "";
if (vString) {
var begin = vString.indexOf("{");
var end = vString.lastIndexOf("}");
vBody = vString.substring(begin+1,end);
}
return vBody;
}
function extract_param(pFunctionDef) {
var vString = pFunctionDef + " ";
var vParam = "";
if (vString) {
var begin = vString.indexOf("(");
var end = vString.indexOf(")");
vParam = vString.substring(begin+1,end);
}
return vParam;
}
function find_name_index(pname,parray) {
var vFound = -1;
for (var i = 0; i < parray.length; i++) {
if (pname == parray[i].name) {
vFound = i;
}
}
return vFound;
}
function get_method_parameter(pFunctionDef,pmethod) {
var vParamString = extract_param(pFunctionDef);
var vParArr = vParamString.split(",");
var vNewPar = [];
// console.log("pmethod="+JSON.stringify(pmethod,null,4));
var vOldPar = pmethod.parameter;
for (var i = 0; i < vParArr.length; i++) {
if (vParArr[i] !== "") {
var par_i = find_name_index(vParArr[i],vOldPar);
if (par_i >= 0) {
// paraemeter already exists in UML of method
// push old parameter definition to new parameter array
vNewPar.push(cloneJSON(vOldPar[par_i]));
} else {
// create the new parameter in UML model
vNewPar.push({
"name": vParArr[i],
"class": " ",
"comment": "the parameter provides ..."
});
}
}
}
//pmethod.parameter = vNewPar;
return vNewPar;
}
function get_method(pMethodID,pFunctionDef,pData) {
var vMethodHash = null;
var vParamString = extract_param(pFunctionDef);
var meth_i = find_name_index(pMethodID,pData.methods);
if (meth_i >= 0) {
console.log("Method '" + pMethodID + "(" + vParamString + ")' found");
// method name found in pUML.data.methods
// update the code
vMethodHash = cloneJSON(pData.methods[meth_i]);
vMethodHash.code = extract_body(pFunctionDef);
vMethodHash.parameter = get_method_parameter(pFunctionDef,vMethodHash);
} else {
console.log("NEW Method '" + pMethodID + "(" + vParamString + ")' created in UML");
vMethodHash = {
"visibility": "public",
"name": pMethodID,
"parameter": [],
"return": " ",
"comment": "the method performs ...",
"code": extract_body(pFunctionDef)
};
vMethodHash.parameter = get_method_parameter(pFunctionDef,vMethodHash);
}
// update the methods in UML model
return vMethodHash;
}
function get_type_of_attribute(obj) {
var TYPES = {
'undefined' : 'undefined',
'number' : 'number',
'boolean' : 'boolean',
'string' : 'string',
'[object Function]': 'function',
'[object RegExp]' : 'regexp',
'[object Array]' : 'array',
'[object Date]' : 'date',
'[object Error]' : 'error'
};
var TOSTRING = Object.prototype.toString;
return TYPES[typeof obj] || TYPES[TOSTRING.call(obj)] || (obj ? 'object' : 'null');
};
function get_attrib(pAttribID,pType,pDefault,pData) {
var vAttribHash = null;
var attrib_i = find_name_index(pAttribID,pData.attributes);
if (attrib_i >= 0) {
console.log("Attribute '" + pAttribID + "' Type: '" + pType + "' found");
// Attrib name found in pUML.data.Attribs
// update the code
vAttribHash = cloneJSON(pData.attributes[attrib_i]);
vAttribHash.init = pDefault;
} else {
console.log("NEW Attrib '" + pAttribID + "' Type: '" + pType + "' created in UML");
vAttribHash = {
"visibility": "public",
"name": pAttribID,
"init": pDefault,
"class": pType,
"comment": "the attribute stores ...",
};
}
// update the methods in UML model
return vAttribHash;
}
function is_function(functionToCheck) {
return functionToCheck && {}.toString.call(functionToCheck) === '[object Function]';
}
function is_constructor(functionToCheck) {
return is_function(functionToCheck);
}
function get_instance_attributes(pClassname,pObject,pData) {
// pObject is the object that is parsed for attributes and methods
var vAttribArray = [];
var vInstance = {};
var att_name = "";
var vType = "";
var vDefault = "";
if (is_constructor(pObject)) {
console.log("Parse Attributes in Constructor");
vInstance = new pObject();
for (att_name in vInstance) {
console.log("CHECK: Attribute '" + att_name + "'");
if (att_name.match(/^[0-9]+$/)) {
console.log("Attribute '" + att_name + "' is a number!");
} else {
if (vInstance.hasOwnProperty(att_name)) {
vType = get_type_of_attribute(vInstance[att_name]);
if (vType != "function") {
vDefault = JSON.stringify(vInstance[att_name],null,4);
//console.log("Attribute: '" + pClassname + "." + att_name + " Type: '"+vType+"' Default: " + vDefault);
vAttribArray.push(get_attrib(att_name,vType,vDefault,pData));
}
}
}
}
} else {
console.log("Parse Attributes in Instance");
vInstance = pObject;
for (att_name in vInstance) {
console.log("CHECK: Attribute '" + att_name + "'");
if (vInstance.hasOwnProperty(att_name)) {
if (!is_function(vInstance[att_name])) {
vType = typeof(vInstance[att_name]);
//console.log("Type of '" + att_name + "'="+typeof(vInstance[att_name]));
vDefault = JSON.stringify(vInstance[att_name],null,4);
//console.log("Attribute: " + pClassname + "." + att_name + " - Default value: " + vDefault + " - Type: "+ vType);
vAttribArray.push(get_attrib(att_name,vType,vDefault,pData));
} else {
console.log("Attribute: '" + att_name + "' is a function!");
}
}
}
}
return vAttribArray;
}
function get_prototype_methods (pClassname,pPrototype,pData) {
var vMethArray = [];
for (var meth_name in pPrototype) {
if (pPrototype.hasOwnProperty(meth_name)) {
// console.log("CALL: " + pClassname + ".prototype." + meth_name + "(" + extract_param(pPrototype[meth_name]) + ")");
// console.log("CODE: " + pClassname + ".prototype." + meth_name + "\nCode:\n"+extract_body(pPrototype[meth_name]));
vMethArray.push(get_method(meth_name,pPrototype[meth_name],pData));
}
}
return vMethArray;
}
function get_instance_methods(pClassname,pObject,pData) {
// pObject is the object that is parsed for attributes and methods
var vMethodArray = [];
var vInstance = {};
if (is_constructor(pObject)) {
vInstance = new pObject();
console.log("pObject='" + pClassname + "' is a constructor");
if (!pData.hasOwnProperty("reposinfo")) {
pData.reposinfo = default_uml.data.reposinfo;
}
pData.reposinfo.static = "no";
if (pObject.hasOwnProperty('prototype')) {
vMethodArray = get_prototype_methods(pClassname,pObject.prototype,pData);
} else {
console.log("pObject='" + pClassname + "' has no prototype definitions!");
}
} else {
vInstance = pObject;
pData.reposinfo.static = "yes";
}
for (var meth_name in vInstance) {
if (vInstance.hasOwnProperty(meth_name)) {
if (is_function(vInstance[meth_name])) {
//console.log("Type of '" + meth_name + "'="+typeof(vInstance[meth_name]));
//console.log("CALL: " + pClassname + "." + meth_name + "(" + extract_param(vInstance[meth_name]) + ")");
//console.log("CODE: " + pClassname + "." + meth_name + "\nCode:\n"+extract_body(vInstance[meth_name]));
vMethodArray.push(get_method(meth_name,vInstance[meth_name],pData));
}
}
}
/*
// scan for methods defined with this.mymethod = function(...)
for (var variable in vInstance) {
if (vInstance.hasOwnProperty(variable)) {
var vType = get_type_of_attribute(vInstance[variable]);
if (vType == "function") {
var vDefault = JSON.stringify(vInstance[variable],null,4);
console.log("Method: 'this." + variable + " Type: '"+vType+"' ' Code: " + vCode);
vMethodArray.push(get_attrib(variable,vType,vDefault,pData));
}
}
}
*/
return vMethodArray;
}
function check_js2uml(pClassname,pDefaultUML,pObject,pkg) {
console.log("CALL: check_js2uml('" + pClassname + "',pUML,pObject,pkg)");
var vUML = null;
if (pkg.js2uml) {
console.log("JS2UML:\n"+JSON.stringify(pkg.js2uml,null,4));
console.log("'js2uml' attribute defined in package.json");
if (!pkg.js2uml.is_constructor) {
console.warn("WARNING: In package.json is js2uml.is_constructor undefined - use js2uml.is_constructor=false as default");
pkg.js2uml.is_constructor = false;
}
if (pkg.js2uml.is_constructor === true) {
if (is_function(pObject)) {
console.log("Classname: "+pClassname+" is a treated as a constructor");
} else {
console.error("ERROR: pObject is not a function and therefore is cannot be a constructor");
//pkg.js2uml.is_constructor = false;
}
} else {
console.log("Object: "+pClassname+" is a treated as a hash with key/value pairs. Values can be also defined as functions.");
}
vUML = parse_js2uml(pClassname,pDefaultUML,pObject,pkg);
} else {
console.warn("Add attribute 'js2uml' to package.json");
}
return vUML;
}
function parse_js2uml(pClassname,pDefaultUML,pObject,pkg) {
console.log("CALL: parse_js2uml('" + pClassname + "',pUML,pObject,pkg)");
var vUML = default_uml;
if (pDefaultUML) {
if (!pDefaultUML.data) {
console.log("pUML.data created and polutated with default values from build4code default");
vUML.data = default_uml.data;
// set classname
} else {
console.log("pDefaultUML.data exists - init vUML with pDefaultUML from repository");
vUML.data = pDefaultUM.data;
}
if (!pDefaultUML.settings) {
console.log("pDefaultUML.settings created and polutated with default values");
vUML.settings = default_uml.settings;
} else {
console.log("pDefaultUML.settings exists from UML default in repository");
vUML.settings = pDefaultUML.settings;
}
} else {
// let default_uml = require('./default_uml');
vUML = default_uml; // content of file /src/js2uml/default_uml.js
}
console.log("buidl4code.parse_js2uml() set classname in UML JSON.");
vUML.data.classname = pClassname;
// pObject is the object that is parsed for attributes and methods
// Extract attributes as constructor
if (!vUML.data.attributes) {
console.warn("Warning: in vUML is the attributes array not defined");
vUML.data.attributes = [];
}
vUML.data.attributes = get_instance_attributes(pClassname,pObject,vUML.data);
// Extract the methods form prototypes
if (!vUML.data.methods) {
console.warn("Warning: in vUML is the methodes array not defined");
vUML.data.attributes = [];
}
vUML.data.methods = get_instance_methods(pClassname,pObject,vUML.data);
update_uml(vUML,pkg);
return vUML;
}
// -------NPM Export Variable: Handlebars4Code---------------
module.exports = js2uml;