UNPKG

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
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;