all files / lib/ handlerParser.js

96.55% Statements 56/58
62.5% Branches 5/8
100% Functions 10/10
96.36% Lines 53/55
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116                              17× 17×   17×       17× 17×           17× 17× 17× 17× 17×   17×   17× 17×   17× 39×       17×                         20×     20×               17×       31× 31× 31× 67×     67×   31×     31× 31× 31× 31× 31×        
'use strict'
 
var logger = require("./logger"), 
	fs = require("fs"),
	stripComments = require("strip-json-comments"),
	_ = require("lodash");
 
 
const CONFIG_FILE_PATH = process.cwd() + "/vatican-conf.json";
 
 
const CLASS_HEADER_REGEXP = /class ([a-zA-Z0-9]+ *){/;
 
const ES5endpointRE = /@endpoint\s*\((url:.+)\s*(method:(?:[ \t]*)(?:get|put|post|delete))\s*(name:.+)?\s*\)[\s\n]*([^\s]*)\.prototype\.([^\s]*)/gim
 
const ES6endpointRE = /@endpoint\s*\((url:.+)\s*(method:(?:[ \t]*)(?:get|put|post|delete))\s*(name:.+)?\s*\)[\s\n]*([a-zA-Z0-9_]*)\([a-zA-Z0-9 ,]*\)/gim
const ES6classNameRE = /class ([a-zA-Z-0-9_ ]+) *{/;
 
 
module.exports = class HandlerParser {
 
	static parse(dir, cb) {
		var paths = [];
	    fs.readdir(dir, function(err, files) {
 
	        Iif(err) {
	            logger.error("Error reading folder: " + dir);
	            cb("Error reading folder: " + dir);
	        } else {
	        	let fpath = "";
	        	let matches = null,
	        		chosenRegExp = ES5endpointRE, //default choice
	        		handlerName = null,
	        		content = null;
 
 
	            _(files).where(function(f) { return f.match(/\.js$/i); }).forEach(function(fname) {
	                fpath = dir + "/" + fname;
	                logger.info("Openning file: " + fpath);
	                content = fs.readFileSync(fpath).toString();
	                let matchesParser = new ES5MatchesParser(fpath);
 
	                if(content.match(CLASS_HEADER_REGEXP)) {
	                	logger.info("ES6 class detected, using ES6 params");
	                	chosenRegExp = ES6endpointRE;
	                	let classNameParts = content.match(ES6classNameRE);
						let handlerClassName = classNameParts[1].trim();
		                matchesParser = new ES6MatchesParser(fpath, handlerClassName);
	                } 
	                content = content.replace(/\/\/\s*@/g, "@") //We allow commenting the line of the endpoint for correct editor syntax coloring
	                content = stripComments(content) //we remove the comments so we don't deal with commented out endpoints
 
	                while( (matches = chosenRegExp.exec(content)) !== null) {
	                    paths.push(matchesParser.getPath(matches));
	                }
	            
	            });
				cb(null, paths);
	        }
	    });
	}
 
}
 
class ES6MatchesParser {
 
	constructor(fpath, className) {
		this.fpath = fpath;
		this.className = className;
	}
 
	getPath(matches) {
        let params = _.compact(matches.slice(1,4));
        let currentPath = {};
        params.forEach(function(p) {
            var parts = p.split(":"),
            	key = parts.shift(),
                value = parts.join(":").trim();
            Eif(value) currentPath[key] = value;
        })
        let actionStr = matches[4];
        
        currentPath['action'] = actionStr.trim();
        currentPath['handlerPath'] = this.fpath;
        currentPath['handlerName'] = this.className;
        currentPath.method = currentPath.method.toUpperCase()
        return currentPath;
	}
}
 
class ES5MatchesParser {
	constructor(fpath) {
		this.fpath = fpath;
	}
 
	getPath(matches) {
        let params = _.compact(matches.slice(1,4))
        let currentPath = {};
        params.forEach(function(p) {
            let parts = p.split(":"),
            	key = parts.shift(),
                value = parts.join(":").trim();
            Eif(value) currentPath[key] = value;
        })
        let actionStr = matches[5],
            handlerName = matches[4]
        
        currentPath['action'] = actionStr.trim();
        currentPath['handlerPath'] = this.fpath;
        currentPath['handlerName'] = handlerName
        currentPath.method = currentPath.method.toUpperCase()
        return currentPath;
	}
}