<commit_before>(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.parser = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var getAllMatches = require("./util").getAllMatches;

var xmlNode = function(tagname,parent,val){
    this.tagname = tagname;
    this.parent = parent;
    this.child = [];
    this.val = val;
    this.addChild = function (child){
        this.child.push(child);
    };
};

//var tagsRegx = new RegExp("<(\\/?[a-zA-Z0-9_:]+)([^>\\/]*)(\\/?)>([^<]+)?","g");
//var tagsRegx = new RegExp("<(\\/?[\\w:-]+)([^>]*)>([^<]+)?","g");
//var cdataRegx = "<!\\[CDATA\\[([^\\]\\]]*)\\]\\]>";
var cdataRegx = "<!\\[CDATA\\[(.*?)(\\]\\]>)";
var tagsRegx = new RegExp("<(\\/?[\\w:\\-\._]+)([^>]*)>("+cdataRegx+")*([^<]+)?","g");

var defaultOptions = {
    attrPrefix : "@_",
    attrNodeName: false,
    textNodeName : "#text",
    ignoreNonTextNodeAttr : true,
    ignoreTextNodeAttr : true,
    ignoreNameSpace : false,
    ignoreRootElement : false,
    textNodeConversion : true,
    textAttrConversion : false,
    arrayMode : false
};

var buildOptions = function (options){
    if(!options) options = {};
    var props = ["attrPrefix","attrNodeName","ignoreNonTextNodeAttr","ignoreTextNodeAttr","ignoreNameSpace","ignoreRootElement","textNodeName","textNodeConversion","textAttrConversion","arrayMode"];
    for (var i = 0; i < props.length; i++) {
        if(options[props[i]] === undefined){
            options[props[i]] = defaultOptions[props[i]];
        }
    }
    return options;
};

var getTraversalObj =function (xmlData,options){
    options = buildOptions(options);
    //xmlData = xmlData.replace(/>(\s+)/g, ">");//Remove spaces and make it single line.
    var tags = getAllMatches(xmlData,tagsRegx);
    var xmlObj = new xmlNode('!xml');
    var currentNode = xmlObj;

    for (var i = 0; i < tags.length ; i++) {
        var tag = resolveNameSpace(tags[i][1],options.ignoreNameSpace),
            nexttag = i+1 < tags.length ? resolveNameSpace(tags[i+1][1],options.ignoreNameSpace) : undefined,
            attrsStr = tags[i][2], attrs,
            val = tags[i][4] ===  undefined ? tags[i][6] :  simplifyCDATA(tags[i][0]);
        if(tag.indexOf("/") === 0){//ending tag
            currentNode = currentNode.parent;
            continue;
        }

        var selfClosingTag = attrsStr.charAt(attrsStr.length-1) === '/';
        var childNode = new xmlNode(tag,currentNode);

        if(selfClosingTag){
            attrs = buildAttributesArr(attrsStr,options.ignoreTextNodeAttr,options.attrPrefix,options.attrNodeName,options.ignoreNameSpace,options.textAttrConversion);
            childNode.val = attrs || "";
            currentNode.addChild(childNode);
        }else if( ("/" + tag) === nexttag){ //Text node
            attrs = buildAttributesArr(attrsStr,options.ignoreTextNodeAttr,options.attrPrefix,options.attrNodeName,options.ignoreNameSpace,options.textAttrConversion);
            val = parseValue(val,options.textNodeConversion);
            if(attrs){
                attrs[options.textNodeName] = val;
                childNode.val = attrs;
            }else{
                if(val !== undefined && val != null){
                    childNode.val = val;
                }else{
                    childNode.val = "";
                }
            }
            currentNode.addChild(childNode);
            i++;
        }else if( (nexttag && nexttag.indexOf("/") === -1) && (val !== undefined && val != null && val.trim() !== "" )){ //Text node with sub nodes
            val = parseValue(val,options.textNodeConversion);
            childNode.addChild(new xmlNode(options.textNodeName,childNode,val));
            currentNode.addChild(childNode);
            currentNode = childNode;
        }else{//starting tag
            attrs = buildAttributesArr(attrsStr,options.ignoreNonTextNodeAttr,options.attrPrefix,options.attrNodeName,options.ignoreNameSpace,options.textAttrConversion);
            if(attrs){
                for (var prop in attrs) {
                  if(attrs.hasOwnProperty(prop)){
                    childNode.addChild(new xmlNode(prop,childNode,attrs[prop]));
                  }
                }
            }
            currentNode.addChild(childNode);
            currentNode = childNode;
        }
    }
    return xmlObj;
};

var xml2json = function (xmlData,options){
    return convertToJson(getTraversalObj(xmlData,options), buildOptions(options).arrayMode);
};

var cdRegx = new RegExp(cdataRegx,"g");

function simplifyCDATA(cdata){
    var result = getAllMatches(cdata,cdRegx);
    var val = "";
    for (var i = 0; i < result.length ; i++) {
        val+=result[i][1];
    }
    return val;
}

function resolveNameSpace(tagname,ignore){
    if(ignore){
        var tags = tagname.split(":");
        var prefix = tagname.charAt(0) === "/" ? "/" : "";
        if(tags.length === 2) {
            if(tags[0] === "xmlns") {
                return "";
            }
            tagname = prefix + tags[1];
        }
    }
    return tagname;
}

function parseValue(val,conversion){
    if(val){
        if(!conversion || isNaN(val)){
            val = "" + val ;
        }else{
            if(val.indexOf(".") !== -1){
                if(parseFloat){
                    val = parseFloat(val);
                }else{
                    val = Number.parseFloat(val);
                }
            }else{
                if(parseInt){
                    val = parseInt(val,10);
                }else{
                    val = Number.parseInt(val,10);
                }
            }
        }
    }else{
        val = "";
    }
    return val;
}

var attrsRegx = new RegExp("([\\w\\-\\.\\:]+)\\s*=\\s*(['\"])(.*?)\\2","g");
function buildAttributesArr(attrStr,ignore,prefix,attrNodeName,ignoreNS,conversion){
    attrStr = attrStr || attrStr.trim();

    if(!ignore && attrStr.length > 3){

        var matches = getAllMatches(attrStr,attrsRegx);
        var attrs = {};
        for (var i = 0; i < matches.length; i++) {
            var attrName = resolveNameSpace(matches[i][1],ignoreNS);
            if(attrName.length && attrName !== "xmlns") {
                attrs[prefix + attrName] = parseValue(matches[i][3], conversion);
            }
        }
        if(!Object.keys(attrs).length){
            return;
        }
        if(attrNodeName){
            var attrCollection = {};
            attrCollection[attrNodeName] = attrs;
            return attrCollection;
        }
        return attrs;
    }
}

var convertToJson = function (node, arrayMode){
    var jObj = {};
    if(node.val !== undefined && node.val != null || node.val === "") {
        return node.val;
    }else{
        for (var index = 0; index < node.child.length; index++) {
            var prop = node.child[index].tagname;
            var obj = convertToJson(node.child[index], arrayMode);
            if(jObj[prop] !== undefined){
                if(!Array.isArray(jObj[prop])){
                    var swap = jObj[prop];
                    jObj[prop] = [];
                    jObj[prop].push(swap);
                }
                jObj[prop].push(obj);
            }else{
                jObj[prop] = arrayMode ? [obj] : obj;
            }
        }
    }
    return jObj;
};

exports.parse = xml2json;
exports.getTraversalObj = getTraversalObj;
exports.convertToJson = convertToJson;
exports.validate = require("./validator").validate;

},{"./util":2,"./validator":3}],2:[function(require,module,exports){
var getAllMatches = function(string, regex) {
  var matches = [];
  var match = regex.exec(string);
  while (match) {
  	var allmatches = [];
    for (var index = 0; index < match.length; index++) {
  		allmatches.push(match[index]);
  	}
    matches.push(allmatches);
    match = regex.exec(string);
  }
  return matches;
};

var doesMatch = function(string,regex){
  var match = regex.exec(string);
  if(match === null || match === undefined) return false;
  else return true;
}

var doesNotMatch = function(string,regex){
  return !doesMatch(string,regex);
}

exports.doesMatch = doesMatch
exports.doesNotMatch = doesNotMatch
exports.getAllMatches = getAllMatches;
},{}],3:[function(require,module,exports){
var util = require("./util");

var tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g");
exports.validate = function(xmlData){
    xmlData = xmlData.replace(/\n/g,"");//make it single line
    xmlData = xmlData.replace(/(^\s*<\?xml.*?\?>)/g,"");//Remove XML starting tag
    xmlData = xmlData.replace(/(<!DOCTYPE[\s\w\"\.\/\-\:]+(\[.*\])*\s*>)/g,"");//Remove DOCTYPE

    var tags = [];
    for (var i = 0; i < xmlData.length; i++) {

        if(xmlData[i] === "<"){//starting of tag
            //read until you reach to '>' avoiding any '>' in attribute value

            i++;

            if(xmlData[i] === "!"){
                i = readCommentAndCDATA(xmlData,i);
                continue;
            }else{
                var closingTag = false;
                if(xmlData[i] === "/"){//closing tag
                    closingTag = true;
                    i++;
                }
                //read tagname
                var tagName = "";
                for(;i < xmlData.length
                    && xmlData[i] !== ">"
                    && xmlData[i] !== " "
                    && xmlData[i] !== "\t" ; i++) {

                    tagName +=xmlData[i];
                }
                tagName = tagName.trim();

                if(tagName[tagName.length-1] === "/"){//self closing tag without attributes
                    tagName = tagName.substring(0,tagName.length-2);
                    return validateTagName(tagName);
                }
                if(!validateTagName(tagName)) return false;

                var attrStr = "";
                var startChar = "";
                for(;i < xmlData.length ;i++){
                    if(xmlData[i] === '"' || xmlData[i] === "'"){
                        if(startChar === ""){
                            startChar = xmlData[i];
                        }else{
                            startChar = "";
                        }
                    }else if(xmlData[i] === ">"){
                        if(startChar === ""){
                            break;
                        }
                    }
                    attrStr += xmlData[i];
                }
                if(startChar !== "") return false;//You have forgot to close the quote
                attrStr = attrStr.trim();

                if(attrStr[attrStr.length-1] === "/" ){//self closing tag
                    attrStr = attrStr.substring(0,attrStr.length-2);

                    if(!validateAttributeString(attrStr)){
                        return false;
                    }else{

                        continue;
                    }
                }else if(closingTag){
                    if(attrStr.length > 0){
                        return false;
                        //throw new Error("XML validation error: closing tag should not have any attribute");
                    }else{
                        var otg = tags.pop();
                        if(tagName !== otg){
                            return false;
                            //throw new Error("XML validation error: no mathicng closing tag");
                        }
                    }
                }else{
                    if(!validateAttributeString(attrStr)){
                        return false;
                    }
                    tags.push(tagName);
                }

                //skip tag text value
                //It may include comments and CDATA value
                for(i++;i < xmlData.length ; i++){
                    if(xmlData[i] === "<"){
                        if(xmlData[i+1] === "!"){//comment or CADATA
                            i++;
                            i = readCommentAndCDATA(xmlData,i);
                            continue;
                        }else{
                            break;
                        }
                    }
                }//end of reading tag text value
                if(xmlData[i] === "<") i--;
            }
        }else{

            if(xmlData[i] === " " || xmlData[i] === "\t") continue;
            return false;
        }
    }

    if(tags.length > 0){
        return false;
        //throw new Error("XML validation error");
    }

    return true;
}

function readCommentAndCDATA(xmlData,i){
    if(xmlData.length > i+5 && xmlData[i+1] === "-" && xmlData[i+2] === "-"){//comment
        for(i+=3;i<xmlData.length;i++){
            if(xmlData[i] === "-" && xmlData[i+1] === "-" && xmlData[i+2] === ">"){
                i+=2;
                break;
            }
        }
    }else if( xmlData.length > i+9
        && xmlData[i+1] === "["
        && xmlData[i+2] === "C"
        && xmlData[i+3] === "D"
        && xmlData[i+4] === "A"
        && xmlData[i+5] === "T"
        && xmlData[i+6] === "A"
        && xmlData[i+7] === "["){

        for(i+=8;i<xmlData.length;i++){
            if(xmlData[i] === "]" && xmlData[i+1] === "]" && xmlData[i+2] === ">" ){
                i+=2;
                break;
            }
        }
    }

    return i;
}
//attr, ="sd", a="amit's", a="sd"b="saf",
function validateAttributeString(attrStr){
    var attrNames = [];
    for(var i=0; i< attrStr.length; i++){
        var startChar = "";
        //read attribute name
        var attrName = "";
        for(;i < attrStr.length && attrStr[i] !== "=" ; i++) {
            attrName +=attrStr[i];
        }
        //validate attrName
        attrName = attrName.trim();

        if(!attrNames.hasOwnProperty(attrName)){
            attrNames[attrName]=1;
        }else{
            return false;
        }
        if(!validateAttrName(attrName)){
            return false;
        }
        i++;

        //skip whitespaces
        for(;i < attrStr.length
            && (attrStr[i] === " "
            || attrStr[i] === "\t") ; i++);

        //read attribute value
        startChar = attrStr[i++];
        /*if(startChar !== "'" || startChar !== '"'){

            return false;
        }*/
        var attrVal = "";
        for(;i < attrStr.length && attrStr[i] !== startChar; i++) {
            attrVal +=attrStr[i];
        }

        //validate attrVal

        if(startChar !== ""){
            startChar = "";
        }
    }

    return true;
}

var validAttrRegxp = new RegExp("^[_a-zA-Z][\\w\\-\\.\\:]*$");

function validateAttrName(attrName){
    return util.doesMatch(attrName,validAttrRegxp);
}
var startsWithXML = new RegExp("^[Xx][Mm][Ll]");
var startsWith = new RegExp("^([a-zA-Z]|_)[\\w\.\\-_:]*");

function validateTagName(tagname){
    if(util.doesMatch(tagname,startsWithXML)) return false;
    else if(util.doesNotMatch(tagname,startsWith)) return false;
    else return true;
}

},{"./util":2}]},{},[1])(1)
});<commit_msg>generate browser js lib<commit_after>(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.parser = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
var getAllMatches = require("./util").getAllMatches;

var xmlNode = function(tagname,parent,val){
    this.tagname = tagname;
    this.parent = parent;
    this.child = [];
    this.val = val;
    this.addChild = function (child){
        this.child.push(child);
    };
};

//var tagsRegx = new RegExp("<(\\/?[a-zA-Z0-9_:]+)([^>\\/]*)(\\/?)>([^<]+)?","g");
//var tagsRegx = new RegExp("<(\\/?[\\w:-]+)([^>]*)>([^<]+)?","g");
//var cdataRegx = "<!\\[CDATA\\[([^\\]\\]]*)\\]\\]>";
var cdataRegx = "<!\\[CDATA\\[(.*?)(\\]\\]>)";
var tagsRegx = new RegExp("<(\\/?[\\w:\\-\._]+)([^>]*)>("+cdataRegx+")*([^<]+)?","g");

var defaultOptions = {
    attrPrefix : "@_",
    attrNodeName: false,
    textNodeName : "#text",
    ignoreNonTextNodeAttr : true,
    ignoreTextNodeAttr : true,
    ignoreNameSpace : false,
    ignoreRootElement : false,
    textNodeConversion : true,
    textAttrConversion : false,
    arrayMode : false
};

var buildOptions = function (options){
    if(!options) options = {};
    var props = ["attrPrefix","attrNodeName","ignoreNonTextNodeAttr","ignoreTextNodeAttr","ignoreNameSpace","ignoreRootElement","textNodeName","textNodeConversion","textAttrConversion","arrayMode"];
    for (var i = 0; i < props.length; i++) {
        if(options[props[i]] === undefined){
            options[props[i]] = defaultOptions[props[i]];
        }
    }
    return options;
};

var getTraversalObj =function (xmlData,options){
    options = buildOptions(options);
    //xmlData = xmlData.replace(/>(\s+)/g, ">");//Remove spaces and make it single line.
    var tags = getAllMatches(xmlData,tagsRegx);
    var xmlObj = new xmlNode('!xml');
    var currentNode = xmlObj;

    for (var i = 0; i < tags.length ; i++) {
        var tag = resolveNameSpace(tags[i][1],options.ignoreNameSpace),
            nexttag = i+1 < tags.length ? resolveNameSpace(tags[i+1][1],options.ignoreNameSpace) : undefined,
            attrsStr = tags[i][2], attrs,
            val = tags[i][4] ===  undefined ? tags[i][6] :  simplifyCDATA(tags[i][0]);
        if(tag.indexOf("/") === 0){//ending tag
            currentNode = currentNode.parent;
            continue;
        }

        var selfClosingTag = attrsStr.charAt(attrsStr.length-1) === '/';
        var childNode = new xmlNode(tag,currentNode);

        if(selfClosingTag){
            attrs = buildAttributesArr(attrsStr,options.ignoreTextNodeAttr,options.attrPrefix,options.attrNodeName,options.ignoreNameSpace,options.textAttrConversion);
            childNode.val = attrs || "";
            currentNode.addChild(childNode);
        }else if( ("/" + tag) === nexttag){ //Text node
            attrs = buildAttributesArr(attrsStr,options.ignoreTextNodeAttr,options.attrPrefix,options.attrNodeName,options.ignoreNameSpace,options.textAttrConversion);
            val = parseValue(val,options.textNodeConversion);
            if(attrs){
                attrs[options.textNodeName] = val;
                childNode.val = attrs;
            }else{
                childNode.val = val;
            }
            currentNode.addChild(childNode);
            i++;
        }else if( (nexttag && nexttag.indexOf("/") === -1) && (val !== undefined && val != null && val.trim() !== "" )){ //Text node with sub nodes
            val = parseValue(val,options.textNodeConversion);
            childNode.addChild(new xmlNode(options.textNodeName,childNode,val));
            currentNode.addChild(childNode);
            currentNode = childNode;
        }else{//starting tag
            attrs = buildAttributesArr(attrsStr,options.ignoreNonTextNodeAttr,options.attrPrefix,options.attrNodeName,options.ignoreNameSpace,options.textAttrConversion);
            if(attrs){
                for (var prop in attrs) {
                  if(attrs.hasOwnProperty(prop)){
                    childNode.addChild(new xmlNode(prop,childNode,attrs[prop]));
                  }
                }
            }
            currentNode.addChild(childNode);
            currentNode = childNode;
        }
    }
    return xmlObj;
};

var xml2json = function (xmlData,options){
    return convertToJson(getTraversalObj(xmlData,options), buildOptions(options).arrayMode);
};

var cdRegx = new RegExp(cdataRegx,"g");

function simplifyCDATA(cdata){
    var result = getAllMatches(cdata,cdRegx);
    var val = "";
    for (var i = 0; i < result.length ; i++) {
        val+=result[i][1];
    }
    return val;
}

function resolveNameSpace(tagname,ignore){
    if(ignore){
        var tags = tagname.split(":");
        var prefix = tagname.charAt(0) === "/" ? "/" : "";
        if(tags.length === 2) {
            if(tags[0] === "xmlns") {
                return "";
            }
            tagname = prefix + tags[1];
        }
    }
    return tagname;
}

function parseValue(val,conversion){
    if(val){
        if(!conversion || isNaN(val)){
            val = "" + val ;
            val = val.replace("\n","");
        }else{
            if(val.indexOf(".") !== -1){
                if(parseFloat){
                    val = parseFloat(val);
                }else{
                    val = Number.parseFloat(val);
                }
            }else{
                if(parseInt){
                    val = parseInt(val,10);
                }else{
                    val = Number.parseInt(val,10);
                }
            }
        }
    }else{
        val = "";
    }
    return val;
}

var attrsRegx = new RegExp("([\\w\\-\\.\\:]+)\\s*=\\s*(['\"])((.|\n)*?)\\2","gm");
function buildAttributesArr(attrStr,ignore,prefix,attrNodeName,ignoreNS,conversion){
    attrStr = attrStr || attrStr.trim();

    if(!ignore && attrStr.length > 3){

        var matches = getAllMatches(attrStr,attrsRegx);
        var attrs = {};
        for (var i = 0; i < matches.length; i++) {
            var attrName = resolveNameSpace(matches[i][1],ignoreNS);
            if(attrName.length && attrName !== "xmlns") {
                attrs[prefix + attrName] = parseValue(matches[i][3], conversion);
            }
        }
        if(!Object.keys(attrs).length){
            return;
        }
        if(attrNodeName){
            var attrCollection = {};
            attrCollection[attrNodeName] = attrs;
            return attrCollection;
        }
        return attrs;
    }
}

var convertToJson = function (node, arrayMode){
    var jObj = {};
    if(node.val !== undefined && node.val != null || node.val === "") {
        return node.val;
    }else{
        for (var index = 0; index < node.child.length; index++) {
            var prop = node.child[index].tagname;
            var obj = convertToJson(node.child[index], arrayMode);
            if(jObj[prop] !== undefined){
                if(!Array.isArray(jObj[prop])){
                    var swap = jObj[prop];
                    jObj[prop] = [];
                    jObj[prop].push(swap);
                }
                jObj[prop].push(obj);
            }else{
                jObj[prop] = arrayMode ? [obj] : obj;
            }
        }
    }
    return jObj;
};

exports.parse = xml2json;
exports.getTraversalObj = getTraversalObj;
exports.convertToJson = convertToJson;
exports.validate = require("./validator").validate;

},{"./util":2,"./validator":3}],2:[function(require,module,exports){
var getAllMatches = function(string, regex) {
  var matches = [];
  var match = regex.exec(string);
  while (match) {
  	var allmatches = [];
    for (var index = 0; index < match.length; index++) {
  		allmatches.push(match[index]);
  	}
    matches.push(allmatches);
    match = regex.exec(string);
  }
  return matches;
};

var doesMatch = function(string,regex){
  var match = regex.exec(string);
  if(match === null || match === undefined) return false;
  else return true;
}

var doesNotMatch = function(string,regex){
  return !doesMatch(string,regex);
}

exports.doesMatch = doesMatch
exports.doesNotMatch = doesNotMatch
exports.getAllMatches = getAllMatches;
},{}],3:[function(require,module,exports){
var util = require("./util");

var tagsPattern = new RegExp("<\\/?([\\w:\\-_\.]+)\\s*\/?>","g");
exports.validate = function(xmlData){
    xmlData = xmlData.replace(/\n/g,"");//make it single line
    xmlData = xmlData.replace(/(^\s*<\?xml.*?\?>)/g,"");//Remove XML starting tag
    xmlData = xmlData.replace(/(<!DOCTYPE[\s\w\"\.\/\-\:]+(\[.*\])*\s*>)/g,"");//Remove DOCTYPE

    var tags = [];
    for (var i = 0; i < xmlData.length; i++) {

        if(xmlData[i] === "<"){//starting of tag
            //read until you reach to '>' avoiding any '>' in attribute value

            i++;

            if(xmlData[i] === "!"){
                i = readCommentAndCDATA(xmlData,i);
                continue;
            }else{
                var closingTag = false;
                if(xmlData[i] === "/"){//closing tag
                    closingTag = true;
                    i++;
                }
                //read tagname
                var tagName = "";
                for(;i < xmlData.length
                    && xmlData[i] !== ">"
                    && xmlData[i] !== " "
                    && xmlData[i] !== "\t" ; i++) {

                    tagName +=xmlData[i];
                }
                tagName = tagName.trim();

                if(tagName[tagName.length-1] === "/"){//self closing tag without attributes
                    tagName = tagName.substring(0,tagName.length-2);
                    return validateTagName(tagName);
                }
                if(!validateTagName(tagName)) return false;

                var attrStr = "";
                var startChar = "";
                for(;i < xmlData.length ;i++){
                    if(xmlData[i] === '"' || xmlData[i] === "'"){
                        if(startChar === ""){
                            startChar = xmlData[i];
                        }else{
                            startChar = "";
                        }
                    }else if(xmlData[i] === ">"){
                        if(startChar === ""){
                            break;
                        }
                    }
                    attrStr += xmlData[i];
                }
                if(startChar !== "") return false;//You have forgot to close the quote
                attrStr = attrStr.trim();

                if(attrStr[attrStr.length-1] === "/" ){//self closing tag
                    attrStr = attrStr.substring(0,attrStr.length-2);

                    if(!validateAttributeString(attrStr)){
                        return false;
                    }else{

                        continue;
                    }
                }else if(closingTag){
                    if(attrStr.length > 0){
                        return false;
                        //throw new Error("XML validation error: closing tag should not have any attribute");
                    }else{
                        var otg = tags.pop();
                        if(tagName !== otg){
                            return false;
                            //throw new Error("XML validation error: no mathicng closing tag");
                        }
                    }
                }else{
                    if(!validateAttributeString(attrStr)){
                        return false;
                    }
                    tags.push(tagName);
                }

                //skip tag text value
                //It may include comments and CDATA value
                for(i++;i < xmlData.length ; i++){
                    if(xmlData[i] === "<"){
                        if(xmlData[i+1] === "!"){//comment or CADATA
                            i++;
                            i = readCommentAndCDATA(xmlData,i);
                            continue;
                        }else{
                            break;
                        }
                    }
                }//end of reading tag text value
                if(xmlData[i] === "<") i--;
            }
        }else{

            if(xmlData[i] === " " || xmlData[i] === "\t") continue;
            return false;
        }
    }

    if(tags.length > 0){
        return false;
        //throw new Error("XML validation error");
    }

    return true;
}

function readCommentAndCDATA(xmlData,i){
    if(xmlData.length > i+5 && xmlData[i+1] === "-" && xmlData[i+2] === "-"){//comment
        for(i+=3;i<xmlData.length;i++){
            if(xmlData[i] === "-" && xmlData[i+1] === "-" && xmlData[i+2] === ">"){
                i+=2;
                break;
            }
        }
    }else if( xmlData.length > i+9
        && xmlData[i+1] === "["
        && xmlData[i+2] === "C"
        && xmlData[i+3] === "D"
        && xmlData[i+4] === "A"
        && xmlData[i+5] === "T"
        && xmlData[i+6] === "A"
        && xmlData[i+7] === "["){

        for(i+=8;i<xmlData.length;i++){
            if(xmlData[i] === "]" && xmlData[i+1] === "]" && xmlData[i+2] === ">" ){
                i+=2;
                break;
            }
        }
    }

    return i;
}
//attr, ="sd", a="amit's", a="sd"b="saf",
function validateAttributeString(attrStr){
    var attrNames = [];
    for(var i=0; i< attrStr.length; i++){
        var startChar = "";
        //read attribute name
        var attrName = "";
        for(;i < attrStr.length && attrStr[i] !== "=" ; i++) {
            attrName +=attrStr[i];
        }
        //validate attrName
        attrName = attrName.trim();

        if(!attrNames.hasOwnProperty(attrName)){
            attrNames[attrName]=1;
        }else{
            return false;
        }
        if(!validateAttrName(attrName)){
            return false;
        }
        i++;

        //skip whitespaces
        for(;i < attrStr.length
            && (attrStr[i] === " "
            || attrStr[i] === "\t") ; i++);

        //read attribute value
        startChar = attrStr[i++];

        var attrVal = "";
        for(;i < attrStr.length && attrStr[i] !== startChar; i++) {
            attrVal +=attrStr[i];
        }

        //validate attrVal

        if(startChar !== ""){
            i++;
            if(i<attrStr.length && (attrStr[i] !== " " && attrStr[i] !== "\t") ){//when no spce between 2 attributes : a="sd"b="saf"
                return false;
            }
            startChar = "";
        }
    }

    return true;
}

var validAttrRegxp = new RegExp("^[_a-zA-Z][\\w\\-\\.\\:]*$");

function validateAttrName(attrName){
    return util.doesMatch(attrName,validAttrRegxp);
}
var startsWithXML = new RegExp("^[Xx][Mm][Ll]");
var startsWith = new RegExp("^([a-zA-Z]|_)[\\w\.\\-_:]*");

function validateTagName(tagname){
    if(util.doesMatch(tagname,startsWithXML)) return false;
    else if(util.doesNotMatch(tagname,startsWith)) return false;
    else return true;
}

},{"./util":2}]},{},[1])(1)
});<|endoftext|>


<commit_before>var fs = require('fs');
var path = require('path');
var util = require('util');
var debuglog = require('debuglog');
var _ = require('lodash');
var hashlib = require('i18next-text').hash;
var map = require('./map');
var pkg = require('../package.json');

/**
 * Creates a new parser
 * @constructor
 */
var Parser = function(options) {
    var defaults = {
        // Provides a list of supported languages by setting the lngs option.
        lngs: ['en'],

        // Sorts the keys in ascending order.
        sort: false,

        // Provides a default value if a value is not specified.
        defaultValue: '',

        // The resGetPath is the source i18n path, it is relative to current working directory.
        resGetPath: 'i18n/__lng__/__ns__.json',

        // The resGetPath is the target i18n path, it is relative to your gulp.dest path.
        resSetPath: 'i18n/__lng__/__ns__.json',

        // Changes namespace and/or key separator by setting nsseparator and/or keyseparator options.
        nsseparator: ':',
        keyseparator: '.',

        // Changes pre-/suffix for variables by setting interpolationPrefix and interpolationSuffix options.
        interpolationPrefix: '__',
        interpolationSuffix: '__',

        ns: {
            // Provides a list of namespaces by setting the namespaces option.
            namespaces: [],
            // Changes the default namespace by setting the ns.defaultNs option.
            defaultNs: 'translation'
        }
    };
    var resStore;

    this.options = _.clone(options);
    this.resStore = resStore = {};

    _.defaults(this.options, defaults);

    options = this.options;

    if ( ! _.isArray(options.ns.namespaces)) {
        options.ns.namespaces = [];
    }
    console.assert(_.isArray(options.ns.namespaces), 'The ns.namespaces option should be an array of strings');

    options.ns.namespaces = _.chain(options.ns.namespaces.concat([options.ns.defaultNs]))
        .flatten()
        .union()
        .value();

    _.each(options.lngs, function(lng) {
        resStore[lng] = resStore[lng] || {};
        _.each(options.ns.namespaces, function(ns) {
            var regex = {
                'lng': new RegExp(_.escapeRegExp(options.interpolationPrefix + 'lng' + options.interpolationSuffix), 'g'),
                'ns': new RegExp(_.escapeRegExp(options.interpolationPrefix + 'ns' + options.interpolationSuffix), 'g')
            };
            var resPath = options.resGetPath
                .replace(regex.lng, lng)
                .replace(regex.ns, ns);

            resStore[lng][ns] = {};

            try {
                var stat = fs.statSync(resPath);
                if (stat.isFile()) {
                    resStore[lng][ns] = JSON.parse(fs.readFileSync(resPath, 'utf-8'));
                }
            }
            catch (err) {
                debuglog('Unable to load ' + JSON.stringify(resPath));
            }
        });
    });

    debuglog(JSON.stringify({
        options: this.options,
        resStore: this.resStore
    }));
};

/**
 * Parses translation keys from `data-i18n` attribute in HTML
 * @param {string} attrs A semicolon-separated list of attributes
 */
Parser.prototype.parseAttrs = function(attrs) {
    var _self = this;

    var keys = [];
    if (attrs.indexOf(';') <= attrs.length-1) {
        keys = attrs.split(';');
    } else {
        keys = [ attrs ];
    }

    _.each(keys, function(key) {
        var attr = 'text';

        key = _.trim(key);

        if (key.length === 0) {
            return;
        }

        if (key.indexOf('[') === 0) {
            var parts = key.split(']');
            key = parts[1];
            attr = parts[0].substr(1, parts[0].length-1);
        }

        if (key.indexOf(';') === key.length-1) {
            key = key.substr(0, key.length-2);
        }

        _self.parseKey(key);
    });
};

/**
 * Parses a key string and stores the key-value pairs to i18n resource store
 * @param {string} key The translation key
 * @param {string} [defaultValue] The key's value
 */
Parser.prototype.parseKey = function(key, defaultValue) {
    var options = this.options;
    var resStore = this.resStore;

    var ns = (typeof options.ns === 'string') ? options.ns : options.ns.defaultNs;
    if (key.indexOf(options.nsseparator) > -1) {
        var parts = key.split(options.nsseparator);
        ns = parts[0];
        key = parts[1];
    }

    var keys = key.split(options.keyseparator);
    _.each(options.lngs, function(lng) {
        var lookupKey;
        var value = resStore[lng] && resStore[lng][ns];
        var x = 0;
        while (keys[x]) {
            value = value && value[keys[x]];
            x++;
        }

        if ( ! _.isUndefined(value)) {
            // Reuse the key existed in the resStore
            lookupKey = '[' + lng + '][' + ns + '][' + keys.join('][') + ']';
            debuglog('[v] resStore' + lookupKey + '="' + map(resStore, lookupKey) + '"');
        } else if (_.isObject(resStore[lng][ns])) {
            var res = resStore[lng][ns];
            _.each(keys, function(elem, index) {
                if (index >= (keys.length - 1)) {
                    res[elem] = _.isUndefined(defaultValue) ? options.defaultValue : defaultValue;
                } else {
                    res[elem] = res[elem] || {};
                    res = res[elem];
                }
            });

            // Add new key to the resStore
            lookupKey = '[' + lng + '][' + ns + '][' + keys.join('][') + ']';
            debuglog('[+] resStore' + lookupKey + '="' + map(resStore, lookupKey) + '"');
        } else { // skip the namespace that is not defined in the i18next options
            console.error('The namespace "' + ns + '" is not defined in your i18next options. Please ensure the namespace exists in the namespaces array.');
        }
    });
};

/**
 * Parses a value string and stores the key-value pairs to i18n resource store
 * @param {string} value The key's value
 * @param {string} defaultKey The translation key
 */
Parser.prototype.parseValue = function(value, defaultKey) {
    var options = this.options;
    var resStore = this.resStore;

    var key = hashlib['sha1'](value); // FIXME
    var ns = (typeof options.ns === 'string') ? options.ns : options.ns.defaultNs;

    _.each(options.lngs, function(lng) {
        var lookupKey = '[' + lng + '][' + ns + '][' + key + ']';

        // Verify existing value
        var _value = map(resStore, lng + '.' + ns + '.' + key);
        if (_.isUndefined(_value)) {
            map(resStore, lng + '.' + ns + '.' + key, value);
            debuglog('[+] resStore' + lookupKey + '="' + map(resStore, lookupKey) + '"');
        } else if (_value === value) {
            debuglog('[v] resStore' + lookupKey + '="' + map(resStore, lookupKey) + '"');
        } else {
            console.error('[x] Key conflict in ' + lookupKey + '="' + _value + '"\n' + 'sha1' + '("' + value + '")=' + key);
        }
    });
};

/**
 * Parses hash arguments
 * @see {@link http://stackoverflow.com/questions/168171/regular-expression-for-parsing-name-value-pairs} for further information.
 * @example
 * var str = ' id=nav-bar class = "top" foo = "bar\\"baz" ';
 * str.match(/([^=,\s]*)\s*=\s*((?:"(?:\\.|[^"\\]+)*"|'(?:\\.|[^'\\]+)*')|[^'"\s]*)/igm) || [];
 * // it will show ["id=nav-bar", "class = "top"", "foo = "bar\"baz""]
 *
 * @param [string] hashArguments A string representation of hash arguments
 */
Parser.prototype.parseHashArguments = function(hashArguments) {
    var hash = {};
    var params = hashArguments.match(/([^=,\s]*)\s*=\s*((?:"(?:\\.|[^"\\]+)*"|'(?:\\.|[^'\\]+)*')|[^'"\s]*)/igm) || [];
    var unquote = function(str, quoteChar) {
        quoteChar = quoteChar || '"';
        if (str[0] === quoteChar && str[str.length - 1] === quoteChar) {
            return str.slice(1, str.length - 1);
        }
        return str;
    };

    _.each(params, function(param) {
        param = _.trim(param);
        var r = param.match(/([^=,\s]*)\s*=\s*((?:"(?:\\.|[^"\\]+)*"|'(?:\\.|[^'\\]+)*')|[^'"\s]*)/) || [];

        if (r.length < 3 || _.isUndefined(r[1]) || _.isUndefined(r[2])) {
            return;
        }

        var key = _.trim(r[1]);
        var value = (function(value) { // value is enclosed with either single quote (') or double quote (") characters
            value = _.trim(value);

            var quoteChars = '\'"';
            var quoteChar = _.find(quoteChars, function(quoteChar) {
                return value.charAt(0) === quoteChar;
            });

            if (quoteChar) { // single quote (') or double quote (")
                value = unquote(value, quoteChar);
            }

            return value;
        }(r[2]));

        hash[key] = value;
    });
    return hash;
};

/**
 * Returns a JSON string containing translation information
 * @param {object} [opts] The options object
 * @param {boolean} [opts.sort] True to sort object by key
 * @param {function|string[]|number[]} [opts.replacer] The same as the JSON.stringify()
 * @param {string|number} [opts.space] The same as the JSON.stringify() method
 * @return {string}
 */
Parser.prototype.toJSON = function(opts) {
    opts = opts || {};
    return JSON.stringify(this.toObject(opts), opts.replacer, opts.space);
};

/**
 * Returns an Object containing translation information
 * @param {object} [opts] The options object
 * @param {boolean} [opts.sort] True to sort object by key
 * @return {object}
 */
Parser.prototype.toObject = function(opts) {
    opts = opts || {};
    opts.sort = !!opts.sort;

    var resStore = _.clone(this.resStore);

    if (opts.sort) {
        _.each(resStore, function(namespaces, lng) {
            _.each(namespaces, function(obj, ns) {
                // Sorted by key
                resStore[lng][ns] = _.chain(obj)
                    .pairs()
                    .sortBy(function(pair) { var key = pair[0]; return key; })
                    .reduce(function(memo, pair) { var key = pair[0], value = pair[1]; memo[key] = value; return memo; }, {})
                    .value();
            });
        });
    }

    return resStore;
};

module.exports = function(options) {
    return new Parser(options);
};
<commit_msg>Updates API documentation<commit_after>var fs = require('fs');
var path = require('path');
var util = require('util');
var debuglog = require('debuglog');
var _ = require('lodash');
var hashlib = require('i18next-text').hash;
var map = require('./map');
var pkg = require('../package.json');

/**
 * Creates a new parser
 * @constructor
 */
var Parser = function(options) {
    var defaults = {
        // Provides a list of supported languages by setting the lngs option.
        lngs: ['en'],

        // Sorts the keys in ascending order.
        sort: false,

        // Provides a default value if a value is not specified.
        defaultValue: '',

        // The resGetPath is the source i18n path, it is relative to current working directory.
        resGetPath: 'i18n/__lng__/__ns__.json',

        // The resGetPath is the target i18n path, it is relative to your gulp.dest path.
        resSetPath: 'i18n/__lng__/__ns__.json',

        // Changes namespace and/or key separator by setting nsseparator and/or keyseparator options.
        nsseparator: ':',
        keyseparator: '.',

        // Changes pre-/suffix for variables by setting interpolationPrefix and interpolationSuffix options.
        interpolationPrefix: '__',
        interpolationSuffix: '__',

        ns: {
            // Provides a list of namespaces by setting the namespaces option.
            namespaces: [],
            // Changes the default namespace by setting the ns.defaultNs option.
            defaultNs: 'translation'
        }
    };
    var resStore;

    this.options = _.clone(options);
    this.resStore = resStore = {};

    _.defaults(this.options, defaults);

    options = this.options;

    if ( ! _.isArray(options.ns.namespaces)) {
        options.ns.namespaces = [];
    }
    console.assert(_.isArray(options.ns.namespaces), 'The ns.namespaces option should be an array of strings');

    options.ns.namespaces = _.chain(options.ns.namespaces.concat([options.ns.defaultNs]))
        .flatten()
        .union()
        .value();

    _.each(options.lngs, function(lng) {
        resStore[lng] = resStore[lng] || {};
        _.each(options.ns.namespaces, function(ns) {
            var regex = {
                'lng': new RegExp(_.escapeRegExp(options.interpolationPrefix + 'lng' + options.interpolationSuffix), 'g'),
                'ns': new RegExp(_.escapeRegExp(options.interpolationPrefix + 'ns' + options.interpolationSuffix), 'g')
            };
            var resPath = options.resGetPath
                .replace(regex.lng, lng)
                .replace(regex.ns, ns);

            resStore[lng][ns] = {};

            try {
                var stat = fs.statSync(resPath);
                if (stat.isFile()) {
                    resStore[lng][ns] = JSON.parse(fs.readFileSync(resPath, 'utf-8'));
                }
            }
            catch (err) {
                debuglog('Unable to load ' + JSON.stringify(resPath));
            }
        });
    });

    debuglog(JSON.stringify({
        options: this.options,
        resStore: this.resStore
    }));
};

/**
 * Parses translation keys from `data-i18n` attribute in HTML
 * @param {string} attrs A semicolon-separated list of attributes
 */
Parser.prototype.parseAttrs = function(attrs) {
    var _self = this;

    var keys = [];
    if (attrs.indexOf(';') <= attrs.length-1) {
        keys = attrs.split(';');
    } else {
        keys = [ attrs ];
    }

    _.each(keys, function(key) {
        var attr = 'text';

        key = _.trim(key);

        if (key.length === 0) {
            return;
        }

        if (key.indexOf('[') === 0) {
            var parts = key.split(']');
            key = parts[1];
            attr = parts[0].substr(1, parts[0].length-1);
        }

        if (key.indexOf(';') === key.length-1) {
            key = key.substr(0, key.length-2);
        }

        _self.parseKey(key);
    });
};

/**
 * Parses a key string and stores the key-value pairs to i18n resource store
 * @param {string} key The translation key
 * @param {string} [defaultValue] The key's value
 */
Parser.prototype.parseKey = function(key, defaultValue) {
    var options = this.options;
    var resStore = this.resStore;

    var ns = (typeof options.ns === 'string') ? options.ns : options.ns.defaultNs;
    if (key.indexOf(options.nsseparator) > -1) {
        var parts = key.split(options.nsseparator);
        ns = parts[0];
        key = parts[1];
    }

    var keys = key.split(options.keyseparator);
    _.each(options.lngs, function(lng) {
        var lookupKey;
        var value = resStore[lng] && resStore[lng][ns];
        var x = 0;
        while (keys[x]) {
            value = value && value[keys[x]];
            x++;
        }

        if ( ! _.isUndefined(value)) {
            // Reuse the key existed in the resStore
            lookupKey = '[' + lng + '][' + ns + '][' + keys.join('][') + ']';
            debuglog('[v] resStore' + lookupKey + '="' + map(resStore, lookupKey) + '"');
        } else if (_.isObject(resStore[lng][ns])) {
            var res = resStore[lng][ns];
            _.each(keys, function(elem, index) {
                if (index >= (keys.length - 1)) {
                    res[elem] = _.isUndefined(defaultValue) ? options.defaultValue : defaultValue;
                } else {
                    res[elem] = res[elem] || {};
                    res = res[elem];
                }
            });

            // Add new key to the resStore
            lookupKey = '[' + lng + '][' + ns + '][' + keys.join('][') + ']';
            debuglog('[+] resStore' + lookupKey + '="' + map(resStore, lookupKey) + '"');
        } else { // skip the namespace that is not defined in the i18next options
            console.error('The namespace "' + ns + '" is not defined in your i18next options. Please ensure the namespace exists in the namespaces array.');
        }
    });
};

/**
 * Parses a value string and stores the key-value pairs to i18n resource store
 * @param {string} value The key's value
 * @param {string} defaultKey The translation key
 */
Parser.prototype.parseValue = function(value, defaultKey) {
    var options = this.options;
    var resStore = this.resStore;

    var key = hashlib['sha1'](value); // FIXME
    var ns = (typeof options.ns === 'string') ? options.ns : options.ns.defaultNs;

    _.each(options.lngs, function(lng) {
        var lookupKey = '[' + lng + '][' + ns + '][' + key + ']';

        // Verify existing value
        var _value = map(resStore, lng + '.' + ns + '.' + key);
        if (_.isUndefined(_value)) {
            map(resStore, lng + '.' + ns + '.' + key, value);
            debuglog('[+] resStore' + lookupKey + '="' + map(resStore, lookupKey) + '"');
        } else if (_value === value) {
            debuglog('[v] resStore' + lookupKey + '="' + map(resStore, lookupKey) + '"');
        } else {
            console.error('[x] Key conflict in ' + lookupKey + '="' + _value + '"\n' + 'sha1' + '("' + value + '")=' + key);
        }
    });
};

/**
 * Parses hash arguments
 * @see [Regular expression for parsing name value pairs]{@link http://stackoverflow.com/questions/168171/regular-expression-for-parsing-name-value-pairs}
 * @example <caption>Example usage:</caption>
 * // it will output ["id=nav-bar", "class = "top"", "foo = "bar\"baz""]
 * var str = ' id=nav-bar class = "top" foo = "bar\\"baz" ';
 * str.match(/([^=,\s]*)\s*=\s*((?:"(?:\\.|[^"\\]+)*"|'(?:\\.|[^'\\]+)*')|[^'"\s]*)/igm) || [];
 * @param [string] hashArguments A string representation of hash arguments
 */
Parser.prototype.parseHashArguments = function(hashArguments) {
    var hash = {};
    var params = hashArguments.match(/([^=,\s]*)\s*=\s*((?:"(?:\\.|[^"\\]+)*"|'(?:\\.|[^'\\]+)*')|[^'"\s]*)/igm) || [];
    var unquote = function(str, quoteChar) {
        quoteChar = quoteChar || '"';
        if (str[0] === quoteChar && str[str.length - 1] === quoteChar) {
            return str.slice(1, str.length - 1);
        }
        return str;
    };

    _.each(params, function(param) {
        param = _.trim(param);
        var r = param.match(/([^=,\s]*)\s*=\s*((?:"(?:\\.|[^"\\]+)*"|'(?:\\.|[^'\\]+)*')|[^'"\s]*)/) || [];

        if (r.length < 3 || _.isUndefined(r[1]) || _.isUndefined(r[2])) {
            return;
        }

        var key = _.trim(r[1]);
        var value = (function(value) { // value is enclosed with either single quote (') or double quote (") characters
            value = _.trim(value);

            var quoteChars = '\'"';
            var quoteChar = _.find(quoteChars, function(quoteChar) {
                return value.charAt(0) === quoteChar;
            });

            if (quoteChar) { // single quote (') or double quote (")
                value = unquote(value, quoteChar);
            }

            return value;
        }(r[2]));

        hash[key] = value;
    });
    return hash;
};

/**
 * Returns a JSON string containing translation information
 * @param {object} [opts] The options object
 * @param {boolean} [opts.sort] True to sort object by key
 * @param {function|string[]|number[]} [opts.replacer] The same as the JSON.stringify()
 * @param {string|number} [opts.space] The same as the JSON.stringify() method
 * @return {string}
 */
Parser.prototype.toJSON = function(opts) {
    opts = opts || {};
    return JSON.stringify(this.toObject(opts), opts.replacer, opts.space);
};

/**
 * Returns an Object containing translation information
 * @param {object} [opts] The options object
 * @param {boolean} [opts.sort] True to sort object by key
 * @return {object}
 */
Parser.prototype.toObject = function(opts) {
    opts = opts || {};
    opts.sort = !!opts.sort;

    var resStore = _.clone(this.resStore);

    if (opts.sort) {
        _.each(resStore, function(namespaces, lng) {
            _.each(namespaces, function(obj, ns) {
                // Sorted by key
                resStore[lng][ns] = _.chain(obj)
                    .pairs()
                    .sortBy(function(pair) { var key = pair[0]; return key; })
                    .reduce(function(memo, pair) { var key = pair[0], value = pair[1]; memo[key] = value; return memo; }, {})
                    .value();
            });
        });
    }

    return resStore;
};

module.exports = function(options) {
    return new Parser(options);
};
<|endoftext|>


<commit_before>/*
 * grunt-accessibility
 * https://github.com/yargalot/grunt-accessibility
 *
 * Copyright (c) 2013 Steven John Miller
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  var path      = require('path');
  var fs        = require('fs');
  var _         = require('underscore');
  var phantom   = require('grunt-lib-phantomjs').init(grunt);
  var asset     = path.join.bind(null, __dirname, '..');

  grunt.registerMultiTask('accessibility', 'Use HTML codesniffer to grade accessibility', function() {

    var options = this.options({
      phantomScript: asset('phantomjs/bridge.js'),
      urls: []
    });

    var done = this.async();
    var log = '',
        logJSON = {};

    grunt.log.writeln('Running accessibility tests'.cyan);

    phantom.on('error.onError', function (msg, trace) {
      grunt.log.writeln('error: ' + msg);
    });

    phantom.on('console', function (msg, trace) {

      var ignore = false;
      var msgSplit = msg.split('|');

      _.each(options.ignore, function(value, key) {
        if (value === msgSplit[1]) {
          ignore = true;
        }
      });

      if (ignore) {
        return;
      }

      if (msgSplit[0] === 'ERROR' || msgSplit[0] === 'NOTICE') {

        if (options.outputFormat === 'json') {
          logJSON[options.file] = logJSON[options.file] || [];
          logJSON[options.file].push({
            type: msgSplit[0],
            msg: msgSplit[2],
            sc: msgSplit[1].split('.')[3],
            technique: msgSplit[1].split('.')[4],
            element: {
              nodeName: msgSplit[3],
              className: msgSplit[4],
              id: msgSplit[5]
            }
          });
        } else {
          log += msg + '\r\n';
        }

        var heading = msgSplit[0] === 'ERROR' ? msgSplit[0].red : msgSplit[0].yellow;
        heading += ' '+ msgSplit[1];

        grunt.log.writeln(heading);
        grunt.log.writeln(msgSplit[2]);
      } else {

        grunt.log.writeln(msg);

      }

    });

    phantom.on('wcaglint.done', function (msg, trace) {
        grunt.log.writeln('Report Finished'.cyan);

        if (options.outputFormat === 'json') {
          grunt.file.write(options.filedest + '.json', JSON.stringify(logJSON[options.file]));
        } else {
          grunt.file.write(options.filedest , log);
          log = '';
        }

        grunt.log.writeln('File "' + options.filedest + '" created.');

        phantom.halt();
    });

    // Built-in error handlers.
    phantom.on('fail.load', function(url) {
      phantom.halt();
      grunt.warn('PhantomJS unable to load URL.');
    });

    phantom.on('fail.timeout', function() {
      phantom.halt();
      grunt.warn('PhantomJS timed out.');
    });

    // Start the running thing
    var totalFiles  = this.files.length;
    var currentFile = 0;

    grunt.util.async.forEachSeries(this.files, function(file, next) {

      if (!file.src) {
        done();
      }

      var filename = path.basename(file.src, ['.html']);

      options.filedest = file.dest;
      options.file = filename;

      phantom.spawn(file.src, {
        // Additional PhantomJS options.
        options: options,
        // Complete the task when done.
        done: function (err) {

          currentFile ++;

          if (currentFile === totalFiles || err) {
            done();
          }

          next();

        }
      });

    });

  });

};
<commit_msg>append format ext<commit_after>/*
 * grunt-accessibility
 * https://github.com/yargalot/grunt-accessibility
 *
 * Copyright (c) 2013 Steven John Miller
 * Licensed under the MIT license.
 */

'use strict';

module.exports = function(grunt) {

  var path      = require('path');
  var fs        = require('fs');
  var _         = require('underscore');
  var phantom   = require('grunt-lib-phantomjs').init(grunt);
  var asset     = path.join.bind(null, __dirname, '..');

  grunt.registerMultiTask('accessibility', 'Use HTML codesniffer to grade accessibility', function() {

    var options = this.options({
      phantomScript: asset('phantomjs/bridge.js'),
      urls: []
    });

    var done = this.async();
    var log = '',
        logJSON = {};

    grunt.log.writeln('Running accessibility tests'.cyan);

    phantom.on('error.onError', function (msg, trace) {
      grunt.log.writeln('error: ' + msg);
    });

    phantom.on('console', function (msg, trace) {

      var ignore = false;
      var msgSplit = msg.split('|');

      _.each(options.ignore, function(value, key) {
        if (value === msgSplit[1]) {
          ignore = true;
        }
      });

      if (ignore) {
        return;
      }

      if (msgSplit[0] === 'ERROR' || msgSplit[0] === 'NOTICE') {

        if (options.outputFormat === 'json') {
          logJSON[options.file] = logJSON[options.file] || [];
          logJSON[options.file].push({
            type: msgSplit[0],
            msg: msgSplit[2],
            sc: msgSplit[1].split('.')[3],
            technique: msgSplit[1].split('.')[4],
            element: {
              nodeName: msgSplit[3],
              className: msgSplit[4],
              id: msgSplit[5]
            }
          });
        } else {
          log += msg + '\r\n';
        }

        var heading = msgSplit[0] === 'ERROR' ? msgSplit[0].red : msgSplit[0].yellow;
        heading += ' '+ msgSplit[1];

        grunt.log.writeln(heading);
        grunt.log.writeln(msgSplit[2]);
      } else {

        grunt.log.writeln(msg);

      }

    });

    phantom.on('wcaglint.done', function (msg, trace) {
        grunt.log.writeln('Report Finished'.cyan);

        if (options.outputFormat === 'json') {
          grunt.file.write(options.filedest + '.json', JSON.stringify(logJSON[options.file]));
        } else {
          grunt.file.write(options.filedest , log);
          log = '';
        }

        grunt.log.writeln('File "' + options.filedest + ('.' + options.outputFormat) || ''  + '" created.');

        phantom.halt();
    });

    // Built-in error handlers.
    phantom.on('fail.load', function(url) {
      phantom.halt();
      grunt.warn('PhantomJS unable to load URL.');
    });

    phantom.on('fail.timeout', function() {
      phantom.halt();
      grunt.warn('PhantomJS timed out.');
    });

    // Start the running thing
    var totalFiles  = this.files.length;
    var currentFile = 0;

    grunt.util.async.forEachSeries(this.files, function(file, next) {

      if (!file.src) {
        done();
      }

      var filename = path.basename(file.src, ['.html']);

      options.filedest = file.dest;
      options.file = filename;

      phantom.spawn(file.src, {
        // Additional PhantomJS options.
        options: options,
        // Complete the task when done.
        done: function (err) {

          currentFile ++;

          if (currentFile === totalFiles || err) {
            done();
          }

          next();

        }
      });

    });

  });

};
<|endoftext|>


<commit_before>/**
 * Parted (https://github.com/chjj/parted)
 * A streaming multipart state parser.
 * Copyright (c) 2011, Christopher Jeffrey. (MIT Licensed)
 */

var fs = require('fs')
  , path = require('path')
  , EventEmitter = require('events').EventEmitter
  , StringDecoder = require('string_decoder').StringDecoder;

var DASH = '-'.charCodeAt(0)
  , CR = '\r'.charCodeAt(0)
  , LF = '\n'.charCodeAt(0)
  , COLON = ':'.charCodeAt(0)
  , SPACE = ' '.charCodeAt(0);

/**
 * Parted
 */

var parted = function(type, options) {
  if (!(this instanceof parted)) {
    return new parted(type, options);
  }

  EventEmitter.call(this);

  this.writable = true;
  this.readable = true;

  this.options = options || {};

  var key = grab(type, 'boundary');
  if (!key) {
    return this._error('No boundary key found.');
  }

  this.key = new Buffer('\r\n--' + key);

  this.state = 'start';
  this.pending = 0;
  this.written = 0;
  this.buff = new Buffer(200);

  this.preamble = true;
  this.epilogue = false;

  this._reset();
};

parted.prototype.__proto__ = EventEmitter.prototype;

/**
 * Parsing
 */

parted.prototype.write = function(data) {
  if (!this.writable
      || this.epilogue) return;

  try {
    this._parse(data);
  } catch(e) {
    this._error(e);
  }

  return true;
};

parted.prototype.end = function(data) {
  if (!this.writable) return;

  this.writable = false;
  this.readable = false;

  if (data) this.write(data);

  if (!this.epilogue) {
    return this._error('Message underflow.');
  }

  if (!this.pending) this.emit('end');

  return true;
};

parted.prototype._parse = function(data) {
  var i = 0
    , len = data.length
    , buff = this.buff
    , key = this.key
    , ch
    , val;

  for (; i < len; i++) {
    if (this.pos >= 200) {
      return this._error('Potential buffer overflow.');
    }

    ch = data[i];

    switch (this.state) {
      case 'start':
        switch (ch) {
          case DASH:
            this.pos = 3;
            this.state = 'key';
            break;
          default:
            break;
        }
        break;
      case 'key':
        if (this.pos === key.length) {
          this.state = 'key_end';
          i--;
        } else if (ch !== key[this.pos]) {
          if (this.preamble) {
            this.state = 'start';
          } else {
            this.state = 'body';
            val = this.pos - i;
            if (val > 0) this._write(key.slice(0, val));
            i--;
          }
        } else {
          this.pos++;
        }
        break;
      case 'key_end':
        switch (ch) {
          case CR:
            this.state = 'key_line_end';
            break;
          case DASH:
            this.state = 'key_dash_end';
            break;
          default:
            return this._error('Parse error 1.');
        }
        break;
      case 'key_line_end':
        switch (ch) {
          case LF:
            if (this.preamble) {
              this.preamble = false;
            } else {
              this._finish();
            }
            this.state = 'header_name';
            this.pos = 0;
            break;
          default:
            return this._error('Parse error 2.');
        }
        break;
      case 'key_dash_end':
        switch (ch) {
          case DASH:
            this._finish();
            this.epilogue = true;
            return;
          default:
            return this._error('Parse error 3.');
        }
        break;
      case 'header_name':
        switch (ch) {
          case COLON:
            val = buff.slice(0, this.pos);
            this.header = val.toString('ascii');
            this.pos = 0;
            this.state = 'header_val';
            break;
          default:
            buff[this.pos++] = ch | 32;
            break;
        }
        break;
      case 'header_val':
        switch (ch) {
          case CR:
            this.state = 'header_val_end';
            break;
          case SPACE:
            if (this.pos === 0) {
              break;
            }
            ; // FALL-THROUGH
          default:
            buff[this.pos++] = ch;
            break;
        }
        break;
      case 'header_val_end':
        switch (ch) {
          case LF:
            val = buff.slice(0, this.pos).toString('ascii');
            if (this.header === 'content-disposition') {
              this.field = grab(val, 'name');
              this.file = grab(val, 'filename');
              if (this.file) {
                this.data = stream(this.file, this.options.path);
              } else {
                this.data = '';
              }
            }
            this.emit('header', this.header, val);
            this.pos = 0;
            this.state = 'header_end';
            break;
          default:
            return this._error('Parse error 4.');
        }
        break;
      case 'header_end':
        switch (ch) {
          case CR:
            this.state = 'head_end';
            break;
          default:
            this.state = 'header_name';
            i--;
            break;
        }
        break;
      case 'head_end':
        switch (ch) {
          case LF:
            this.state = 'body';
            i++;
            if (i >= len) return;
            data = data.slice(i);
            i = 0;
            len = data.length;
            break;
          default:
            return this._error('Parse error 5.');
        }
        break;
      case 'body':
        switch (ch) {
          case CR:
            if (i > 0) {
              this._write(data.slice(0, i));
            }
            this.pos = 1;
            this.state = 'key';
            data = data.slice(i);
            i = 0;
            len = data.length;
            break;
          default:
            break;
        }
        break;
    }
  }

  if (this.state === 'body') {
    this._write(data);
  }
};

parted.prototype._write = function(data) {
  if (this.data == null) {
    return this._error('No disposition.');
  }

  if (this.file) {
    this.data.write(data);
  } else {
    this.data += this.decoder.write(data);
  }

  this.written += data.length;
  this.emit('data', data.length);
};

parted.prototype._reset = function() {
  this.decoder = new StringDecoder('utf8');
  this.pos = 0;
  this.field = null;
  this.data = null;
  this.file = null;
  this.header = null;
};

parted.prototype._error = function(err) {
  this.destroy();
  this.emit('error', new Error(err + ''));
};

parted.prototype.destroy = function(err) {
  this.writable = false;
  this.readable = false;
  this._reset();
};

parted.prototype._finish = function() {
  var self = this
    , field = this.field
    , data = this.data
    , part;

  this.pending++;

  if (data.path) {
    part = data.path;
    data.end(next);
  } else {
    part = data;
    next();
  }

  this._reset();

  function next() {
    self.pending--;

    self.emit('part', field, part);

    if (self.epilogue && !self.pending) {
      self.emit('end');
    }
  }
};

/**
 * Uploads
 */

parted.root = '/tmp';

/**
 * Middleware
 */

parted.middleware = function(options) {
  options = options || {};
  options.limit = options.limit || Infinity;
  return function(req, res, next) {
    if (req.method === 'GET'
        || req.method === 'HEAD'
        || req.body) return next();

    var type = req.headers['content-type'];

    if (type && type.indexOf('multipart/form-data') === 0) {
      var parser = new parted(type, options)
        , parts = {};

      parser.on('error', function(err) {
        req.destroy();
        next(err);
      });

      parser.on('part', function(field, part) {
        parts[field] = part;
      });

      parser.on('data', function(bytes) {
        if (this.written > options.limit) {
          this.emit('error', new Error('Overflow.'));
          this.destroy();
        }
      });

      parser.on('end', next);

      req.body = parts;
      req.pipe(parser);
    } else {
      next();
    }
  };
};

/**
 * Helpers
 */

var stream = function(name, dir) {
  var ext = path.extname(name) || ''
    , name = path.basename(name, ext) || ''
    , dir = dir || parted.root;

  name = Date.now() + '_' + name.substring(0, 10);
  name = path.join(dir, name) + ext.substring(0, 6);
  name = name.replace(/\0/g, '');

  return fs.createWriteStream(name);
};

var grab = function(str, name) {
  if (!str) return;

  var rx = new RegExp(name + '\\s*=\\s*([^;,]+)', 'i')
    , cap = rx.exec(str);

  if (cap) {
    return cap[1].trim().replace(/^['"]|['"]$/g, '');
  }
};

/**
 * Expose
 */

module.exports = parted;
<commit_msg>decoder<commit_after>/**
 * Parted (https://github.com/chjj/parted)
 * A streaming multipart state parser.
 * Copyright (c) 2011, Christopher Jeffrey. (MIT Licensed)
 */

var fs = require('fs')
  , path = require('path')
  , EventEmitter = require('events').EventEmitter
  , StringDecoder = require('string_decoder').StringDecoder;

var DASH = '-'.charCodeAt(0)
  , CR = '\r'.charCodeAt(0)
  , LF = '\n'.charCodeAt(0)
  , COLON = ':'.charCodeAt(0)
  , SPACE = ' '.charCodeAt(0);

/**
 * Parted
 */

var parted = function(type, options) {
  if (!(this instanceof parted)) {
    return new parted(type, options);
  }

  EventEmitter.call(this);

  this.writable = true;
  this.readable = true;

  this.options = options || {};

  var key = grab(type, 'boundary');
  if (!key) {
    return this._error('No boundary key found.');
  }

  this.key = new Buffer('\r\n--' + key);

  this.state = 'start';
  this.pending = 0;
  this.written = 0;
  this.buff = new Buffer(200);

  this.preamble = true;
  this.epilogue = false;

  this._reset();
};

parted.prototype.__proto__ = EventEmitter.prototype;

/**
 * Parsing
 */

parted.prototype.write = function(data) {
  if (!this.writable
      || this.epilogue) return;

  try {
    this._parse(data);
  } catch(e) {
    this._error(e);
  }

  return true;
};

parted.prototype.end = function(data) {
  if (!this.writable) return;

  this.writable = false;
  this.readable = false;

  if (data) this.write(data);

  if (!this.epilogue) {
    return this._error('Message underflow.');
  }

  if (!this.pending) this.emit('end');

  return true;
};

parted.prototype._parse = function(data) {
  var i = 0
    , len = data.length
    , buff = this.buff
    , key = this.key
    , ch
    , val;

  for (; i < len; i++) {
    if (this.pos >= 200) {
      return this._error('Potential buffer overflow.');
    }

    ch = data[i];

    switch (this.state) {
      case 'start':
        switch (ch) {
          case DASH:
            this.pos = 3;
            this.state = 'key';
            break;
          default:
            break;
        }
        break;
      case 'key':
        if (this.pos === key.length) {
          this.state = 'key_end';
          i--;
        } else if (ch !== key[this.pos]) {
          if (this.preamble) {
            this.state = 'start';
          } else {
            this.state = 'body';
            val = this.pos - i;
            if (val > 0) this._write(key.slice(0, val));
            i--;
          }
        } else {
          this.pos++;
        }
        break;
      case 'key_end':
        switch (ch) {
          case CR:
            this.state = 'key_line_end';
            break;
          case DASH:
            this.state = 'key_dash_end';
            break;
          default:
            return this._error('Parse error 1.');
        }
        break;
      case 'key_line_end':
        switch (ch) {
          case LF:
            if (this.preamble) {
              this.preamble = false;
            } else {
              this._finish();
            }
            this.state = 'header_name';
            this.pos = 0;
            break;
          default:
            return this._error('Parse error 2.');
        }
        break;
      case 'key_dash_end':
        switch (ch) {
          case DASH:
            this._finish();
            this.epilogue = true;
            return;
          default:
            return this._error('Parse error 3.');
        }
        break;
      case 'header_name':
        switch (ch) {
          case COLON:
            val = buff.slice(0, this.pos);
            this.header = val.toString('ascii');
            this.pos = 0;
            this.state = 'header_val';
            break;
          default:
            buff[this.pos++] = ch | 32;
            break;
        }
        break;
      case 'header_val':
        switch (ch) {
          case CR:
            this.state = 'header_val_end';
            break;
          case SPACE:
            if (this.pos === 0) {
              break;
            }
            ; // FALL-THROUGH
          default:
            buff[this.pos++] = ch;
            break;
        }
        break;
      case 'header_val_end':
        switch (ch) {
          case LF:
            val = buff.slice(0, this.pos).toString('ascii');
            if (this.header === 'content-disposition') {
              this.field = grab(val, 'name');
              this.file = grab(val, 'filename');
              if (this.file) {
                this.data = stream(this.file, this.options.path);
              } else {
                this.data = '';
              }
            }
            this.emit('header', this.header, val);
            this.pos = 0;
            this.state = 'header_end';
            break;
          default:
            return this._error('Parse error 4.');
        }
        break;
      case 'header_end':
        switch (ch) {
          case CR:
            this.state = 'head_end';
            break;
          default:
            this.state = 'header_name';
            i--;
            break;
        }
        break;
      case 'head_end':
        switch (ch) {
          case LF:
            this.state = 'body';
            i++;
            if (i >= len) return;
            data = data.slice(i);
            i = 0;
            len = data.length;
            break;
          default:
            return this._error('Parse error 5.');
        }
        break;
      case 'body':
        switch (ch) {
          case CR:
            if (i > 0) {
              this._write(data.slice(0, i));
            }
            this.pos = 1;
            this.state = 'key';
            data = data.slice(i);
            i = 0;
            len = data.length;
            break;
          default:
            break;
        }
        break;
    }
  }

  if (this.state === 'body') {
    this._write(data);
  }
};

parted.prototype._write = function(data) {
  if (this.data == null) {
    return this._error('No disposition.');
  }

  if (this.file) {
    this.data.write(data);
  } else {
    this.data += this.decode.write(data);
  }

  this.written += data.length;
  this.emit('data', data.length);
};

parted.prototype._reset = function() {
  this.decode = new StringDecoder('utf8');
  this.pos = 0;
  this.field = null;
  this.data = null;
  this.file = null;
  this.header = null;
};

parted.prototype._error = function(err) {
  this.destroy();
  this.emit('error', new Error(err + ''));
};

parted.prototype.destroy = function(err) {
  this.writable = false;
  this.readable = false;
  this._reset();
};

parted.prototype._finish = function() {
  var self = this
    , field = this.field
    , data = this.data
    , part;

  this.pending++;

  if (data.path) {
    part = data.path;
    data.end(next);
  } else {
    part = data;
    next();
  }

  this._reset();

  function next() {
    self.pending--;

    self.emit('part', field, part);

    if (self.epilogue && !self.pending) {
      self.emit('end');
    }
  }
};

/**
 * Uploads
 */

parted.root = '/tmp';

/**
 * Middleware
 */

parted.middleware = function(options) {
  options = options || {};
  options.limit = options.limit || Infinity;
  return function(req, res, next) {
    if (req.method === 'GET'
        || req.method === 'HEAD'
        || req.body) return next();

    var type = req.headers['content-type'];

    if (type && type.indexOf('multipart/form-data') === 0) {
      var parser = new parted(type, options)
        , parts = {};

      parser.on('error', function(err) {
        req.destroy();
        next(err);
      });

      parser.on('part', function(field, part) {
        parts[field] = part;
      });

      parser.on('data', function(bytes) {
        if (this.written > options.limit) {
          this.emit('error', new Error('Overflow.'));
          this.destroy();
        }
      });

      parser.on('end', next);

      req.body = parts;
      req.pipe(parser);
    } else {
      next();
    }
  };
};

/**
 * Helpers
 */

var stream = function(name, dir) {
  var ext = path.extname(name) || ''
    , name = path.basename(name, ext) || ''
    , dir = dir || parted.root;

  name = Date.now() + '_' + name.substring(0, 10);
  name = path.join(dir, name) + ext.substring(0, 6);
  name = name.replace(/\0/g, '');

  return fs.createWriteStream(name);
};

var grab = function(str, name) {
  if (!str) return;

  var rx = new RegExp(name + '\\s*=\\s*([^;,]+)', 'i')
    , cap = rx.exec(str);

  if (cap) {
    return cap[1].trim().replace(/^['"]|['"]$/g, '');
  }
};

/**
 * Expose
 */

module.exports = parted;
<|endoftext|>


<commit_before>/*
 * requirejs-templates
 * https://github.com/sergiovilar/grunt-requirejs-templates
 *
 * Copyright (c) 2013 Sérgio Vilar
 * Licensed under the MIT license.
 */

/*jshint evil:true */

'use strict';

module.exports = function(grunt) {

  var fs = require('fs');
  var file = require('file');
  var mkdirp = require('mkdirp');

  function extractPath(string){

    var quotes;
    if(string.indexOf("'") > -1){
      quotes = "'";
    }else if(string.indexOf('"') > -1){
      quotes = '"';
    }
    var arr = string.split(quotes);
    return arr[1];

  }

  function removeBracketsAndQuotes(string){

    var regex = new RegExp('"', 'g');

    string = string.replace("[","");
    string = string.replace("]","");
    string = string.replace(regex,"");
    string = string.replace(/\\n/g,"");

    string = string.trim();

    return string;

  }

  Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another
      for(var i in o2) { o1[i] = o2[i]; }
      return o1;
  };

  grunt.registerMultiTask('requirejs_templates', 'A plugin to insert the content of template files like underscore, handlebars to variables into the javascript code', function() {

    try{

      var defaults = {
        appDir: ".",
        scripts: "scripts",
        templates: "templates"
      };

      var options = Object.merge(defaults, this.data.options);

      // Lê os arquivos
      file.walkSync(options.appDir + '/' + options.scripts, function(path, dirPath, dirs, files){

        for(var u in dirs){

          var data = fs.readFileSync(process.cwd() + '/' + path + '/' + dirs[u], 'utf8');

          if(data.indexOf('text!' + options.templates) > -1){

            var templates_signature = '';

            var defineHeader_array1 = data.split('define([');
            var defineHeader_array2 = defineHeader_array1[1].split('{');

            var defineHeader = 'define([' + defineHeader_array2[0] + '{';
            var newDefineHeader = defineHeader;

            var templatesList = eval("[" + defineHeader_array2[0].trim().split(']')[0] + "]");

            var variables = defineHeader_array2[0].split(']')[1].split('(')[1].split(')')[0];
            var requires = defineHeader_array2[0].trim().split(']')[0];

            var variablesList = variables.split(', ');
            var _variablesList = variables.split(', ');

            var templates = [];
            var require_files = [];
            var arr = requires.split(',');
            for(var i in arr){
              require_files.push(arr[i]);
              if(arr[i].indexOf('text!' + options.templates) > -1){
                templates.push(arr[i].trim());
              }
            }

            var templates_counter = 0;

            for(var w in templates){

              var templateFilePath = extractPath(templates[w]).replace('text!' + options.templates, options.appDir + '/' + options.templates);
              var templateData = fs.readFileSync(process.cwd() + '/' + templateFilePath, 'utf8');
              templateData = templateData.replace(/\n/g, '').trim();

              var index;
              for(var z in templatesList){
                if(templatesList[z] === extractPath(templates[w])){
                  index = z;
                }
              }

              index = index - templates_counter;

              var templateContent = "\n    var "+variablesList[index] + " = '" + templateData + "';";
              templates_signature += templateContent;

              variablesList.splice(index, 1);
              require_files.splice(index, 1);

              templates_counter++;

            }

            newDefineHeader = newDefineHeader.replace(requires, removeBracketsAndQuotes(JSON.stringify(require_files)).replace(new RegExp(',', 'g'), ",\n"));
            newDefineHeader = newDefineHeader.replace(variables, removeBracketsAndQuotes(JSON.stringify(variablesList)));
            newDefineHeader += "\n" + templates_signature;

            if(require_files.length < 2){
              newDefineHeader = newDefineHeader.replace("define([\n    ","define([");
            }

            var newFileContent = data.replace(defineHeader, newDefineHeader);

            if(options.output){

              mkdirp.sync(process.cwd() + '/' + options.output + '/' + path);
              fs.writeFileSync(process.cwd() + '/' + options.output + '/' + path + '/' + dirs[u], newFileContent, 'utf8');

            }else{
              fs.writeFileSync(process.cwd() + '/' + path + '/' + dirs[u], newFileContent, 'utf8');
            }

          }

        }

      });

    }catch(e){
      grunt.log.writeln("Error: "+e.message);
      console.log(e.stack);
    }

  });

};<commit_msg>Fix for windows endlines<commit_after>/*
 * requirejs-templates
 * https://github.com/sergiovilar/grunt-requirejs-templates
 *
 * Copyright (c) 2013 Sérgio Vilar
 * Licensed under the MIT license.
 */

/*jshint evil:true */

'use strict';

module.exports = function(grunt) {

  var fs = require('fs');
  var file = require('file');
  var mkdirp = require('mkdirp');

  function extractPath(string){

    var quotes;
    if(string.indexOf("'") > -1){
      quotes = "'";
    }else if(string.indexOf('"') > -1){
      quotes = '"';
    }
    var arr = string.split(quotes);
    return arr[1];

  }

  function removeBracketsAndQuotes(string){

    var regex = new RegExp('"', 'g');

    string = string.replace("[","");
    string = string.replace("]","");
    string = string.replace(regex,"");
    string = string.replace(/\\n/g,"");
    string = string.replace(/\\r/g,"");

    string = string.trim();

    return string;

  }

  Object.merge = function (o1, o2) { // Function to merge all of the properties from one object into another
      for(var i in o2) { o1[i] = o2[i]; }
      return o1;
  };

  grunt.registerMultiTask('requirejs_templates', 'A plugin to insert the content of template files like underscore, handlebars to variables into the javascript code', function() {

    try{

      var defaults = {
        appDir: ".",
        scripts: "scripts",
        templates: "templates"
      };

      var options = Object.merge(defaults, this.data.options);

      // Lê os arquivos
      file.walkSync(options.appDir + '/' + options.scripts, function(path, dirPath, dirs, files){

        for(var u in dirs){

          var data = fs.readFileSync(process.cwd() + '/' + path + '/' + dirs[u], 'utf8');

          if(data.indexOf('text!' + options.templates) > -1){

            var templates_signature = '';

            var defineHeader_array1 = data.split('define([');
            var defineHeader_array2 = defineHeader_array1[1].split('{');

            var defineHeader = 'define([' + defineHeader_array2[0] + '{';
            var newDefineHeader = defineHeader;

            var templatesList = eval("[" + defineHeader_array2[0].trim().split(']')[0] + "]");

            var variables = defineHeader_array2[0].split(']')[1].split('(')[1].split(')')[0];
            var requires = defineHeader_array2[0].trim().split(']')[0];

            var variablesList = variables.split(', ');
            var _variablesList = variables.split(', ');

            var templates = [];
            var require_files = [];
            var arr = requires.split(',');
            for(var i in arr){
              require_files.push(arr[i]);
              if(arr[i].indexOf('text!' + options.templates) > -1){
                templates.push(arr[i].trim());
              }
            }

            var templates_counter = 0;

            for(var w in templates){

              var templateFilePath = extractPath(templates[w]).replace('text!' + options.templates, options.appDir + '/' + options.templates);
              var templateData = fs.readFileSync(process.cwd() + '/' + templateFilePath, 'utf8');
              templateData = templateData.replace(/\n/g, '').replace(/\r/g, '').trim();

              var index;
              for(var z in templatesList){
                if(templatesList[z] === extractPath(templates[w])){
                  index = z;
                }
              }

              index = index - templates_counter;

              var templateContent = "\n    var "+variablesList[index] + " = '" + templateData + "';";
              templates_signature += templateContent;

              variablesList.splice(index, 1);
              require_files.splice(index, 1);

              templates_counter++;

            }

            newDefineHeader = newDefineHeader.replace(requires, removeBracketsAndQuotes(JSON.stringify(require_files)).replace(new RegExp(',', 'g'), ",\n"));
            newDefineHeader = newDefineHeader.replace(variables, removeBracketsAndQuotes(JSON.stringify(variablesList)));
            newDefineHeader += "\n" + templates_signature;

            if(require_files.length < 2){
              newDefineHeader = newDefineHeader.replace("define([\n    ","define([");
            }

            var newFileContent = data.replace(defineHeader, newDefineHeader);

            if(options.output){

              mkdirp.sync(process.cwd() + '/' + options.output + '/' + path);
              fs.writeFileSync(process.cwd() + '/' + options.output + '/' + path + '/' + dirs[u], newFileContent, 'utf8');

            }else{
              fs.writeFileSync(process.cwd() + '/' + path + '/' + dirs[u], newFileContent, 'utf8');
            }

          }

        }

      });

    }catch(e){
      grunt.log.writeln("Error: "+e.message);
      console.log(e.stack);
    }

  });

};
<|endoftext|>


<commit_before>frappe.provide('frappe.ui.form');

frappe.quick_edit = function(doctype, name) {
	frappe.db.get_doc(doctype, name).then(doc => {
		frappe.ui.form.make_quick_entry(doctype, null, null, doc);
	});
};

frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback, doc, force) => {
	var trimmed_doctype = doctype.replace(/ /g, '');
	var controller_name = "QuickEntryForm";

	if(frappe.ui.form[trimmed_doctype + "QuickEntryForm"]){
		controller_name = trimmed_doctype + "QuickEntryForm";
	}

	frappe.quick_entry = new frappe.ui.form[controller_name](doctype, after_insert, init_callback, doc, force);
	return frappe.quick_entry.setup();
};

frappe.ui.form.QuickEntryForm = Class.extend({
	init: function(doctype, after_insert, init_callback, doc, force) {
		this.doctype = doctype;
		this.after_insert = after_insert;
		this.init_callback = init_callback;
		this.doc = doc;
		this.force = force ? force : false;
	},

	setup: function() {
		return new Promise(resolve => {
			frappe.model.with_doctype(this.doctype, () => {
				this.check_quick_entry_doc();
				this.set_meta_and_mandatory_fields();
				if (this.is_quick_entry() || this.force) {
					this.render_dialog();
					resolve(this);
				} else {
					frappe.quick_entry = null;
					frappe.set_route('Form', this.doctype, this.doc.name)
						.then(() => resolve(this));
				}
			});
		});
	},

	set_meta_and_mandatory_fields: function(){
		this.meta = frappe.get_meta(this.doctype);
		let fields = this.meta.fields;

		// prepare a list of mandatory, bold and allow in quick entry fields
		this.mandatory = fields.filter(df => {
			return ((df.reqd || df.bold || df.allow_in_quick_entry) && !df.read_only);
		});
	},

	check_quick_entry_doc: function() {
		if (!this.doc) {
			this.doc = frappe.model.get_new_doc(this.doctype, null, null, true);
		}
	},

	is_quick_entry: function(){
		if(this.meta.quick_entry != 1) {
			return false;
		}

		this.validate_for_prompt_autoname();

		if (this.has_child_table() || !this.mandatory.length) {
			return false;
		}

		return true;
	},

	too_many_mandatory_fields: function(){
		if(this.mandatory.length > 7) {
			// too many fields, show form
			return true;
		}
		return false;
	},

	has_child_table: function(){
		if($.map(this.mandatory, function(d) {
			return d.fieldtype==='Table' ? d : null; }).length) {
			// has mandatory table, quit!
			return true;
		}
		return false;
	},

	validate_for_prompt_autoname: function(){
		if(this.meta.autoname && this.meta.autoname.toLowerCase()==='prompt') {
			this.mandatory = [{fieldname:'__newname', label:__('{0} Name', [this.meta.name]),
				reqd: 1, fieldtype:'Data'}].concat(this.mandatory);
		}
	},

	render_dialog: function(){
		var me = this;
		this.dialog = new frappe.ui.Dialog({
			title: __("New {0}", [__(this.doctype)]),
			fields: this.mandatory,
			doc: this.doc
		});

		this.register_primary_action();
		this.render_edit_in_full_page_link();
		// ctrl+enter to save
		this.dialog.wrapper.keydown(function(e) {
			if((e.ctrlKey || e.metaKey) && e.which==13) {
				if(!frappe.request.ajax_count) {
					// not already working -- double entry
					me.dialog.get_primary_btn().trigger("click");
					e.preventDefault();
					return false;
				}
			}
		});

		this.dialog.onhide = () => frappe.quick_entry = null;
		this.dialog.show();

		this.dialog.refresh_dependency();
		this.set_defaults();

		if (this.init_callback) {
			this.init_callback(this.dialog);
		}
	},

	register_primary_action: function(){
		var me = this;
		this.dialog.set_primary_action(__('Save'), function() {
			if(me.dialog.working) {
				return;
			}
			var data = me.dialog.get_values();

			if(data) {
				me.dialog.working = true;
				me.dialog.set_message(__('Saving...'));
				me.insert().then(() => {
					me.dialog.clear_message();
				});
			}
		});
	},

	insert: function() {
		let me = this;
		return new Promise(resolve => {
			me.update_doc();
			frappe.call({
				method: "frappe.client.save",
				args: {
					doc: me.dialog.doc
				},
				callback: function(r) {

					if (frappe.model.is_submittable(me.doctype)) {
						frappe.run_serially([
							() => me.dialog.working = true,
							() => {
								me.dialog.set_primary_action(__('Submit'), function() {
									me.submit(r.message);
								});
							}
						]);
					} else {
						me.dialog.hide();
						// delete the old doc
						frappe.model.clear_doc(me.dialog.doc.doctype, me.dialog.doc.name);
						me.dialog.doc = r.message;
						if(frappe._from_link) {
							frappe.ui.form.update_calling_link(me.dialog.doc);
						} else {
							if(me.after_insert) {
								me.after_insert(me.dialog.doc);
							} else {
								me.open_form_if_not_list();
							}
						}
					}
				},
				error: function() {
					if (!me.skip_redirect_on_error) {
						me.open_doc(true);
					}
				},
				always: function() {
					me.dialog.working = false;
					resolve(me.dialog.doc);
				},
				freeze: true
			});
		});
	},

	submit: function(doc) {
		var me = this;
		frappe.call({
			method: "frappe.client.submit",
			args : {
				doc: doc
			},
			callback: function(r) {
				me.dialog.hide();
				// delete the old doc
				frappe.model.clear_doc(me.dialog.doc.doctype, me.dialog.doc.name);
				me.dialog.doc = r.message;
				if (frappe._from_link) {
					frappe.ui.form.update_calling_link(me.dialog.doc);
				}
				cur_frm.reload_doc();
			}
		});
	},

	open_form_if_not_list: function() {
		let route = frappe.get_route();
		let doc = this.dialog.doc;
		if (route && !(route[0]==='List' && route[1]===doc.doctype)) {
			frappe.run_serially([
				() => frappe.set_route('Form', doc.doctype, doc.name)
			]);
		}
	},

	update_doc: function(){
		var me = this;
		var data = this.dialog.get_values(true);
		$.each(data, function(key, value) {
			if(key==='__newname') {
				me.dialog.doc.name = value;
			}
			else {
				if(!is_null(value)) {
					me.dialog.doc[key] = value;
				}
			}
		});
		return this.dialog.doc;
	},

	open_doc: function(set_hooks) {
		this.dialog.hide();
		this.update_doc();
		if (set_hooks && this.after_insert) {
			frappe.route_options = frappe.route_options || {};
			frappe.route_options.after_save = (frm) => {
				this.after_insert(frm);
			};
		}
		frappe.set_route('Form', this.doctype, this.doc.name);
	},

	render_edit_in_full_page_link: function(){
		var me = this;
		var $link = $('
' +
			'<button class="edit-full btn-default btn-sm">' + __("Edit in full page") + '</button>
').appendTo(this.dialog.body);

		$link.find('.edit-full').on('click', function() {
			// edit in form
			me.open_doc(true);
		});
	},

	set_defaults: function(){
		var me = this;
		// set defaults
		$.each(this.dialog.fields_dict, function(fieldname, field) {
			field.doctype = me.doc.doctype;
			field.docname = me.doc.name;

			if(!is_null(me.doc[fieldname])) {
				field.set_input(me.doc[fieldname]);
			}
		});
	}
});
<commit_msg>feat: trigger after insert for submittable quick entry<commit_after>frappe.provide('frappe.ui.form');

frappe.quick_edit = function(doctype, name) {
	frappe.db.get_doc(doctype, name).then(doc => {
		frappe.ui.form.make_quick_entry(doctype, null, null, doc);
	});
};

frappe.ui.form.make_quick_entry = (doctype, after_insert, init_callback, doc, force) => {
	var trimmed_doctype = doctype.replace(/ /g, '');
	var controller_name = "QuickEntryForm";

	if(frappe.ui.form[trimmed_doctype + "QuickEntryForm"]){
		controller_name = trimmed_doctype + "QuickEntryForm";
	}

	frappe.quick_entry = new frappe.ui.form[controller_name](doctype, after_insert, init_callback, doc, force);
	return frappe.quick_entry.setup();
};

frappe.ui.form.QuickEntryForm = Class.extend({
	init: function(doctype, after_insert, init_callback, doc, force) {
		this.doctype = doctype;
		this.after_insert = after_insert;
		this.init_callback = init_callback;
		this.doc = doc;
		this.force = force ? force : false;
	},

	setup: function() {
		return new Promise(resolve => {
			frappe.model.with_doctype(this.doctype, () => {
				this.check_quick_entry_doc();
				this.set_meta_and_mandatory_fields();
				if (this.is_quick_entry() || this.force) {
					this.render_dialog();
					resolve(this);
				} else {
					frappe.quick_entry = null;
					frappe.set_route('Form', this.doctype, this.doc.name)
						.then(() => resolve(this));
				}
			});
		});
	},

	set_meta_and_mandatory_fields: function(){
		this.meta = frappe.get_meta(this.doctype);
		let fields = this.meta.fields;

		// prepare a list of mandatory, bold and allow in quick entry fields
		this.mandatory = fields.filter(df => {
			return ((df.reqd || df.bold || df.allow_in_quick_entry) && !df.read_only);
		});
	},

	check_quick_entry_doc: function() {
		if (!this.doc) {
			this.doc = frappe.model.get_new_doc(this.doctype, null, null, true);
		}
	},

	is_quick_entry: function(){
		if(this.meta.quick_entry != 1) {
			return false;
		}

		this.validate_for_prompt_autoname();

		if (this.has_child_table() || !this.mandatory.length) {
			return false;
		}

		return true;
	},

	too_many_mandatory_fields: function(){
		if(this.mandatory.length > 7) {
			// too many fields, show form
			return true;
		}
		return false;
	},

	has_child_table: function(){
		if($.map(this.mandatory, function(d) {
			return d.fieldtype==='Table' ? d : null; }).length) {
			// has mandatory table, quit!
			return true;
		}
		return false;
	},

	validate_for_prompt_autoname: function(){
		if(this.meta.autoname && this.meta.autoname.toLowerCase()==='prompt') {
			this.mandatory = [{fieldname:'__newname', label:__('{0} Name', [this.meta.name]),
				reqd: 1, fieldtype:'Data'}].concat(this.mandatory);
		}
	},

	render_dialog: function(){
		var me = this;
		this.dialog = new frappe.ui.Dialog({
			title: __("New {0}", [__(this.doctype)]),
			fields: this.mandatory,
			doc: this.doc
		});

		this.register_primary_action();
		this.render_edit_in_full_page_link();
		// ctrl+enter to save
		this.dialog.wrapper.keydown(function(e) {
			if((e.ctrlKey || e.metaKey) && e.which==13) {
				if(!frappe.request.ajax_count) {
					// not already working -- double entry
					me.dialog.get_primary_btn().trigger("click");
					e.preventDefault();
					return false;
				}
			}
		});

		this.dialog.onhide = () => frappe.quick_entry = null;
		this.dialog.show();

		this.dialog.refresh_dependency();
		this.set_defaults();

		if (this.init_callback) {
			this.init_callback(this.dialog);
		}
	},

	register_primary_action: function(){
		var me = this;
		this.dialog.set_primary_action(__('Save'), function() {
			if(me.dialog.working) {
				return;
			}
			var data = me.dialog.get_values();

			if(data) {
				me.dialog.working = true;
				me.dialog.set_message(__('Saving...'));
				me.insert().then(() => {
					me.dialog.clear_message();
				});
			}
		});
	},

	insert: function() {
		let me = this;
		return new Promise(resolve => {
			me.update_doc();
			frappe.call({
				method: "frappe.client.save",
				args: {
					doc: me.dialog.doc
				},
				callback: function(r) {

					if (frappe.model.is_submittable(me.doctype)) {
						frappe.run_serially([
							() => me.dialog.working = true,
							() => {
								me.dialog.set_primary_action(__('Submit'), function() {
									me.submit(r.message);
								});
							}
						]);
					} else {
						me.dialog.hide();
						// delete the old doc
						frappe.model.clear_doc(me.dialog.doc.doctype, me.dialog.doc.name);
						me.dialog.doc = r.message;
						if(frappe._from_link) {
							frappe.ui.form.update_calling_link(me.dialog.doc);
						} else {
							if(me.after_insert) {
								me.after_insert(me.dialog.doc);
							} else {
								me.open_form_if_not_list();
							}
						}
					}
				},
				error: function() {
					if (!me.skip_redirect_on_error) {
						me.open_doc(true);
					}
				},
				always: function() {
					me.dialog.working = false;
					resolve(me.dialog.doc);
				},
				freeze: true
			});
		});
	},

	submit: function(doc) {
		var me = this;
		frappe.call({
			method: "frappe.client.submit",
			args : {
				doc: doc
			},
			callback: function(r) {
				me.dialog.hide();
				// delete the old doc
				frappe.model.clear_doc(me.dialog.doc.doctype, me.dialog.doc.name);
				me.dialog.doc = r.message;
				if (frappe._from_link) {
					frappe.ui.form.update_calling_link(me.dialog.doc);
				} else {
					if(me.after_insert) {
						me.after_insert(me.dialog.doc);
					} else {
						me.open_form_if_not_list();
					}
				}

				cur_frm && cur_frm.reload_doc();
			}
		});
	},

	open_form_if_not_list: function() {
		let route = frappe.get_route();
		let doc = this.dialog.doc;
		if (route && !(route[0]==='List' && route[1]===doc.doctype)) {
			frappe.run_serially([
				() => frappe.set_route('Form', doc.doctype, doc.name)
			]);
		}
	},

	update_doc: function(){
		var me = this;
		var data = this.dialog.get_values(true);
		$.each(data, function(key, value) {
			if(key==='__newname') {
				me.dialog.doc.name = value;
			}
			else {
				if(!is_null(value)) {
					me.dialog.doc[key] = value;
				}
			}
		});
		return this.dialog.doc;
	},

	open_doc: function(set_hooks) {
		this.dialog.hide();
		this.update_doc();
		if (set_hooks && this.after_insert) {
			frappe.route_options = frappe.route_options || {};
			frappe.route_options.after_save = (frm) => {
				this.after_insert(frm);
			};
		}
		frappe.set_route('Form', this.doctype, this.doc.name);
	},

	render_edit_in_full_page_link: function(){
		var me = this;
		var $link = $('
' +
			'<button class="edit-full btn-default btn-sm">' + __("Edit in full page") + '</button>
').appendTo(this.dialog.body);

		$link.find('.edit-full').on('click', function() {
			// edit in form
			me.open_doc(true);
		});
	},

	set_defaults: function(){
		var me = this;
		// set defaults
		$.each(this.dialog.fields_dict, function(fieldname, field) {
			field.doctype = me.doc.doctype;
			field.docname = me.doc.name;

			if(!is_null(me.doc[fieldname])) {
				field.set_input(me.doc[fieldname]);
			}
		});
	}
});
<|endoftext|>