<commit_before>/*
 * stylestats
 * https://github.com/t32k/stylestats
 *
 * Copyright (c) 2014
 * Licensed under the MIT license.
 */

'use strict';

var _ = require('underscore');
var fs = require('fs');
var path = require('path');
var glob = require('glob');
var gzipSize = require('gzip-size');
var request = require('request');
var Promise = require('promise');
var cssParse = require('css-parse');

var util = require('./util');

/**
 * StyleStats class
 * @param args
 * @param config
 * @constructor
 */
function StyleStats(args, config) {

    var that = this;
    var URL = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/;

    args = Array.isArray(args) ? args : [args];

    this.urls = [];
    this.files = [];

    // check arguments which is url or file path or other
    args.forEach(function(arg) {
        if (util.isFile(arg) && path.extname === '.css') {
            that.files.push(arg);
        } else if (util.isDirectory(arg)) {
            fs.readdirSync(arg).filter(function(file) {
                return (path.extname(file) === '.css');
            }).forEach(function(file) {
                that.files.push(arg + file);
            });
        } else if (URL.test(arg) && path.extname(arg).indexOf('.css') > -1) {
            that.urls.push(arg);
        } else {
            glob.sync(arg).filter(function(file) {
                return (path.extname(file) === '.css');
            }).forEach(function(file) {
                that.files.push(file);
            });
        }
    });

    // all of css string
    this.cssString = '';

    // css string array from arguments
    // they will be joined into css string
    this.styles = [];

    // array of rule
    // referenced in analyzeRules
    this.rules = [];

    // array of css selector
    // referenced in analyzeSelectors
    this.selectors = [];

    // array of css declaration
    // referenced in analyzeDeclarations
    this.declarations = [];

    var defaultOptions = require('./default.json');
    var customOptions = {};
    if (config && util.isFile(config)) {
        var configString = fs.readFileSync(config, {
            encoding: "utf-8"
        });
        try {
            customOptions = JSON.parse(configString);
        } catch (e) {
            throw e;
        }
    } else if (_.isObject(config)) {
        customOptions = config;
    }
    this.options = _.extend({}, defaultOptions, customOptions);
}

/**
 * Analyze rules
 * @returns {
 *   cssDeclarations: Array
 * }
 */
StyleStats.prototype.analyzeRules = function () {
    var result = {
        cssDeclarations: []
    };
    this.rules.forEach(function(rule) {
        if (Array.isArray(rule.declarations)) {
            result.cssDeclarations.push({
                selector: rule.selectors,
                count: rule.declarations.length
            });
        }
    });
    result.cssDeclarations.sort(function decreasingOrder(a, b) {
        return b.count - a.count;
    });
    return result;
};

/**
 * Analyze selectors
 * @returns {
 *   idSelectors: number,
 *   universalSelectors: number,
 *   unqualifiedAttributeSelectors: number,
 *   javascriptSpecificSelectors: number,
 *   identifiers: Array}
 * }
 */
StyleStats.prototype.analyzeSelectors = function() {
    var regexp = new RegExp(this.options.javascriptSpecificSelectors, 'g');
    var result = {
        idSelectors: 0,
        universalSelectors: 0,
        unqualifiedAttributeSelectors: 0,
        javascriptSpecificSelectors: 0,
        identifiers: []
    };
    this.selectors.forEach(function(selector) {
        if (selector.indexOf('#') > -1) {
            result.idSelectors += 1;
        }
        if (selector.indexOf('*') > -1) {
            result.universalSelectors += 1;
        }
        if (selector.trim().match(/\[.+\]$/g)) {
            result.unqualifiedAttributeSelectors += 1;
        }
        if (regexp.test(selector.trim())) {
            result.javascriptSpecificSelectors += 1;
        }
        var trimedSelector = selector.replace(/\s?([\>|\+|\~])\s?/g, '$1');
        trimedSelector = trimedSelector.replace(/\s+/g, ' ');
        var count = trimedSelector.split(/\s|\>|\+|\~/).length;
        result.identifiers.push({
            selector: selector,
            count: count
        });
    });
    result.identifiers.sort(function decreasingOrder(a, b) {
        return b.count - a.count;
    });
    return result;
};

/**
 * Analyze declarations
 * @returns {
 *   dataUriSize: string,
 *   importantKeywords: number,
 *   floatProperties: number,
 *   uniqueFontSize: Array,
 *   uniqueColor: Array,
 *   properties: {}
 * }
 */
StyleStats.prototype.analyzeDeclarations = function() {
    var result = {
        dataUriSize: '',
        importantKeywords: 0,
        floatProperties: 0,
        uniqueFontSize: [],
        uniqueColor: [],
        properties: {}
    };
    this.declarations.forEach(function(declaration) {
        if (declaration.value.indexOf('data:image') > -1) {
            result.dataUriSize += declaration.value.match(/data\:image\/[A-Za-z0-9;,\+\=\/]+/);
        }
        if (declaration.value.indexOf('!important') > -1) {
            result.importantKeywords += 1;
        }
        if (declaration.property.indexOf('float') > -1) {
            result.floatProperties += 1;
        }
        if (declaration.property.indexOf('font-size') > -1) {
            result.uniqueFontSize.push(declaration.value.replace(/\!important/, '').trim());
        }
        if (declaration.property.match(/^color$/)) {
            var color = declaration.value.replace(/\!important/, '');
            color = color.toUpperCase().trim();
            result.uniqueColor.push(color);
        }
        if (result.properties[declaration.property]) {
            result.properties[declaration.property] += 1;
        } else {
            result.properties[declaration.property] = 1;
        }

    });
    // Return byte size.
    result.dataUriSize = Buffer.byteLength(result.dataUriSize, 'utf8');
    // Sort `font-size` property.
    result.uniqueFontSize = _.sortBy(_.uniq(result.uniqueFontSize).slice(), function(item) {
        return item.replace(/[^0-9\.]/g, '') - 0;
    });
    // Sort `color` property.
    result.uniqueColor = _.sortBy(_.uniq(_.without(result.uniqueColor, 'TRANSPARENT')));
    // Sort propertie count.
    var propertiesCount = [];
    Object.keys(result.properties).forEach(function(key) {
        propertiesCount.push({
            property: key,
            count: result.properties[key]
        });
    });
    result.properties = propertiesCount.sort(function decreasingOrder(a, b) {
        return b.count - a.count;
    });
    return result;
};

/**
 * Parse css
 * @param {Function} callback
 */
StyleStats.prototype.parse = function(callback) {

    var that = this;
    var requestPromises = [];

    this.urls.forEach(function(url) {
        requestPromises.push(requestSync(url));
    });
    this.files.forEach(function(file) {
        that.styles.push(fs.readFileSync(file, {
            encoding: "utf-8"
        }));
    });

    Promise.all(requestPromises).done(function onFulfilled(value) {
        that.styles.push(value.join(''));
        that.cssString = that.styles.join('');
        that.cssSize = Buffer.byteLength(that.cssString, 'utf8');

        var rawRules = cssParse(that.cssString).stylesheet.rules;
        var mediaQueries = 0;

        rawRules.forEach(function(rule) {
            if (rule.type === 'rule') {
                that.rules.push(rule);
            } else if (rule.type === 'media') {
                mediaQueries += 1;
                rule.rules.forEach(function(rule) {
                    if (rule.type === 'rule') {
                        that.rules.push(rule);
                    }
                });
            }
        });

        that.rules.forEach(function (rule) {
            rule.selectors.forEach(function(selector) {
                that.selectors.push(selector);
            });
            rule.declarations.forEach(function(declaration) {
                if (declaration.type === 'declaration') {
                    that.declarations.push(declaration);
                }
            });
        });

        var ruleAnalysis = that.analyzeRules();
        var selectorAnalysis = that.analyzeSelectors();
        var declarationAnalysis = that.analyzeDeclarations();

        var stats = {};
        var options = that.options;

        stats.published = new Date();
        stats.paths = [];
        Array.prototype.push.apply(stats.paths, that.files);
        Array.prototype.push.apply(stats.paths, that.urls);

        if (options.stylesheets) {
            stats.stylesheets = that.files.length + that.urls.length;
        }
        if (options.size) {
            stats.size = that.cssSize;
        }
        if (options.dataUriSize) {
            stats.dataUriSize = declarationAnalysis.dataUriSize;
        }
        if (options.dataUriSize && options.ratioOfDataUriSize && declarationAnalysis.dataUriSize !== 0) {
            stats.ratioOfDataUriSize = declarationAnalysis.dataUriSize / that.cssSize;
        }
        if (options.gzippedSize) {
            stats.gzippedSize = gzipSize.sync(that.cssString);
        }
        if (options.rules) {
            stats.rules = that.rules.length;
        }
        if (options.selectors) {
            stats.selectors = that.selectors.length;
        }
        if (options.rules && options.selectors && options.simplicity) {
            stats.simplicity = stats.rules / stats.selectors;
        }
        // Most Identifier
        var mostIdentifier = selectorAnalysis.identifiers.shift();
        if (mostIdentifier && options.mostIdentifier) {
            stats.mostIdentifier = mostIdentifier.count;
        }
        if (mostIdentifier && options.mostIdentifierSelector) {
            stats.mostIdentifierSelector = mostIdentifier.selector;
        }
        var lowestDefinition = ruleAnalysis.cssDeclarations.shift();
        if (lowestDefinition && options.lowestCohesion) {
            stats.lowestCohesion = lowestDefinition.count;
        }
        if (lowestDefinition && options.lowestCohesionSelector) {
            stats.lowestCohesionSelector = lowestDefinition.selector;
        }
        if (options.totalUniqueFontSizes) {
            stats.totalUniqueFontSizes = declarationAnalysis.uniqueFontSize.length;
        }
        if (options.uniqueFontSize) {
            stats.uniqueFontSize = declarationAnalysis.uniqueFontSize;
        }
        if (options.totalUniqueColors) {
            stats.totalUniqueColors = declarationAnalysis.uniqueColor.length;
        }
        if (options.uniqueColor) {
            stats.uniqueColor = declarationAnalysis.uniqueColor;
        }
        if (options.idSelectors) {
            stats.idSelectors = selectorAnalysis.idSelectors;
        }
        if (options.universalSelectors) {
            stats.universalSelectors = selectorAnalysis.universalSelectors;
        }
        if (options.unqualifiedAttributeSelectors) {
            stats.unqualifiedAttributeSelectors = selectorAnalysis.unqualifiedAttributeSelectors;
        }
        if (options.javascriptSpecificSelectors) {
            stats.javascriptSpecificSelectors = selectorAnalysis.javascriptSpecificSelectors;
        }
        if (options.importantKeywords) {
            stats.importantKeywords = declarationAnalysis.importantKeywords;
        }
        if (options.floatProperties) {
            stats.floatProperties = declarationAnalysis.floatProperties;
        }
        if (options.mediaQueries) {
            stats.mediaQueries = mediaQueries;
        }
        if (options.propertiesCount) {
            stats.propertiesCount = declarationAnalysis.properties.slice(0, options.propertiesCount);
        }
        if (_.isFunction(callback)) {
            callback(null, stats);
        }
    }, function onRejected(error) {
        if (_.isFunction(callback)) {
            callback(error, null);
        }
    });
};

function requestSync(url) {
    return new Promise(function(resolve, reject) {
        request(url, function(error, response, body) {
            if (!error && response.statusCode === 200) {
                resolve(body);
            } else if (!error) {
                reject('Status code is ' + response.statusCode);
            } else {
                reject(error);
            }
        });
    });
}

module.exports = StyleStats;<commit_msg>Change defined function lines<commit_after>/*
 * stylestats
 * https://github.com/t32k/stylestats
 *
 * Copyright (c) 2014
 * Licensed under the MIT license.
 */

'use strict';

var _ = require('underscore');
var fs = require('fs');
var path = require('path');
var glob = require('glob');
var gzipSize = require('gzip-size');
var request = require('request');
var Promise = require('promise');
var cssParse = require('css-parse');

var util = require('./util');

function requestSync(url) {
    return new Promise(function(resolve, reject) {
        request(url, function(error, response, body) {
            if (!error && response.statusCode === 200) {
                resolve(body);
            } else if (!error) {
                reject('Status code is ' + response.statusCode);
            } else {
                reject(error);
            }
        });
    });
}

/**
 * StyleStats class
 * @param args
 * @param config
 * @constructor
 */
function StyleStats(args, config) {

    var that = this;
    var URL = /((([A-Za-z]{3,9}:(?:\/\/)?)(?:[-;:&=\+\$,\w]+@)?[A-Za-z0-9.-]+|(?:www.|[-;:&=\+\$,\w]+@)[A-Za-z0-9.-]+)((?:\/[\+~%\/.\w-_]*)?\??(?:[-\+=&;%@.\w_]*)#?(?:[\w]*))?)/;

    args = Array.isArray(args) ? args : [args];

    this.urls = [];
    this.files = [];

    // check arguments which is url or file path or other
    args.forEach(function(arg) {
        if (util.isFile(arg) && path.extname === '.css') {
            that.files.push(arg);
        } else if (util.isDirectory(arg)) {
            fs.readdirSync(arg).filter(function(file) {
                return (path.extname(file) === '.css');
            }).forEach(function(file) {
                that.files.push(arg + file);
            });
        } else if (URL.test(arg) && path.extname(arg).indexOf('.css') > -1) {
            that.urls.push(arg);
        } else {
            glob.sync(arg).filter(function(file) {
                return (path.extname(file) === '.css');
            }).forEach(function(file) {
                that.files.push(file);
            });
        }
    });

    // all of css string
    this.cssString = '';

    // css string array from arguments
    // they will be joined into css string
    this.styles = [];

    // array of rule
    // referenced in analyzeRules
    this.rules = [];

    // array of css selector
    // referenced in analyzeSelectors
    this.selectors = [];

    // array of css declaration
    // referenced in analyzeDeclarations
    this.declarations = [];

    var defaultOptions = require('./default.json');
    var customOptions = {};
    if (config && util.isFile(config)) {
        var configString = fs.readFileSync(config, {
            encoding: "utf-8"
        });
        try {
            customOptions = JSON.parse(configString);
        } catch (e) {
            throw e;
        }
    } else if (_.isObject(config)) {
        customOptions = config;
    }
    this.options = _.extend({}, defaultOptions, customOptions);
}

/**
 * Analyze rules
 * @returns {
 *   cssDeclarations: Array
 * }
 */
StyleStats.prototype.analyzeRules = function() {
    var result = {
        cssDeclarations: []
    };
    this.rules.forEach(function(rule) {
        if (Array.isArray(rule.declarations)) {
            result.cssDeclarations.push({
                selector: rule.selectors,
                count: rule.declarations.length
            });
        }
    });
    result.cssDeclarations.sort(function decreasingOrder(a, b) {
        return b.count - a.count;
    });
    return result;
};

/**
 * Analyze selectors
 * @returns {
 *   idSelectors: number,
 *   universalSelectors: number,
 *   unqualifiedAttributeSelectors: number,
 *   javascriptSpecificSelectors: number,
 *   identifiers: Array}
 * }
 */
StyleStats.prototype.analyzeSelectors = function() {
    var regexp = new RegExp(this.options.javascriptSpecificSelectors, 'g');
    var result = {
        idSelectors: 0,
        universalSelectors: 0,
        unqualifiedAttributeSelectors: 0,
        javascriptSpecificSelectors: 0,
        identifiers: []
    };
    this.selectors.forEach(function(selector) {
        if (selector.indexOf('#') > -1) {
            result.idSelectors += 1;
        }
        if (selector.indexOf('*') > -1) {
            result.universalSelectors += 1;
        }
        if (selector.trim().match(/\[.+\]$/g)) {
            result.unqualifiedAttributeSelectors += 1;
        }
        if (regexp.test(selector.trim())) {
            result.javascriptSpecificSelectors += 1;
        }
        var trimedSelector = selector.replace(/\s?([\>|\+|\~])\s?/g, '$1');
        trimedSelector = trimedSelector.replace(/\s+/g, ' ');
        var count = trimedSelector.split(/\s|\>|\+|\~/).length;
        result.identifiers.push({
            selector: selector,
            count: count
        });
    });
    result.identifiers.sort(function decreasingOrder(a, b) {
        return b.count - a.count;
    });
    return result;
};

/**
 * Analyze declarations
 * @returns {
 *   dataUriSize: string,
 *   importantKeywords: number,
 *   floatProperties: number,
 *   uniqueFontSize: Array,
 *   uniqueColor: Array,
 *   properties: {}
 * }
 */
StyleStats.prototype.analyzeDeclarations = function() {
    var result = {
        dataUriSize: '',
        importantKeywords: 0,
        floatProperties: 0,
        uniqueFontSize: [],
        uniqueColor: [],
        properties: {}
    };
    this.declarations.forEach(function(declaration) {
        if (declaration.value.indexOf('data:image') > -1) {
            result.dataUriSize += declaration.value.match(/data\:image\/[A-Za-z0-9;,\+\=\/]+/);
        }
        if (declaration.value.indexOf('!important') > -1) {
            result.importantKeywords += 1;
        }
        if (declaration.property.indexOf('float') > -1) {
            result.floatProperties += 1;
        }
        if (declaration.property.indexOf('font-size') > -1) {
            result.uniqueFontSize.push(declaration.value.replace(/\!important/, '').trim());
        }
        if (declaration.property.match(/^color$/)) {
            var color = declaration.value.replace(/\!important/, '');
            color = color.toUpperCase().trim();
            result.uniqueColor.push(color);
        }
        if (result.properties[declaration.property]) {
            result.properties[declaration.property] += 1;
        } else {
            result.properties[declaration.property] = 1;
        }

    });
    // Return byte size.
    result.dataUriSize = Buffer.byteLength(result.dataUriSize, 'utf8');
    // Sort `font-size` property.
    result.uniqueFontSize = _.sortBy(_.uniq(result.uniqueFontSize).slice(), function(item) {
        return item.replace(/[^0-9\.]/g, '') - 0;
    });
    // Sort `color` property.
    result.uniqueColor = _.sortBy(_.uniq(_.without(result.uniqueColor, 'TRANSPARENT')));
    // Sort propertie count.
    var propertiesCount = [];
    Object.keys(result.properties).forEach(function(key) {
        propertiesCount.push({
            property: key,
            count: result.properties[key]
        });
    });
    result.properties = propertiesCount.sort(function decreasingOrder(a, b) {
        return b.count - a.count;
    });
    return result;
};

/**
 * Parse css
 * @param {Function} callback
 */
StyleStats.prototype.parse = function(callback) {

    var that = this;
    var requestPromises = [];

    this.urls.forEach(function(url) {
        requestPromises.push(requestSync(url));
    });
    this.files.forEach(function(file) {
        that.styles.push(fs.readFileSync(file, {
            encoding: "utf-8"
        }));
    });

    Promise.all(requestPromises).done(function onFulfilled(value) {
        that.styles.push(value.join(''));
        that.cssString = that.styles.join('');
        that.cssSize = Buffer.byteLength(that.cssString, 'utf8');

        var rawRules = cssParse(that.cssString).stylesheet.rules;
        var mediaQueries = 0;

        rawRules.forEach(function(rule) {
            if (rule.type === 'rule') {
                that.rules.push(rule);
            } else if (rule.type === 'media') {
                mediaQueries += 1;
                rule.rules.forEach(function(rule) {
                    if (rule.type === 'rule') {
                        that.rules.push(rule);
                    }
                });
            }
        });

        that.rules.forEach(function(rule) {
            rule.selectors.forEach(function(selector) {
                that.selectors.push(selector);
            });
            rule.declarations.forEach(function(declaration) {
                if (declaration.type === 'declaration') {
                    that.declarations.push(declaration);
                }
            });
        });

        var ruleAnalysis = that.analyzeRules();
        var selectorAnalysis = that.analyzeSelectors();
        var declarationAnalysis = that.analyzeDeclarations();

        var stats = {};
        var options = that.options;

        stats.published = new Date();
        stats.paths = [];
        Array.prototype.push.apply(stats.paths, that.files);
        Array.prototype.push.apply(stats.paths, that.urls);

        if (options.stylesheets) {
            stats.stylesheets = that.files.length + that.urls.length;
        }
        if (options.size) {
            stats.size = that.cssSize;
        }
        if (options.dataUriSize) {
            stats.dataUriSize = declarationAnalysis.dataUriSize;
        }
        if (options.dataUriSize && options.ratioOfDataUriSize && declarationAnalysis.dataUriSize !== 0) {
            stats.ratioOfDataUriSize = declarationAnalysis.dataUriSize / that.cssSize;
        }
        if (options.gzippedSize) {
            stats.gzippedSize = gzipSize.sync(that.cssString);
        }
        if (options.rules) {
            stats.rules = that.rules.length;
        }
        if (options.selectors) {
            stats.selectors = that.selectors.length;
        }
        if (options.rules && options.selectors && options.simplicity) {
            stats.simplicity = stats.rules / stats.selectors;
        }
        // Most Identifier
        var mostIdentifier = selectorAnalysis.identifiers.shift();
        if (mostIdentifier && options.mostIdentifier) {
            stats.mostIdentifier = mostIdentifier.count;
        }
        if (mostIdentifier && options.mostIdentifierSelector) {
            stats.mostIdentifierSelector = mostIdentifier.selector;
        }
        var lowestDefinition = ruleAnalysis.cssDeclarations.shift();
        if (lowestDefinition && options.lowestCohesion) {
            stats.lowestCohesion = lowestDefinition.count;
        }
        if (lowestDefinition && options.lowestCohesionSelector) {
            stats.lowestCohesionSelector = lowestDefinition.selector;
        }
        if (options.totalUniqueFontSizes) {
            stats.totalUniqueFontSizes = declarationAnalysis.uniqueFontSize.length;
        }
        if (options.uniqueFontSize) {
            stats.uniqueFontSize = declarationAnalysis.uniqueFontSize;
        }
        if (options.totalUniqueColors) {
            stats.totalUniqueColors = declarationAnalysis.uniqueColor.length;
        }
        if (options.uniqueColor) {
            stats.uniqueColor = declarationAnalysis.uniqueColor;
        }
        if (options.idSelectors) {
            stats.idSelectors = selectorAnalysis.idSelectors;
        }
        if (options.universalSelectors) {
            stats.universalSelectors = selectorAnalysis.universalSelectors;
        }
        if (options.unqualifiedAttributeSelectors) {
            stats.unqualifiedAttributeSelectors = selectorAnalysis.unqualifiedAttributeSelectors;
        }
        if (options.javascriptSpecificSelectors) {
            stats.javascriptSpecificSelectors = selectorAnalysis.javascriptSpecificSelectors;
        }
        if (options.importantKeywords) {
            stats.importantKeywords = declarationAnalysis.importantKeywords;
        }
        if (options.floatProperties) {
            stats.floatProperties = declarationAnalysis.floatProperties;
        }
        if (options.mediaQueries) {
            stats.mediaQueries = mediaQueries;
        }
        if (options.propertiesCount) {
            stats.propertiesCount = declarationAnalysis.properties.slice(0, options.propertiesCount);
        }
        if (_.isFunction(callback)) {
            callback(null, stats);
        }
    }, function onRejected(error) {
        if (_.isFunction(callback)) {
            callback(error, null);
        }
    });
};

module.exports = StyleStats;<|endoftext|>


<commit_before>// Prepares request environment (`this` context of server methods/filters).

'use strict';

var _       = require('lodash');
var Puncher = require('puncher');

////////////////////////////////////////////////////////////////////////////////

var DEFAULT_HTTP_PORT  = 80;
var DEFAULT_HTTPS_PORT = 443;

// Finds the most appropriate server binding in config, by ApiPath.
// Probably, can be cached (if use _.memoize, swap params first)
//
function findServerSocketConfig(N, apiPath) {
  var splitted = apiPath.split('.'), bind;

  // Reduce apiPath looking for matching binds.
  while (!_.isEmpty(splitted)) {
    bind = N.config.bind[splitted.join('.')];

    if (bind) {
      return bind; // Found.
    }

    splitted.pop();
  }

  return N.config.bind['default'] || null;
}

// Resolve full phrase path
//
function resolveI18nPath(path, _self) {
  if (path.charAt(0) === '@') {
    // absolute
    return path.slice(1);
  }
  // relative
  return _self.method + '.' + path;
}

////////////////////////////////////////////////////////////////////////////////
// Env helpers

var DEFAULT_HELPERS = {
  // Server and render helper closures.
  //
  set_layout: function set_layout_helper(layout) {
    this.res.layout = layout;
  },

  link_to: function link_to_helper(name, params) {
    return this.__N.router.linkTo(name, params) || '#';
  },

  // Constructs full URL using current env and N.config.bind
  //
  url_to: function url_to_helper(apiPath, params, linkDefaults) {
    // Reconstruct linkDefaults to prevent side-effects.
    linkDefaults = _.pick(linkDefaults || {}, 'protocol', 'hostname', 'port');

    // Detect protocol.
    if (!linkDefaults.protocol) {
      linkDefaults.protocol = this.req.isEncrypted ? 'https' : 'http';
    }

    // Detect hostname.
    if (!linkDefaults.hostname && this.origin.req.headers.host) {
      linkDefaults.hostname = this.origin.req.headers.host.split(':')[0];
    }

    var bind = findServerSocketConfig(this.__N, apiPath);

    // Detect port.
    if (bind && !linkDefaults.port) {
      if (linkDefaults.protocol === 'https') {
        // For encrypted HTTPS connection.
        linkDefaults.port = bind.ssl.listen.port;

        if (bind.ssl.forwarded || DEFAULT_HTTPS_PORT === bind.ssl.listen.port) {
          linkDefaults.port = null; // Do not set default port explicitly.
        }
      } else {
        // For plain HTTP connection.
        linkDefaults.port = bind.listen.port;

        if (bind.forwarded || DEFAULT_HTTP_PORT === bind.listen.port) {
          linkDefaults.port = null; // Do not set default port explicitly.
        }
      }
    }

    return this.__N.router.linkTo(apiPath, params, linkDefaults);
  },

  asset_path: function asset_path_helper(path) {
    var asset = this.__N.assets.manifest.assets[path];

    return asset ? this.__N.router.linkTo('core.assets', { path: asset }) : '#';
  },

  asset_include: function asset_include_helper(path) {
    var asset  = this.__N.assets.environment.findAsset(path),
        result = '';

    if (asset) {
      try {
        result = asset.toString();
      } catch (err) {
        this.__N.logger.error(
          'Failed inline asset %s:\n%s',
          path,
          err.stack || err.message || err
        );
      }
    }

    return result;
  },

  t: function translate_helper(phrase, params) {
    var locale = this.runtime.locale || this.__N.config.locales['default'];

    return this.__N.i18n.t(locale, phrase, params);
  },

  t_exists: function translate_exists_helper(phrase) {
    var locale = this.runtime.locale || this.__N.config.locales['default'];

    return this.__N.i18n.hasPhrase(locale, phrase);
  },

  add_raw_data: function add_raw_data_helper(key, data) {
    if (this.runtime.page_data.hasOwnProperty(key)) {
      this.__N.logger.warn('Override of %j key in env.runtime.page_data');
    }

    this.runtime.page_data[key] = data;
  }
};

////////////////////////////////////////////////////////////////////////////////

/**
 *  lib.env(options) -> Object
 *  - options (Object): Environment options.
 *
 *  Create new request environment object.
 *
 *
 *  ##### Options
 *
 *  - **http**: HTTP origin object that contains `req` and `res`.
 *  - **rpc**: API3 (Ajax) origin that contains `req` and `res`.
 *  - **skip**: Array of middlewares to skip
 *  - **session**: Session object
 *  - **locale**: Locale name as String
 *  - **method**: Name of the server method, e.g. `'forums.posts.show'`
 *  - **layout**: Layout name as String
 **/
function Env(N, options) {
  var self = this;

  // Private, for helpers
  this.__N = N;

  this.params   = options.params || {};
  this.method   = null;

  // Contains server chain response on success
  this.data     = {};

  // internal, to pass error from server chain to responders
  this.err      = null;
  // internal, rendered data
  this.body     = null;
  // internal, http status code (set in responders)
  this.status   = N.io.OK;
  // filled by formidable with `fields & `files` structures, for http POST requests
  this.post     = null;

  this.headers  = {};

  this.runtime  = {
    page_data: {}
  };

  var puncher = new Puncher();
  puncher.start('Total');

  this.extras   = {
    puncher: puncher,
    settings: {
      params: {},
      fetch: function fetchSettings(keys, callback) {
        N.settings.get(keys, this.params, {}, callback);
      }
    }
  };

  this.origin   = {
    req: options.req,
    res: options.res
  };

  this.session  = options.session || null;

  this.req      = {
    type:        options.type,
    isEncrypted: options.isEncrypted,
    ip:          options.remoteAddress,
    matched:     options.matched || null,
    tzOffset:    new Date().getTimezoneOffset() // use server tz by default
  };

  this.res      = {
    head: {
      title: null, // should be filled with default value

      // List of assets for yepnope,
      // Each element is an object with properties:
      //
      //    type:   css|js
      //    link:   asset_url
      //
      // example: assets.push({type: 'js', link: '//example.com/foo.js'});
      assets: []
    },
    menus: {},
    blocks: {}
  };

  this.log_request = function log_request_dummy() {};

  //
  // Pin helpers
  //

  this.helpers  = {};

  Object.keys(DEFAULT_HELPERS).forEach(function (h) {
    this.helpers[h] = DEFAULT_HELPERS[h].bind(this);
  }, this);

  this.helpers.t.exists = this.helpers.t_exists; // alias

  // Server-only helper closures.
  //
  this.t        = function translate_helper(phrase, params) {
    return self.helpers.t(resolveI18nPath(phrase, self), params);
  };

  this.t.exists = function translate_exists_helper(phrase) {
    return self.helpers.t_exists(resolveI18nPath(phrase, self));
  };
}

////////////////////////////////////////////////////////////////////////////////

module.exports = function createEnv(N, options) {
  return new Env(N, options);
};

module.exports.helpers = DEFAULT_HELPERS; // for modifications
<commit_msg>`env` partial cleanup<commit_after>// Prepares request environment (`this` context of server methods/filters).

'use strict';

var _       = require('lodash');
var Puncher = require('puncher');

////////////////////////////////////////////////////////////////////////////////

var DEFAULT_HTTP_PORT  = 80;
var DEFAULT_HTTPS_PORT = 443;

// Finds the most appropriate server binding in config, by ApiPath.
// Probably, can be cached (if use _.memoize, swap params first)
//
function findServerSocketConfig(N, apiPath) {
  var splitted = apiPath.split('.'), bind;

  // Reduce apiPath looking for matching binds.
  while (!_.isEmpty(splitted)) {
    bind = N.config.bind[splitted.join('.')];

    if (bind) {
      return bind; // Found.
    }

    splitted.pop();
  }

  return N.config.bind['default'] || null;
}

// Resolve full phrase path
//
function resolveI18nPath(path, _self) {
  if (path.charAt(0) === '@') {
    // absolute
    return path.slice(1);
  }
  // relative
  return _self.method + '.' + path;
}

////////////////////////////////////////////////////////////////////////////////
// Env helpers

var DEFAULT_INIT_HANDLERS = [];

var DEFAULT_HELPERS = {
  // Server and render helper closures.
  //
  set_layout: function set_layout_helper(layout) {
    this.res.layout = layout;
  },

  link_to: function link_to_helper(name, params) {
    return this.__N.router.linkTo(name, params) || '#';
  },

  // Constructs full URL using current env and N.config.bind
  //
  url_to: function url_to_helper(apiPath, params, linkDefaults) {
    // Reconstruct linkDefaults to prevent side-effects.
    linkDefaults = _.pick(linkDefaults || {}, 'protocol', 'hostname', 'port');

    // Detect protocol.
    if (!linkDefaults.protocol) {
      linkDefaults.protocol = this.req.isEncrypted ? 'https' : 'http';
    }

    // Detect hostname.
    if (!linkDefaults.hostname && this.origin.req.headers.host) {
      linkDefaults.hostname = this.origin.req.headers.host.split(':')[0];
    }

    var bind = findServerSocketConfig(this.__N, apiPath);

    // Detect port.
    if (bind && !linkDefaults.port) {
      if (linkDefaults.protocol === 'https') {
        // For encrypted HTTPS connection.
        linkDefaults.port = bind.ssl.listen.port;

        if (bind.ssl.forwarded || DEFAULT_HTTPS_PORT === bind.ssl.listen.port) {
          linkDefaults.port = null; // Do not set default port explicitly.
        }
      } else {
        // For plain HTTP connection.
        linkDefaults.port = bind.listen.port;

        if (bind.forwarded || DEFAULT_HTTP_PORT === bind.listen.port) {
          linkDefaults.port = null; // Do not set default port explicitly.
        }
      }
    }

    return this.__N.router.linkTo(apiPath, params, linkDefaults);
  },

  asset_path: function asset_path_helper(path) {
    var asset = this.__N.assets.manifest.assets[path];

    return asset ? this.__N.router.linkTo('core.assets', { path: asset }) : '#';
  },

  asset_include: function asset_include_helper(path) {
    var asset  = this.__N.assets.environment.findAsset(path),
        result = '';

    if (asset) {
      try {
        result = asset.toString();
      } catch (err) {
        this.__N.logger.error(
          'Failed inline asset %s:\n%s',
          path,
          err.stack || err.message || err
        );
      }
    }

    return result;
  },

  // ---------------------------------------------------------------------------
  // It's common to override this helpers. For example to take locale from
  // `env.current_user`, to don't touch `env.runtime`. That can be convenient if
  // you need to quickly subcall another server method with cloned env directly
  // (without wrappers).
  t: function translate_helper(phrase, params) {
    var locale = this.runtime.locale || this.__N.config.locales['default'];

    return this.__N.i18n.t(locale, phrase, params);
  },

  t_exists: function translate_exists_helper(phrase) {
    var locale = this.runtime.locale || this.__N.config.locales['default'];

    return this.__N.i18n.hasPhrase(locale, phrase);
  },
  // ---------------------------------------------------------------------------

  add_raw_data: function add_raw_data_helper(key, data) {
    if (this.runtime.page_data.hasOwnProperty(key)) {
      this.__N.logger.warn('Override of %j key in env.runtime.page_data');
    }

    this.runtime.page_data[key] = data;
  }
};

////////////////////////////////////////////////////////////////////////////////

/**
 *  lib.env(options) -> Object
 *  - options (Object): Environment options.
 *
 *  Create new request environment object.
 *
 *
 *  ##### Options
 *
 *  - **http**: HTTP origin object that contains `req` and `res`.
 *  - **rpc**: API3 (Ajax) origin that contains `req` and `res`.
 *  - **skip**: Array of middlewares to skip
 *  - **session**: Session object
 *  - **locale**: Locale name as String
 *  - **method**: Name of the server method, e.g. `'forums.posts.show'`
 *  - **layout**: Layout name as String
 **/
function Env(N, options) {
  var self = this;

  // Private, for helpers
  this.__N = N;

  this.params   = options.params || {};
  this.method   = null;

  // Contains server chain response on success
  this.data     = {};

  // internal, to pass error from server chain to responders
  this.err      = null;
  // internal, rendered data
  this.body     = null;
  // internal, http status code (set in responders)
  this.status   = N.io.OK;
  // filled by formidable with `fields & `files` structures, for http POST requests
  this.post     = null;

  this.headers  = {};

  this.runtime  = {
    page_data: {}
  };

  var puncher = new Puncher();
  puncher.start('Total');

  this.extras   = {
    puncher: puncher,
    settings: {
      params: {},
      fetch: function fetchSettings(keys, callback) {
        N.settings.get(keys, this.params, {}, callback);
      }
    }
  };

  this.origin   = {
    req: options.req,
    res: options.res
  };

  this.session  = options.session || null;

  this.req      = {
    type:        options.type,
    isEncrypted: options.isEncrypted,
    ip:          options.remoteAddress,
    matched:     options.matched || null,
    tzOffset:    new Date().getTimezoneOffset() // use server tz by default
  };

  this.res      = {
    head: {
      title: null, // should be filled with default value

      // List of assets for loader,
      // Each element is an object with properties:
      //
      //    type:   css|js
      //    link:   asset_url
      //
      // example: assets.push({type: 'js', link: '//example.com/foo.js'});
      assets: []
    },
    menus: {},
    blocks: {}
  };

  this.log_request = function log_request_dummy() {};

  // Pin helpers (those are shared with server methods and renderer)
  //
  this.helpers  = {};

  Object.keys(DEFAULT_HELPERS).forEach(function (h) {
    self.helpers[h] = DEFAULT_HELPERS[h].bind(self);
  });

  // TODO: remove this alias
  this.helpers.t.exists = function (phrase) {
    return self.helpers.t_exists(phrase);
  };

  // Server-only helper closures.
  //
  this.t        = function translate_helper(phrase, params) {
    return self.helpers.t(resolveI18nPath(phrase, self), params);
  };

  this.t.exists = function translate_exists_helper(phrase) {
    return self.helpers.t_exists(resolveI18nPath(phrase, self));
  };

  // Run initializers for complex things (nested properties).
  // For example - settings, cookies
  //
  DEFAULT_INIT_HANDLERS.forEach(function (i) {
    DEFAULT_INIT_HANDLERS[i](self);
  });
}

////////////////////////////////////////////////////////////////////////////////

module.exports = function createEnv(N, options) {
  return new Env(N, options);
};

// for modifications
module.exports.helpers      = DEFAULT_HELPERS;       // mixed to env & renderer
module.exports.initHandlers = DEFAULT_INIT_HANDLERS; // executed on `new`
<|endoftext|>


<commit_before>/**
@module bee
**/

/**
node任务
-------------
用node环境执行某段脚本

### 用法

    <node>
    //具有bee对象
    console.log(bee);
    console.log("hello");
    </node>

@class node
**/
module.exports = function(bee) {

  bee.register('node', function(options, callback) {
    var content = options.value;
    var vm = require('vm');
    vm.runInNewContext(content, {
      bee: bee
    });
  });
}<commit_msg>node task<commit_after>/**
@module bee
**/

/**
node任务
-------------
用node环境执行某段脚本

### 用法

    <node>
    //具有bee对象
    console.log(bee);
    console.log("hello");
    </node>

@class node
**/
module.exports = function(bee) {

  bee.register('node', function(options) {
    var content = options.value;
    var vm = require('vm');
    try{
      vm.runInNewContext(content, { bee: bee});
    }catch(err){
      bee.error(err);
    }
  });
}<|endoftext|>


<commit_before>'use strict';
var net = require('net');
var fs = require('fs');
var msgpack = require('msgpack-lite');

function MockFluentdServer(options) {
  var self = this;
  this._port = null;
  this._options = options;
  this._received = [];
  this._clients  = {};
  this._server = net.createServer(function(socket) {
    var clientKey = socket.remoteAddress + ":" + socket.remotePort;
    self._clients[clientKey] = socket;
    socket.on('end', function(){
      delete(self._clients[clientKey]);
    });
    var stream = msgpack.createDecodeStream();
    socket.pipe(stream).on('data', function(m) {
      self._received.push({
        tag: m[0],
        time: m[1],
        data: m[2],
        options: m[3]
      });
      var options = m[3];
      if (self._options.requireAckResponse && options && options.chunk) {
        var response = {
          ack: options.chunk
        };
        socket.write(msgpack.encode(response));
      }
    });
  });
}

MockFluentdServer.prototype.__defineGetter__('port', function() {
  return this._port;
});

MockFluentdServer.prototype.__defineGetter__('messages', function() {
  return this._received;
});

MockFluentdServer.prototype.listen = function(callback){
  var self = this;
  this._server.listen(function(){
    self._port = self._server.address().port;
    callback();
  });
};

MockFluentdServer.prototype.close = function(callback) {
  var self = this;
  this._server.close(function() {
    callback();
  });
  for (var i in self._clients) {
    self._clients[i].end();
    // self._clients[i].destroy();
  }
};

module.exports = {
  runServer: function(options, callback) {
    var server = new MockFluentdServer(options);
    server.listen(function() {
      callback(server, function(_callback) {
         // wait 100 ms to receive all messages and then close
         setTimeout(function() {
           var messages = server.messages;
           server.close(function() {
             _callback && _callback(messages);
           });
         }, 100);
       });
    });
  }
};
<commit_msg>Use arrow function to reduce `var self = this;` assignments<commit_after>'use strict';
var net = require('net');
var fs = require('fs');
var msgpack = require('msgpack-lite');

function MockFluentdServer(options) {
  this._port = null;
  this._options = options;
  this._received = [];
  this._clients  = {};
  this._server = net.createServer((socket) => {
    var clientKey = socket.remoteAddress + ":" + socket.remotePort;
    this._clients[clientKey] = socket;
    socket.on('end', () => {
      delete(this._clients[clientKey]);
    });
    var stream = msgpack.createDecodeStream();
    socket.pipe(stream).on('data', (m) => {
      this._received.push({
        tag: m[0],
        time: m[1],
        data: m[2],
        options: m[3]
      });
      var options = m[3];
      if (this._options.requireAckResponse && options && options.chunk) {
        var response = {
          ack: options.chunk
        };
        socket.write(msgpack.encode(response));
      }
    });
  });
}

MockFluentdServer.prototype.__defineGetter__('port', function() {
  return this._port;
});

MockFluentdServer.prototype.__defineGetter__('messages', function() {
  return this._received;
});

MockFluentdServer.prototype.listen = function(callback){
  this._server.listen(() => {
    this._port = this._server.address().port;
    callback();
  });
};

MockFluentdServer.prototype.close = function(callback) {
  this._server.close(function() {
    callback();
  });
  for (var i in this._clients) {
    this._clients[i].end();
    // this._clients[i].destroy();
  }
};

module.exports = {
  runServer: function(options, callback) {
    var server = new MockFluentdServer(options);
    server.listen(function() {
      callback(server, function(_callback) {
         // wait 100 ms to receive all messages and then close
         setTimeout(function() {
           var messages = server.messages;
           server.close(function() {
             _callback && _callback(messages);
           });
         }, 100);
       });
    });
  }
};
<|endoftext|>


<commit_before>"use strict";

// LIBRARY

const {Cu} = require("chrome");
const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);

const P = Object.getPrototypeOf;
//console.log('Debugger:', typeof Debugger, Object.getOwnPropertyNames(Debugger), Object.getOwnPropertyNames(P(Debugger)))

// Safer and more declarative replacement for resumption value
Debugger.Resumption = {
    return : function(value){
        return {return: value};
    },
    yield : function(value){
        return {yield: value};
    },
    throw : function(value){
        return {throw: value};
    },
    stop : null,
    continue : undefined
};

function allKeys(o){
    console.group()
    while(o !== null){
        console.log(Object.getOwnPropertyNames(o))
        o = P(o)
    }
    console.groupEnd()
}

function frameName(f){
    return f.type === 'call' ?
        f.callee.name || '(anonymous)':
        f.type ;
}

const getObjectId = (function(){
    var wm = new WeakMap();
    var id = 1;
    return function (frame){
        if(wm.has(frame))
            return wm.get(frame);
        else{
            wm.set(frame, id);
            return id++;
        }
    };
})();

function frameEnvIds(frame){
    var env = frame.environment;
    var ids = [];

    while(env){
        ids.push(getObjectId(env));
        env = env.parent;
    }

    console.log('environments of frame', frameName(frame), ':',ids.join(' → '));
}

Debugger.Object.prototype.toString = function(){
    var object = this;
    var jsonableCopy = {};
    //allKeys(this);

    object.getOwnPropertyNames().forEach(function(prop){
        var desc = object.getOwnPropertyDescriptor(prop);
        jsonableCopy[prop] = desc.value;
    });

    return JSON.stringify(jsonableCopy);
};
Debugger.Object.prototype.toJSON = Debugger.Object.prototype.toString;

function copyArguments(args){
    return Array.prototype.map.call(args, function(e){ return e;});
}

function toArgumentString(v){
    if(v === null)
        return 'null';
    if(typeof v === 'function')
        return 'function '+v.name;
    if(typeof v === 'object')
        return JSON.stringify(v); // useless. The object is a Debugger.Object
    if(typeof v === 'string')
        return "'"+v+"'";

    return String(v);
}

function completionThrowValueToString(t){
    if(t instanceof Debugger.Object){
        if(t.class === 'Error')
            return t.getOwnPropertyDescriptor('message').value;

        return String(t);
    }
    else
        return String(t);
}

module.exports = function trackStack(global){

    var doc = global.document;
    var console = global.console;

    var dbg = new Debugger(global);
    dbg.uncaughtExceptionHook = function(e){
        console.error('uncaughtExceptionHook', e, e.stack);
    };

    var frameData = [];
    var trackedError;

    function reinit(){
        frameData = [];
        trackedError = undefined;
    }

    function isCurrentlyTracking(){
        return frameData.length >= 1;
    }

    var uncaughtErrorFramePopHandler = (function(){

        return function(completionValue){
            var frame = this;
            //console.log('Leaving frame', frameName(frame), 'with completion value', completionValue);

            if('throw' in completionValue){
                var thrownValue = completionValue.throw;

                if(isCurrentlyTracking()){
                    if(!Object.is(trackedError, thrownValue)){
                        // a different error than the currently tracked is being thrown
                        reinit();
                        trackedError = thrownValue;
                    }
                }
                else{
                    trackedError = thrownValue;
                }

                frameData.push({
                    script : frame.script,
                    offset : frame.offset,
                    frameName : frameName(frame),
                    argCopies : copyArguments(frame.arguments)
                });

                // inline <script>s run after the HTML parser have frame.type === "global"
                if(frame.older === null || frame.older.type === 'global'){
                    console.group();
                    console.error('Uncaught error! Error message:', completionThrowValueToString(thrownValue) );

                    console.group();
                    frameData.reverse().forEach(function(f){
                        const {offset, frameName, script, argCopies} = f;

                        console.error(script.url+': l.'+script.getOffsetLine(offset) +' '+
                            frameName + '('+ argCopies.map(toArgumentString).join(', ') + ')' );
                    });
                    console.groupEnd();

                    console.groupEnd();
                    reinit()
                }
            }
            else{
                reinit();
            }
        };
    })();

    dbg.onEnterFrame = function(frame){
        //console.log('Entering frame', frameName(frame));
        if(frameData.length >= 0) // apparently, the error was caught
            reinit();

        var env = frame.environment;
        var names = env.names();

        frame.onPop = uncaughtErrorFramePopHandler;
    };

};
<commit_msg>cleanups<commit_after>"use strict";

// LIBRARY

const {Cu} = require("chrome");
const { addDebuggerToGlobal } = Cu.import("resource://gre/modules/jsdebugger.jsm");
addDebuggerToGlobal(this);

const P = Object.getPrototypeOf;
//console.log('Debugger:', typeof Debugger, Object.getOwnPropertyNames(Debugger), Object.getOwnPropertyNames(P(Debugger)))

// Safer and more declarative replacement for resumption value
Debugger.Resumption = {
    return : function(value){
        return {return: value};
    },
    yield : function(value){
        return {yield: value};
    },
    throw : function(value){
        return {throw: value};
    },
    stop : null,
    continue : undefined
};

function allKeys(o){
    console.group()
    while(o !== null){
        console.log(Object.getOwnPropertyNames(o))
        o = P(o)
    }
    console.groupEnd()
}

function frameName(f){
    return f.type === 'call' ?
        f.callee.name || '(anonymous)':
        f.type ;
}

const getObjectId = (function(){
    var wm = new WeakMap();
    var id = 1;
    return function (frame){
        if(wm.has(frame))
            return wm.get(frame);
        else{
            wm.set(frame, id);
            return id++;
        }
    };
})();

function frameEnvIds(frame){
    var env = frame.environment;
    var ids = [];

    while(env){
        ids.push(getObjectId(env));
        env = env.parent;
    }

    console.log('environments of frame', frameName(frame), ':',ids.join(' → '));
}

Debugger.Object.prototype.toString = function(){
    var object = this;
    var jsonableCopy = {};
    //allKeys(this);

    object.getOwnPropertyNames().forEach(function(prop){
        var desc = object.getOwnPropertyDescriptor(prop);
        jsonableCopy[prop] = desc.value;
    });

    return JSON.stringify(jsonableCopy);
};
Debugger.Object.prototype.toJSON = Debugger.Object.prototype.toString;

function copyArguments(args){
    return Array.prototype.map.call(args, function(e){ return e;});
}

function toArgumentString(v){
    if(v === null)
        return 'null';
    if(typeof v === 'function')
        return 'function '+v.name;
    if(typeof v === 'object')
        return JSON.stringify(v); // useless. The object is a Debugger.Object
    if(typeof v === 'string')
        return "'"+v+"'";

    return String(v);
}

function completionThrowValueToString(t){
    if(t instanceof Debugger.Object){
        if(t.class === 'Error')
            return t.getOwnPropertyDescriptor('message').value;

        return String(t);
    }
    else
        return String(t);
}

module.exports = function trackStack(global){

    var doc = global.document;
    var console = global.console;

    var dbg = new Debugger(global);
    dbg.uncaughtExceptionHook = function(e){
        console.error('uncaughtExceptionHook', e, e.stack);
    };

    var frameData = [];
    var trackedError;

    function reinit(){
        frameData = [];
        trackedError = undefined;
    }

    function isCurrentlyTracking(){
        return frameData.length >= 1;
    }

    var uncaughtErrorFramePopHandler = (function(){

        return function(completionValue){
            var frame = this;

            if('throw' in completionValue){
                var thrownValue = completionValue.throw;

                if(isCurrentlyTracking()){
                    if(!Object.is(trackedError, thrownValue)){
                        // a different error than the currently tracked is being thrown
                        reinit();
                        trackedError = thrownValue;
                    }
                }
                else{
                    trackedError = thrownValue;
                }

                frameData.push({
                    script : frame.script,
                    offset : frame.offset,
                    frameName : frameName(frame),
                    argCopies : copyArguments(frame.arguments)
                });

                // inline <script>s run after the HTML parser have frame.type === "global"
                if(frame.older === null || frame.older.type === 'global'){
                    console.group();
                    console.error('Uncaught error! Error message:', completionThrowValueToString(thrownValue) );

                    console.group();
                    frameData.reverse().forEach(function(f){
                        const {offset, frameName, script, argCopies} = f;

                        console.error(script.url+': l.'+script.getOffsetLine(offset) +' '+
                            frameName + '('+ argCopies.map(toArgumentString).join(', ') + ')' );
                    });
                    console.groupEnd();

                    console.groupEnd();
                    reinit()
                }
            }
            else{
                // different sort of completion value: the error was caught
                reinit();
            }
        };
    })();

    dbg.onEnterFrame = function(frame){
        if(frameData.length >= 0) // apparently, the error was caught and a function was called after that
            reinit();

        frame.onPop = uncaughtErrorFramePopHandler;
    };

};
<|endoftext|>


<commit_before>/*
 * Bosonic transpiler
 * https://github.com/bosonic/transpiler
 *
 * Copyright (c) 2013 Raphaël Rougeron
 * Licensed under the MIT license.
 */

'use strict';

var _ = require('underscore'),
    fs = require('fs'),
    cheerio = require('cheerio'),
    esprima = require('esprima'),
    escodegen = require('escodegen'),
    estraverse = require('estraverse'),
    sweet = require('sweet.js');

function camelize(str) {
    var camelized = str.replace(/(\-|_|\.|\s)+(.)?/g, function(match, separator, chr) {
        return chr ? chr.toUpperCase() : '';
    }).replace(/^([A-Z])/, function(match, separator, chr) {
        return match.toLowerCase();
    });
    return camelized.charAt(0).toUpperCase() + camelized.slice(1);
}
String.prototype.camelize = function() {
    return camelize(this);
};

function decamelize(str) {
    str = str.charAt(0).toLowerCase() + str.slice(1);
    return str.replace(/([a-z\d])([A-Z])/g, '$1-$2').toLowerCase();
}
String.prototype.decamelize = function() {
    return decamelize(this);
};

function shimSelector(selector, elementName) {
    var shimed = false,
        selectorRegexes = [
            [/^:host\(([^:]+)\)$/, elementName+'$1'],
            [/^:host(:hover|:active|:focus)$/, elementName+'$1'],
            [/^:host(\[[^:]+\])$/, elementName+'$1'],
            [/^:host$/, elementName],
            [/^:ancestor\(([^:]+)\)$/, '$1 '+elementName], // deprecated; replaced by :host-context
            [/^:host-context\(([^:]+)\)$/, '$1 '+elementName],
            [/^::content/, elementName],
        ];

    for (var i = 0; i < selectorRegexes.length; i++) {
        var re = selectorRegexes[i];
        if (selector.match(re[0])) {
            shimed = true;
            selector = selector.replace(re[0], re[1]);
            break;
        }
    }
    if (!shimed && !selector.match(new RegExp(elementName))) {
        selector = elementName + ' ' + selector;
    }
    return selector;
}

function shimStyles(styles, elementName) {

    var css = require('css'),
        parseTree = css.parse(styles);

    parseTree.stylesheet.rules.forEach(function(rule) {
        rule.selectors.forEach(function(selector, i, selectorsRef) {
            selectorsRef[i] = shimSelector(selector, elementName);
        });
    });

    return css.stringify(parseTree);
}

function preCompile(elementName, script, template, extendee) {
    var sourceAst = esprima.parse(script, { loc: true }),
        fullElementName = extendee ? "'" + elementName + "' extends '" + extendee + "'" : "'" + elementName + "'";

    // According to the spec, the last value of the <script> must be an object whose properties will define
    // the new element's API. This object must therefore be wrapped in an ExpressionStatement
    var exprStmt = sourceAst.body[sourceAst.body.length - 1];
    if (exprStmt.type !== 'ExpressionStatement') {
        throw new Error('The last value of the <script> must be an ExpressionStatement');
    }
    if (exprStmt.expression.type !== 'ObjectExpression') {
        throw new Error('The last value of the <script> must be an ExpressionStatement whose expression must be an object literal');
    }

    // We grab all the code prior to the ExpressionStatement and prepend it to the code to output
    var outerCode = [];
    for (var i = 0; i <= sourceAst.body.length - 2; i++) {
        outerCode.push(escodegen.generate(sourceAst.body[i]));
    }

    var precompiledCode = outerCode.join("\n");
    precompiledCode+= '\ndef__element ' + fullElementName + ' ' + escodegen.generate(exprStmt.expression) + '\n';
    if (template) {
        template = "'"+template.replace(/\r?\n/g, '')+"'";
        precompiledCode+= '\ndef__template "' + elementName + '" ' + template + '\n';
    }

    return precompiledCode;
}

function compile(precompiledCode) {
    var macros = fs.readFileSync(__dirname + '/macros/element.sjs', 'utf8')
        + '\n' + fs.readFileSync(__dirname + '/macros/template.sjs', 'utf8');
    return sweet.compile(macros + '\n' + precompiledCode, { readableNames: true }).code;
}

function transpile(fullpath, htmlString, cb) {
    var mainScript,
        sourceAst,
        scriptDeps = [],
        cssDeps = [],
        $ = cheerio.load(htmlString),
        element = $('element'),
        template = $('template').html(),
        style = $('style').html(),
        scripts = $('script'),
        stylesheets = $('link[rel=stylesheet]'),
        style_main = $('link[rel=first]'),
        elementName = element.attr('name'),
        extendee = element.attr('extends');

    style = style || "";

    var f = require("path");
    var name = f.basename(fullpath);
    var stripped_name = name.split(".")[0];
    if (style_main && style_main[0]) {
        var path = style_main[0].attribs.href || ("./styles/" + stripped_name + ".less");
        var fs = require("fs");
        var t = fs.readFileSync(path).toString();
        style += "\r\n" + t;
    }
    var less = require('less');

    less.render(style,
        {
            paths: ['.', "./styles"],  // Specify search paths for @import directives
            compress: true // Minify CSS output
        },
        function (e, output) {
            if (e) { console.log(e); return cb(e); }
            style = output.css;
            //style = output;
            scripts.each(function(i, script) {
                if ($(this).attr('src') && $(this).attr('embed')) {
                    scriptDeps.push($(this).attr('src'));
                } else if(!$(this).attr('src')) {
                    if (mainScript !== undefined) {
                        throw new Error('Only one <script> is permitted in a Web Component declaration');
                    }
                    mainScript = $(this).html();
                }
            });

            stylesheets.each(function(i, link) {
                cssDeps.push($(this).attr('href'));
            });

            if (style !== null) {
                style = shimStyles(style, elementName);
            }

            // We can't normalize whitespace during the first parse because it will normalize WS in the JS too
            if (template !== null) {
                $ = cheerio.load(htmlString, {
                    normalizeWhitespace: true
                });
                template = $('template').html();
            }

            if (mainScript === undefined) {
                throw new Error('A <script> is mandatory in a Web Component declaration');
            }

            var precompiledCode = preCompile(elementName, mainScript, template, extendee);

            var output = '(function () {\n' + compile(precompiledCode) + '\n}());\n';

            // We do another pass with Esprima in order to indent JS code correctly
            var outputAst = esprima.parse(output);
            output = escodegen.generate(outputAst);

            cb(undefined, {
                js: output,
                css: style,
                template: template,
                scripts: scriptDeps,
                stylesheets: cssDeps
        });
    });

 }

exports = module.exports = {
    transpile: transpile,
    preCompile: preCompile,
    compile: compile,
    shimStyles: shimStyles,
    shimSelector: shimSelector
}

<commit_msg>Correct error handling<commit_after>/*
 * Bosonic transpiler
 * https://github.com/bosonic/transpiler
 *
 * Copyright (c) 2013 Raphaël Rougeron
 * Licensed under the MIT license.
 */

'use strict';

var _ = require('underscore'),
    fs = require('fs'),
    cheerio = require('cheerio'),
    esprima = require('esprima'),
    escodegen = require('escodegen'),
    estraverse = require('estraverse'),
    sweet = require('sweet.js');

function camelize(str) {
    var camelized = str.replace(/(\-|_|\.|\s)+(.)?/g, function(match, separator, chr) {
        return chr ? chr.toUpperCase() : '';
    }).replace(/^([A-Z])/, function(match, separator, chr) {
        return match.toLowerCase();
    });
    return camelized.charAt(0).toUpperCase() + camelized.slice(1);
}
String.prototype.camelize = function() {
    return camelize(this);
};

function decamelize(str) {
    str = str.charAt(0).toLowerCase() + str.slice(1);
    return str.replace(/([a-z\d])([A-Z])/g, '$1-$2').toLowerCase();
}
String.prototype.decamelize = function() {
    return decamelize(this);
};

function shimSelector(selector, elementName) {
    var shimed = false,
        selectorRegexes = [
            [/^:host\(([^:]+)\)$/, elementName+'$1'],
            [/^:host(:hover|:active|:focus)$/, elementName+'$1'],
            [/^:host(\[[^:]+\])$/, elementName+'$1'],
            [/^:host$/, elementName],
            [/^:ancestor\(([^:]+)\)$/, '$1 '+elementName], // deprecated; replaced by :host-context
            [/^:host-context\(([^:]+)\)$/, '$1 '+elementName],
            [/^::content/, elementName],
        ];

    for (var i = 0; i < selectorRegexes.length; i++) {
        var re = selectorRegexes[i];
        if (selector.match(re[0])) {
            shimed = true;
            selector = selector.replace(re[0], re[1]);
            break;
        }
    }
    if (!shimed && !selector.match(new RegExp(elementName))) {
        selector = elementName + ' ' + selector;
    }
    return selector;
}

function shimStyles(styles, elementName) {

    var css = require('css'),
        parseTree = css.parse(styles);

    parseTree.stylesheet.rules.forEach(function(rule) {
        rule.selectors.forEach(function(selector, i, selectorsRef) {
            selectorsRef[i] = shimSelector(selector, elementName);
        });
    });

    return css.stringify(parseTree);
}

function preCompile(elementName, script, template, extendee) {
    var sourceAst = esprima.parse(script, { loc: true }),
        fullElementName = extendee ? "'" + elementName + "' extends '" + extendee + "'" : "'" + elementName + "'";

    // According to the spec, the last value of the <script> must be an object whose properties will define
    // the new element's API. This object must therefore be wrapped in an ExpressionStatement
    var exprStmt = sourceAst.body[sourceAst.body.length - 1];
    if (exprStmt.type !== 'ExpressionStatement') {
        throw new Error('The last value of the <script> must be an ExpressionStatement');
    }
    if (exprStmt.expression.type !== 'ObjectExpression') {
        throw new Error('The last value of the <script> must be an ExpressionStatement whose expression must be an object literal');
    }

    // We grab all the code prior to the ExpressionStatement and prepend it to the code to output
    var outerCode = [];
    for (var i = 0; i <= sourceAst.body.length - 2; i++) {
        outerCode.push(escodegen.generate(sourceAst.body[i]));
    }

    var precompiledCode = outerCode.join("\n");
    precompiledCode+= '\ndef__element ' + fullElementName + ' ' + escodegen.generate(exprStmt.expression) + '\n';
    if (template) {
        template = "'"+template.replace(/\r?\n/g, '')+"'";
        precompiledCode+= '\ndef__template "' + elementName + '" ' + template + '\n';
    }

    return precompiledCode;
}

function compile(precompiledCode) {
    var macros = fs.readFileSync(__dirname + '/macros/element.sjs', 'utf8')
        + '\n' + fs.readFileSync(__dirname + '/macros/template.sjs', 'utf8');
    return sweet.compile(macros + '\n' + precompiledCode, { readableNames: true }).code;
}

function transpile(fullpath, htmlString, cb) {
    var mainScript,
        sourceAst,
        scriptDeps = [],
        cssDeps = [],
        $ = cheerio.load(htmlString),
        element = $('element'),
        template = $('template').html(),
        style = $('style').html(),
        scripts = $('script'),
        stylesheets = $('link[rel=stylesheet]'),
        style_main = $('link[rel=first]'),
        elementName = element.attr('name'),
        extendee = element.attr('extends');

    style = style || "";

    var f = require("path");
    var name = f.basename(fullpath);
    var stripped_name = name.split(".")[0];
    if (style_main && style_main[0]) {
        var path = style_main[0].attribs.href || ("./styles/" + stripped_name + ".less");
        var fs = require("fs");
        var t = fs.readFileSync(path).toString();
        style += "\r\n" + t;
    }
    var less = require('less');

    less.render(style,
        {
            paths: ['.', "./styles"],  // Specify search paths for @import directives
            compress: true // Minify CSS output
        },
        function (e, output) {
            if (e) { console.log(e); return cb(e); }
            style = output.css;
            //style = output;
            try {
                scripts.each(function (i, script) {
                    if ($(this).attr('src') && $(this).attr('embed')) {
                        scriptDeps.push($(this).attr('src'));
                    } else if (!$(this).attr('src')) {
                        if (mainScript !== undefined) {
                            return cb(new Error('Only one <script> is permitted in a Web Component declaration'));
                        }
                        mainScript = $(this).html();
                    }
                });

                stylesheets.each(function (i, link) {
                    cssDeps.push($(this).attr('href'));
                });

                if (style !== null) {
                    style = shimStyles(style, elementName);
                }

                // We can't normalize whitespace during the first parse because it will normalize WS in the JS too
                if (template !== null) {
                    $ = cheerio.load(htmlString, {
                        normalizeWhitespace: true
                    });
                    template = $('template').html();
                }

                if (mainScript === undefined) {
                    return cb(new Error('A <script> is mandatory in a Web Component declaration'));
                }

                var precompiledCode = preCompile(elementName, mainScript, template, extendee);

                var output = '(function () {\n' + compile(precompiledCode) + '\n}());\n';

                // We do another pass with Esprima in order to indent JS code correctly
                var outputAst = esprima.parse(output);
                output = escodegen.generate(outputAst);

                cb(undefined, {
                    js: output,
                    css: style,
                    template: template,
                    scripts: scriptDeps,
                    stylesheets: cssDeps
                });
            } catch (e) {
                cb(e);
            }
    });

 }

exports = module.exports = {
    transpile: transpile,
    preCompile: preCompile,
    compile: compile,
    shimStyles: shimStyles,
    shimSelector: shimSelector
}

<|endoftext|>


<commit_before>var events = require('events');
var util = require('util');

function Transport() {
}
util.inherits(Transport, events.EventEmitter);

var http = require('http');
function HTTPTransport() {
    this.defaultPort = 80; // Opbeat currently doesn't support HTTP
    this.transport = http;
}
util.inherits(HTTPTransport, Transport);
HTTPTransport.prototype.send = function(client, message, headers) {
    var options = {
        hostname: client.dsn.host,
        path: client.dsn.path,
        headers: headers,
        method: 'POST',
        port: client.dsn.port || this.defaultPort
    }, req = this.transport.request(options, function(res){
        res.setEncoding('utf8');
        var body = [];
        res.on('data', function(data) {
            body.push(data);
        });
        res.on('end', function(){
            if(res.statusCode >= 200 && res.statusCode < 300) {
                client.emit('logged', res.headers.location);
            } else {
                body = body.join('');
                var e = new Error('HTTP Error (' + res.statusCode + '): ' + body);
                e.response = res;
                e.statusCode = res.statusCode;
                e.responseBody = body;
                client.emit('error', e);
            }
        });
    });
    req.on('error', function(e){
        client.emit('error', e);
    });
    req.end(message);
}

var https = require('https');
function HTTPSTransport() {
    this.defaultPort = 443;
    this.transport = https;
}
util.inherits(HTTPSTransport, HTTPTransport);

// Opbeat currently doesn't support UDP
var dgram = require('dgram');
function UDPTransport() {
    this.defaultPort = 12345;
}
util.inherits(UDPTransport, Transport);
UDPTransport.prototype.send = function(client, message, headers) {
    var self = client;
    message = new Buffer(headers['X-Sentry-Auth'] + '\n\n'+ message);

    var udp = dgram.createSocket('udp4');
    udp.send(message, 0, message.length, self.dsn.port || this.defaultPort, self.dsn.host, function(e, bytes) {
        if(e){
            return self.emit('error', e);
        }
        self.emit('logged');
        udp.close();
    });
}

module.exports.http = new HTTPTransport();
module.exports.https = new HTTPSTransport();
module.exports.udp = new UDPTransport();
<commit_msg>Remove unused transport protocols<commit_after>var util = require('util');

var http = require('http');
function HTTPTransport() {
    // Opbeat currently doesn't support HTTP
    this.defaultPort = 80;
    this.transport = http;
}
HTTPTransport.prototype.send = function(client, message, headers) {
    var options = {
        hostname: client.dsn.host,
        path: client.dsn.path,
        headers: headers,
        method: 'POST',
        port: client.dsn.port || this.defaultPort
    }, req = this.transport.request(options, function(res){
        res.setEncoding('utf8');
        var body = [];
        res.on('data', function(data) {
            body.push(data);
        });
        res.on('end', function(){
            if(res.statusCode >= 200 && res.statusCode < 300) {
                client.emit('logged', res.headers.location);
            } else {
                body = body.join('');
                var e = new Error('HTTP Error (' + res.statusCode + '): ' + body);
                e.response = res;
                e.statusCode = res.statusCode;
                e.responseBody = body;
                client.emit('error', e);
            }
        });
    });
    req.on('error', function(e){
        client.emit('error', e);
    });
    req.end(message);
}

var https = require('https');
function HTTPSTransport() {
    this.defaultPort = 443;
    this.transport = https;
}
util.inherits(HTTPSTransport, HTTPTransport);

module.exports.https = new HTTPSTransport();
<|endoftext|>


<commit_before>'use strict';

var remove        = require('es5-ext/lib/Array/prototype/remove')
  , isFunction    = require('es5-ext/lib/Function/is-function')
  , d             = require('es5-ext/lib/Object/descriptor')
  , startsWith    = require('es5-ext/lib/String/prototype/starts-with')
  , combineErrors = require('../utils/combine-errors')
  , serialize     = require('../utils/serialize')
  , objects       = require('../objects')
  , proto         = require('../_proto')
  , relation      = require('../_relation')
  , RelTransport  = require('../_relation/transport')

  , slice = Array.prototype.slice
  , create = Object.create, defineProperty = Object.defineProperty
  , defineProperties = Object.defineProperties
  , getOwnPropertyNames = Object.getOwnPropertyNames
  , getPrototypeOf = Object.getPrototypeOf

  , nameRe = /^[A-Z][0-9a-zA-Z]*$/
  , relTypes = { relation: true, 'relation-set-item': true }
  , Base, baseProto, rel, setRelationProto, setItemProto;

setItemProto = function (item) {
	var old = getPrototypeOf(item), nu = this._setItem_;

	remove.call(old._children_, item);
	item.__proto__ = nu;
	if (!nu.hasOwnProperty('_children_')) {
		defineProperty(nu, '_children_', d('', []));
	}
	nu._children_.push(item);

	item._forEachRelation_(setRelationProto.bind(nu));
};

setRelationProto = function (rel) {
	var nu = this['_' + rel.name], old = getPrototypeOf(rel);

	// Clear old setup
	remove.call(old._children_, rel);

	// Update
	rel.__proto__ = nu;

	// Setup new
	if (!nu.hasOwnProperty('_children_')) {
		defineProperty(nu, '_children_', d('', []));
	}
	nu._children_.push(rel);

	// Reload value
	if (!rel.hasOwnProperty('_value')) rel._update_();

	// Update set item proto
	if (rel.hasOwnProperty('__setItem_')) setItemProto.call(nu, rel.__setItem_);

	// Update relation proto
	rel._forEachRelation_(setRelationProto.bind(nu));
};

Base = module.exports = objects.Base = function Self(value) {
	return Self.is(value) ? value :
			Self.prototype.create.apply(Self.prototype, arguments);
};
Base.__proto__ = proto;
defineProperties(Base, {
	_id_: d('', 'Base'),
	_type_: d('c', 'namespace'),
	_childType_: d('c', 'primitive'),
	Base: d('ce', Base),
	create: d('c', function (name) {
		var error = this.validateCreate.apply(this, arguments);
		if (error) throw error;
		return this.$create.apply(this, arguments);
	}),
	validateCreate: d('c', function (name) {
		if (!nameRe.test(name)) return new Error(name + " is not a valid name");
		if (name in Base) return new Error(name + " is already taken");
		return this.validateConstruction.apply(this, slice.call(arguments, 1));
	}),
	$create: d('c', function (name) {
		var constructor = this.$$create(name);
		constructor._signal_(this);
		constructor.$construct.apply(constructor, slice.call(arguments, 1));
		return constructor;
	}),
	$$create: d('c', function (id) {
		var constructor = function Self(value) {
			return Self.is(value) ? value :
					Self.prototype.create.apply(Self.prototype, arguments);
		};
		constructor.__proto__ = this;
		objects[id] = defineProperty(constructor, '_id_', d('', id));
		objects[id + '#'] = constructor.prototype = create(this.prototype, {
			constructor: d(constructor),
			ns: d(constructor),
			_id_: d('', id + '#')
		});
		if (!this.hasOwnProperty('_children_')) {
			defineProperty(this, '_children_', d('', []));
		}
		if (!this.prototype.hasOwnProperty('_children_')) {
			defineProperty(this.prototype, '_children_', d('', []));
		}
		this._children_.push(constructor);
		this.prototype._children_.push(constructor.prototype);
		return (Base[id] = constructor);
	}),
	$$setValue: d('c', function (nu) {
		var old = getPrototypeOf(this);
		if (!nu) nu = Base;
		if (old === nu) return;

		this.__proto__ = nu;
		this.prototype.__proto__ = nu.prototype;

		remove.call(old._children_, this);
		remove.call(old.prototype._children_, this.prototype);
		if (!nu.hasOwnProperty('_children_')) {
			defineProperty(nu, '_children_', d('', []));
		}
		if (!nu.prototype.hasOwnProperty('_children_')) {
			defineProperty(nu.prototype, '_children_', d('', []));
		}
		nu._children_.push(this);
		nu.prototype._children_.push(this);

		if (old === Base) Base[this._id_] = this;
		if (nu === Base) delete Base[this._id_];

		// Fix relations proto
		this._forEachRelation_(setRelationProto.bind(nu));
		this.prototype._forEachRelation_(setRelationProto.bind(nu.prototype));
	}),
	rel: d('c', function (data) {
		if (data == null) return this;
		return new RelTransport(this, data);
	}),
	required: d.gs('c', function () {
		return new RelTransport(this, { required: true });
	}),
	_serialize_: d('c', serialize)
});

objects['Base#'] = baseProto = Base.prototype = create(proto, {
	_id_: d('', 'Base#'),
	_type_: d('prototype'),
	constructor: d(Base),
	ns: d(Base),
	create: d(Base.create),
	validateCreate: d(function (value) {
		if (!serialize(value)) {
			return new TypeError(value + ' is not valid dbjs value');
		}
		return null;
	}),
	$create: d(function (value) { return value; }),
	$$create: d(function (id) {
		var obj, ns;
		obj = proto.$$create.call(this, id);
		if (this._type_ === 'prototype') defineProperty(obj, '_type_', d('object'));
		ns = this.ns;
		while (ns._type_ && (ns !== Base)) {
			ns[id] = obj;
			ns = getPrototypeOf(ns);
		}
		return obj;
	}),
	$$setValue: d(function (nu) {
		var ns, old, id;
		if (!nu) nu = baseProto;
		old = getPrototypeOf(this);
		if (old === nu) return;
		this.__proto__ = nu;

		remove.call(old._children_, this);
		if (!nu.hasOwnProperty('_children_')) {
			defineProperty(nu, '_children_', d('', []));
		}
		nu._children_.push(this);

		ns = old.ns;
		id = this._id_;
		while (ns._type_ && (ns !== Base)) {
			delete ns[id];
			ns = getPrototypeOf(ns);
		}
		ns = nu.ns;
		while (ns._type_ && (ns !== Base)) {
			ns[id] = this;
			ns = getPrototypeOf(ns);
		}

		// Fix relations proto
		this._forEachRelation_(setRelationProto.bind(nu));
	})
});
proto._children_.push(Base, Base.prototype);

relation.__ns.$$setValue(Base);
rel = Base._getRel_('$construct');
rel.$$setValue(function (construct, nsProps, objProps) {
	if (!isFunction(construct)) {
		objProps = nsProps;
		nsProps = construct;
		construct = null;
	} else if (!nsProps) {
		nsProps = { $construct: construct };
	} else {
		nsProps.$construct = construct;
	}

	if (nsProps) this.$setProperties(nsProps);
	if (objProps) this.prototype.$setProperties(objProps);
});
rel._required.$$setValue(true);

rel = Base._getRel_('validateConstruction');
rel.$$setValue(function (construct, nsProps, objProps) {
	var error;
	if (!isFunction(construct)) {
		objProps = nsProps;
		nsProps = construct;
		construct = null;
	} else if (!nsProps) {
		nsProps = { construct: construct };
	} else {
		nsProps.construct = construct;
	}

	error = combineErrors(nsProps && this.validateCreateProperties(nsProps),
		objProps && this.prototype.validateCreateProperties(objProps));
	if (!error) return null;
	error.message = "Invalid properties";
	return error;
});
rel._required.$$setValue(true);

rel = Base._getRel_('is');
rel.$$setValue(function (value) { return true; });
rel._required.$$setValue(true);

rel = Base._getRel_('normalize');
rel.$$setValue(function (value) { return value; });
rel._required.$$setValue(true);

Base._toString.$$setValue(Function.prototype.toString);
<commit_msg>Improve comments<commit_after>'use strict';

var remove        = require('es5-ext/lib/Array/prototype/remove')
  , isFunction    = require('es5-ext/lib/Function/is-function')
  , d             = require('es5-ext/lib/Object/descriptor')
  , startsWith    = require('es5-ext/lib/String/prototype/starts-with')
  , combineErrors = require('../utils/combine-errors')
  , serialize     = require('../utils/serialize')
  , objects       = require('../objects')
  , proto         = require('../_proto')
  , relation      = require('../_relation')
  , RelTransport  = require('../_relation/transport')

  , slice = Array.prototype.slice
  , create = Object.create, defineProperty = Object.defineProperty
  , defineProperties = Object.defineProperties
  , getOwnPropertyNames = Object.getOwnPropertyNames
  , getPrototypeOf = Object.getPrototypeOf

  , nameRe = /^[A-Z][0-9a-zA-Z]*$/
  , relTypes = { relation: true, 'relation-set-item': true }
  , Base, baseProto, rel, setRelationProto, setItemProto;

setItemProto = function (item) {
	var old = getPrototypeOf(item), nu = this._setItem_;

	remove.call(old._children_, item);
	item.__proto__ = nu;
	if (!nu.hasOwnProperty('_children_')) {
		defineProperty(nu, '_children_', d('', []));
	}
	nu._children_.push(item);

	item._forEachRelation_(setRelationProto.bind(nu));
};

setRelationProto = function (rel) {
	var nu = this['_' + rel.name], old = getPrototypeOf(rel);

	// Clear old setup
	remove.call(old._children_, rel);

	// Update
	rel.__proto__ = nu;

	// Setup new
	if (!nu.hasOwnProperty('_children_')) {
		defineProperty(nu, '_children_', d('', []));
	}
	nu._children_.push(rel);

	// Update value if inherited
	if (!rel.hasOwnProperty('_value')) rel._update_();

	// Update base set item proto
	if (rel.hasOwnProperty('__setItem_')) setItemProto.call(nu, rel.__setItem_);

	// Update relations proto
	rel._forEachRelation_(setRelationProto.bind(nu));
};

Base = module.exports = objects.Base = function Self(value) {
	return Self.is(value) ? value :
			Self.prototype.create.apply(Self.prototype, arguments);
};
Base.__proto__ = proto;
defineProperties(Base, {
	_id_: d('', 'Base'),
	_type_: d('c', 'namespace'),
	_childType_: d('c', 'primitive'),
	Base: d('ce', Base),
	create: d('c', function (name) {
		var error = this.validateCreate.apply(this, arguments);
		if (error) throw error;
		return this.$create.apply(this, arguments);
	}),
	validateCreate: d('c', function (name) {
		if (!nameRe.test(name)) return new Error(name + " is not a valid name");
		if (name in Base) return new Error(name + " is already taken");
		return this.validateConstruction.apply(this, slice.call(arguments, 1));
	}),
	$create: d('c', function (name) {
		var constructor = this.$$create(name);
		constructor._signal_(this);
		constructor.$construct.apply(constructor, slice.call(arguments, 1));
		return constructor;
	}),
	$$create: d('c', function (id) {
		var constructor = function Self(value) {
			return Self.is(value) ? value :
					Self.prototype.create.apply(Self.prototype, arguments);
		};
		constructor.__proto__ = this;
		objects[id] = defineProperty(constructor, '_id_', d('', id));
		objects[id + '#'] = constructor.prototype = create(this.prototype, {
			constructor: d(constructor),
			ns: d(constructor),
			_id_: d('', id + '#')
		});
		if (!this.hasOwnProperty('_children_')) {
			defineProperty(this, '_children_', d('', []));
		}
		if (!this.prototype.hasOwnProperty('_children_')) {
			defineProperty(this.prototype, '_children_', d('', []));
		}
		this._children_.push(constructor);
		this.prototype._children_.push(constructor.prototype);
		return (Base[id] = constructor);
	}),
	$$setValue: d('c', function (nu) {
		var old = getPrototypeOf(this);
		if (!nu) nu = Base;
		if (old === nu) return;

		this.__proto__ = nu;
		this.prototype.__proto__ = nu.prototype;

		remove.call(old._children_, this);
		remove.call(old.prototype._children_, this.prototype);
		if (!nu.hasOwnProperty('_children_')) {
			defineProperty(nu, '_children_', d('', []));
		}
		if (!nu.prototype.hasOwnProperty('_children_')) {
			defineProperty(nu.prototype, '_children_', d('', []));
		}
		nu._children_.push(this);
		nu.prototype._children_.push(this);

		if (old === Base) Base[this._id_] = this;
		if (nu === Base) delete Base[this._id_];

		// Fix relations proto
		this._forEachRelation_(setRelationProto.bind(nu));
		this.prototype._forEachRelation_(setRelationProto.bind(nu.prototype));
	}),
	rel: d('c', function (data) {
		if (data == null) return this;
		return new RelTransport(this, data);
	}),
	required: d.gs('c', function () {
		return new RelTransport(this, { required: true });
	}),
	_serialize_: d('c', serialize)
});

objects['Base#'] = baseProto = Base.prototype = create(proto, {
	_id_: d('', 'Base#'),
	_type_: d('prototype'),
	constructor: d(Base),
	ns: d(Base),
	create: d(Base.create),
	validateCreate: d(function (value) {
		if (!serialize(value)) {
			return new TypeError(value + ' is not valid dbjs value');
		}
		return null;
	}),
	$create: d(function (value) { return value; }),
	$$create: d(function (id) {
		var obj, ns;
		obj = proto.$$create.call(this, id);
		if (this._type_ === 'prototype') defineProperty(obj, '_type_', d('object'));
		ns = this.ns;
		while (ns._type_ && (ns !== Base)) {
			ns[id] = obj;
			ns = getPrototypeOf(ns);
		}
		return obj;
	}),
	$$setValue: d(function (nu) {
		var ns, old, id;
		if (!nu) nu = baseProto;
		old = getPrototypeOf(this);
		if (old === nu) return;
		this.__proto__ = nu;

		remove.call(old._children_, this);
		if (!nu.hasOwnProperty('_children_')) {
			defineProperty(nu, '_children_', d('', []));
		}
		nu._children_.push(this);

		ns = old.ns;
		id = this._id_;
		while (ns._type_ && (ns !== Base)) {
			delete ns[id];
			ns = getPrototypeOf(ns);
		}
		ns = nu.ns;
		while (ns._type_ && (ns !== Base)) {
			ns[id] = this;
			ns = getPrototypeOf(ns);
		}

		// Fix relations proto
		this._forEachRelation_(setRelationProto.bind(nu));
	})
});
proto._children_.push(Base, Base.prototype);

relation.__ns.$$setValue(Base);
rel = Base._getRel_('$construct');
rel.$$setValue(function (construct, nsProps, objProps) {
	if (!isFunction(construct)) {
		objProps = nsProps;
		nsProps = construct;
		construct = null;
	} else if (!nsProps) {
		nsProps = { $construct: construct };
	} else {
		nsProps.$construct = construct;
	}

	if (nsProps) this.$setProperties(nsProps);
	if (objProps) this.prototype.$setProperties(objProps);
});
rel._required.$$setValue(true);

rel = Base._getRel_('validateConstruction');
rel.$$setValue(function (construct, nsProps, objProps) {
	var error;
	if (!isFunction(construct)) {
		objProps = nsProps;
		nsProps = construct;
		construct = null;
	} else if (!nsProps) {
		nsProps = { construct: construct };
	} else {
		nsProps.construct = construct;
	}

	error = combineErrors(nsProps && this.validateCreateProperties(nsProps),
		objProps && this.prototype.validateCreateProperties(objProps));
	if (!error) return null;
	error.message = "Invalid properties";
	return error;
});
rel._required.$$setValue(true);

rel = Base._getRel_('is');
rel.$$setValue(function (value) { return true; });
rel._required.$$setValue(true);

rel = Base._getRel_('normalize');
rel.$$setValue(function (value) { return value; });
rel._required.$$setValue(true);

Base._toString.$$setValue(Function.prototype.toString);
<|endoftext|>