<commit_before>"use strict";

var fs          = require('fs'),
    xml2js      = require('xml2js'),
    _           = require('underscore'),
    builder     = require('xmlbuilder'),
    async       = require('async'),
    SvgParser   = require(__dirname + '/parser'),
    Matrix      = require(__dirname + '/matrix/extends'),
    gm          = require('gm').subClass({ imageMagick: true }),
    utils       = require(__dirname + '/matrix/utils');

var Svg = function Svg() {
    if (!(this instanceof Svg))
        throw 'this function in a constructor. Use new to call it';

    this.elements = [];
    this.size     = { width: 100, height : 100 };
};

/**
 * Set Svg Elements
 * @param {Array}       elements            SvgObject Array (rect|polygon|polyline|...)
 */
Svg.prototype.setElements = function setElements(elements) {
    this.elements = elements;
};

/**
 * Add SvgObject element to current SVG
 * @param {SvgObject}   element             SvgObject Element
 */
Svg.prototype.addElement = function toJSON(element) {
    this.elements.push(element);
};

/**
 * Convert Svg to Json format
 * @param {boolean}     matrix              String representation without transform attribute
 * @returns {object}                        Svg Json Object representation
 */
Svg.prototype.toJSON = function toXml(matrix) {
    if(typeof matrix == 'undefined') matrix = false;

    var json = {
        elements : []
    };

    _.each(this.elements, function (element) {
        json.elements.push(element.toJSON(matrix));
    });

    return json;
};

/**
 * Convert Svg to Xml format
 * @param {boolean}     matrix              String representation without transform attribute
 * @returns {object}                        XMLBuilder Svg representation
 */
Svg.prototype.toXml = function toXml(matrix) {
    if(typeof matrix == 'undefined') matrix = false;

    var xml = builder.create('svg');
    xml.att('version', '1.1');
    xml.att('xmlns', 'http://www.w3.org/2000/svg');
    xml.att('width', this.size.width+'px');
    xml.att('height', this.size.height+'px');

    _.each(this.elements, function (element) {
        xml.importXMLBuilder(element.toXml(matrix));
    });

    return xml;
};

/**
 * Convert SVG to String :
 *     '<svg>...</svg>'
 * @param {boolean}     content             false : return only svg content, true : return all svg in <svg> tag
 * @param {boolean}     [matrix]            String representation without transform attribute
 * @returns {string}                        Svg String representation
 */
Svg.prototype.toString = function toString(content, matrix) {
    if(typeof matrix == 'undefined') matrix = false;

    if (content == true) {
        return this.toXml(matrix).toString();
    } else {
        var string = '';
        _.each(this.elements, function(element){
            string += element.toXml(matrix).toString();
        });
        return string;
    }
};

/**
 * Find elements in SVG and return new Svg object with all elements by selected type
 *
 * @param   {string}    type                Selected type (rect|polygon|g|...)
 * @param   {boolean}   all                 true : find all type in groups and root, false : find only in root
 * @returns {Svg}                           new Svg object with selected types elements
 */
Svg.prototype.findByType = function findByType(type, all) {
    var svg = new Svg();

    _.each(this.elements, function (elem) {
        if (elem.type == type) {
            svg.addElement(elem);
        }

        if (all && elem.type == 'g') {
            var group = elem.findByType(type, all);
            _.each(group.childs, function (child) {
                svg.addElement(child);
            });
        }
    });

    return svg;
};

/**
 * Find one element by id in SVG
 *
 * @param   {string}    id                  Item id
 * @returns {SvgObject}                     SvgObject element
 */
Svg.prototype.findById = function (id) {
    var returnElem = null;

    _.each(this.elements, function (elem) {
        if (elem.id == id) {
            returnElem = elem;
        }else if (elem.type == 'g') {
            returnElem = elem.findById(id);
        }
    });

    return returnElem;
};

/**
 * Find one element by id and type in SVG
 *
 * @param   {string}    id                  Item id
 * @param   {string}    type                Item type (rect, path, ...)
 * @returns {SvgObject}                     SvgObject element
 */
Svg.prototype.findByIdAndType = function findByIdAndType(id, type) {
    var returnElem = null;

    _.each(this.elements, function (elem) {
        if (elem.id == id && elem.type == type) {
            returnElem = elem;
        }else if (elem.type == 'g') {
            returnElem = elem.findByIdAndType(id, type);
        }
    });

    return returnElem;
};

/**
 * Find one element by id without param type in SVG
 *
 * @param   {string}    id                  Item id
 * @param   {string}    type                Item type (rect, path, ...)
 * @returns {SvgObject}                     SvgObject element
 */
Svg.prototype.findByIdWithoutType = function findByIdWithoutType(id, type) {
    var returnElem = null;

    _.each(this.elements, function (elem) {
        if (elem.id === id && elem.type !== type) {
            returnElem = elem;
        }else if (elem.type === 'g') {
            returnElem = elem.findByIdWithoutType(id, type);
        }
    });

    return returnElem;
};

/**
 * Remove All elements by type. If type is 'g', all childs elements are moved on svg root node.
 * @param {string}      type                Type to remove
 */
Svg.prototype.removeAllByType = function removeAllByType(type) {
    var elements = [];
    _.each(this.elements, function (elem) {
        if (elem.type === 'g') {
            var elms = elem.removeAllByType(type);
            if (type === 'g') {
                elements = _.union(elements, elms);
            }
        }
        if (elem.type !== type) {
            elements.push(elem);
        }
    });

    this.elements = elements;
};

/**
 * Generate new Svg element with all applied matrix to all elements.
 * Convert rect into polygon
 * @param {array|Matrix}        matrix              Matrix to be applied in addition to those elements.
 * @param {function}            callback            Callback Function
 */
Svg.prototype.applyMatrix = function applyMatrix(matrix, callback) {
    var svg = new Svg();

    var applyMatrix = new Matrix();
    if (matrix != null) {
        if(matrix instanceof Array){
            _.each(matrix, function(mat){
                applyMatrix.add(mat);
            });
        }else{
            applyMatrix = matrix;
        }
    }

    async.each(this.elements, function (elem, c) {
        elem.getBBox( function (bbox) {
            var applyCloneMatrix = applyMatrix.clone();
            var matrix = applyCloneMatrix.add(Matrix.fromElement(bbox, elem));
            elem.applyMatrix(matrix, function(e){
                svg.addElement(e);
                c();
            });
        });
    }, function () {
        callback(svg);
    });
};

/**
 * Save Svg file
 * @param {object}      params              Functon Params
 * @param {string}      [params.output]     Output file
 * @param {function}    callback            Callback Function
 */
Svg.prototype.save = function save(params, callback) {
    var defOpts = {
        output : '/tmp/export_' + new Date().getTime() + '.svg'
    };

    params = _.extend({}, defOpts, params);

    fs.writeFile(params.output, this.toString(true), function (err) {
        if (err) {
            callback(err);
            return;
        }
        callback(null, params.output);
    });
};

/**
 * Save Svg file in Png Format
 * @param {object}      params              Functon Params
 * @param {string}      [params.output]     Output file
 * @param {function}    callback            Callback Function
 */
Svg.prototype.savePng = function savePng(params, callback) {
    var defOpts = {
        output : '/tmp/export_' + new Date().getTime() + '.png'
    };

    params = _.extend({}, defOpts, params);

    this.save({}, function (err, file) {
        if (err) {
            callback(err);
            return;
        }

        gm(file).write(params.output, function (err) {
            if (err) {
                callback(err);
                return;
            }

            callback(null, params.output);
        });
    });
};

/**
 * Refresh SVG size
 * @param {function}    callback        Callback Function
 */
Svg.prototype.getSize = function getSize(callback) {
    var minX = +Infinity,
        maxX = -Infinity,
        minY = +Infinity,
        maxY = -Infinity,
        self = this;

    async.each(this.elements, function (child, done) {
        child.getBBox(function (bbox) {
            minX = Math.min(minX, bbox.x);
            minY = Math.min(minY, bbox.y);
            maxX = Math.max(maxX, bbox.x2);
            maxY = Math.max(maxY, bbox.y2);
            done();
        });
    }, function () {
        var bbox  = utils.bbox(minX,minY,maxX,maxY);
        self.size = { width : bbox.w, height : bbox.h  };

        callback(self.size);
    });
};

/**
 * Get SVG bbox
 * @param {function}    callback        Callback Function
 */
Svg.prototype.getBBox = function getBBox(callback) {
    var minX = +Infinity,
        maxX = -Infinity,
        minY = +Infinity,
        maxY = -Infinity;

    async.each(this.elements, function (child, done) {
        child.getBBox(function (bbox) {
            minX = Math.min(minX, bbox.x);
            minY = Math.min(minY, bbox.y);
            maxX = Math.max(maxX, bbox.x2);
            maxY = Math.max(maxY, bbox.y2);
            done();
        });
    }, function () {
        callback(utils.bbox(minX,minY,maxX,maxY));
    });
};

/**
 * Calculate all innerboxes in SVG. Return copy of current svg with elements with data attribute innerbox.
 * @param {function}    callback                    Callback Function
 */
Svg.prototype.calculateAllInnerBoxes = function calculateAllInnerBoxes(callback) {
    var svg = new Svg();
    async.each(this.elements, function (child, done) {
        switch (child.type) {
            case 'rect' :
            case 'polygon' :
            case 'polyline' :
            case 'circle' :
                child.getInnerBox(function (innerBox) {
                    child.data.innerbox = innerBox;
                    svg.addElement(child);
                    done();
                });
                break;
            case 'g' :
                child.calculateAllInnerBoxes( function (group) {
                    svg.addElement(child);
                    done();
                });
                break;
            default :
                svg.addElement(child);
                done();
        }
    }, function () {
        svg.getSize(function () {
            callback(svg);
        });
    });
};

/**
 * Remove specifics types of objetcs in svg
 * @param {object}          params              Function params
 * @param {string|Array}    params.type         target type(s) (g, rect, ...)
 */
Svg.prototype.removeByType = function removeByType(params) {
    this.elements = _.filter(this.elements, function (element) {
        if (!_.isArray(params.type)) {
            var t = params.type;
            params.type = [];
            params.type.push(t);
        }

        if (element.type === 'g') {
            // remove elements for group
            element.removeByType(params);
            // if remove group type, add all elements in svg
            if (_.contains(params.type, 'g')) {
                _.union(this.elements, element.childs);
            }
        }

        return !_.contains(params.type, element.type);
    }, this);
};

/**
 * Convert Svg elements into Path.
 * Works only on rect, polygon and polyline
 */
Svg.prototype.convertElementsToPath = function convertElementsToPath() {
    var elements = [];

    _.each(this.elements, function (element) {
        switch(element.type) {
            case 'rect' :
            case 'polygon' :
            case 'polyline' :
                elements.push(element.toPath());
                break;
            case 'g' :
                elements.push(element.convertElementsToPath());
                break;
            default :
                elements.push(element);
        }
    }, this);

    this.elements = elements;
};

module.exports = Svg;

/**
 * Create Svg from Svg Document
 * @param {string}      path                Uri of source file
 * @param {function}    callback            Callback Function
 */
module.exports.fromSvgDocument = function fromSvgDocument(path, callback) {
    fs.readFile(path, function (error, data) {
        if (error) {
            callback(error);
            return;
        }
        Svg.fromXmlString(data.toString(), callback);
    });
};

/**
 * Create Svg from Xml String representation
 * @param {string}      string              Svg string representation
 * @param {function}    callback            Callback Function
 */
module.exports.fromXmlString = function fromXmlString(string, callback) {
    var parser  = new xml2js.Parser();

    parser.addListener('end', function (result) {
        SvgParser.convertXml(result, function (err, elements) {
            if (err) {
                callback(err);
                return;
            }

            var svg = new Svg();
            svg.setElements(elements);
            svg.getSize(function () {
                callback(null, svg);
            });
        });
    });

    parser.parseString(string);
};

module.exports.fromJsonFile = function fromJsonFile(path, callback) {
    fs.readFile(path, function (error, data) {
        if (error) {
            callback(error);
            return;
        }
        Svg.fromJsonString(data.toString(), callback);
    });
};

module.exports.fromJsonString = function fromJsonString(string, callback) {
    var json = JSON.parse(string);

    Svg.fromJson(json, callback);
};

module.exports.fromJson = function fromJson(json, callback) {
    SvgParser.convertJson(json, function (err, elements) {
        if (err) {
            callback(err);
            return;
        }

        var svg = new Svg();
        svg.setElements(elements);

        svg.getSize(function () {
            callback(null, svg);
        });
    });
};

/**
 * Create SVG from dxf file
 * @param {object}      params              Function params
 * @param {string}      params.path         DXF File path
 * @param {Array}       params.layers       Import element for passed layers names
 * @param {function}    callback            Callback Function
 */
module.exports.fromDxfFile = function fromDxfFile(params, callback) {
    SvgParser.convertDxf(params, function (err, result) {
        if (err) {
            callback (err);
            return;
        }

        var svg = new Svg();
        _.each(result.polygons, function (polygon) {
            // test if params.layers is set and if polygon is in specified layers
            if (!params.layers || params.layers.length == 0 || _.contains(params.layers, polygon.layer)) {
                svg.addElement(SvgParser.parseJsonPolygon({
                    points : polygon.points,
                    fill : 'white',
                    stroke : 'black'
                }));
            }
        }, this);
        _.each(result.circles, function (circle) {
            if (!params.layers || params.layers.length == 0 || _.contains(params.layers, circle.layer)) {
                svg.addElement(SvgParser.parseJsonPolygon({
                    points : circle.points,
                    fill : 'white',
                    stroke : 'black'
                }));
            }
        });
        _.each(result.texts, function (text) {
            if (!params.layers || params.layers.length == 0 || _.contains(params.layers, text.layer)) {
                svg.addElement(SvgParser.parseJsonText({
                    fill : 'black',
                    value : text.contents,
                    x : text.point.x,
                    y : text.point.y
                }));
            }
        });
        svg.getBBox(function (bbox) {
            var matrix = new Matrix(1, 0, 0, -1, Math.abs(Math.min(bbox.x, bbox.x2))+10, Math.abs(Math.min(bbox.y, bbox.y2))+10);
            svg.applyMatrix(matrix, function (svg) {
                svg.getSize(function () {
                    callback(null, svg);
                });
            });
        });
    });
};<commit_msg>add function styleSheet to svg to add possibles external stylesheets for SVG<commit_after>"use strict";

var fs          = require('fs'),
    xml2js      = require('xml2js'),
    _           = require('underscore'),
    builder     = require('xmlbuilder'),
    async       = require('async'),
    SvgParser   = require(__dirname + '/parser'),
    Matrix      = require(__dirname + '/matrix/extends'),
    gm          = require('gm').subClass({ imageMagick: true }),
    utils       = require(__dirname + '/matrix/utils');

var Svg = function Svg() {
    if (!(this instanceof Svg))
        throw 'this function in a constructor. Use new to call it';

    this.elements       = [];
    this.size           = { width: 100, height : 100 };
    this.stylesheets    = [];
};

/**
 * Set Svg Elements
 * @param {Array}       elements            SvgObject Array (rect|polygon|polyline|...)
 */
Svg.prototype.setElements = function setElements(elements) {
    this.elements = elements;
};

/**
 * Add SvgObject element to current SVG
 * @param {SvgObject}   element             SvgObject Element
 */
Svg.prototype.addElement = function toJSON(element) {
    this.elements.push(element);
};

/**
 * Add Specific stylesheet in SVG
 * @param {string}      cssFilePath         Css File Path to add
 */
Svg.prototype.addStyleSheet = function addStyleSheet(cssFilePath) {
    this.stylesheets.push(cssFilePath);
};

/**
 * Convert Svg to Json format
 * @param {boolean}     matrix              String representation without transform attribute
 * @returns {object}                        Svg Json Object representation
 */
Svg.prototype.toJSON = function toXml(matrix) {
    if(typeof matrix == 'undefined') matrix = false;

    var json = {
        elements    : [],
        stylesheets : this.stylesheets
    };

    _.each(this.elements, function (element) {
        json.elements.push(element.toJSON(matrix));
    });

    return json;
};

/**
 * Convert Svg to Xml format
 * @param {boolean}     matrix              String representation without transform attribute
 * @returns {object}                        XMLBuilder Svg representation
 */
Svg.prototype.toXml = function toXml(matrix) {
    if(typeof matrix == 'undefined') matrix = false;

    var xml = builder.create('svg');
    xml.att('version', '1.1');
    xml.att('xmlns', 'http://www.w3.org/2000/svg');
    xml.att('width', this.size.width+'px');
    xml.att('height', this.size.height+'px');

    _.each(this.stylesheets, function (styleSheet) {
        xml.ins('xml-stylesheet', 'type="text/xsl" href="'+ styleSheet +'"');
    });

    _.each(this.elements, function (element) {
        xml.importXMLBuilder(element.toXml(matrix));
    });

    return xml;
};

/**
 * Convert SVG to String :
 *     '<svg>...</svg>'
 * @param {boolean}     content             false : return only svg content, true : return all svg in <svg> tag
 * @param {boolean}     [matrix]            String representation without transform attribute
 * @returns {string}                        Svg String representation
 */
Svg.prototype.toString = function toString(content, matrix) {
    if(typeof matrix == 'undefined') matrix = false;

    if (content == true) {
        return this.toXml(matrix).toString();
    } else {
        var string = '';
        _.each(this.elements, function(element){
            string += element.toXml(matrix).toString();
        });
        return string;
    }
};

/**
 * Find elements in SVG and return new Svg object with all elements by selected type
 *
 * @param   {string}    type                Selected type (rect|polygon|g|...)
 * @param   {boolean}   all                 true : find all type in groups and root, false : find only in root
 * @returns {Svg}                           new Svg object with selected types elements
 */
Svg.prototype.findByType = function findByType(type, all) {
    var svg = new Svg();

    _.each(this.elements, function (elem) {
        if (elem.type == type) {
            svg.addElement(elem);
        }

        if (all && elem.type == 'g') {
            var group = elem.findByType(type, all);
            _.each(group.childs, function (child) {
                svg.addElement(child);
            });
        }
    });

    return svg;
};

/**
 * Find one element by id in SVG
 *
 * @param   {string}    id                  Item id
 * @returns {SvgObject}                     SvgObject element
 */
Svg.prototype.findById = function (id) {
    var returnElem = null;

    _.each(this.elements, function (elem) {
        if (elem.id == id) {
            returnElem = elem;
        }else if (elem.type == 'g') {
            returnElem = elem.findById(id);
        }
    });

    return returnElem;
};

/**
 * Find one element by id and type in SVG
 *
 * @param   {string}    id                  Item id
 * @param   {string}    type                Item type (rect, path, ...)
 * @returns {SvgObject}                     SvgObject element
 */
Svg.prototype.findByIdAndType = function findByIdAndType(id, type) {
    var returnElem = null;

    _.each(this.elements, function (elem) {
        if (elem.id == id && elem.type == type) {
            returnElem = elem;
        }else if (elem.type == 'g') {
            returnElem = elem.findByIdAndType(id, type);
        }
    });

    return returnElem;
};

/**
 * Find one element by id without param type in SVG
 *
 * @param   {string}    id                  Item id
 * @param   {string}    type                Item type (rect, path, ...)
 * @returns {SvgObject}                     SvgObject element
 */
Svg.prototype.findByIdWithoutType = function findByIdWithoutType(id, type) {
    var returnElem = null;

    _.each(this.elements, function (elem) {
        if (elem.id === id && elem.type !== type) {
            returnElem = elem;
        }else if (elem.type === 'g') {
            returnElem = elem.findByIdWithoutType(id, type);
        }
    });

    return returnElem;
};

/**
 * Remove All elements by type. If type is 'g', all childs elements are moved on svg root node.
 * @param {string}      type                Type to remove
 */
Svg.prototype.removeAllByType = function removeAllByType(type) {
    var elements = [];
    _.each(this.elements, function (elem) {
        if (elem.type === 'g') {
            var elms = elem.removeAllByType(type);
            if (type === 'g') {
                elements = _.union(elements, elms);
            }
        }
        if (elem.type !== type) {
            elements.push(elem);
        }
    });

    this.elements = elements;
};

/**
 * Generate new Svg element with all applied matrix to all elements.
 * Convert rect into polygon
 * @param {array|Matrix}        matrix              Matrix to be applied in addition to those elements.
 * @param {function}            callback            Callback Function
 */
Svg.prototype.applyMatrix = function applyMatrix(matrix, callback) {
    var svg = new Svg();

    var applyMatrix = new Matrix();
    if (matrix != null) {
        if(matrix instanceof Array){
            _.each(matrix, function(mat){
                applyMatrix.add(mat);
            });
        }else{
            applyMatrix = matrix;
        }
    }

    async.each(this.elements, function (elem, c) {
        elem.getBBox( function (bbox) {
            var applyCloneMatrix = applyMatrix.clone();
            var matrix = applyCloneMatrix.add(Matrix.fromElement(bbox, elem));
            elem.applyMatrix(matrix, function(e){
                svg.addElement(e);
                c();
            });
        });
    }, function () {
        callback(svg);
    });
};

/**
 * Save Svg file
 * @param {object}      params              Functon Params
 * @param {string}      [params.output]     Output file
 * @param {function}    callback            Callback Function
 */
Svg.prototype.save = function save(params, callback) {
    var defOpts = {
        output : '/tmp/export_' + new Date().getTime() + '.svg'
    };

    params = _.extend({}, defOpts, params);

    fs.writeFile(params.output, this.toString(true), function (err) {
        if (err) {
            callback(err);
            return;
        }
        callback(null, params.output);
    });
};

/**
 * Save Svg file in Png Format
 * @param {object}      params              Functon Params
 * @param {string}      [params.output]     Output file
 * @param {function}    callback            Callback Function
 */
Svg.prototype.savePng = function savePng(params, callback) {
    var defOpts = {
        output : '/tmp/export_' + new Date().getTime() + '.png'
    };

    params = _.extend({}, defOpts, params);

    this.save({}, function (err, file) {
        if (err) {
            callback(err);
            return;
        }

        gm(file).write(params.output, function (err) {
            if (err) {
                callback(err);
                return;
            }

            callback(null, params.output);
        });
    });
};

/**
 * Refresh SVG size
 * @param {function}    callback        Callback Function
 */
Svg.prototype.getSize = function getSize(callback) {
    var minX = +Infinity,
        maxX = -Infinity,
        minY = +Infinity,
        maxY = -Infinity,
        self = this;

    async.each(this.elements, function (child, done) {
        child.getBBox(function (bbox) {
            minX = Math.min(minX, bbox.x);
            minY = Math.min(minY, bbox.y);
            maxX = Math.max(maxX, bbox.x2);
            maxY = Math.max(maxY, bbox.y2);
            done();
        });
    }, function () {
        var bbox  = utils.bbox(minX,minY,maxX,maxY);
        self.size = { width : bbox.w, height : bbox.h  };

        callback(self.size);
    });
};

/**
 * Get SVG bbox
 * @param {function}    callback        Callback Function
 */
Svg.prototype.getBBox = function getBBox(callback) {
    var minX = +Infinity,
        maxX = -Infinity,
        minY = +Infinity,
        maxY = -Infinity;

    async.each(this.elements, function (child, done) {
        child.getBBox(function (bbox) {
            minX = Math.min(minX, bbox.x);
            minY = Math.min(minY, bbox.y);
            maxX = Math.max(maxX, bbox.x2);
            maxY = Math.max(maxY, bbox.y2);
            done();
        });
    }, function () {
        callback(utils.bbox(minX,minY,maxX,maxY));
    });
};

/**
 * Calculate all innerboxes in SVG. Return copy of current svg with elements with data attribute innerbox.
 * @param {function}    callback                    Callback Function
 */
Svg.prototype.calculateAllInnerBoxes = function calculateAllInnerBoxes(callback) {
    var svg = new Svg();
    async.each(this.elements, function (child, done) {
        switch (child.type) {
            case 'rect' :
            case 'polygon' :
            case 'polyline' :
            case 'circle' :
                child.getInnerBox(function (innerBox) {
                    child.data.innerbox = innerBox;
                    svg.addElement(child);
                    done();
                });
                break;
            case 'g' :
                child.calculateAllInnerBoxes( function (group) {
                    svg.addElement(child);
                    done();
                });
                break;
            default :
                svg.addElement(child);
                done();
        }
    }, function () {
        svg.getSize(function () {
            callback(svg);
        });
    });
};

/**
 * Remove specifics types of objetcs in svg
 * @param {object}          params              Function params
 * @param {string|Array}    params.type         target type(s) (g, rect, ...)
 */
Svg.prototype.removeByType = function removeByType(params) {
    this.elements = _.filter(this.elements, function (element) {
        if (!_.isArray(params.type)) {
            var t = params.type;
            params.type = [];
            params.type.push(t);
        }

        if (element.type === 'g') {
            // remove elements for group
            element.removeByType(params);
            // if remove group type, add all elements in svg
            if (_.contains(params.type, 'g')) {
                _.union(this.elements, element.childs);
            }
        }

        return !_.contains(params.type, element.type);
    }, this);
};

/**
 * Convert Svg elements into Path.
 * Works only on rect, polygon and polyline
 */
Svg.prototype.convertElementsToPath = function convertElementsToPath() {
    var elements = [];

    _.each(this.elements, function (element) {
        switch(element.type) {
            case 'rect' :
            case 'polygon' :
            case 'polyline' :
                elements.push(element.toPath());
                break;
            case 'g' :
                elements.push(element.convertElementsToPath());
                break;
            default :
                elements.push(element);
        }
    }, this);

    this.elements = elements;
};

module.exports = Svg;

/**
 * Create Svg from Svg Document
 * @param {string}      path                Uri of source file
 * @param {function}    callback            Callback Function
 */
module.exports.fromSvgDocument = function fromSvgDocument(path, callback) {
    fs.readFile(path, function (error, data) {
        if (error) {
            callback(error);
            return;
        }
        Svg.fromXmlString(data.toString(), callback);
    });
};

/**
 * Create Svg from Xml String representation
 * @param {string}      string              Svg string representation
 * @param {function}    callback            Callback Function
 */
module.exports.fromXmlString = function fromXmlString(string, callback) {
    var parser  = new xml2js.Parser();

    parser.addListener('end', function (result) {
        SvgParser.convertXml(result, function (err, elements) {
            if (err) {
                callback(err);
                return;
            }

            var svg = new Svg();
            svg.setElements(elements);
            svg.getSize(function () {
                callback(null, svg);
            });
        });
    });

    parser.parseString(string);
};

module.exports.fromJsonFile = function fromJsonFile(path, callback) {
    fs.readFile(path, function (error, data) {
        if (error) {
            callback(error);
            return;
        }
        Svg.fromJsonString(data.toString(), callback);
    });
};

module.exports.fromJsonString = function fromJsonString(string, callback) {
    var json = JSON.parse(string);

    Svg.fromJson(json, callback);
};

module.exports.fromJson = function fromJson(json, callback) {
    SvgParser.convertJson(json, function (err, elements) {
        if (err) {
            callback(err);
            return;
        }

        var svg = new Svg();
        svg.setElements(elements);

        svg.getSize(function () {
            callback(null, svg);
        });
    });
};

/**
 * Create SVG from dxf file
 * @param {object}      params              Function params
 * @param {string}      params.path         DXF File path
 * @param {Array}       params.layers       Import element for passed layers names
 * @param {function}    callback            Callback Function
 */
module.exports.fromDxfFile = function fromDxfFile(params, callback) {
    SvgParser.convertDxf(params, function (err, result) {
        if (err) {
            callback (err);
            return;
        }

        var svg = new Svg();
        _.each(result.polygons, function (polygon) {
            // test if params.layers is set and if polygon is in specified layers
            if (!params.layers || params.layers.length == 0 || _.contains(params.layers, polygon.layer)) {
                svg.addElement(SvgParser.parseJsonPolygon({
                    points : polygon.points,
                    fill : 'white',
                    stroke : 'black'
                }));
            }
        }, this);
        _.each(result.circles, function (circle) {
            if (!params.layers || params.layers.length == 0 || _.contains(params.layers, circle.layer)) {
                svg.addElement(SvgParser.parseJsonPolygon({
                    points : circle.points,
                    fill : 'white',
                    stroke : 'black'
                }));
            }
        });
        _.each(result.texts, function (text) {
            if (!params.layers || params.layers.length == 0 || _.contains(params.layers, text.layer)) {
                svg.addElement(SvgParser.parseJsonText({
                    fill : 'black',
                    value : text.contents,
                    x : text.point.x,
                    y : text.point.y
                }));
            }
        });
        svg.getBBox(function (bbox) {
            var matrix = new Matrix(1, 0, 0, -1, Math.abs(Math.min(bbox.x, bbox.x2))+10, Math.abs(Math.min(bbox.y, bbox.y2))+10);
            svg.applyMatrix(matrix, function (svg) {
                svg.getSize(function () {
                    callback(null, svg);
                });
            });
        });
    });
};<|endoftext|>


<commit_before>/**
 * @license
 * Copyright 2019 Google LLC.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
import './file-pane.js';
import './output-pane.js';
import '../configuration/whitelisted.js';
import {DevShellLoader} from './loader.js';

import {Runtime} from '../../build/runtime/runtime.js';
import {Arc} from '../../build/runtime/arc.js';
import {IdGenerator} from '../../build/runtime/id.js';
import {Modality} from '../../build/runtime/modality.js';
import {ModalityHandler} from '../../build/runtime/modality-handler.js';
import {PecIndustry} from '../../build/platform/pec-industry-web.js';
import {RecipeResolver} from '../../build/runtime/recipe/recipe-resolver.js';
import {SlotComposer} from '../../build/runtime/slot-composer.js';
import {SlotDomConsumer} from '../../build/runtime/slot-dom-consumer.js';
import {StorageProviderFactory} from '../../build/runtime/storage/storage-provider-factory.js';
import {devtoolsArcInspectorFactory} from '../../build/devtools-connector/devtools-arc-inspector.js';

import '../../build/services/ml5-service.js';
import '../../build/services/random-service.js';

const files = document.getElementById('file-pane');
const output = document.getElementById('output-pane');
const popup = document.getElementById('popup');
init();

function init() {
  files.init(execute, document.getElementById('toggle-files'), document.getElementById('export-files'));
  document.getElementById('execute').addEventListener('click', execute);
  document.getElementById('help').addEventListener('click', showHelp);
  popup.addEventListener('click', () => popup.style.display = 'none');

  const params = new URLSearchParams(window.location.search);
  const manifestParam = params.get('m') || params.get('manifest');
  if (manifestParam) {
    files.seedManifest(manifestParam.split(';').map(m => `import '${m}'`));
    execute();
  } else {
    const exampleManifest = `\
import 'https://$particles/Tutorial/1_HelloWorld/HelloWorld.recipe'

schema Data
  Number num
  Text txt

resource DataResource
  start
  [{"num": 73, "txt": "xyz"}]

store DataStore of Data in DataResource

particle P in 'a.js'
  consume root
  in Data data

recipe
  map DataStore as h0
  P
    data <- h0`;

    const exampleParticle = `\
defineParticle(({DomParticle, html}) => {
  return class extends DomParticle {
    get template() {
      return html\`<span>{{num}}</span> : <span>{{str}}</span>\`;
    }
    render({data}) {
      return data ? {num: data.num, str: data.txt} : {};
    }
  };
});`;

    files.seedExample(exampleManifest, exampleParticle);
  }
}

function execute() {
  wrappedExecute().catch(e => output.showError('Unhandled exception', e.stack));
}

async function wrappedExecute() {
  SlotDomConsumer.clearCache();  // prevent caching of template strings
  document.dispatchEvent(new Event('clear-arcs-explorer'));
  output.reset();

  const loader = new DevShellLoader(files.getFileMap());
  const pecFactory = PecIndustry(loader);

  let manifest;
  try {
    const options = {loader, fileName: './manifest', throwImportErrors: true};
    manifest = await Runtime.parseManifest(files.getManifest(), options);
  } catch (e) {
    output.showError('Error in Manifest.parse', e);
    return;
  }

  if (manifest.allRecipes.length == 0) {
    output.showError('No recipes found in Manifest.parse');
  }

  let arcIndex = 1;
  for (const recipe of manifest.allRecipes) {
    const id = IdGenerator.newSession().newArcId('arc' + arcIndex++);
    const arcPanel = output.addArcPanel(id);

    const errors = new Map();
    if (!recipe.normalize({errors})) {
      arcPanel.showError('Error in recipe.normalize', [...errors.values()].join('\n'));
      continue;
    }

    const slotComposer = new SlotComposer({
      modalityName: Modality.Name.Dom,
      modalityHandler: ModalityHandler.domHandler,
      containers: {
        toproot: arcPanel.arcToproot,
        root: arcPanel.arcRoot,
        modal: arcPanel.arcModal,
      }
    });
    const storage = new StorageProviderFactory(id);
    const arc = new Arc({
      id,
      context: manifest,
      pecFactories: [pecFactory],
      slotComposer,
      loader,
      storageProviderFactory: storage,
      inspectorFactory: devtoolsArcInspectorFactory
    });
    arcPanel.attachArc(arc);

    recipe.normalize();

    let resolvedRecipe = null;
    if (recipe.isResolved()) {
      resolvedRecipe = recipe;
    } else {
      const resolver = new RecipeResolver(arc);
      const options = {errors: new Map()};
      resolvedRecipe = await resolver.resolve(recipe, options);
      if (!resolvedRecipe) {
        arcPanel.showError('Error in RecipeResolver', `${
          [...options.errors.entries()].join('\n')
        }.\n${recipe.toString()}`);
        continue;
      }
    }

    try {
      await arc.instantiate(resolvedRecipe);
    } catch (e) {
      arcPanel.showError('Error in arc.instantiate', e);
      continue;
    }
    const description = await Runtime.getArcDescription(arc);
    await arcPanel.arcInstantiated(description);
  }
}

function showHelp() {
  popup.style.display = 'block';
  document.addEventListener('keydown', hideHelp);
}

function hideHelp(e) {
  popup.style.display = 'none';
  e.preventDefault();
  document.removeEventListener('keydown', hideHelp);
}
<commit_msg>Fix filename in DevShell seed example (#3425)<commit_after>/**
 * @license
 * Copyright 2019 Google LLC.
 * This code may only be used under the BSD style license found at
 * http://polymer.github.io/LICENSE.txt
 * Code distributed by Google as part of this project is also
 * subject to an additional IP rights grant found at
 * http://polymer.github.io/PATENTS.txt
 */
import './file-pane.js';
import './output-pane.js';
import '../configuration/whitelisted.js';
import {DevShellLoader} from './loader.js';

import {Runtime} from '../../build/runtime/runtime.js';
import {Arc} from '../../build/runtime/arc.js';
import {IdGenerator} from '../../build/runtime/id.js';
import {Modality} from '../../build/runtime/modality.js';
import {ModalityHandler} from '../../build/runtime/modality-handler.js';
import {PecIndustry} from '../../build/platform/pec-industry-web.js';
import {RecipeResolver} from '../../build/runtime/recipe/recipe-resolver.js';
import {SlotComposer} from '../../build/runtime/slot-composer.js';
import {SlotDomConsumer} from '../../build/runtime/slot-dom-consumer.js';
import {StorageProviderFactory} from '../../build/runtime/storage/storage-provider-factory.js';
import {devtoolsArcInspectorFactory} from '../../build/devtools-connector/devtools-arc-inspector.js';

import '../../build/services/ml5-service.js';
import '../../build/services/random-service.js';

const files = document.getElementById('file-pane');
const output = document.getElementById('output-pane');
const popup = document.getElementById('popup');
init();

function init() {
  files.init(execute, document.getElementById('toggle-files'), document.getElementById('export-files'));
  document.getElementById('execute').addEventListener('click', execute);
  document.getElementById('help').addEventListener('click', showHelp);
  popup.addEventListener('click', () => popup.style.display = 'none');

  const params = new URLSearchParams(window.location.search);
  const manifestParam = params.get('m') || params.get('manifest');
  if (manifestParam) {
    files.seedManifest(manifestParam.split(';').map(m => `import '${m}'`));
    execute();
  } else {
    const exampleManifest = `\
import 'https://$particles/Tutorial/1_HelloWorld/HelloWorld.arcs'

schema Data
  Number num
  Text txt

resource DataResource
  start
  [{"num": 73, "txt": "xyz"}]

store DataStore of Data in DataResource

particle P in 'a.js'
  consume root
  in Data data

recipe
  map DataStore as h0
  P
    data <- h0`;

    const exampleParticle = `\
defineParticle(({DomParticle, html}) => {
  return class extends DomParticle {
    get template() {
      return html\`<span>{{num}}</span> : <span>{{str}}</span>\`;
    }
    render({data}) {
      return data ? {num: data.num, str: data.txt} : {};
    }
  };
});`;

    files.seedExample(exampleManifest, exampleParticle);
  }
}

function execute() {
  wrappedExecute().catch(e => output.showError('Unhandled exception', e.stack));
}

async function wrappedExecute() {
  SlotDomConsumer.clearCache();  // prevent caching of template strings
  document.dispatchEvent(new Event('clear-arcs-explorer'));
  output.reset();

  const loader = new DevShellLoader(files.getFileMap());
  const pecFactory = PecIndustry(loader);

  let manifest;
  try {
    const options = {loader, fileName: './manifest', throwImportErrors: true};
    manifest = await Runtime.parseManifest(files.getManifest(), options);
  } catch (e) {
    output.showError('Error in Manifest.parse', e);
    return;
  }

  if (manifest.allRecipes.length == 0) {
    output.showError('No recipes found in Manifest.parse');
  }

  let arcIndex = 1;
  for (const recipe of manifest.allRecipes) {
    const id = IdGenerator.newSession().newArcId('arc' + arcIndex++);
    const arcPanel = output.addArcPanel(id);

    const errors = new Map();
    if (!recipe.normalize({errors})) {
      arcPanel.showError('Error in recipe.normalize', [...errors.values()].join('\n'));
      continue;
    }

    const slotComposer = new SlotComposer({
      modalityName: Modality.Name.Dom,
      modalityHandler: ModalityHandler.domHandler,
      containers: {
        toproot: arcPanel.arcToproot,
        root: arcPanel.arcRoot,
        modal: arcPanel.arcModal,
      }
    });
    const storage = new StorageProviderFactory(id);
    const arc = new Arc({
      id,
      context: manifest,
      pecFactories: [pecFactory],
      slotComposer,
      loader,
      storageProviderFactory: storage,
      inspectorFactory: devtoolsArcInspectorFactory
    });
    arcPanel.attachArc(arc);

    recipe.normalize();

    let resolvedRecipe = null;
    if (recipe.isResolved()) {
      resolvedRecipe = recipe;
    } else {
      const resolver = new RecipeResolver(arc);
      const options = {errors: new Map()};
      resolvedRecipe = await resolver.resolve(recipe, options);
      if (!resolvedRecipe) {
        arcPanel.showError('Error in RecipeResolver', `${
          [...options.errors.entries()].join('\n')
        }.\n${recipe.toString()}`);
        continue;
      }
    }

    try {
      await arc.instantiate(resolvedRecipe);
    } catch (e) {
      arcPanel.showError('Error in arc.instantiate', e);
      continue;
    }
    const description = await Runtime.getArcDescription(arc);
    await arcPanel.arcInstantiated(description);
  }
}

function showHelp() {
  popup.style.display = 'block';
  document.addEventListener('keydown', hideHelp);
}

function hideHelp(e) {
  popup.style.display = 'none';
  e.preventDefault();
  document.removeEventListener('keydown', hideHelp);
}
<|endoftext|>


<commit_before>var deepEqual = require('deep-equal');
var defined = require('defined');
var path = require('path');
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
var has = require('has');
var trim = require('string.prototype.trim');

module.exports = Test;

var nextTick = typeof setImmediate !== 'undefined'
    ? setImmediate
    : process.nextTick
;

inherits(Test, EventEmitter);

var getTestArgs = function (name_, opts_, cb_) {
    var name = '(anonymous)';
    var opts = {};
    var cb;

    for (var i = 0; i < arguments.length; i++) {
        var arg = arguments[i];
        var t = typeof arg;
        if (t === 'string') {
            name = arg;
        }
        else if (t === 'object') {
            opts = arg || opts;
        }
        else if (t === 'function') {
            cb = arg;
        }
    }
    return { name: name, opts: opts, cb: cb };
};

function Test (name_, opts_, cb_) {
    if (! (this instanceof Test)) {
        return new Test(name_, opts_, cb_);
    }

    var args = getTestArgs(name_, opts_, cb_);

    this.readable = true;
    this.name = args.name || '(anonymous)';
    this.assertCount = 0;
    this.pendingCount = 0;
    this._skip = args.opts.skip || false;
    this._timeout = args.opts.timeout;
    this._plan = undefined;
    this._cb = args.cb;
    this._progeny = [];
    this._ok = true;

    for (var prop in this) {
        this[prop] = (function bind(self, val) {
            if (typeof val === 'function') {
                return function bound() {
                    return val.apply(self, arguments);
                };
            }
            else return val;
        })(this, this[prop]);
    }
}

Test.prototype.run = function () {
    if (!this._cb || this._skip) {
        return this._end();
    }
    if (this._timeout != null) {
        this.timeoutAfter(this._timeout);
    }
    this.emit('prerun');
    this._cb(this);
    this.emit('run');
};

Test.prototype.test = function (name, opts, cb) {
    var self = this;
    var t = new Test(name, opts, cb);
    this._progeny.push(t);
    this.pendingCount++;
    this.emit('test', t);
    t.on('prerun', function () {
        self.assertCount++;
    })

    if (!self._pendingAsserts()) {
        nextTick(function () {
            self._end();
        });
    }

    nextTick(function() {
        if (!self._plan && self.pendingCount == self._progeny.length) {
            self._end();
        }
    });
};

Test.prototype.comment = function (msg) {
    var that = this;
    String(trim(msg)).split('\n').forEach(function (aMsg) {
        that.emit('result', trim(aMsg).replace(/^#\s*/, ''));
    });
};

Test.prototype.plan = function (n) {
    this._plan = n;
    this.emit('plan', n);
};

Test.prototype.timeoutAfter = function(ms) {
    if (!ms) throw new Error('timeoutAfter requires a timespan');
    var self = this;
    var timeout = setTimeout(function() {
        self.fail('test timed out after ' + ms + 'ms');
        self.end();
    }, ms);
    this.once('end', function() {
        clearTimeout(timeout);
    });
}

Test.prototype.end = function (err) {
    var self = this;
    if (arguments.length >= 1 && !!err) {
        this.ifError(err);
    }

    if (this.calledEnd) {
        this.fail('.end() called twice');
    }
    this.calledEnd = true;
    this._end();
};

Test.prototype._end = function (err) {
    var self = this;
    if (this._progeny.length) {
        var t = this._progeny.shift();
        t.on('end', function () { self._end() });
        t.run();
        return;
    }

    if (!this.ended) this.emit('end');
    var pendingAsserts = this._pendingAsserts();
    if (!this._planError && this._plan !== undefined && pendingAsserts) {
        this._planError = true;
        this.fail('plan != count', {
            expected : this._plan,
            actual : this.assertCount
        });
    }
    this.ended = true;
};

Test.prototype._exit = function () {
    if (this._plan !== undefined &&
        !this._planError && this.assertCount !== this._plan) {
        this._planError = true;
        this.fail('plan != count', {
            expected : this._plan,
            actual : this.assertCount,
            exiting : true
        });
    }
    else if (!this.ended) {
        this.fail('test exited without ending', {
            exiting: true
        });
    }
};

Test.prototype._pendingAsserts = function () {
    if (this._plan === undefined) {
        return 1;
    }
    else {
        return this._plan - (this._progeny.length + this.assertCount);
    }
};

Test.prototype._assert = function assert (ok, opts) {
    var self = this;
    var extra = opts.extra || {};

    var res = {
        id : self.assertCount ++,
        ok : Boolean(ok),
        skip : defined(extra.skip, opts.skip),
        name : defined(extra.message, opts.message, '(unnamed assert)'),
        operator : defined(extra.operator, opts.operator)
    };
    if (has(opts, 'actual') || has(extra, 'actual')) {
        res.actual = defined(extra.actual, opts.actual);
    }
    if (has(opts, 'expected') || has(extra, 'expected')) {
        res.expected = defined(extra.expected, opts.expected);
    }
    this._ok = Boolean(this._ok && ok);

    if (!ok) {
        res.error = defined(extra.error, opts.error, new Error(res.name));
    }

    if (!ok) {
        var e = new Error('exception');
        var err = (e.stack || '').split('\n');
        var dir = path.dirname(__dirname) + '/';

        for (var i = 0; i < err.length; i++) {
            var m = /^[^\s]*\s*\bat\s+(.+)/.exec(err[i]);
            if (!m) {
                continue;
            }

            var s = m[1].split(/\s+/);
            var filem = /(\/[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[1]);
            if (!filem) {
                filem = /(\/[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[2]);

                if (!filem) {
                    filem = /(\/[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[3]);

                    if (!filem) {
                        continue;
                    }
                }
            }

            if (filem[1].slice(0, dir.length) === dir) {
                continue;
            }

            res.functionName = s[0];
            res.file = filem[1];
            res.line = Number(filem[2]);
            if (filem[3]) res.column = filem[3];

            res.at = m[1];
            break;
        }
    }

    self.emit('result', res);

    var pendingAsserts = self._pendingAsserts();
    if (!pendingAsserts) {
        if (extra.exiting) {
            self._end();
        } else {
            nextTick(function () {
                self._end();
            });
        }
    }

    if (!self._planError && pendingAsserts < 0) {
        self._planError = true;
        self.fail('plan != count', {
            expected : self._plan,
            actual : self._plan - pendingAsserts
        });
    }
};

Test.prototype.fail = function (msg, extra) {
    this._assert(false, {
        message : msg,
        operator : 'fail',
        extra : extra
    });
};

Test.prototype.pass = function (msg, extra) {
    this._assert(true, {
        message : msg,
        operator : 'pass',
        extra : extra
    });
};

Test.prototype.skip = function (msg, extra) {
    this._assert(true, {
        message : msg,
        operator : 'skip',
        skip : true,
        extra : extra
    });
};

Test.prototype.ok
= Test.prototype['true']
= Test.prototype.assert
= function (value, msg, extra) {
    this._assert(value, {
        message : msg,
        operator : 'ok',
        expected : true,
        actual : value,
        extra : extra
    });
};

Test.prototype.notOk
= Test.prototype['false']
= Test.prototype.notok
= function (value, msg, extra) {
    this._assert(!value, {
        message : msg,
        operator : 'notOk',
        expected : false,
        actual : value,
        extra : extra
    });
};

Test.prototype.error
= Test.prototype.ifError
= Test.prototype.ifErr
= Test.prototype.iferror
= function (err, msg, extra) {
    this._assert(!err, {
        message : defined(msg, String(err)),
        operator : 'error',
        actual : err,
        extra : extra
    });
};

Test.prototype.equal
= Test.prototype.equals
= Test.prototype.isEqual
= Test.prototype.is
= Test.prototype.strictEqual
= Test.prototype.strictEquals
= function (a, b, msg, extra) {
    this._assert(a === b, {
        message : defined(msg, 'should be equal'),
        operator : 'equal',
        actual : a,
        expected : b,
        extra : extra
    });
};

Test.prototype.notEqual
= Test.prototype.notEquals
= Test.prototype.notStrictEqual
= Test.prototype.notStrictEquals
= Test.prototype.isNotEqual
= Test.prototype.isNot
= Test.prototype.not
= Test.prototype.doesNotEqual
= Test.prototype.isInequal
= function (a, b, msg, extra) {
    this._assert(a !== b, {
        message : defined(msg, 'should not be equal'),
        operator : 'notEqual',
        actual : a,
        notExpected : b,
        extra : extra
    });
};

Test.prototype.deepEqual
= Test.prototype.deepEquals
= Test.prototype.isEquivalent
= Test.prototype.same
= function (a, b, msg, extra) {
    this._assert(deepEqual(a, b, { strict: true }), {
        message : defined(msg, 'should be equivalent'),
        operator : 'deepEqual',
        actual : a,
        expected : b,
        extra : extra
    });
};

Test.prototype.deepLooseEqual
= Test.prototype.looseEqual
= Test.prototype.looseEquals
= function (a, b, msg, extra) {
    this._assert(deepEqual(a, b), {
        message : defined(msg, 'should be equivalent'),
        operator : 'deepLooseEqual',
        actual : a,
        expected : b,
        extra : extra
    });
};

Test.prototype.notDeepEqual
= Test.prototype.notEquivalent
= Test.prototype.notDeeply
= Test.prototype.notSame
= Test.prototype.isNotDeepEqual
= Test.prototype.isNotDeeply
= Test.prototype.isNotEquivalent
= Test.prototype.isInequivalent
= function (a, b, msg, extra) {
    this._assert(!deepEqual(a, b, { strict: true }), {
        message : defined(msg, 'should not be equivalent'),
        operator : 'notDeepEqual',
        actual : a,
        notExpected : b,
        extra : extra
    });
};

Test.prototype.notDeepLooseEqual
= Test.prototype.notLooseEqual
= Test.prototype.notLooseEquals
= function (a, b, msg, extra) {
    this._assert(!deepEqual(a, b), {
        message : defined(msg, 'should be equivalent'),
        operator : 'notDeepLooseEqual',
        actual : a,
        expected : b,
        extra : extra
    });
};

Test.prototype['throws'] = function (fn, expected, msg, extra) {
    if (typeof expected === 'string') {
        msg = expected;
        expected = undefined;
    }

    var caught = undefined;

    try {
        fn();
    } catch (err) {
        caught = { error : err };
        var message = err.message;
        delete err.message;
        err.message = message;
    }

    var passed = caught;

    if (expected instanceof RegExp) {
        passed = expected.test(caught && caught.error);
        expected = String(expected);
    }

    if (typeof expected === 'function' && caught) {
        passed = caught.error instanceof expected;
        caught.error = caught.error.constructor;
    }

    this._assert(passed, {
        message : defined(msg, 'should throw'),
        operator : 'throws',
        actual : caught && caught.error,
        expected : expected,
        error: !passed && caught && caught.error,
        extra : extra
    });
};

Test.prototype.doesNotThrow = function (fn, expected, msg, extra) {
    if (typeof expected === 'string') {
        msg = expected;
        expected = undefined;
    }
    var caught = undefined;
    try {
        fn();
    }
    catch (err) {
        caught = { error : err };
    }
    this._assert(!caught, {
        message : defined(msg, 'should not throw'),
        operator : 'throws',
        actual : caught && caught.error,
        expected : expected,
        error : caught && caught.error,
        extra : extra
    });
};

Test.skip = function (name_, _opts, _cb) {
    var args = getTestArgs.apply(null, arguments);
    args.opts.skip = true;
    return Test(args.name, args.opts, args.cb);
};

// vim: set softtabstop=4 shiftwidth=4:

<commit_msg>Removed unnecessary cast<commit_after>var deepEqual = require('deep-equal');
var defined = require('defined');
var path = require('path');
var inherits = require('inherits');
var EventEmitter = require('events').EventEmitter;
var has = require('has');
var trim = require('string.prototype.trim');

module.exports = Test;

var nextTick = typeof setImmediate !== 'undefined'
    ? setImmediate
    : process.nextTick
;

inherits(Test, EventEmitter);

var getTestArgs = function (name_, opts_, cb_) {
    var name = '(anonymous)';
    var opts = {};
    var cb;

    for (var i = 0; i < arguments.length; i++) {
        var arg = arguments[i];
        var t = typeof arg;
        if (t === 'string') {
            name = arg;
        }
        else if (t === 'object') {
            opts = arg || opts;
        }
        else if (t === 'function') {
            cb = arg;
        }
    }
    return { name: name, opts: opts, cb: cb };
};

function Test (name_, opts_, cb_) {
    if (! (this instanceof Test)) {
        return new Test(name_, opts_, cb_);
    }

    var args = getTestArgs(name_, opts_, cb_);

    this.readable = true;
    this.name = args.name || '(anonymous)';
    this.assertCount = 0;
    this.pendingCount = 0;
    this._skip = args.opts.skip || false;
    this._timeout = args.opts.timeout;
    this._plan = undefined;
    this._cb = args.cb;
    this._progeny = [];
    this._ok = true;

    for (var prop in this) {
        this[prop] = (function bind(self, val) {
            if (typeof val === 'function') {
                return function bound() {
                    return val.apply(self, arguments);
                };
            }
            else return val;
        })(this, this[prop]);
    }
}

Test.prototype.run = function () {
    if (!this._cb || this._skip) {
        return this._end();
    }
    if (this._timeout != null) {
        this.timeoutAfter(this._timeout);
    }
    this.emit('prerun');
    this._cb(this);
    this.emit('run');
};

Test.prototype.test = function (name, opts, cb) {
    var self = this;
    var t = new Test(name, opts, cb);
    this._progeny.push(t);
    this.pendingCount++;
    this.emit('test', t);
    t.on('prerun', function () {
        self.assertCount++;
    })

    if (!self._pendingAsserts()) {
        nextTick(function () {
            self._end();
        });
    }

    nextTick(function() {
        if (!self._plan && self.pendingCount == self._progeny.length) {
            self._end();
        }
    });
};

Test.prototype.comment = function (msg) {
    var that = this;
    trim(msg).split('\n').forEach(function (aMsg) {
        that.emit('result', trim(aMsg).replace(/^#\s*/, ''));
    });
};

Test.prototype.plan = function (n) {
    this._plan = n;
    this.emit('plan', n);
};

Test.prototype.timeoutAfter = function(ms) {
    if (!ms) throw new Error('timeoutAfter requires a timespan');
    var self = this;
    var timeout = setTimeout(function() {
        self.fail('test timed out after ' + ms + 'ms');
        self.end();
    }, ms);
    this.once('end', function() {
        clearTimeout(timeout);
    });
}

Test.prototype.end = function (err) {
    var self = this;
    if (arguments.length >= 1 && !!err) {
        this.ifError(err);
    }

    if (this.calledEnd) {
        this.fail('.end() called twice');
    }
    this.calledEnd = true;
    this._end();
};

Test.prototype._end = function (err) {
    var self = this;
    if (this._progeny.length) {
        var t = this._progeny.shift();
        t.on('end', function () { self._end() });
        t.run();
        return;
    }

    if (!this.ended) this.emit('end');
    var pendingAsserts = this._pendingAsserts();
    if (!this._planError && this._plan !== undefined && pendingAsserts) {
        this._planError = true;
        this.fail('plan != count', {
            expected : this._plan,
            actual : this.assertCount
        });
    }
    this.ended = true;
};

Test.prototype._exit = function () {
    if (this._plan !== undefined &&
        !this._planError && this.assertCount !== this._plan) {
        this._planError = true;
        this.fail('plan != count', {
            expected : this._plan,
            actual : this.assertCount,
            exiting : true
        });
    }
    else if (!this.ended) {
        this.fail('test exited without ending', {
            exiting: true
        });
    }
};

Test.prototype._pendingAsserts = function () {
    if (this._plan === undefined) {
        return 1;
    }
    else {
        return this._plan - (this._progeny.length + this.assertCount);
    }
};

Test.prototype._assert = function assert (ok, opts) {
    var self = this;
    var extra = opts.extra || {};

    var res = {
        id : self.assertCount ++,
        ok : Boolean(ok),
        skip : defined(extra.skip, opts.skip),
        name : defined(extra.message, opts.message, '(unnamed assert)'),
        operator : defined(extra.operator, opts.operator)
    };
    if (has(opts, 'actual') || has(extra, 'actual')) {
        res.actual = defined(extra.actual, opts.actual);
    }
    if (has(opts, 'expected') || has(extra, 'expected')) {
        res.expected = defined(extra.expected, opts.expected);
    }
    this._ok = Boolean(this._ok && ok);

    if (!ok) {
        res.error = defined(extra.error, opts.error, new Error(res.name));
    }

    if (!ok) {
        var e = new Error('exception');
        var err = (e.stack || '').split('\n');
        var dir = path.dirname(__dirname) + '/';

        for (var i = 0; i < err.length; i++) {
            var m = /^[^\s]*\s*\bat\s+(.+)/.exec(err[i]);
            if (!m) {
                continue;
            }

            var s = m[1].split(/\s+/);
            var filem = /(\/[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[1]);
            if (!filem) {
                filem = /(\/[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[2]);

                if (!filem) {
                    filem = /(\/[^:\s]+:(\d+)(?::(\d+))?)/.exec(s[3]);

                    if (!filem) {
                        continue;
                    }
                }
            }

            if (filem[1].slice(0, dir.length) === dir) {
                continue;
            }

            res.functionName = s[0];
            res.file = filem[1];
            res.line = Number(filem[2]);
            if (filem[3]) res.column = filem[3];

            res.at = m[1];
            break;
        }
    }

    self.emit('result', res);

    var pendingAsserts = self._pendingAsserts();
    if (!pendingAsserts) {
        if (extra.exiting) {
            self._end();
        } else {
            nextTick(function () {
                self._end();
            });
        }
    }

    if (!self._planError && pendingAsserts < 0) {
        self._planError = true;
        self.fail('plan != count', {
            expected : self._plan,
            actual : self._plan - pendingAsserts
        });
    }
};

Test.prototype.fail = function (msg, extra) {
    this._assert(false, {
        message : msg,
        operator : 'fail',
        extra : extra
    });
};

Test.prototype.pass = function (msg, extra) {
    this._assert(true, {
        message : msg,
        operator : 'pass',
        extra : extra
    });
};

Test.prototype.skip = function (msg, extra) {
    this._assert(true, {
        message : msg,
        operator : 'skip',
        skip : true,
        extra : extra
    });
};

Test.prototype.ok
= Test.prototype['true']
= Test.prototype.assert
= function (value, msg, extra) {
    this._assert(value, {
        message : msg,
        operator : 'ok',
        expected : true,
        actual : value,
        extra : extra
    });
};

Test.prototype.notOk
= Test.prototype['false']
= Test.prototype.notok
= function (value, msg, extra) {
    this._assert(!value, {
        message : msg,
        operator : 'notOk',
        expected : false,
        actual : value,
        extra : extra
    });
};

Test.prototype.error
= Test.prototype.ifError
= Test.prototype.ifErr
= Test.prototype.iferror
= function (err, msg, extra) {
    this._assert(!err, {
        message : defined(msg, String(err)),
        operator : 'error',
        actual : err,
        extra : extra
    });
};

Test.prototype.equal
= Test.prototype.equals
= Test.prototype.isEqual
= Test.prototype.is
= Test.prototype.strictEqual
= Test.prototype.strictEquals
= function (a, b, msg, extra) {
    this._assert(a === b, {
        message : defined(msg, 'should be equal'),
        operator : 'equal',
        actual : a,
        expected : b,
        extra : extra
    });
};

Test.prototype.notEqual
= Test.prototype.notEquals
= Test.prototype.notStrictEqual
= Test.prototype.notStrictEquals
= Test.prototype.isNotEqual
= Test.prototype.isNot
= Test.prototype.not
= Test.prototype.doesNotEqual
= Test.prototype.isInequal
= function (a, b, msg, extra) {
    this._assert(a !== b, {
        message : defined(msg, 'should not be equal'),
        operator : 'notEqual',
        actual : a,
        notExpected : b,
        extra : extra
    });
};

Test.prototype.deepEqual
= Test.prototype.deepEquals
= Test.prototype.isEquivalent
= Test.prototype.same
= function (a, b, msg, extra) {
    this._assert(deepEqual(a, b, { strict: true }), {
        message : defined(msg, 'should be equivalent'),
        operator : 'deepEqual',
        actual : a,
        expected : b,
        extra : extra
    });
};

Test.prototype.deepLooseEqual
= Test.prototype.looseEqual
= Test.prototype.looseEquals
= function (a, b, msg, extra) {
    this._assert(deepEqual(a, b), {
        message : defined(msg, 'should be equivalent'),
        operator : 'deepLooseEqual',
        actual : a,
        expected : b,
        extra : extra
    });
};

Test.prototype.notDeepEqual
= Test.prototype.notEquivalent
= Test.prototype.notDeeply
= Test.prototype.notSame
= Test.prototype.isNotDeepEqual
= Test.prototype.isNotDeeply
= Test.prototype.isNotEquivalent
= Test.prototype.isInequivalent
= function (a, b, msg, extra) {
    this._assert(!deepEqual(a, b, { strict: true }), {
        message : defined(msg, 'should not be equivalent'),
        operator : 'notDeepEqual',
        actual : a,
        notExpected : b,
        extra : extra
    });
};

Test.prototype.notDeepLooseEqual
= Test.prototype.notLooseEqual
= Test.prototype.notLooseEquals
= function (a, b, msg, extra) {
    this._assert(!deepEqual(a, b), {
        message : defined(msg, 'should be equivalent'),
        operator : 'notDeepLooseEqual',
        actual : a,
        expected : b,
        extra : extra
    });
};

Test.prototype['throws'] = function (fn, expected, msg, extra) {
    if (typeof expected === 'string') {
        msg = expected;
        expected = undefined;
    }

    var caught = undefined;

    try {
        fn();
    } catch (err) {
        caught = { error : err };
        var message = err.message;
        delete err.message;
        err.message = message;
    }

    var passed = caught;

    if (expected instanceof RegExp) {
        passed = expected.test(caught && caught.error);
        expected = String(expected);
    }

    if (typeof expected === 'function' && caught) {
        passed = caught.error instanceof expected;
        caught.error = caught.error.constructor;
    }

    this._assert(passed, {
        message : defined(msg, 'should throw'),
        operator : 'throws',
        actual : caught && caught.error,
        expected : expected,
        error: !passed && caught && caught.error,
        extra : extra
    });
};

Test.prototype.doesNotThrow = function (fn, expected, msg, extra) {
    if (typeof expected === 'string') {
        msg = expected;
        expected = undefined;
    }
    var caught = undefined;
    try {
        fn();
    }
    catch (err) {
        caught = { error : err };
    }
    this._assert(!caught, {
        message : defined(msg, 'should not throw'),
        operator : 'throws',
        actual : caught && caught.error,
        expected : expected,
        error : caught && caught.error,
        extra : extra
    });
};

Test.skip = function (name_, _opts, _cb) {
    var args = getTestArgs.apply(null, arguments);
    args.opts.skip = true;
    return Test(args.name, args.opts, args.cb);
};

// vim: set softtabstop=4 shiftwidth=4:

<|endoftext|>


<commit_before>'use strict'

/**
 * Parse time given as a string, like '2min' or a number in ms.
 * Valid units: 'ms', 's', 'min', 'h', 'd'
 * @param {number|string} time
 * @returns {number} - in ms
 */
module.exports = function (time) {
	if (typeof time === 'number') {
		return checkUint(time)
	} else if (typeof time !== 'string') {
		throw new Error('Invalid time: ' + time)
	}
	var unit = time.match(/(ms|s|min|h|d)$/),
		multiple = 1
	if (unit) {
		time = time.substr(0, time.length - unit[0].length)
		multiple = {
			ms: 1,
			s: 1e3,
			min: 60e3,
			h: 3600e3,
			d: 24 * 3600e3
		}[unit[0]]
	}
	return checkUint(Number(time) * multiple)
}

/**
 * Check if the given number is a safe natural number
 * @param {number} n
 * @returns {number}
 * @throws
 * @private
 */
function checkUint(n) {
	if (typeof n !== 'number' ||
		!Number.isFinite(n) ||
		n < 0 ||
		n > 2147483647 ||
		Math.round(n) !== n) {
		throw new Error('Invalid timer value, please check if the syntax is correct')
	}
	return n
}<commit_msg>Tiny jsdocs fix<commit_after>'use strict'

/**
 * Parse time given as a string, like '2min' or a number in ms.
 * Valid units: 'ms', 's', 'min', 'h', 'd'
 * @param {number|string} time
 * @returns {number} - in ms
 */
module.exports = function (time) {
	if (typeof time === 'number') {
		return checkUint(time)
	} else if (typeof time !== 'string') {
		throw new Error('Invalid time: ' + time)
	}
	var unit = time.match(/(ms|s|min|h|d)$/),
		multiple = 1
	if (unit) {
		time = time.substr(0, time.length - unit[0].length)
		multiple = {
			ms: 1,
			s: 1e3,
			min: 60e3,
			h: 3600e3,
			d: 24 * 3600e3
		}[unit[0]]
	}
	return checkUint(Number(time) * multiple)
}

/**
 * Check if the given number is a safe natural number
 * @param {number} n
 * @returns {number}
 * @throws {Error}
 * @private
 */
function checkUint(n) {
	if (typeof n !== 'number' ||
		!Number.isFinite(n) ||
		n < 0 ||
		n > 2147483647 ||
		Math.round(n) !== n) {
		throw new Error('Invalid timer value, please check if the syntax is correct')
	}
	return n
}<|endoftext|>


<commit_before>'use strict';

const VError            = require('verror');
const SrcCollection     = require('./src-collection');
const SrcFile           = require('./src-file');
const Logger            = require('shark-logger');
const co                = require('co');
const expand            = require('expand');
const extend            = require('node.extend');

function *SharkTree(paths, logger) {
	var newPaths = {};
	yield co(function *() {
		for (var destPath in paths) {
			if (paths.hasOwnProperty(destPath)) {
				var content = null;
				var options = {};
				var dataExpanded = [];
				var dataType = ({}).toString.call(paths[destPath]);
				switch(dataType) {
					case '[object String]':
					case '[object Array]':
						dataExpanded = yield expand(paths[destPath]);
						break;

					case '[object Object]':
						var data = paths[destPath] || {};
						dataExpanded = yield expand(data.files || []);
						options = data.options || {};
						content = data.content || null;
						break;

					default:
						throw new VError('Invalid dataType "%s"', dataType);
						break;
				}

				newPaths[destPath] = {
					files: dataExpanded,
					options: options,
					content: content
				};
			}
		}
	});

	var instance = new SharkTreeInternal(newPaths, logger);
	// ugly hack to use .name in comparing instead of intanceof, need refactor
	instance.constructor = SharkTree;
	return instance;
}

function SharkTreeInternal(data, logger) {
	if (!(this instanceof SharkTreeInternal)) {
		return new SharkTreeInternal(data, logger);
	}

	this._tree = {};

	if (typeof logger === 'undefined') {
		throw new VError('logger argument is empty');
	}

	if (logger.constructor && logger.constructor.name !== Logger.INTERNAL_LOGGER.name) {
		throw new VError('logger is not instanceof SharkLogger');
	}

	this.logger = logger;

	Object.keys(data).forEach(function(destPath) {
		if (this._tree.hasOwnProperty(destPath)) {
			throw new VError('tree already has property "%s"', destPath);
		}

		this._tree[destPath] = new SrcCollection(data[destPath], destPath);
	}.bind(this));
}

SharkTreeInternal.prototype = {
	constructor: SharkTreeInternal,

	forEach: function(cb) {
		var tree = this._tree;
		Object.keys(tree).forEach(function(destPath) {
			cb(destPath, tree[destPath]);
		});
	},

	getTree: function() {
		return this._tree;
	},

	forEachDestSeries: function(cb) {
		return new Promise(function(fulfill, reject) {
			var tree = this._tree;
			var dests = Object.keys(tree);
			var destsCount = dests.length;

			var nextIteration = function(index) {
				var dest = dests[index];
				var srcCollection = tree[dest];
				cb(dest, srcCollection, function(error) {
					var newIndex = index + 1;
					if (error) {
						reject(new VError(error), 'Tree#forEachDestSeries nextIteration error');
					}
					else {
						if (newIndex < destsCount) {
							nextIteration(newIndex);
						}
						else {
							fulfill();
						}
					}
				});
			};

			if (destsCount === 0) {
				fulfill();
			}
			else {
				nextIteration(0);
			}
		}.bind(this));
	},

	hasDest: function(destPath) {
		return this._tree.hasOwnProperty(destPath);
	},

	getSrcCollectionByDest: function(destPath) {
		return this._tree[destPath];
	},

	fillContent: function *() {
		for (var destPath in this._tree) {
			if (this._tree.hasOwnProperty(destPath)) {
				try {
					var srcCollection = this.getSrcCollectionByDest(destPath);
					yield srcCollection.fillContent();
				}
				catch (error) {
					throw new VError(error);
				}
			}
		}
	},

	writeContentToFiles: function() {
		return this.forEachDestSeries(co.wrap(function *(destPath, srcCollection, done) {
			try {
				yield srcCollection.writeContentToFile();
				done();
			}
			catch (error) {
				done(new VError(error, 'Tree#writeContentToFiles error'));
			}
		}.bind(this)));
	},

	merge: function() {
		// need refactoring and tests
		var trees = [].slice.call(arguments, 0);
		var currTree = this._tree;

		trees.forEach(function(tree) {
			tree.forEach(function(destPath, srcCollection) {
				currTree[destPath] = srcCollection;
			});
		});
	},

	createTreeFromDest: function *(destPath) {
		if (!this.hasDest(destPath)) {
			throw new VError('Can\'t createTreeFromDest, destPath "%s" does not exists', destPath);
		}
		var srcCollection = this.getSrcCollectionByDest(destPath);
		var newTree = yield SharkTree([], this.logger);

		newTree._tree[destPath] = new SrcCollection({
			files: [],
			options: extend({}, srcCollection.getOptions())
		}, destPath);

		srcCollection.forEach(function(srcFile) {
			newTree._tree[destPath]._srcArr.push(new SrcFile({
				src: srcFile.getSrc(),
				content: srcFile.getContent(),
				dest: destPath
			}));
		});

		return newTree;
	}
};

module.exports = SharkTree;<commit_msg>Add transformToOneToOne method to tree<commit_after>'use strict';

const VError            = require('verror');
const SrcCollection     = require('./src-collection');
const SrcFile           = require('./src-file');
const Logger            = require('shark-logger');
const co                = require('co');
const expand            = require('expand');
const extend            = require('node.extend');

function *SharkTree(paths, logger) {
	var newPaths = {};
	yield co(function *() {
		for (var destPath in paths) {
			if (paths.hasOwnProperty(destPath)) {
				var content = null;
				var options = {};
				var dataExpanded = [];
				var dataType = ({}).toString.call(paths[destPath]);
				switch(dataType) {
					case '[object String]':
					case '[object Array]':
						dataExpanded = yield expand(paths[destPath]);
						break;

					case '[object Object]':
						var data = paths[destPath] || {};
						dataExpanded = yield expand(data.files || []);
						options = data.options || {};
						content = data.content || null;
						break;

					default:
						throw new VError('Invalid dataType "%s"', dataType);
						break;
				}

				newPaths[destPath] = {
					files: dataExpanded,
					options: options,
					content: content
				};
			}
		}
	});

	var instance = new SharkTreeInternal(newPaths, logger);
	// ugly hack to use .name in comparing instead of intanceof, need refactor
	instance.constructor = SharkTree;
	return instance;
}

function SharkTreeInternal(data, logger) {
	if (!(this instanceof SharkTreeInternal)) {
		return new SharkTreeInternal(data, logger);
	}

	this._tree = {};

	if (typeof logger === 'undefined') {
		throw new VError('logger argument is empty');
	}

	if (logger.constructor && logger.constructor.name !== Logger.INTERNAL_LOGGER.name) {
		throw new VError('logger is not instanceof SharkLogger');
	}

	this.logger = logger;

	Object.keys(data).forEach(function(destPath) {
		if (this._tree.hasOwnProperty(destPath)) {
			throw new VError('tree already has property "%s"', destPath);
		}

		this._tree[destPath] = new SrcCollection(data[destPath], destPath);
	}.bind(this));
}

SharkTreeInternal.prototype = {
	constructor: SharkTreeInternal,

	forEach: function(cb) {
		var tree = this._tree;
		Object.keys(tree).forEach(function(destPath) {
			cb(destPath, tree[destPath]);
		});
	},

	getTree: function() {
		return this._tree;
	},

	forEachDestSeries: function(cb) {
		return new Promise(function(fulfill, reject) {
			var tree = this._tree;
			var dests = Object.keys(tree);
			var destsCount = dests.length;

			var nextIteration = function(index) {
				var dest = dests[index];
				var srcCollection = tree[dest];
				cb(dest, srcCollection, function(error) {
					var newIndex = index + 1;
					if (error) {
						reject(new VError(error), 'Tree#forEachDestSeries nextIteration error');
					}
					else {
						if (newIndex < destsCount) {
							nextIteration(newIndex);
						}
						else {
							fulfill();
						}
					}
				});
			};

			if (destsCount === 0) {
				fulfill();
			}
			else {
				nextIteration(0);
			}
		}.bind(this));
	},

	hasDest: function(destPath) {
		return this._tree.hasOwnProperty(destPath);
	},

	getSrcCollectionByDest: function(destPath) {
		return this._tree[destPath];
	},

	fillContent: function *() {
		for (var destPath in this._tree) {
			if (this._tree.hasOwnProperty(destPath)) {
				try {
					var srcCollection = this.getSrcCollectionByDest(destPath);
					yield srcCollection.fillContent();
				}
				catch (error) {
					throw new VError(error);
				}
			}
		}
	},

	writeContentToFiles: function() {
		return this.forEachDestSeries(co.wrap(function *(destPath, srcCollection, done) {
			try {
				yield srcCollection.writeContentToFile();
				done();
			}
			catch (error) {
				done(new VError(error, 'Tree#writeContentToFiles error'));
			}
		}.bind(this)));
	},

	merge: function() {
		// need refactoring and tests
		var trees = [].slice.call(arguments, 0);
		var currTree = this._tree;

		trees.forEach(function(tree) {
			tree.forEach(function(destPath, srcCollection) {
				currTree[destPath] = srcCollection;
			});
		});
	},

	createTreeFromDest: function *(destPath) {
		if (!this.hasDest(destPath)) {
			throw new VError('Can\'t createTreeFromDest, destPath "%s" does not exists', destPath);
		}
		var srcCollection = this.getSrcCollectionByDest(destPath);
		var newTree = yield SharkTree([], this.logger);

		newTree._tree[destPath] = new SrcCollection({
			files: [],
			options: extend({}, srcCollection.getOptions())
		}, destPath);

		srcCollection.forEach(function(srcFile) {
			newTree._tree[destPath]._srcArr.push(new SrcFile({
				src: srcFile.getSrc(),
				content: srcFile.getContent(),
				dest: destPath
			}));
		});

		return newTree;
	},

	transformToOneToOne: function() {
		this.forEach(function(destPath) {
			this._tree[destPath].transformToOneToOne();
		}.bind(this));
	}
};

module.exports = SharkTree;<|endoftext|>


<commit_before>/* type.js: Types of files.
 * Copyright © 2011 Jan Keromnes, Thaddee Tyl. All rights reserved.
 * The following code is covered by the GPLv2 license. */

var nodepath = require('path'),
    nodefs = require('fs'),
    driver = require('./driver'),
    mime = require('camp').mime;

// Types are internally represented by integers.
//
// We go from _mime type_ world to _int_ world and back
// with `fromName` and `nameFromType`.

var fromName = {},     // Links the mime type to a unique integer.
    nbTypes = 0,   // Number of different types.
    fallbacks = [],    // Array of parent types (all being integers).
    nameFromType = [];  // Array of mime types (Strings).

function addType(mimeType, parents) {
  fallbacks.push(parents || []);
  nameFromType.push(mimeType);
  fromName[mimeType] = nbTypes;
  nbTypes++;
}

// The following algorithm is not cyclic-aware.
// Please do not create cycles in the type system.
function isCompatible(type, ancestor) {
  if (type === ancestor)  return true;
  if (!fallbacks[type]) {
    console.error('TYPE:isCompatible: type %s (%s) does not have fallbacks',
        nameFromType[type], type);
    return false;
  }
  for (var i = 0;  i < fallbacks[type].length;  i++) {
    if (isCompatible(fallbacks[type][i], ancestor))  return true;
  }
  return false;
}

// Defining current types (and their compatibility table).

addType('dir');            // contains a JSON string of files.
addType('binary');
addType('text', [fromName['binary']]);

addType('application/pdf', [fromName['binary']]);
addType('application/ps', [fromName['application/pdf'], fromName['binary']]);
addType('image/jpeg', [fromName['binary']]);
addType('image/jpg', [fromName['binary']]);
addType('image/tiff', [fromName['binary']]);
addType('image/gif', [fromName['binary']]);
addType('image/vnd.microsoft.icon', [fromName['binary']]);
addType('image/png', [fromName['binary']]);

addType('application/json', [fromName['text']]);
addType('application/x-aspx', [fromName['text']]);
addType('application/x-ejs', [fromName['text']]);
addType('application/x-httpd-php', [fromName['text']]);
addType('application/x-httpd-php-open', [fromName['text']]);
addType('application/x-jsp', [fromName['text']]);
addType('application/x-sparql-query', [fromName['text']]);
addType('application/xml', [fromName['text']]);
addType('application/xquery', [fromName['text']]);
addType('text/css', [fromName['text']]);
addType('text/html', [fromName['text']]);
addType('text/javascript', [fromName['text']]);
addType('text/n-triples', [fromName['text']]);
addType('text/tiki', [fromName['text']]);
addType('text/vbscript', [fromName['text']]);
addType('text/velocity', [fromName['text']]);
addType('text/x-c++src', [fromName['text']]);
addType('text/x-clojure', [fromName['text']]);
addType('text/x-coffeescript', [fromName['text']]);
addType('text/x-csharp', [fromName['text']]);
addType('text/x-csrc', [fromName['text']]);
addType('text/x-diff', [fromName['text']]);
addType('text/x-ecl', [fromName['text']]);
addType('text/x-erlang', [fromName['text']]);
addType('text/x-go', [fromName['text']]);
addType('text/x-groovy', [fromName['text']]);
addType('text/x-haskell', [fromName['text']]);
addType('text/x-ini', [fromName['text']]);
addType('text/x-java', [fromName['text']]);
addType('text/x-less', [fromName['text']]);
addType('text/x-lua', [fromName['text']]);
addType('text/x-markdown', [fromName['text']]);
addType('text/x-mysql', [fromName['text']]);
addType('text/x-pascal', [fromName['text']]);
addType('text/x-perl', [fromName['text']]);
addType('text/x-php', [fromName['text']]);
addType('text/x-pig', [fromName['text']]);
addType('text/x-plsql', [fromName['text']]);
addType('text/x-properties', [fromName['text']]);
addType('text/x-python', [fromName['text']]);
addType('text/x-rpm-changes', [fromName['text']]);
addType('text/x-rpm-spec', [fromName['text']]);
addType('text/x-rsrc', [fromName['text']]);
addType('text/x-rst', [fromName['text']]);
addType('text/x-ruby', [fromName['text']]);
addType('text/x-rustsrc', [fromName['text']]);
addType('text/x-scheme', [fromName['text']]);
addType('text/x-sh', [fromName['text']]);
addType('text/x-smarty', [fromName['text']]);
addType('text/x-stex', [fromName['text']]);
addType('text/x-stsrc', [fromName['text']]);
addType('text/x-tiddlywiki', [fromName['text']]);
addType('text/x-verilog', [fromName['text']]);
addType('text/x-yaml', [fromName['text']]);

// Get the type associated to the extention of the file.
//
function guessType (vpath, cb) {
  var npath = driver.normalize(vpath);
  nodefs.stat(driver.relative(npath), function (err, stats) {
    if (err) {
      cb(err);
      return;
    }
    if (stats.isDirectory()) {
      cb(null, fromName['dir']);
    } else if (stats.isFile()) {
      cb(null, fromName[
          mime[nodepath.extname(npath).slice(1)] || 'text'
      ]);
    } else {
      cb(new Error("File is neither a directory, nor a file."));
    }
  });
};

// Driver access.

var drivers = [];  // Sparse array from types to I/O primitives.

for (var prims in driver.primitives) {
  drivers[fromName[prims]] = driver.primitives[prims];
}

// This is not cycle-aware.
// Do not create loops in the type system.
function findDriver(type) {
  var driver;
  if (driver = drivers[type]) {
    return driver;  // There is a driver for this type.
  } else if (fallbacks[type]) {
    for (var i = 0; i < fallbacks[type].length; i++) {
      if (driver = findDriver(fallbacks[type][i])) {
        return driver;
      }
    }
  }
  console.error("Type:findDriver: cannot find driver of type %s.",
      nameFromType[type]);
  return null;
}

// We export the following:
//
// - addType(mimeType :: String, parents :: Array)
// - fromName: Map from mime types (String) to type number
// - nameFromType: Array of all types in order
// - isCompatible(type :: Number, ancestor :: Number)
// - guessType(vpath :: String, cb :: Function)
// - driver(type :: Number)

exports.addType = addType;
exports.fromName = fromName;
exports.nameFromType = nameFromType;
exports.isCompatible = isCompatible;
exports.guessType = guessType;
exports.driver = findDriver;

<commit_msg>type: Add type for ogg and mp3.<commit_after>// Types of files.
// Copyright © 2011-2013 Thaddee Tyl, Jan Keromnes. All rights reserved.
// The following code is covered by the GPLv2 license.

var nodepath = require('path');
var nodefs = require('fs');
var driver = require('./driver');
var mime = require('camp').mime;

// Types are internally represented by integers.
//
// We go from _mime type_ world to _int_ world and back
// with `fromName` and `nameFromType`.

var fromName = {};      // Links the mime type to a unique integer.
var nbTypes = 0;        // Number of different types.
var fallbacks = [];     // Array of parent types (all being integers).
var nameFromType = [];  // Array of mime types (Strings).

function addType(mimeType, parents) {
  fallbacks.push(parents || []);
  nameFromType.push(mimeType);
  fromName[mimeType] = nbTypes;
  nbTypes++;
}

// The following algorithm is not cyclic-aware.
// Please do not create cycles in the type system.
function isCompatible(type, ancestor) {
  if (type === ancestor)  return true;
  if (!fallbacks[type]) {
    console.error('TYPE:isCompatible: type %s (%s) does not have fallbacks',
        nameFromType[type], type);
    return false;
  }
  for (var i = 0;  i < fallbacks[type].length;  i++) {
    if (isCompatible(fallbacks[type][i], ancestor))  return true;
  }
  return false;
}

// Defining current types (and their compatibility table).

addType('dir');            // contains a JSON string of files.
addType('binary');
addType('text', [fromName['binary']]);

addType('application/pdf', [fromName['binary']]);
addType('application/ps', [fromName['application/pdf'], fromName['binary']]);
addType('image/jpeg', [fromName['binary']]);
addType('image/jpg', [fromName['binary']]);
addType('image/tiff', [fromName['binary']]);
addType('image/gif', [fromName['binary']]);
addType('image/vnd.microsoft.icon', [fromName['binary']]);
addType('image/png', [fromName['binary']]);
addType('application/ogg', [fromName['binary']]);
addType('audio/mpeg', [fromName['binary']]);

addType('application/json', [fromName['text']]);
addType('application/x-aspx', [fromName['text']]);
addType('application/x-ejs', [fromName['text']]);
addType('application/x-httpd-php', [fromName['text']]);
addType('application/x-httpd-php-open', [fromName['text']]);
addType('application/x-jsp', [fromName['text']]);
addType('application/x-sparql-query', [fromName['text']]);
addType('application/xml', [fromName['text']]);
addType('application/xquery', [fromName['text']]);
addType('text/css', [fromName['text']]);
addType('text/html', [fromName['text']]);
addType('text/javascript', [fromName['text']]);
addType('text/n-triples', [fromName['text']]);
addType('text/tiki', [fromName['text']]);
addType('text/vbscript', [fromName['text']]);
addType('text/velocity', [fromName['text']]);
addType('text/x-c++src', [fromName['text']]);
addType('text/x-clojure', [fromName['text']]);
addType('text/x-coffeescript', [fromName['text']]);
addType('text/x-csharp', [fromName['text']]);
addType('text/x-csrc', [fromName['text']]);
addType('text/x-diff', [fromName['text']]);
addType('text/x-ecl', [fromName['text']]);
addType('text/x-erlang', [fromName['text']]);
addType('text/x-go', [fromName['text']]);
addType('text/x-groovy', [fromName['text']]);
addType('text/x-haskell', [fromName['text']]);
addType('text/x-ini', [fromName['text']]);
addType('text/x-java', [fromName['text']]);
addType('text/x-less', [fromName['text']]);
addType('text/x-lua', [fromName['text']]);
addType('text/x-markdown', [fromName['text']]);
addType('text/x-mysql', [fromName['text']]);
addType('text/x-pascal', [fromName['text']]);
addType('text/x-perl', [fromName['text']]);
addType('text/x-php', [fromName['text']]);
addType('text/x-pig', [fromName['text']]);
addType('text/x-plsql', [fromName['text']]);
addType('text/x-properties', [fromName['text']]);
addType('text/x-python', [fromName['text']]);
addType('text/x-rpm-changes', [fromName['text']]);
addType('text/x-rpm-spec', [fromName['text']]);
addType('text/x-rsrc', [fromName['text']]);
addType('text/x-rst', [fromName['text']]);
addType('text/x-ruby', [fromName['text']]);
addType('text/x-rustsrc', [fromName['text']]);
addType('text/x-scheme', [fromName['text']]);
addType('text/x-sh', [fromName['text']]);
addType('text/x-smarty', [fromName['text']]);
addType('text/x-stex', [fromName['text']]);
addType('text/x-stsrc', [fromName['text']]);
addType('text/x-tiddlywiki', [fromName['text']]);
addType('text/x-verilog', [fromName['text']]);
addType('text/x-yaml', [fromName['text']]);

// Get the type associated to the extention of the file.
//
function guessType (vpath, cb) {
  var npath = driver.normalize(vpath);
  nodefs.stat(driver.relative(npath), function (err, stats) {
    if (err) {
      cb(err);
      return;
    }
    if (stats.isDirectory()) {
      cb(null, fromName['dir']);
    } else if (stats.isFile()) {
      cb(null, fromName[
          mime[nodepath.extname(npath).slice(1)] || 'text'
      ]);
    } else {
      cb(new Error("File is neither a directory, nor a file."));
    }
  });
};

// Driver access.

var drivers = [];  // Sparse array from types to I/O primitives.

for (var prims in driver.primitives) {
  drivers[fromName[prims]] = driver.primitives[prims];
}

// This is not cycle-aware.
// Do not create loops in the type system.
function findDriver(type) {
  var driver;
  if (driver = drivers[type]) {
    return driver;  // There is a driver for this type.
  } else if (fallbacks[type]) {
    for (var i = 0; i < fallbacks[type].length; i++) {
      if (driver = findDriver(fallbacks[type][i])) {
        return driver;
      }
    }
  }
  console.error("Type:findDriver: cannot find driver of type %s.",
      nameFromType[type]);
  return null;
}

// We export the following:
//
// - addType(mimeType :: String, parents :: Array)
// - fromName: Map from mime types (String) to type number
// - nameFromType: Array of all types in order
// - isCompatible(type :: Number, ancestor :: Number)
// - guessType(vpath :: String, cb :: Function)
// - driver(type :: Number)

exports.addType = addType;
exports.fromName = fromName;
exports.nameFromType = nameFromType;
exports.isCompatible = isCompatible;
exports.guessType = guessType;
exports.driver = findDriver;

<|endoftext|>


<commit_before>'use strict';

module.exports = Typo;

var substitute = require('./runtime');
var Stream = require('stream');
var util = require('util');

function mix (receiver, supplier, override){
    var key;

    if(arguments.length === 2){
        override = true;
    }

    for(key in supplier){
        if(override || !(key in receiver)){
            receiver[key] = supplier[key]
        }
    }

    return receiver;
}

util.inherits(Typo, Stream);

// @param {Object} options
// - output: {Stream.Writeable}
// - clean: {boolean} if true, typo will not output SGR charactors
function Typo (options) {
    options = options || {};

    this.clean = options.clean;
    this._helpers = new Typo.Helpers();

    var output = options.output;

    output && this.pipe(output);
};

Typo.prototype.write = function (value) {

    // prevent error of `process.stdout`
    this.emit('data', String(value));
};

Typo.prototype.log = function (template, params, callback) {
    var self = this;

    this.template(template, params, function(err, value) {
        if(err){
            return callback && callback(err);
        }

        self.write(value);

        callback && callback(null, value);
    });
};

Typo.prototype.template = function (template, params, callback) {
    if(arguments.length === 2 && typeof params === 'function'){
        callback = params;
        params = {};
    }

    var self = this;

    return substitute(template, params, this._helpers, function (err, value) {
        if(callback){
            if(err){
                return callback(err);
            }

            callback(null, self._clean(value));
        }
    });
};

// Register a helper function or register several helpers
// @param {string} pattern
// @param {function(value[, callback])} parser
//    - value: {mixed}
//  - callback: {function(err, value)} if there's `callback` arguemtn in parser, `parser` will be considered as an asynchronous method
//        - err: {Object} error object
//        - value: {mixed} parsed value
// @param {boolean=} override
Typo.prototype.register = function(pattern, parser) {
    Typo._register(this._helpers, pattern, parser);
};

// Register a typo plugin
Typo.prototype.plugin = function(plugin) {
    this.register(plugin.helpers);
};

Typo._register = function (host, pattern, parser){
    if(Object(pattern) === pattern){
        var patterns = pattern;

        for(pattern in patterns){
            parser = patterns[pattern];
            Typo._register(host, pattern, parser);
        }

    }else if(typeof pattern === 'string' && typeof parser === 'function'){
        if( !(pattern in host) ){
            host[pattern] = parser;
        }
    }
};

// var REGEX_SUFFIX = /\x1B\[\d+m$/i;

// foreground   : '\x1b[38;5;<cgr>m';
// background   : '\x1b[48;5;<cgr>m';
// normal cgr   : '\x1b[<cgr>m'
// suffix       : '\x1b[\d+m'
var REGEX_CGR = /\x1B\[(?:\d+;)*\d+m/ig;

Typo.prototype._clean = function (string) {
    return this.clean ? string.replace(REGEX_CGR, '') : string;
};

function Helpers(){};

// register ansi helpers
mix(Helpers.prototype, require('./helper/cgr'));

Typo.Helpers = Helpers;

<commit_msg>fixes #2: fix a bug that could not disable styling when using sync template method<commit_after>'use strict';

module.exports = Typo;

var substitute = require('./runtime');
var Stream = require('stream');
var util = require('util');

function mix (receiver, supplier, override){
    var key;

    if(arguments.length === 2){
        override = true;
    }

    for(key in supplier){
        if(override || !(key in receiver)){
            receiver[key] = supplier[key]
        }
    }

    return receiver;
}

util.inherits(Typo, Stream);

// @param {Object} options
// - output: {Stream.Writeable}
// - clean: {boolean} if true, typo will not output SGR charactors
function Typo (options) {
    options = options || {};

    this.clean = options.clean;
    this._helpers = new Typo.Helpers();

    var output = options.output;

    output && this.pipe(output);
};

Typo.prototype.write = function (value) {

    // prevent error of `process.stdout`
    this.emit('data', String(value));
};

Typo.prototype.log = function (template, params, callback) {
    var self = this;

    this.template(template, params, function(err, value) {
        if(err){
            return callback && callback(err);
        }

        self.write(value);

        callback && callback(null, value);
    });
};

Typo.prototype.template = function (template, params, callback) {
    if(arguments.length === 2 && typeof params === 'function'){
        callback = params;
        params = {};
    }

    var self = this;

    var value = substitute(template, params, this._helpers, function (err, value) {
        if(callback){
            if(err){
                return callback(err);
            }

            callback(null, self._clean(value));
        }
    });

    return this._clean(value);
};

// Register a helper function or register several helpers
// @param {string} pattern
// @param {function(value[, callback])} parser
//    - value: {mixed}
//  - callback: {function(err, value)} if there's `callback` arguemtn in parser, `parser` will be considered as an asynchronous method
//        - err: {Object} error object
//        - value: {mixed} parsed value
// @param {boolean=} override
Typo.prototype.register = function(pattern, parser) {
    Typo._register(this._helpers, pattern, parser);
};

// Register a typo plugin
Typo.prototype.plugin = function(plugin) {
    this.register(plugin.helpers);
};

Typo._register = function (host, pattern, parser){
    if(Object(pattern) === pattern){
        var patterns = pattern;

        for(pattern in patterns){
            parser = patterns[pattern];
            Typo._register(host, pattern, parser);
        }

    }else if(typeof pattern === 'string' && typeof parser === 'function'){
        if( !(pattern in host) ){
            host[pattern] = parser;
        }
    }
};

// var REGEX_SUFFIX = /\x1B\[\d+m$/i;

// foreground   : '\x1b[38;5;<cgr>m';
// background   : '\x1b[48;5;<cgr>m';
// normal cgr   : '\x1b[<cgr>m'
// suffix       : '\x1b[\d+m'
var REGEX_CGR = /\x1B\[(?:\d+;)*\d+m/ig;

Typo.prototype._clean = function (subject) {
    return this.clean ? subject && subject.replace(REGEX_CGR, '') : subject;
};

function Helpers(){};

// register ansi helpers
mix(Helpers.prototype, require('./helper/cgr'));

Typo.Helpers = Helpers;

<|endoftext|>