<commit_before>'use strict';

/*!
 * Pug
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var fs = require('fs');
var path = require('path');
var lex = require('pug-lexer');
var stripComments = require('pug-strip-comments');
var parse = require('pug-parser');
var load = require('pug-load');
var filters = require('pug-filters');
var link = require('pug-linker');
var generateCode = require('pug-code-gen');
var runtime = require('pug-runtime');
var runtimeWrap = require('pug-runtime/wrap');

/**
 * Pug runtime helpers.
 */

exports.runtime = runtime;

/**
 * Template function cache.
 */

exports.cache = {};

function applyPlugins(value, options, plugins, name) {
  return plugins.reduce(function (value, plugin) {
    return (
      plugin[name]
      ? plugin[name](value, options)
      : value
    );
  }, value);
}
/**
 * Object for global custom filters.  Note that you can also just pass a `filters`
 * option to any other method.
 */
exports.filters = {};

/**
 * Compile the given `str` of pug and return a function body.
 *
 * @param {String} str
 * @param {Object} options
 * @return {Object}
 * @api private
 */

function compileBody(str, options){
  var debug_sources = {};
  debug_sources[options.filename] = str;
  var dependencies = [];
  var plugins = options.plugins || [];
  var ast = load.string(str, {
    filename: options.filename,
    basedir: options.basedir,
    lex: function (str, options) {
      var lexOptions = {};
      Object.keys(options).forEach(function (key) {
        lexOptions[key] = options[key];
      });
      lexOptions.plugins = plugins.filter(function (plugin) {
        return !!plugin.lex;
      }).map(function (plugin) {
        return plugin.lex;
      });
      return applyPlugins(lex(str, lexOptions), options, plugins, 'postLex');
    },
    parse: function (tokens, options) {
      tokens = tokens.map(function (token) {
        if (token.type === 'path' && path.extname(token.val) === '') {
          return {
            type: 'path',
            line: token.line,
            col: token.col,
            val: token.val + '.pug'
          };
        }
        return token;
      });
      tokens = stripComments(tokens, options);
      tokens = applyPlugins(tokens, options, plugins, 'preParse');
      var parseOptions = {};
      Object.keys(options).forEach(function (key) {
        parseOptions[key] = options[key];
      });
      parseOptions.plugins = plugins.filter(function (plugin) {
        return !!plugin.parse;
      }).map(function (plugin) {
        return plugin.parse;
      });

      return applyPlugins(
        applyPlugins(parse(tokens, parseOptions), options, plugins, 'postParse'),
        options, plugins, 'preLoad'
      );
    },
    read: function (filename) {
      dependencies.push(filename);
      var str = applyPlugins(fs.readFileSync(filename, 'utf8'), {filename: filename}, plugins, 'preLex');
      debug_sources[filename] = str;
      return str;
    }
  });
  ast = applyPlugins(ast, options, plugins, 'postLoad');
  ast = applyPlugins(ast, options, plugins, 'preFilters');

  var filtersSet = {};
  Object.keys(exports.filters).forEach(function (key) {
    filtersSet[key] = exports.filters[key];
  });
  if (options.filters) {
    Object.keys(options.filters).forEach(function (key) {
      filtersSet[key] = options.filters[key];
    });
  }
  ast = filters.handleFilters(ast, filtersSet, options.filterOptions);

  ast = applyPlugins(ast, options, plugins, 'postFilters');
  ast = applyPlugins(ast, options, plugins, 'preLink');
  ast = link(ast);
  ast = applyPlugins(ast, options, plugins, 'postLink');

  // Compile
  ast = applyPlugins(ast, options, plugins, 'preCodeGen');
  var js = generateCode(ast, {
    pretty: options.pretty,
    compileDebug: options.compileDebug,
    doctype: options.doctype,
    inlineRuntimeFunctions: options.inlineRuntimeFunctions,
    globals: options.globals,
    self: options.self,
    includeSources: options.includeSources ? debug_sources : false,
    templateName: options.templateName
  });
  js = applyPlugins(js, options, plugins, 'postCodeGen');

  // Debug compiler
  if (options.debug) {
    console.error('\nCompiled Function:\n\n\u001b[90m%s\u001b[0m', js.replace(/^/gm, '  '));
  }

  return {body: js, dependencies: dependencies};
}

/**
 * Get the template from a string or a file, either compiled on-the-fly or
 * read from cache (if enabled), and cache the template if needed.
 *
 * If `str` is not set, the file specified in `options.filename` will be read.
 *
 * If `options.cache` is true, this function reads the file from
 * `options.filename` so it must be set prior to calling this function.
 *
 * @param {Object} options
 * @param {String=} str
 * @return {Function}
 * @api private
 */
function handleTemplateCache (options, str) {
  var key = options.filename;
  if (options.cache && exports.cache[key]) {
    return exports.cache[key];
  } else {
    if (str === undefined) str = fs.readFileSync(options.filename, 'utf8');
    var templ = exports.compile(str, options);
    if (options.cache) exports.cache[key] = templ;
    return templ;
  }
}

/**
 * Compile a `Function` representation of the given pug `str`.
 *
 * Options:
 *
 *   - `compileDebug` when `false` debugging code is stripped from the compiled
       template, when it is explicitly `true`, the source code is included in
       the compiled template for better accuracy.
 *   - `filename` used to improve errors when `compileDebug` is not `false` and to resolve imports/extends
 *
 * @param {String} str
 * @param {Options} options
 * @return {Function}
 * @api public
 */

exports.compile = function(str, options){
  var options = options || {}

  str = String(str);

  var parsed = compileBody(str, {
    compileDebug: options.compileDebug !== false,
    filename: options.filename,
    basedir: options.basedir,
    pretty: options.pretty,
    doctype: options.doctype,
    inlineRuntimeFunctions: options.inlineRuntimeFunctions,
    globals: options.globals,
    self: options.self,
    includeSources: options.compileDebug === true,
    debug: options.debug,
    templateName: 'template',
    filters: options.filters,
    filterOptions: options.filterOptions,
    plugins: options.plugins,
  });

  var res = options.inlineRuntimeFunctions
    ? new Function('', parsed.body + ';return template;')()
    : runtimeWrap(parsed.body);

  res.dependencies = parsed.dependencies;

  return res;
};

/**
 * Compile a JavaScript source representation of the given pug `str`.
 *
 * Options:
 *
 *   - `compileDebug` When it is `true`, the source code is included in
 *     the compiled template for better error messages.
 *   - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends
 *   - `name` the name of the resulting function (defaults to "template")
 *
 * @param {String} str
 * @param {Options} options
 * @return {Object}
 * @api public
 */

exports.compileClientWithDependenciesTracked = function(str, options){
  var options = options || {};

  str = String(str);
  var parsed = compileBody(str, {
    compileDebug: options.compileDebug,
    filename: options.filename,
    basedir: options.basedir,
    pretty: options.pretty,
    doctype: options.doctype,
    inlineRuntimeFunctions: options.inlineRuntimeFunctions !== false,
    globals: options.globals,
    self: options.self,
    includeSources: options.compileDebug,
    debug: options.debug,
    templateName: options.name || 'template',
    filters: options.filters,
    filterOptions: options.filterOptions,
    plugins: options.plugins,
  });

  return {body: parsed.body, dependencies: parsed.dependencies};
};

/**
 * Compile a JavaScript source representation of the given pug `str`.
 *
 * Options:
 *
 *   - `compileDebug` When it is `true`, the source code is included in
 *     the compiled template for better error messages.
 *   - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends
 *   - `name` the name of the resulting function (defaults to "template")
 *
 * @param {String} str
 * @param {Options} options
 * @return {String}
 * @api public
 */
exports.compileClient = function (str, options) {
  return exports.compileClientWithDependenciesTracked(str, options).body;
};

/**
 * Compile a `Function` representation of the given pug file.
 *
 * Options:
 *
 *   - `compileDebug` when `false` debugging code is stripped from the compiled
       template, when it is explicitly `true`, the source code is included in
       the compiled template for better accuracy.
 *
 * @param {String} path
 * @param {Options} options
 * @return {Function}
 * @api public
 */
exports.compileFile = function (path, options) {
  options = options || {};
  options.filename = path;
  return handleTemplateCache(options);
};

/**
 * Render the given `str` of pug.
 *
 * Options:
 *
 *   - `cache` enable template caching
 *   - `filename` filename required for `include` / `extends` and caching
 *
 * @param {String} str
 * @param {Object|Function} options or fn
 * @param {Function|undefined} fn
 * @returns {String}
 * @api public
 */

exports.render = function(str, options, fn){
  // support callback API
  if ('function' == typeof options) {
    fn = options, options = undefined;
  }
  if (typeof fn === 'function') {
    var res
    try {
      res = exports.render(str, options);
    } catch (ex) {
      return fn(ex);
    }
    return fn(null, res);
  }

  options = options || {};

  // cache requires .filename
  if (options.cache && !options.filename) {
    throw new Error('the "filename" option is required for caching');
  }

  return handleTemplateCache(options, str)(options);
};

/**
 * Render a Pug file at the given `path`.
 *
 * @param {String} path
 * @param {Object|Function} options or callback
 * @param {Function|undefined} fn
 * @returns {String}
 * @api public
 */

exports.renderFile = function(path, options, fn){
  // support callback API
  if ('function' == typeof options) {
    fn = options, options = undefined;
  }
  if (typeof fn === 'function') {
    var res
    try {
      res = exports.renderFile(path, options);
    } catch (ex) {
      return fn(ex);
    }
    return fn(null, res);
  }

  options = options || {};

  options.filename = path;
  return handleTemplateCache(options)(options);
};

/**
 * Compile a Pug file at the given `path` for use on the client.
 *
 * @param {String} path
 * @param {Object} options
 * @returns {String}
 * @api public
 */

exports.compileFileClient = function(path, options){
  var key = path + ':client';
  options = options || {};

  options.filename = path;

  if (options.cache && exports.cache[key]) {
    return exports.cache[key];
  }

  var str = fs.readFileSync(options.filename, 'utf8');
  var out = exports.compileClient(str, options);
  if (options.cache) exports.cache[key] = out;
  return out;
};

/**
 * Express support.
 */

exports.__express = function(path, options, fn) {
  if(options.compileDebug == undefined && process.env.NODE_ENV === 'production') {
    options.compileDebug = false;
  }
  exports.renderFile(path, options, fn);
}
<commit_msg>Add plugin hooks for resolve and read (#2412)<commit_after>'use strict';

/*!
 * Pug
 * Copyright(c) 2010 TJ Holowaychuk <tj@vision-media.ca>
 * MIT Licensed
 */

/**
 * Module dependencies.
 */

var fs = require('fs');
var path = require('path');
var lex = require('pug-lexer');
var stripComments = require('pug-strip-comments');
var parse = require('pug-parser');
var load = require('pug-load');
var filters = require('pug-filters');
var link = require('pug-linker');
var generateCode = require('pug-code-gen');
var runtime = require('pug-runtime');
var runtimeWrap = require('pug-runtime/wrap');

/**
 * Pug runtime helpers.
 */

exports.runtime = runtime;

/**
 * Template function cache.
 */

exports.cache = {};

function applyPlugins(value, options, plugins, name) {
  return plugins.reduce(function (value, plugin) {
    return (
      plugin[name]
      ? plugin[name](value, options)
      : value
    );
  }, value);
}

function findReplacementFunc(plugins, name) {
  var eligiblePlugins = plugins.filter(function (plugin) {
    return plugin[name];
  });

  if (eligiblePlugins.length > 1) {
    throw new Error('Two or more plugins all implement ' + name + ' method.');
  } else if (eligiblePlugins.length) {
    return eligiblePlugins[0][name];
  } else {
    return null;
  }
}

/**
 * Object for global custom filters.  Note that you can also just pass a `filters`
 * option to any other method.
 */
exports.filters = {};

/**
 * Compile the given `str` of pug and return a function body.
 *
 * @param {String} str
 * @param {Object} options
 * @return {Object}
 * @api private
 */

function compileBody(str, options){
  var debug_sources = {};
  debug_sources[options.filename] = str;
  var dependencies = [];
  var plugins = options.plugins || [];
  var ast = load.string(str, {
    filename: options.filename,
    basedir: options.basedir,
    lex: function (str, options) {
      var lexOptions = {};
      Object.keys(options).forEach(function (key) {
        lexOptions[key] = options[key];
      });
      lexOptions.plugins = plugins.filter(function (plugin) {
        return !!plugin.lex;
      }).map(function (plugin) {
        return plugin.lex;
      });
      return applyPlugins(lex(str, lexOptions), options, plugins, 'postLex');
    },
    parse: function (tokens, options) {
      tokens = tokens.map(function (token) {
        if (token.type === 'path' && path.extname(token.val) === '') {
          return {
            type: 'path',
            line: token.line,
            col: token.col,
            val: token.val + '.pug'
          };
        }
        return token;
      });
      tokens = stripComments(tokens, options);
      tokens = applyPlugins(tokens, options, plugins, 'preParse');
      var parseOptions = {};
      Object.keys(options).forEach(function (key) {
        parseOptions[key] = options[key];
      });
      parseOptions.plugins = plugins.filter(function (plugin) {
        return !!plugin.parse;
      }).map(function (plugin) {
        return plugin.parse;
      });

      return applyPlugins(
        applyPlugins(parse(tokens, parseOptions), options, plugins, 'postParse'),
        options, plugins, 'preLoad'
      );
    },
    resolve: function (filename, source, loadOptions) {
      var replacementFunc = findReplacementFunc(plugins, 'resolve');
      if (replacementFunc) {
        return replacementFunc(filename, source, options);
      }

      return load.resolve(filename, source, loadOptions);
    },
    read: function (filename, loadOptions) {
      dependencies.push(filename);

      var contents;

      var replacementFunc = findReplacementFunc(plugins, 'read');
      if (replacementFunc) {
        contents = replacementFunc(filename, options);
      } else {
        contents = load.read(filename, loadOptions);
      }

      var str = applyPlugins(contents, {filename: filename}, plugins, 'preLex');
      debug_sources[filename] = str;
      return str;
    }
  });
  ast = applyPlugins(ast, options, plugins, 'postLoad');
  ast = applyPlugins(ast, options, plugins, 'preFilters');

  var filtersSet = {};
  Object.keys(exports.filters).forEach(function (key) {
    filtersSet[key] = exports.filters[key];
  });
  if (options.filters) {
    Object.keys(options.filters).forEach(function (key) {
      filtersSet[key] = options.filters[key];
    });
  }
  ast = filters.handleFilters(ast, filtersSet, options.filterOptions);

  ast = applyPlugins(ast, options, plugins, 'postFilters');
  ast = applyPlugins(ast, options, plugins, 'preLink');
  ast = link(ast);
  ast = applyPlugins(ast, options, plugins, 'postLink');

  // Compile
  ast = applyPlugins(ast, options, plugins, 'preCodeGen');
  var js = generateCode(ast, {
    pretty: options.pretty,
    compileDebug: options.compileDebug,
    doctype: options.doctype,
    inlineRuntimeFunctions: options.inlineRuntimeFunctions,
    globals: options.globals,
    self: options.self,
    includeSources: options.includeSources ? debug_sources : false,
    templateName: options.templateName
  });
  js = applyPlugins(js, options, plugins, 'postCodeGen');

  // Debug compiler
  if (options.debug) {
    console.error('\nCompiled Function:\n\n\u001b[90m%s\u001b[0m', js.replace(/^/gm, '  '));
  }

  return {body: js, dependencies: dependencies};
}

/**
 * Get the template from a string or a file, either compiled on-the-fly or
 * read from cache (if enabled), and cache the template if needed.
 *
 * If `str` is not set, the file specified in `options.filename` will be read.
 *
 * If `options.cache` is true, this function reads the file from
 * `options.filename` so it must be set prior to calling this function.
 *
 * @param {Object} options
 * @param {String=} str
 * @return {Function}
 * @api private
 */
function handleTemplateCache (options, str) {
  var key = options.filename;
  if (options.cache && exports.cache[key]) {
    return exports.cache[key];
  } else {
    if (str === undefined) str = fs.readFileSync(options.filename, 'utf8');
    var templ = exports.compile(str, options);
    if (options.cache) exports.cache[key] = templ;
    return templ;
  }
}

/**
 * Compile a `Function` representation of the given pug `str`.
 *
 * Options:
 *
 *   - `compileDebug` when `false` debugging code is stripped from the compiled
       template, when it is explicitly `true`, the source code is included in
       the compiled template for better accuracy.
 *   - `filename` used to improve errors when `compileDebug` is not `false` and to resolve imports/extends
 *
 * @param {String} str
 * @param {Options} options
 * @return {Function}
 * @api public
 */

exports.compile = function(str, options){
  var options = options || {}

  str = String(str);

  var parsed = compileBody(str, {
    compileDebug: options.compileDebug !== false,
    filename: options.filename,
    basedir: options.basedir,
    pretty: options.pretty,
    doctype: options.doctype,
    inlineRuntimeFunctions: options.inlineRuntimeFunctions,
    globals: options.globals,
    self: options.self,
    includeSources: options.compileDebug === true,
    debug: options.debug,
    templateName: 'template',
    filters: options.filters,
    filterOptions: options.filterOptions,
    plugins: options.plugins,
  });

  var res = options.inlineRuntimeFunctions
    ? new Function('', parsed.body + ';return template;')()
    : runtimeWrap(parsed.body);

  res.dependencies = parsed.dependencies;

  return res;
};

/**
 * Compile a JavaScript source representation of the given pug `str`.
 *
 * Options:
 *
 *   - `compileDebug` When it is `true`, the source code is included in
 *     the compiled template for better error messages.
 *   - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends
 *   - `name` the name of the resulting function (defaults to "template")
 *
 * @param {String} str
 * @param {Options} options
 * @return {Object}
 * @api public
 */

exports.compileClientWithDependenciesTracked = function(str, options){
  var options = options || {};

  str = String(str);
  var parsed = compileBody(str, {
    compileDebug: options.compileDebug,
    filename: options.filename,
    basedir: options.basedir,
    pretty: options.pretty,
    doctype: options.doctype,
    inlineRuntimeFunctions: options.inlineRuntimeFunctions !== false,
    globals: options.globals,
    self: options.self,
    includeSources: options.compileDebug,
    debug: options.debug,
    templateName: options.name || 'template',
    filters: options.filters,
    filterOptions: options.filterOptions,
    plugins: options.plugins,
  });

  return {body: parsed.body, dependencies: parsed.dependencies};
};

/**
 * Compile a JavaScript source representation of the given pug `str`.
 *
 * Options:
 *
 *   - `compileDebug` When it is `true`, the source code is included in
 *     the compiled template for better error messages.
 *   - `filename` used to improve errors when `compileDebug` is not `true` and to resolve imports/extends
 *   - `name` the name of the resulting function (defaults to "template")
 *
 * @param {String} str
 * @param {Options} options
 * @return {String}
 * @api public
 */
exports.compileClient = function (str, options) {
  return exports.compileClientWithDependenciesTracked(str, options).body;
};

/**
 * Compile a `Function` representation of the given pug file.
 *
 * Options:
 *
 *   - `compileDebug` when `false` debugging code is stripped from the compiled
       template, when it is explicitly `true`, the source code is included in
       the compiled template for better accuracy.
 *
 * @param {String} path
 * @param {Options} options
 * @return {Function}
 * @api public
 */
exports.compileFile = function (path, options) {
  options = options || {};
  options.filename = path;
  return handleTemplateCache(options);
};

/**
 * Render the given `str` of pug.
 *
 * Options:
 *
 *   - `cache` enable template caching
 *   - `filename` filename required for `include` / `extends` and caching
 *
 * @param {String} str
 * @param {Object|Function} options or fn
 * @param {Function|undefined} fn
 * @returns {String}
 * @api public
 */

exports.render = function(str, options, fn){
  // support callback API
  if ('function' == typeof options) {
    fn = options, options = undefined;
  }
  if (typeof fn === 'function') {
    var res
    try {
      res = exports.render(str, options);
    } catch (ex) {
      return fn(ex);
    }
    return fn(null, res);
  }

  options = options || {};

  // cache requires .filename
  if (options.cache && !options.filename) {
    throw new Error('the "filename" option is required for caching');
  }

  return handleTemplateCache(options, str)(options);
};

/**
 * Render a Pug file at the given `path`.
 *
 * @param {String} path
 * @param {Object|Function} options or callback
 * @param {Function|undefined} fn
 * @returns {String}
 * @api public
 */

exports.renderFile = function(path, options, fn){
  // support callback API
  if ('function' == typeof options) {
    fn = options, options = undefined;
  }
  if (typeof fn === 'function') {
    var res
    try {
      res = exports.renderFile(path, options);
    } catch (ex) {
      return fn(ex);
    }
    return fn(null, res);
  }

  options = options || {};

  options.filename = path;
  return handleTemplateCache(options)(options);
};

/**
 * Compile a Pug file at the given `path` for use on the client.
 *
 * @param {String} path
 * @param {Object} options
 * @returns {String}
 * @api public
 */

exports.compileFileClient = function(path, options){
  var key = path + ':client';
  options = options || {};

  options.filename = path;

  if (options.cache && exports.cache[key]) {
    return exports.cache[key];
  }

  var str = fs.readFileSync(options.filename, 'utf8');
  var out = exports.compileClient(str, options);
  if (options.cache) exports.cache[key] = out;
  return out;
};

/**
 * Express support.
 */

exports.__express = function(path, options, fn) {
  if(options.compileDebug == undefined && process.env.NODE_ENV === 'production') {
    options.compileDebug = false;
  }
  exports.renderFile(path, options, fn);
}
<|endoftext|>


<commit_before>var async = require('async');

var specs = require('require-dir')('.');

module.exports = function(o) {
    if(!o.sugar) {
        return console.warn('Missing sugar!');
    }
    // address, engine and assert are optional
    if(!o.assert) {
        o.assert = require('assert');
    }

    var schemas = require('../schemas')(o.sugar, o.engine);
    var api = require('./api')(o.sugar, schemas, o.assert);
    var tests = Object.keys(specs).map(function(name) {
        return {
            name: name,
            test: specs[name](o.sugar, schemas, o.assert, api)
        };
    });

    console.log('Executing tests!');

    o.sugar.connect(o.address, function(err) {
        if(err) {
            return console.error('Failed to connect to database!', err);
        }

        async.series(setup(tests, removeData.bind(null, o.sugar, schemas)), function(err) {
            if(err) {
                return console.error(err);
            }

            console.log('Tests executed!');

            o.sugar.disconnect(noop);
        });
    });
};

function removeData(sugar, schemas, t) {
    return function(cb) {
        async.eachSeries(Object.keys(schemas), function(name, cb) {
            sugar.removeAll(schemas[name], cb);
        }, t.bind(undefined, cb));
    };
}

function setup(tests, fn) {
    return tests.map(function(t) {
        return function(cb) {
            console.log('Executing', t.name);

            fn(t.test)(cb);
        };
    });
}

function noop() {}

<commit_msg>Disconnect also in fail<commit_after>var async = require('async');

var specs = require('require-dir')('.');

module.exports = function(o) {
    if(!o.sugar) {
        return console.warn('Missing sugar!');
    }
    // address, engine and assert are optional
    if(!o.assert) {
        o.assert = require('assert');
    }

    var schemas = require('../schemas')(o.sugar, o.engine);
    var api = require('./api')(o.sugar, schemas, o.assert);
    var tests = Object.keys(specs).map(function(name) {
        return {
            name: name,
            test: specs[name](o.sugar, schemas, o.assert, api)
        };
    });

    console.log('Executing tests!');

    o.sugar.connect(o.address, function(err) {
        if(err) {
            return console.error('Failed to connect to database!', err);
        }

        async.series(setup(tests, removeData.bind(null, o.sugar, schemas)), function(err) {
            if(err) {
                console.error(err);
            }
            else {
                console.log('Tests executed!');
            }

            o.sugar.disconnect(noop);
        });
    });
};

function removeData(sugar, schemas, t) {
    return function(cb) {
        async.eachSeries(Object.keys(schemas), function(name, cb) {
            sugar.removeAll(schemas[name], cb);
        }, t.bind(undefined, cb));
    };
}

function setup(tests, fn) {
    return tests.map(function(t) {
        return function(cb) {
            console.log('Executing', t.name);

            fn(t.test)(cb);
        };
    });
}

function noop() {}

<|endoftext|>


<commit_before>'use strict';
var CoreControllerHelper = require('periodicjs.core.controllerhelper'),
	CoreController,
	Contenttype,
	logger,
	mongoose,
	existingPeriodicContentType,
	newPeriodicalContentTypeDocument = {
		title: 'periodical',
		name: 'periodical',
		attributes: [{
			title: 'dek',
			datatype: 'string',
			name: 'dek',
		}, {
			title: 'effect',
			datatype: 'array',
			defaultvalue: 'push,fadeout,side,sidefixed,jam3',
			name: 'effect',
		}, {
			title: 'static',
			datatype: 'array',
			defaultvalue: 'false,true',
			name: 'static',
		}]
	};

var checkContentTypePeriodical = function (callback) {
	CoreController.loadModel({
		docid: 'periodical',
		model: Contenttype,
		callback: callback
	});
};

var updatePeriodicalContentType = function (callback) {
	CoreController.updateModel({
		model: Contenttype,
		id: existingPeriodicContentType._id,
		updatedoc: newPeriodicalContentTypeDocument,
		callback: callback
	});
};

var createPeriodicalContentType = function (callback) {
	CoreController.createModel({
		model: Contenttype,
		newdoc: newPeriodicalContentTypeDocument,
		callback: callback
	});
};

var setup = function (resources) {
	logger = resources.logger;
	mongoose = resources.mongoose;
	// appSettings = resources.settings,
	CoreController = new CoreControllerHelper(resources);
	Contenttype = mongoose.model('Contenttype');

	mongoose.connection.on('open', function () {
		checkContentTypePeriodical(function (err, doc) {
			if (err) {
				logger.error(err);
			}
			else if (doc) {
				existingPeriodicContentType = doc;
				updatePeriodicalContentType(function (err, updatedcontenttype) {
					if (err) {
						logger.error(err);
					}
					else {
						logger.info('Old Periodical Content Type');
						// console.log(existingPeriodicContentType);
						logger.info('Updated Periodical Content Type');
						// console.log(updatedcontenttype);
					}
				});
			}
			else {
				createPeriodicalContentType(function (err, newcontenttype) {
					if (err) {
						logger.error(err);
					}
					else {
						logger.info('createdNewContentType');
						// console.log(newcontenttype);
					}
				});
			}
		});
	});
};

module.exports = setup;
<commit_msg>added default content types<commit_after>'use strict';
var CoreControllerHelper = require('periodicjs.core.controllerhelper'),
	CoreController,
	Contenttype,
	AppDBSetting,
	logger,
	mongoose,
	existingPeriodicContentType,
	usablePeriodicContentType,
	itemDefaultContenttype,
	newPeriodicalContentTypeDocument = {
		title: 'periodical',
		name: 'periodical',
		attributes: [{
			title: 'dek',
			datatype: 'string',
			name: 'dek',
		}, {
			title: 'effect',
			datatype: 'array',
			defaultvalue: 'push,fadeout,side,sidefixed,jam3',
			name: 'effect',
		}, {
			title: 'static',
			datatype: 'array',
			defaultvalue: 'false,true',
			name: 'static',
		}]
	};

var createDefaultItemContentType = function () {
	var newDefaultItemContentType = {
		name: 'item_default_contenttypes'
	};

	CoreController.createModel({
		model: AppDBSetting,
		newdoc: newDefaultItemContentType,
		callback: function (err, newappsettingdocument) {
			if (err) {
				logger.error(err);
			}
			else {
				itemDefaultContenttype = newappsettingdocument;
				logger.silly('add newly created default content type');
				updateDefaultItemContentType(itemDefaultContenttype);
			}
		}
	});
};

var updateDefaultItemContentType = function (appsettingdocumenttouse) {
	var alreadyHasDefault = false;
	for (var x in appsettingdocumenttouse.value) {
		if (usablePeriodicContentType._id.toString() === appsettingdocumenttouse.value[x].toString()) {
			alreadyHasDefault = true;
		}
	}
	if (alreadyHasDefault) {
		logger.silly('appsettingdocumenttouse.value', appsettingdocumenttouse.value, 'already has', usablePeriodicContentType._id);
	}
	else {
		var objectToModify = {
			'value': usablePeriodicContentType._id
		};
		CoreController.updateModel({
			model: AppDBSetting,
			id: appsettingdocumenttouse._id,
			appendArray: true,
			updatedoc: objectToModify,
			callback: function (err, updatedsetting) {
				if (err) {
					logger.error(err);
				}
				else {
					console.log('updated settings', updatedsetting);
				}
			}
		});
	}
};

var addDefaultItemContentType = function () {
	CoreController.loadModel({
		docid: 'item_default_contenttypes',
		model: AppDBSetting,
		callback: function (err, appsettingdocument) {
			if (err) {
				logger.error(err);
			}
			else if (appsettingdocument) {
				itemDefaultContenttype = appsettingdocument;
				logger.silly('add default content type');
				updateDefaultItemContentType(itemDefaultContenttype);
			}
			else {
				logger.silly('create new default item content type');
				createDefaultItemContentType();
			}
		}
	});
};

var checkContentTypePeriodical = function (callback) {
	CoreController.loadModel({
		docid: 'periodical',
		model: Contenttype,
		callback: callback
	});
};

var updatePeriodicalContentType = function (callback) {
	CoreController.updateModel({
		model: Contenttype,
		id: existingPeriodicContentType._id,
		updatedoc: newPeriodicalContentTypeDocument,
		callback: callback
	});
};

var createPeriodicalContentType = function (callback) {
	CoreController.createModel({
		model: Contenttype,
		newdoc: newPeriodicalContentTypeDocument,
		callback: callback
	});
};

var setup = function (resources) {
	logger = resources.logger;
	mongoose = resources.mongoose;
	// appSettings = resources.settings,
	CoreController = new CoreControllerHelper(resources);
	Contenttype = mongoose.model('Contenttype');
	AppDBSetting = mongoose.model('Setting');

	mongoose.connection.on('open', function () {
		checkContentTypePeriodical(function (err, doc) {
			if (err) {
				logger.error(err);
			}
			else if (doc) {
				existingPeriodicContentType = doc;
				updatePeriodicalContentType(function (err, updatedcontenttype) {
					if (err) {
						logger.error(err);
					}
					else {
						logger.info('Old Periodical Content Type');
						// console.log(existingPeriodicContentType);
						logger.info('Updated Periodical Content Type');
						// console.log(updatedcontenttype);
						usablePeriodicContentType = updatedcontenttype;
						addDefaultItemContentType();
					}
				});
			}
			else {
				createPeriodicalContentType(function (err, newcontenttype) {
					if (err) {
						logger.error(err);
					}
					else {
						logger.info('createdNewContentType');
						// console.log(newcontenttype);
						usablePeriodicContentType = newcontenttype;
						addDefaultItemContentType();
					}
				});
			}
		});
	});
};

module.exports = setup;
<|endoftext|>


<commit_before>var _ = require('lodash');
var async = require('async');
var defaultValidations = require('./defaultValidations');
var Model = require('racer/lib/Model');

module.exports = Validator;

/**
 * Creates a validator object and initiates it
 * @param {Model} model - A scoped model to the location on where to put the validator's data
 * @param {Model|string|Object} [origin|defaultObject] - Either a scoped model to the location where the original data is stored. Or, a path (as string) to the location where to find the original data. If not passed, the fields parameter is mandatory. Can also be passed in as a defaultObject. If passed in as default objet, the fields parameter is also mandatory.
 * @param {Collection.<string, Object>} [fields] - A collection of fields to use. If not passed, the origin parameter is mandatory. The key for each object is the field name, and the value is the field object (specified below).
   * @param {*} [fields.<fieldName>.default] - A default value for this specific field.
   * @param {String} [fields.<fieldName>.group] - A group the field belongs to. Useful for looking up validity of multiple fields simultaneously.
   * @param {Object[]} [fields.<fieldName>.validations] - A list of validations to apply.
     * @param {String|Function|RegEx} [fields.<fieldName>.validations.<index>.rule] - The rule to use when validating this rule. Either, this can be a string matching the name of a default rule (specified in default checks or passed in as an option), OR a function which will get run with the value to be validated as input and a callback to return the validity with, OR a RegEx to test against.
     * @param {String} [fields.<fieldName>.validations.<index>.message] - The error message to show if validation fails
 * @param {Object} [options] - An options object
   * @param {Collection.<string, Function|RegEx>} [options.rules] - A collection of default rules to add to this instance. Each key is the name of the rule. The value is the rule, either a function or regular expression similar to field specific functions/regular expressions passed in the fields parameter
 * @returns {Validator} - Instance of Validator
 */
function Validator(model, origin, fields, options) {
  // Parse out arguments
  var self = this;
  var args = Array.prototype.slice.call(arguments);

  if(!args.length) throw new Error('You must specify a model!');
  if(args.length == 1) throw new Error('You must either specify an origin or a fields object');

  this.model = args.shift();
  var arg = args.shift();

  // Origin cases
  if(arg instanceof Model) {
    this.origin = arg;

    arg = args.shift();
  } else if(typeof arg === 'string') {
    this.origin = this.model.scope(arg);

    arg = args.shift();
  }

  // If only a collection was passed, assume we want to add to a new doc
  if(this.origin) {
    var segments = this.origin._splitPath();

    if(segments.length === 1) {
      // Generate a new id
      this.origin = this.origin.at(model.id());
    }
  }

  if(arg) {
    // Case where we've passed in a default object
    if(!Array.isArray(arg) && typeof args[0] !== 'undefined') {
      var defaultObject = arg;

      arg = args.shift();
    }

    // Fields argument
    if(Array.isArray(arg)) {
      // Support passing in an array of fields
      this.fields = _.zipObject(arg, _.fill(Array(arg.length), {}));
    } else {
      this.fields = _.cloneDeep(arg);
    }

    if(defaultObject) {
      _.each(defaultObject, function (val, key) {
        if(!self.fields[key]) self.fields[key] = {};

        self.fields[key]['default'] = val;
      });
    }
  }

  this.options = _.assign({
    rules: {},
    messages: {}
  }, args.shift());

  // Setup
  this._setup();
}

// TODO: Add proper docs for external facing methods, such as this one
Validator.prototype.getValues = function (noId) {
  var values = {};
  var fieldsObject = this._getFieldsObject();
  var exclude = ['hasChangedFields', 'hasInvalidFields', 'groups'];
  if(noId) exclude.push('id');

  function get(collection, fieldsObject, values) {
    _.each(collection, function (field, fieldName) {
      if(!fieldsObject || fieldsObject[fieldName] === true || typeof fieldsObject[fieldName] === 'undefined') {
        if(exclude.indexOf(fieldName) > -1) return;

        values[fieldName] = field.value;
        return;
      }

      values[fieldName] = values[fieldName] || {};

      get(field, fieldsObject[fieldName], values[fieldName]);
    });
  }

  get(this.model.get(), fieldsObject, values);

  return values;
};

Validator.prototype._getFieldsObject = function () {
  var fieldsObject = {};

  function set(fieldsObject, segments) {
    var segment = segments.shift();

    if(segments.length < 1) return fieldsObject[segment] = true;

    fieldsObject[segment] = fieldsObject[segment] || {};
    set(fieldsObject[segment], segments);
  }

  _.each(this.fields, function (field, fieldName) {
    var segments = fieldName.split('.');

    set(fieldsObject, segments);
  });

  return fieldsObject;
};

// TODO: Add proper docs for external facing methods, such as this one
Validator.prototype.validate = function (fieldname, callback) {
  this._validate(fieldname, callback);
};

// TODO: Add proper docs for external facing methods, such as this one
Validator.prototype.validateAll = function(callback) {
  var self = this;

  var validating = [];

  _.each(this.fields, function (field, fieldName) {
    if(!field.validations) return;

    validating.push(function (asyncCallback) {
      self._validate(fieldName, function (valid) {
        asyncCallback(valid ? null : true, valid);
      });
    });
  });

  async.parallel(validating, function (err, res) {
    if (callback) callback(err ? false : true, res);
  });
};

// TODO: Add proper docs for external facing methods, such as this one
Validator.prototype.setInvalid = function (fieldName, message) {
  this._setValidity(fieldName, false);
  this.model.push(fieldName + '.messages', message || defaultValidations['default'].message);
};

/*
 * @public
 * Reset values to origin.
 */
Validator.prototype.reset = function () {
  this._setup();
};

/*
 * @public
 * Validates and commits to model.
 *
 * @param {Boolean} [force] - Whether to force commit without validating.
 * @param {Function} [callback] - A function that is called after validation. Passes valid state.
 */
Validator.prototype.commit = function (force, callback) {
  if (!this.origin) return;

  if (arguments.length === 1 && typeof arguments[0] !== 'boolean')  {
    callback = arguments[0];
    force = false;
  }

  if (force) {
    this._commitToModel();

    return;
  }

  var self = this;
  this.validateAll(function (valid) {
    if (valid) self._commitToModel();

    if (callback) callback(valid);
  });
};

Validator.prototype._commitToModel = function () {
  var values = this.getValues(true);

  if(this.origin.get('id')) {
    this.origin.setEach(values);
  } else {
    // REVIEW: If we haven fetched/subscribed to a doc which we have the id for (i.e. we try to add a doc which already exists in DB), we get random errors that we don't handle (but doesn't seem to really affect anything)
    var id = this.origin.leaf();
    values.id = id;
    this.origin.parent().add(values);
  }
};

Validator.prototype._setup = function () {
  var self = this;

  if (this.fields) {
    _.each(this.fields, function (field, fieldName) {
      self._addFieldProperties(fieldName, field);
    });
  }

  if(this.origin) this._addFromOrigin();

  this.model.on('change', '**', function (path, value) {
    var segments = path.split('.');
    var contains = _.contains(segments, 'value');
    var last = _.last(segments);
    var field;

    if (contains) {
      var valueIndex = _.findIndex(segments, function (segment) {
        return segment === 'value';
      });

      field = _.slice(segments, 0, valueIndex).join('.');
      // REVIEW: Why only when we have origin?
      if (self.origin) {
        if (value !== self.origin.get(field)) {
          self.model.set(field + '.hasChanged', true);
        } else {
          self.model.set(field + '.hasChanged', false);
        }

        self._setChangedState();
      }
    } else {
      field = _.dropRight(segments).join('.');
    }

    if(last === 'isValid' && self.fields && self.fields[field]) {
      self._setGroupValidity(field, value);
    }
  });
};

Validator.prototype._setGroupValidity = function (field, value) {
  var group = this.fields[field].group || 'default';
  var path = 'groups.' + group + '.isValid';
  var currentlyValid = this.model.get(path);

  // No change in status
  if(currentlyValid == value) return;

  // It was true, now it's not valid anymore
  if(!value) this.model.set(path, false);

  // It was false, but might be true now if all others are also true
  var self = this;
  var allValid = _.every(this.fields, function (field, key) {
    var fieldGroup = field.group || 'default';

    if(fieldGroup !== group) return true;

    if(self.model.get(key + '.isValid')) return true;

    return false;
  });

  if(!allValid) return;

  this.model.set(path, true);
};

Validator.prototype._addFromOrigin = function () {
  var self = this;
  var fieldsObject = this._getFieldsObject();

  function add(collection, segments, fieldsObject) {
    _.each(collection, function (value, fieldName) {
      var newSegments = segments.concat([fieldName]);
      var path = newSegments.join('.');

      if(!fieldsObject || fieldsObject[fieldName] === true || typeof fieldsObject[fieldName] === 'undefined') {
        self.model.set(path + '.value', value);
        return;
      }

      add(value, newSegments, fieldsObject[fieldName]);
    });
  }

  add(this.origin.get(), [], fieldsObject);
};

Validator.prototype._addFieldProperties = function (fieldName, field) {
  var self = this;
  var data = {value: null};

  if(field) {
    data = {value: field.default};

    if(field.validations) {
      _.assign(data, {
        validations: this._assignValidations(field.validations),
        isValid: false,
        isInvalid: false,
        validate: function (callback) {
          return self._validate(fieldName, callback);
        }
      });
    }
  }

  this.model.setEach(fieldName, data);
};

Validator.prototype._validate = function (fieldName, callback) {
  this.model.del(fieldName + '.messages');
  this.model.set(fieldName + '.validating', true);
  var serial = this.model.increment(fieldName + '.serial');
  var self = this;

  var field = this.model.get(fieldName);
  if (!field || !field.hasOwnProperty('validations')) {
    if (callback) callback(true);
    return;
  }

  var validating = [];
  for (var i = 0; i < field.validations.length; i++) {
    validating.push(this._check(fieldName, field.value, field.validations[i], serial, this));
  }

  async.parallel(validating, function (err, results) {
    var valid = err ? false : true;

    self._setValidity(fieldName, valid);

    if (callback) callback(valid);
    if (serial === self.model.get(fieldName + '.serial')) self.model.del(fieldName + '.validating');
  });
};

Validator.prototype._assignValidations = function (validations) {
  for (var i = 0; i < validations.length; i++) {
    var validation = validations[i];

    if (!validation.message) validation.message = this._getMessage(validation.rule);

    if (typeof validation.rule === 'string') validation.rule = this._getRule(validation.rule);

    if (typeof validation.rule !== 'function' && !_.isRegExp(validation.rule)) throw new Error('This rule is not (or does not point to) a RegEx or a function.');
  }

  return validations;
};

Validator.prototype._getRule = function (ruleName) {
  if(this.options.rules[ruleName]) return this.options.rules[ruleName];

  if(defaultValidations.hasOwnProperty(ruleName)) return defaultValidations[ruleName].rule;

  throw new Error('Rule: "' + ruleName + '" is not available. You need to add it as an option.');
};

Validator.prototype._getMessage = function (ruleName) {
  return this.options.messages[ruleName] || ((defaultValidations.hasOwnProperty(ruleName)) ? defaultValidations[ruleName].message : defaultValidations['default'].message);
};

Validator.prototype._check = function (fieldName, value, validation, serial, context) {
  return function (callback) {
    var setValidity = function (valid) {
      var current = (serial === context.model.get(fieldName + '.serial'));
      if (current && !valid) context.model.push(fieldName + '.messages', validation.message);

      callback(current && valid ? null : true, valid);
    };

    if (_.isRegExp(validation.rule)) setValidity(validation.rule.test(value));

    if (typeof validation.rule === 'function') validation.rule(value, setValidity);
  };
};

Validator.prototype._setValidity = function (fieldName, validity) {
  this.model.setEach(fieldName, { isValid: validity, isInvalid: !validity });
  this._setState();
};

Validator.prototype._setState = function() {
  this.model.set('hasInvalidFields', !!_.result(_.find(this.model.get(), {'isInvalid': true}), 'isInvalid'));
};

Validator.prototype._setChangedState = function() {
  function find(collection, property) {
    return _.findKey(collection, function (field, fieldName) {
      if (field.hasOwnProperty('value')) {
        return field[property];
      }

      if (typeof field === 'object') return find(field, property);

      return false;
    });
  }

  this.model.set('hasChangedFields', !!find(this.model.get(), 'hasChanged'));
};
<commit_msg>Fix get copy of origin<commit_after>var _ = require('lodash');
var async = require('async');
var defaultValidations = require('./defaultValidations');
var Model = require('racer/lib/Model');

module.exports = Validator;

/**
 * Creates a validator object and initiates it
 * @param {Model} model - A scoped model to the location on where to put the validator's data
 * @param {Model|string|Object} [origin|defaultObject] - Either a scoped model to the location where the original data is stored. Or, a path (as string) to the location where to find the original data. If not passed, the fields parameter is mandatory. Can also be passed in as a defaultObject. If passed in as default objet, the fields parameter is also mandatory.
 * @param {Collection.<string, Object>} [fields] - A collection of fields to use. If not passed, the origin parameter is mandatory. The key for each object is the field name, and the value is the field object (specified below).
   * @param {*} [fields.<fieldName>.default] - A default value for this specific field.
   * @param {String} [fields.<fieldName>.group] - A group the field belongs to. Useful for looking up validity of multiple fields simultaneously.
   * @param {Object[]} [fields.<fieldName>.validations] - A list of validations to apply.
     * @param {String|Function|RegEx} [fields.<fieldName>.validations.<index>.rule] - The rule to use when validating this rule. Either, this can be a string matching the name of a default rule (specified in default checks or passed in as an option), OR a function which will get run with the value to be validated as input and a callback to return the validity with, OR a RegEx to test against.
     * @param {String} [fields.<fieldName>.validations.<index>.message] - The error message to show if validation fails
 * @param {Object} [options] - An options object
   * @param {Collection.<string, Function|RegEx>} [options.rules] - A collection of default rules to add to this instance. Each key is the name of the rule. The value is the rule, either a function or regular expression similar to field specific functions/regular expressions passed in the fields parameter
 * @returns {Validator} - Instance of Validator
 */
function Validator(model, origin, fields, options) {
  // Parse out arguments
  var self = this;
  var args = Array.prototype.slice.call(arguments);

  if(!args.length) throw new Error('You must specify a model!');
  if(args.length == 1) throw new Error('You must either specify an origin or a fields object');

  this.model = args.shift();
  var arg = args.shift();

  // Origin cases
  if(arg instanceof Model) {
    this.origin = arg;

    arg = args.shift();
  } else if(typeof arg === 'string') {
    this.origin = this.model.scope(arg);

    arg = args.shift();
  }

  // If only a collection was passed, assume we want to add to a new doc
  if(this.origin) {
    var segments = this.origin._splitPath();

    if(segments.length === 1) {
      // Generate a new id
      this.origin = this.origin.at(model.id());
    }
  }

  if(arg) {
    // Case where we've passed in a default object
    if(!Array.isArray(arg) && typeof args[0] !== 'undefined') {
      var defaultObject = arg;

      arg = args.shift();
    }

    // Fields argument
    if(Array.isArray(arg)) {
      // Support passing in an array of fields
      this.fields = _.zipObject(arg, _.fill(Array(arg.length), {}));
    } else {
      this.fields = _.cloneDeep(arg);
    }

    if(defaultObject) {
      _.each(defaultObject, function (val, key) {
        if(!self.fields[key]) self.fields[key] = {};

        self.fields[key]['default'] = val;
      });
    }
  }

  this.options = _.assign({
    rules: {},
    messages: {}
  }, args.shift());

  // Setup
  this._setup();
}

// TODO: Add proper docs for external facing methods, such as this one
Validator.prototype.getValues = function (noId) {
  var values = {};
  var fieldsObject = this._getFieldsObject();
  var exclude = ['hasChangedFields', 'hasInvalidFields', 'groups'];
  if(noId) exclude.push('id');

  function get(collection, fieldsObject, values) {
    _.each(collection, function (field, fieldName) {
      if(!fieldsObject || fieldsObject[fieldName] === true || typeof fieldsObject[fieldName] === 'undefined') {
        if(exclude.indexOf(fieldName) > -1) return;

        values[fieldName] = field.value;
        return;
      }

      values[fieldName] = values[fieldName] || {};

      get(field, fieldsObject[fieldName], values[fieldName]);
    });
  }

  get(this.model.get(), fieldsObject, values);

  return values;
};

Validator.prototype._getFieldsObject = function () {
  var fieldsObject = {};

  function set(fieldsObject, segments) {
    var segment = segments.shift();

    if(segments.length < 1) return fieldsObject[segment] = true;

    fieldsObject[segment] = fieldsObject[segment] || {};
    set(fieldsObject[segment], segments);
  }

  _.each(this.fields, function (field, fieldName) {
    var segments = fieldName.split('.');

    set(fieldsObject, segments);
  });

  return fieldsObject;
};

// TODO: Add proper docs for external facing methods, such as this one
Validator.prototype.validate = function (fieldname, callback) {
  this._validate(fieldname, callback);
};

// TODO: Add proper docs for external facing methods, such as this one
Validator.prototype.validateAll = function(callback) {
  var self = this;

  var validating = [];

  _.each(this.fields, function (field, fieldName) {
    if(!field.validations) return;

    validating.push(function (asyncCallback) {
      self._validate(fieldName, function (valid) {
        asyncCallback(valid ? null : true, valid);
      });
    });
  });

  async.parallel(validating, function (err, res) {
    if (callback) callback(err ? false : true, res);
  });
};

// TODO: Add proper docs for external facing methods, such as this one
Validator.prototype.setInvalid = function (fieldName, message) {
  this._setValidity(fieldName, false);
  this.model.push(fieldName + '.messages', message || defaultValidations['default'].message);
};

/*
 * @public
 * Reset values to origin.
 */
Validator.prototype.reset = function () {
  this._setup();
};

/*
 * @public
 * Validates and commits to model.
 *
 * @param {Boolean} [force] - Whether to force commit without validating.
 * @param {Function} [callback] - A function that is called after validation. Passes valid state.
 */
Validator.prototype.commit = function (force, callback) {
  if (!this.origin) return;

  if (arguments.length === 1 && typeof arguments[0] !== 'boolean')  {
    callback = arguments[0];
    force = false;
  }

  if (force) {
    this._commitToModel();

    return;
  }

  var self = this;
  this.validateAll(function (valid) {
    if (valid) self._commitToModel();

    if (callback) callback(valid);
  });
};

Validator.prototype._commitToModel = function () {
  var values = this.getValues(true);

  if(this.origin.get('id')) {
    this.origin.setEach(values);
  } else {
    // REVIEW: If we haven fetched/subscribed to a doc which we have the id for (i.e. we try to add a doc which already exists in DB), we get random errors that we don't handle (but doesn't seem to really affect anything)
    var id = this.origin.leaf();
    values.id = id;
    this.origin.parent().add(values);
  }
};

Validator.prototype._setup = function () {
  var self = this;

  if (this.fields) {
    _.each(this.fields, function (field, fieldName) {
      self._addFieldProperties(fieldName, field);
    });
  }

  if(this.origin) this._addFromOrigin();

  this.model.on('change', '**', function (path, value) {
    var segments = path.split('.');
    var contains = _.contains(segments, 'value');
    var last = _.last(segments);
    var field;

    if (contains) {
      var valueIndex = _.findIndex(segments, function (segment) {
        return segment === 'value';
      });

      field = _.slice(segments, 0, valueIndex).join('.');
      // REVIEW: Why only when we have origin?
      if (self.origin) {
        if (value !== self.origin.get(field)) {
          self.model.set(field + '.hasChanged', true);
        } else {
          self.model.set(field + '.hasChanged', false);
        }

        self._setChangedState();
      }
    } else {
      field = _.dropRight(segments).join('.');
    }

    if(last === 'isValid' && self.fields && self.fields[field]) {
      self._setGroupValidity(field, value);
    }
  });
};

Validator.prototype._setGroupValidity = function (field, value) {
  var group = this.fields[field].group || 'default';
  var path = 'groups.' + group + '.isValid';
  var currentlyValid = this.model.get(path);

  // No change in status
  if(currentlyValid == value) return;

  // It was true, now it's not valid anymore
  if(!value) this.model.set(path, false);

  // It was false, but might be true now if all others are also true
  var self = this;
  var allValid = _.every(this.fields, function (field, key) {
    var fieldGroup = field.group || 'default';

    if(fieldGroup !== group) return true;

    if(self.model.get(key + '.isValid')) return true;

    return false;
  });

  if(!allValid) return;

  this.model.set(path, true);
};

Validator.prototype._addFromOrigin = function () {
  var self = this;
  var fieldsObject = this._getFieldsObject();

  function add(collection, segments, fieldsObject) {
    _.each(collection, function (value, fieldName) {
      var newSegments = segments.concat([fieldName]);
      var path = newSegments.join('.');

      if(!fieldsObject || fieldsObject[fieldName] === true || typeof fieldsObject[fieldName] === 'undefined') {
        self.model.set(path + '.value', value);
        return;
      }

      add(value, newSegments, fieldsObject[fieldName]);
    });
  }

  add(this.origin.getDeepCopy(), [], fieldsObject);
};

Validator.prototype._addFieldProperties = function (fieldName, field) {
  var self = this;
  var data = {value: null};

  if(field) {
    data = {value: field.default};

    if(field.validations) {
      _.assign(data, {
        validations: this._assignValidations(field.validations),
        isValid: false,
        isInvalid: false,
        validate: function (callback) {
          return self._validate(fieldName, callback);
        }
      });
    }
  }

  this.model.setEach(fieldName, data);
};

Validator.prototype._validate = function (fieldName, callback) {
  this.model.del(fieldName + '.messages');
  this.model.set(fieldName + '.validating', true);
  var serial = this.model.increment(fieldName + '.serial');
  var self = this;

  var field = this.model.get(fieldName);
  if (!field || !field.hasOwnProperty('validations')) {
    if (callback) callback(true);
    return;
  }

  var validating = [];
  for (var i = 0; i < field.validations.length; i++) {
    validating.push(this._check(fieldName, field.value, field.validations[i], serial, this));
  }

  async.parallel(validating, function (err, results) {
    var valid = err ? false : true;

    self._setValidity(fieldName, valid);

    if (callback) callback(valid);
    if (serial === self.model.get(fieldName + '.serial')) self.model.del(fieldName + '.validating');
  });
};

Validator.prototype._assignValidations = function (validations) {
  for (var i = 0; i < validations.length; i++) {
    var validation = validations[i];

    if (!validation.message) validation.message = this._getMessage(validation.rule);

    if (typeof validation.rule === 'string') validation.rule = this._getRule(validation.rule);

    if (typeof validation.rule !== 'function' && !_.isRegExp(validation.rule)) throw new Error('This rule is not (or does not point to) a RegEx or a function.');
  }

  return validations;
};

Validator.prototype._getRule = function (ruleName) {
  if(this.options.rules[ruleName]) return this.options.rules[ruleName];

  if(defaultValidations.hasOwnProperty(ruleName)) return defaultValidations[ruleName].rule;

  throw new Error('Rule: "' + ruleName + '" is not available. You need to add it as an option.');
};

Validator.prototype._getMessage = function (ruleName) {
  return this.options.messages[ruleName] || ((defaultValidations.hasOwnProperty(ruleName)) ? defaultValidations[ruleName].message : defaultValidations['default'].message);
};

Validator.prototype._check = function (fieldName, value, validation, serial, context) {
  return function (callback) {
    var setValidity = function (valid) {
      var current = (serial === context.model.get(fieldName + '.serial'));
      if (current && !valid) context.model.push(fieldName + '.messages', validation.message);

      callback(current && valid ? null : true, valid);
    };

    if (_.isRegExp(validation.rule)) setValidity(validation.rule.test(value));

    if (typeof validation.rule === 'function') validation.rule(value, setValidity);
  };
};

Validator.prototype._setValidity = function (fieldName, validity) {
  this.model.setEach(fieldName, { isValid: validity, isInvalid: !validity });
  this._setState();
};

Validator.prototype._setState = function() {
  this.model.set('hasInvalidFields', !!_.result(_.find(this.model.get(), {'isInvalid': true}), 'isInvalid'));
};

Validator.prototype._setChangedState = function() {
  function find(collection, property) {
    return _.findKey(collection, function (field, fieldName) {
      if (field.hasOwnProperty('value')) {
        return field[property];
      }

      if (typeof field === 'object') return find(field, property);

      return false;
    });
  }

  this.model.set('hasChangedFields', !!find(this.model.get(), 'hasChanged'));
};
<|endoftext|>


<commit_before>"use strict";

const forEach = require("iterate-object")

module.exports = class i18nError {
    constructor (errors = {}) {
        this._errors = {}
        this._lang = null
        this.add(errors)
    }

    _get (info) {
        let errMsg = info.err.message
        errMsg = errMsg[this._lang] || errMsg
        if (typeof errMsg === "object") {
            for (let k in errMsg) {
                errMsg = errMsg[k]
                break
            }
        }

        for (let i = 1; i < arguments.length; ++i) {
            errMsg = errMsg.replace(new RegExp("{" + i + "+}", "g"), arguments[i]);
        }

        const err = new Error(errMsg)
        Object.keys(info.err).forEach(c => {
            if (c === "message") { return }
            err[c] = info.err[c]
        })
        return err
    }

    setLang (lang) {
        this._lang = lang
    }

    add (name, err) {
        if (typeof name === "object") {
            forEach(name, (err, name) => this.add(name, err))
            return this
        }
        if (typeof err === "string") {
            err = { message: err }
        }
        this._errors[name] = err
        this[name] = this._get.bind(this, {
            err,
            name
        })
        return this
    }
}
<commit_msg>Documentation01<commit_after>"use strict";

const forEach = require("iterate-object")

module.exports = class i18nError {
    constructor (errors = {}) {
        this._errors = {}
        this._lang = null
        this.add(errors)
    }

    _get (info) {

        // The error message gets checked out and temporarily memorized
        let errMsg = info.err.message
        errMsg = errMsg[this._lang] || errMsg
        if (typeof errMsg === "object") {
            for (let k in errMsg) {
                errMsg = errMsg[k]
                break
            }
        }

        // The identified language influences the replacement of the error message

        for (let i = 1; i < arguments.length; ++i) {
            errMsg = errMsg.replace(new RegExp("{" + i + "+}", "g"), arguments[i]);
        }

        const err = new Error(errMsg)
        Object.keys(info.err).forEach(c => {
            if (c === "message") { return }
            err[c] = info.err[c]
        })
        return err
    }

    setLang (lang) {
        this._lang = lang
    }

    add (name, err) {

        //The error is added
        if (typeof name === "object") {
            forEach(name, (err, name) => this.add(name, err))
            return this
        }
        if (typeof err === "string") {
            err = { message: err }
        }

        //The new function is created and the paramater gets returned
        this._errors[name] = err
        this[name] = this._get.bind(this, {
            err,
            name
        })
        return this
    }
}
<|endoftext|>


<commit_before>var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var util = require('util');
var zlib = require('zlib');

var mime = require('mime');
var Negotiator = require('negotiator');
var react = require('react-tools');
var sass = require('node-sass');
var sassGraph = require('sass-graph');
var Snockets = require('snockets');
var Uglify = require('uglify-js');
var UglifyCss = require('uglifycss');
var watch = require('watch');

var availableEncodings = ['gzip', 'identity'];
var gzipContentTypes = require('./gzipContentTypes.js');

exports.static = function static(directory, options) {
    directory = path.resolve(directory || 'public');

    options = options ? Object.assign({}, options) : {};
    options.sass = options.sass || {};
    if (!options.sass) {
        options.sass = {};
    }
    if (!options.snockets) {
        options.snockets = {};
    }
    if (!options.jsx) {
        options.jsx = {};
    }

    options.snockets.async = false;

    if (!options.uglifycss) {
        options.uglifycss = {
            enabled: true
        };
    }

    if (!options.uglifyjs) {
        options.uglifyjs = {
            compress: {
                sequences: false
            },
            enabled: true
        };
    }

    if (!options.watch) {
        options.watch = {
            enabled: true
        };
    }

    if (options.hostname) {
        if (typeof options.hostname !== 'string') {
            throw Error('hostname must be a string');
        } else if (options.hostname.slice(-1) === '/') {
            options.hostname = options.hostname.slice(0, options.hostname.length - 1);
        }
    }

    if (options.sass.imagePath) {
        if (typeof options.sass.imagePath !== 'string') {
            throw Error('sass.imagePath must be a string');
        }
    }

    if (!options.sass.functions) {
        options.sass.functions = {};
    }

    options.sass.functions['image-url($img)'] = function(img) {
        return new sass.types.String('url("' +
            (options.sass.imagePath ?
                path.join('/', options.sass.imagePath, img.getValue()) :
                path.join('/', img.getValue())
            ) +
            '")');
    };

    var files = {};
    var snockets = new Snockets();
    var stylesheets = [];

    function cacheFile(filePath, stat) {
        // Make sure stat wasn't an extra index parameter
        stat = typeof stat === 'object' ? stat : fs.statSync(filePath);

        if (!stat.isDirectory()) {
            var data;
            var ext = path.extname(filePath);
            var relativeUrl = toRelativeUrl(filePath);

            // Compilation steps
            if (ext === '.scss' && !shouldIgnore(relativeUrl, options.sass.ignore)) {
                // Sass
                options.sass.file = filePath;
                data = sass.renderSync(options.sass).css.toString();

                // Future steps should treat this as plain CSS
                relativeUrl = relativeUrl.replace(/.scss$/, '.css');
                ext = '.css';
            } else if (ext === '.js' && !shouldIgnore(relativeUrl, options.snockets.ignore)) {
                // Snockets
                try {
                    data = snockets.getConcatenation(filePath, options.snockets);
                } catch (e) {
                    // Snockets can't parse, so just pass the js file along
                    console.warn('Snockets skipping ' + filePath + ":\n" + e);
                    data = fs.readFileSync(filePath).toString();
                }
            }

            if (ext === '.js' && !shouldIgnore(relativeUrl, options.jsx.ignore)) {
                // React
                data = data || fs.readFileSync(filePath).toString();

                try {
                    data = react.transform(data, options.jsx);
                } catch (e) {
                    // Snockets can't parse, so just pass the js file along
                    console.warn('JSX compiler skipping ' + filePath + ":\n" + e);
                    data = fs.readFileSync(filePath).toString();
                }

                ext = '.js';
            }

            // Postprocessing steps
            if (ext === '.css') {
                if (options.uglifycss.enabled) {
                    // Uglifycss
                    data = data ?
                        UglifyCss.processString(data, options.uglifycss) :
                        UglifyCss.processFiles([filePath], options.uglifycss);
                }
            } else if (ext === '.js' && options.uglifyjs.enabled && !shouldIgnore(relativeUrl, options.uglifyjs.ignore)) {
                // Uglifyjs
                options.uglifyjs.fromString = !!data;

                try {
                    data = options.uglifyjs.fromString ?
                        Uglify.minify(data.toString(), options.uglifyjs).code :
                        Uglify.minify(filePath, options.uglifyjs).code;
                } catch (e) {
                    console.warn(util.format('UglifyJS skipping %s:\n %s (line %s, col %s, pos %s)', filePath, e.message, e.line, e.col, e.pos));
                }
            }

            // Have data?
            data = data || fs.readFileSync(filePath);

            // Cache file and hash, generate hash later if it's CSS because we're going to modify the contents
            files[relativeUrl] = {
                content: data,
                contentLength: typeof data === 'string' ? Buffer.byteLength(data) : data.length,
                contentType: mime.lookup(relativeUrl),
                hash: ext !== '.css' ? crypto.createHash('md5').update(data).digest('hex') : '',
                modified: stat.mtime
            };

            if (ext === '.css') {
                stylesheets.push(relativeUrl);
            }

            return relativeUrl;
        }
    }

    function dehashifyPath(filePath) {
        var hashRegex = /-[0-9a-f]+(\.[^\.]*$)/;
        var hashMatch = filePath.match(hashRegex);
        var hash = hashMatch ? hashMatch[0].slice(1).replace(/\.([^\.]*$)/, '') : '';

        return {
            path: hash.length==32 ? filePath.replace(hashRegex, '$1') : filePath,
            hash: hash.length==32 ? hash : null
        };
    }

    function gzip(file, callback) {
        if (file.gzippedContent && file.gzippedContentLength) {
            return callback(null, file);
        }

        zlib.gzip(file.content, function gzipFile(err, gzippedContent) {
            if (err) {
                return callback(err);
            }

            file.gzippedContent = gzippedContent;
            file.gzippedContentLength = gzippedContent.length;

            callback(null, file);
        });
    }

    function hashifyCss(cssPath) {
        return files[cssPath].content.toString().replace(/url\(['"]?(.*?)['"]?\)/g, function(match, filename) {
            var file;

            if(filename[0] === '/') {
                file = files[filename];
            } else {
                var cssDir = path.dirname(cssPath);
                filename = path.normalize(path.join(cssDir, filename)).replace(/\\/g, '/');
                file = files[filename];
            }

            if (file) {
                return 'url(' + urlBuilder(filename, file.hash) + ')'; // Add hash
            }

            return match; // Passthrough
        });
    }

    function hashifyPath(filePath, hash) {
        if (filePath.indexOf('.') != -1) {
            return filePath.replace(/\.([^\.]*)([?#].*)?$/, '-' + hash + '.$1$2');
        }

        return filePath.replace(/([?#].*)?$/, '-' + hash + '$1');
    }

    function prefixSlash(path) {
        return path[0] === '/' ? path : '/' + path;
    }

    function reloadFile(filePath, stat) {
        stat = typeof stat === 'object' ? stat : fs.statSync(filePath);

        if (stat.isDirectory()) {
            fs.readdir(filePath, function(err, contents) {
                if (err) {
                    console.warn(err);
                } else {
                    contents.forEach(function reloadDirContent(innerPath) {
                        reloadFile(path.join(filePath, innerPath));
                    });
                }
            });
        }

        var ext = path.extname(filePath);

        if (ext === '.scss') {
            var sassDependencies = sassGraph.parseDir(directory);

            if (sassDependencies.index[filePath]) {
                sassDependencies.index[filePath].importedBy.forEach(reloadFile);
            }
        } else if (ext === '.js') {
            // Clear snockets cache
            snockets.cache = {};
            snockets.concatCache = {};

            snockets.scan(filePath);
            snockets.depGraph.parentsOf(filePath).forEach(reloadFile);
        }

        var relativeUrl = cacheFile(filePath, stat);

        if (stylesheets.indexOf(relativeUrl) != -1) {
            files[relativeUrl].content = hashifyCss(relativeUrl);
            files[relativeUrl].hash = crypto.createHash('md5').update(files[relativeUrl].content).digest('hex');
        }
    }

    function toRelativeUrl(filePath) {
        var relativeUrl = path.relative(directory, path.resolve(filePath));

        // Make URI-friendly and prepend a /
        return prefixSlash(relativeUrl).replace(/\\/g, '/');
    }

    function shouldIgnore(filePath, ignore) {
        if (!ignore) {
            // Not ignoring anything
            return false;
        }

        if (Array.isArray(ignore)) {
            // Multiple things to ignore
            return ignore.some(function ignoreElementMatch(ignored) {
                return shouldIgnore(filePath, ignored);
            });
        }

        return filePath.match(ignore) !== null;
    }

    function stripQueryAndTarget(filePath) {
        return filePath.replace(/[?#].*$/, '');
    }

    function urlBuilder(filePath) {
        var file = files[stripQueryAndTarget(prefixSlash(filePath))];

        if (file) {
            var uri = hashifyPath(prefixSlash(filePath), file.hash);

            if (options && options.hostname) {
                uri = '//' + options.hostname + uri;
            }

            return uri;
        } else {
            return filePath;
        }
    }

    // Load all files synchronously
    (function loadFiles(workingDir) {
        var contents = fs.readdirSync(workingDir);

        contents.forEach(function loadDirectory(file) {
            var filePath = path.join(workingDir, file);
            var stat = fs.statSync(filePath);

            if (stat.isDirectory()) {
                return loadFiles(filePath);
            }

            cacheFile(filePath, stat);
        });
    })(directory);

    // Hashify URLs in stylesheets
    stylesheets.forEach(function(stylesheet) {
        files[stylesheet].content = hashifyCss(stylesheet);
        files[stylesheet].hash = crypto.createHash('md5').update(files[stylesheet].content).digest('hex');
    });

    // Watch directory for changes
    if (options.watch.enabled) {
        watch.createMonitor(directory, function monitorFiles(monitor) {
            monitor.on('changed', reloadFile);
            monitor.on('created', reloadFile);

            monitor.on('removed', function removeFile(f, stat) {
                var compiledPath = f.replace(/\.scss$/, '.css');
                delete files[toRelativeUrl(compiledPath)];
            });
        });
    }

    return function staticMiddleware(req, res, next) {
        // Ignore anything that's not a GET or HEAD request
        if (req.method !== 'GET' && req.method !== 'HEAD') {
            return next();
        }

        // Register view helper if we haven't already
        if (!req.app.locals.electricity) {
            req.app.locals.electricity = {
                url: urlBuilder
            };
        }

        var reqInfo = dehashifyPath(req.path);
        var file = files[reqInfo.path];

        if (!file) {
            // Fall back to checking original path
            file = files[req.path];

            if (!file) {
                // Still no match
                return next();
            }
        }

        // Verify file matches the requested hash, otherwise 302
        if (reqInfo.hash !== file.hash) {
            res.set({
                'Cache-Control': 'no-cache',
                'Expires': '0',
                'Pragma': 'no-cache'
            });

            return res.redirect(hashifyPath(reqInfo.path, file.hash));
        }

        var expires = new Date();
        expires.setYear(expires.getFullYear() + 1);

        res.set({
            'Cache-Control': 'public, max-age=31536000', // One year
            'Content-Type': file.contentType,
            'ETag': file.hash,
            'Expires': expires.toUTCString(),
            'Last-Modified': file.modified.toUTCString()
        });

        if (options.headers) {
            res.set(options.headers);
        }

        if (req.get('If-None-Match') === file.hash) {
            res.status(304);
            res.end();
        } else if (new Date(req.get('If-Modified-Since')) >= file.modified) {
            res.status(304);
            res.end();
        } else {
            res.set({
                'Content-Length': file.contentLength
            });

            res.status(200);

            if (req.method === 'HEAD') {
                return res.end();
            }

            var negotiator = new Negotiator(req);

            if (negotiator.encodings(availableEncodings).indexOf('gzip') === 0 && gzipContentTypes.indexOf(file.contentType) !== -1) {
                gzip(file, function gzipCallback(err, gzippedFile) {
                    if (err) {
                        return next(err);
                    }

                    res.set({
                        'Content-Encoding': 'gzip',
                        'Content-Length': gzippedFile.gzippedContentLength
                    });

                    res.send(file.gzippedContent);
                });
            } else {
                res.send(file.content);
            }
        }
    };
};

// Object.assign polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}
<commit_msg>Update index.js<commit_after>var crypto = require('crypto');
var fs = require('fs');
var path = require('path');
var util = require('util');
var zlib = require('zlib');

var mime = require('mime');
var Negotiator = require('negotiator');
var react = require('react-tools');
var sass = require('node-sass');
var sassGraph = require('sass-graph');
var Snockets = require('snockets');
var Uglify = require('uglify-js');
var UglifyCss = require('uglifycss');
var watch = require('watch');

var availableEncodings = ['gzip', 'identity'];
var gzipContentTypes = require('./gzipContentTypes.js');

exports.static = function static(directory, options) {
    directory = path.resolve(directory || 'public');

    options = options ? Object.assign({}, options) : {};
    options.sass = options.sass || {};

    if (!options.sass) {
        options.sass = {};
    }

    if (!options.snockets) {
        options.snockets = {};
    }

    if (!options.jsx) {
        options.jsx = {};
    }

    options.snockets.async = false;

    if (!options.uglifycss) {
        options.uglifycss = {
            enabled: true
        };
    }

    if (!options.uglifyjs) {
        options.uglifyjs = {
            compress: {
                sequences: false
            },
            enabled: true
        };
    }

    if (!options.watch) {
        options.watch = {
            enabled: true
        };
    }

    if (options.hostname) {
        if (typeof options.hostname !== 'string') {
            throw Error('hostname must be a string');
        } else if (options.hostname.slice(-1) === '/') {
            options.hostname = options.hostname.slice(0, options.hostname.length - 1);
        }
    }

    if (options.sass.imagePath) {
        if (typeof options.sass.imagePath !== 'string') {
            throw Error('sass.imagePath must be a string');
        }
    }

    if (!options.sass.functions) {
        options.sass.functions = {};
    }

    options.sass.functions['image-url($img)'] = function(img) {
        return new sass.types.String('url("' +
            (options.sass.imagePath ?
                path.join('/', options.sass.imagePath, img.getValue()) :
                path.join('/', img.getValue())
            ) +
            '")');
    };

    var files = {};
    var snockets = new Snockets();
    var stylesheets = [];

    function cacheFile(filePath, stat) {
        // Make sure stat wasn't an extra index parameter
        stat = typeof stat === 'object' ? stat : fs.statSync(filePath);

        if (!stat.isDirectory()) {
            var data;
            var ext = path.extname(filePath);
            var relativeUrl = toRelativeUrl(filePath);

            // Compilation steps
            if (ext === '.scss' && !shouldIgnore(relativeUrl, options.sass.ignore)) {
                // Sass
                options.sass.file = filePath;
                data = sass.renderSync(options.sass).css.toString();

                // Future steps should treat this as plain CSS
                relativeUrl = relativeUrl.replace(/.scss$/, '.css');
                ext = '.css';
            } else if (ext === '.js' && !shouldIgnore(relativeUrl, options.snockets.ignore)) {
                // Snockets
                try {
                    data = snockets.getConcatenation(filePath, options.snockets);
                } catch (e) {
                    // Snockets can't parse, so just pass the js file along
                    console.warn('Snockets skipping ' + filePath + ":\n" + e);
                    data = fs.readFileSync(filePath).toString();
                }
            }

            if (ext === '.js' && !shouldIgnore(relativeUrl, options.jsx.ignore)) {
                // React
                data = data || fs.readFileSync(filePath).toString();

                try {
                    data = react.transform(data, options.jsx);
                } catch (e) {
                    // Snockets can't parse, so just pass the js file along
                    console.warn('JSX compiler skipping ' + filePath + ":\n" + e);
                    data = fs.readFileSync(filePath).toString();
                }

                ext = '.js';
            }

            // Postprocessing steps
            if (ext === '.css') {
                if (options.uglifycss.enabled) {
                    // Uglifycss
                    data = data ?
                        UglifyCss.processString(data, options.uglifycss) :
                        UglifyCss.processFiles([filePath], options.uglifycss);
                }
            } else if (ext === '.js' && options.uglifyjs.enabled && !shouldIgnore(relativeUrl, options.uglifyjs.ignore)) {
                // Uglifyjs
                options.uglifyjs.fromString = !!data;

                try {
                    data = options.uglifyjs.fromString ?
                        Uglify.minify(data.toString(), options.uglifyjs).code :
                        Uglify.minify(filePath, options.uglifyjs).code;
                } catch (e) {
                    console.warn(util.format('UglifyJS skipping %s:\n %s (line %s, col %s, pos %s)', filePath, e.message, e.line, e.col, e.pos));
                }
            }

            // Have data?
            data = data || fs.readFileSync(filePath);

            // Cache file and hash, generate hash later if it's CSS because we're going to modify the contents
            files[relativeUrl] = {
                content: data,
                contentLength: typeof data === 'string' ? Buffer.byteLength(data) : data.length,
                contentType: mime.lookup(relativeUrl),
                hash: ext !== '.css' ? crypto.createHash('md5').update(data).digest('hex') : '',
                modified: stat.mtime
            };

            if (ext === '.css') {
                stylesheets.push(relativeUrl);
            }

            return relativeUrl;
        }
    }

    function dehashifyPath(filePath) {
        var hashRegex = /-[0-9a-f]+(\.[^\.]*$)/;
        var hashMatch = filePath.match(hashRegex);
        var hash = hashMatch ? hashMatch[0].slice(1).replace(/\.([^\.]*$)/, '') : '';

        return {
            path: hash.length==32 ? filePath.replace(hashRegex, '$1') : filePath,
            hash: hash.length==32 ? hash : null
        };
    }

    function gzip(file, callback) {
        if (file.gzippedContent && file.gzippedContentLength) {
            return callback(null, file);
        }

        zlib.gzip(file.content, function gzipFile(err, gzippedContent) {
            if (err) {
                return callback(err);
            }

            file.gzippedContent = gzippedContent;
            file.gzippedContentLength = gzippedContent.length;

            callback(null, file);
        });
    }

    function hashifyCss(cssPath) {
        return files[cssPath].content.toString().replace(/url\(['"]?(.*?)['"]?\)/g, function(match, filename) {
            var file;

            if(filename[0] === '/') {
                file = files[filename];
            } else {
                var cssDir = path.dirname(cssPath);
                filename = path.normalize(path.join(cssDir, filename)).replace(/\\/g, '/');
                file = files[filename];
            }

            if (file) {
                return 'url(' + urlBuilder(filename, file.hash) + ')'; // Add hash
            }

            return match; // Passthrough
        });
    }

    function hashifyPath(filePath, hash) {
        if (filePath.indexOf('.') != -1) {
            return filePath.replace(/\.([^\.]*)([?#].*)?$/, '-' + hash + '.$1$2');
        }

        return filePath.replace(/([?#].*)?$/, '-' + hash + '$1');
    }

    function prefixSlash(path) {
        return path[0] === '/' ? path : '/' + path;
    }

    function reloadFile(filePath, stat) {
        stat = typeof stat === 'object' ? stat : fs.statSync(filePath);

        if (stat.isDirectory()) {
            fs.readdir(filePath, function(err, contents) {
                if (err) {
                    console.warn(err);
                } else {
                    contents.forEach(function reloadDirContent(innerPath) {
                        reloadFile(path.join(filePath, innerPath));
                    });
                }
            });
        }

        var ext = path.extname(filePath);

        if (ext === '.scss') {
            var sassDependencies = sassGraph.parseDir(directory);

            if (sassDependencies.index[filePath]) {
                sassDependencies.index[filePath].importedBy.forEach(reloadFile);
            }
        } else if (ext === '.js') {
            // Clear snockets cache
            snockets.cache = {};
            snockets.concatCache = {};

            snockets.scan(filePath);
            snockets.depGraph.parentsOf(filePath).forEach(reloadFile);
        }

        var relativeUrl = cacheFile(filePath, stat);

        if (stylesheets.indexOf(relativeUrl) != -1) {
            files[relativeUrl].content = hashifyCss(relativeUrl);
            files[relativeUrl].hash = crypto.createHash('md5').update(files[relativeUrl].content).digest('hex');
        }
    }

    function toRelativeUrl(filePath) {
        var relativeUrl = path.relative(directory, path.resolve(filePath));

        // Make URI-friendly and prepend a /
        return prefixSlash(relativeUrl).replace(/\\/g, '/');
    }

    function shouldIgnore(filePath, ignore) {
        if (!ignore) {
            // Not ignoring anything
            return false;
        }

        if (Array.isArray(ignore)) {
            // Multiple things to ignore
            return ignore.some(function ignoreElementMatch(ignored) {
                return shouldIgnore(filePath, ignored);
            });
        }

        return filePath.match(ignore) !== null;
    }

    function stripQueryAndTarget(filePath) {
        return filePath.replace(/[?#].*$/, '');
    }

    function urlBuilder(filePath) {
        var file = files[stripQueryAndTarget(prefixSlash(filePath))];

        if (file) {
            var uri = hashifyPath(prefixSlash(filePath), file.hash);

            if (options && options.hostname) {
                uri = '//' + options.hostname + uri;
            }

            return uri;
        } else {
            return filePath;
        }
    }

    // Load all files synchronously
    (function loadFiles(workingDir) {
        var contents = fs.readdirSync(workingDir);

        contents.forEach(function loadDirectory(file) {
            var filePath = path.join(workingDir, file);
            var stat = fs.statSync(filePath);

            if (stat.isDirectory()) {
                return loadFiles(filePath);
            }

            cacheFile(filePath, stat);
        });
    })(directory);

    // Hashify URLs in stylesheets
    stylesheets.forEach(function(stylesheet) {
        files[stylesheet].content = hashifyCss(stylesheet);
        files[stylesheet].hash = crypto.createHash('md5').update(files[stylesheet].content).digest('hex');
    });

    // Watch directory for changes
    if (options.watch.enabled) {
        watch.createMonitor(directory, function monitorFiles(monitor) {
            monitor.on('changed', reloadFile);
            monitor.on('created', reloadFile);

            monitor.on('removed', function removeFile(f, stat) {
                var compiledPath = f.replace(/\.scss$/, '.css');
                delete files[toRelativeUrl(compiledPath)];
            });
        });
    }

    return function staticMiddleware(req, res, next) {
        // Ignore anything that's not a GET or HEAD request
        if (req.method !== 'GET' && req.method !== 'HEAD') {
            return next();
        }

        // Register view helper if we haven't already
        if (!req.app.locals.electricity) {
            req.app.locals.electricity = {
                url: urlBuilder
            };
        }

        var reqInfo = dehashifyPath(req.path);
        var file = files[reqInfo.path];

        if (!file) {
            // Fall back to checking original path
            file = files[req.path];

            if (!file) {
                // Still no match
                return next();
            }
        }

        // Verify file matches the requested hash, otherwise 302
        if (reqInfo.hash !== file.hash) {
            res.set({
                'Cache-Control': 'no-cache',
                'Expires': '0',
                'Pragma': 'no-cache'
            });

            return res.redirect(hashifyPath(reqInfo.path, file.hash));
        }

        var expires = new Date();
        expires.setYear(expires.getFullYear() + 1);

        res.set({
            'Cache-Control': 'public, max-age=31536000', // One year
            'Content-Type': file.contentType,
            'ETag': file.hash,
            'Expires': expires.toUTCString(),
            'Last-Modified': file.modified.toUTCString()
        });

        if (options.headers) {
            res.set(options.headers);
        }

        if (req.get('If-None-Match') === file.hash) {
            res.status(304);
            res.end();
        } else if (new Date(req.get('If-Modified-Since')) >= file.modified) {
            res.status(304);
            res.end();
        } else {
            res.set({ 'Content-Length': file.contentLength });
            res.status(200);

            if (req.method === 'HEAD') {
                return res.end();
            }

            var negotiator = new Negotiator(req);

            if (negotiator.encodings(availableEncodings).indexOf('gzip') === 0 && gzipContentTypes.indexOf(file.contentType) !== -1) {
                gzip(file, function gzipCallback(err, gzippedFile) {
                    if (err) {
                        return next(err);
                    }

                    res.set({
                        'Content-Encoding': 'gzip',
                        'Content-Length': gzippedFile.gzippedContentLength
                    });

                    res.send(file.gzippedContent);
                });
            } else {
                res.send(file.content);
            }
        }
    };
};

// Object.assign polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
if (!Object.assign) {
  Object.defineProperty(Object, 'assign', {
    enumerable: false,
    configurable: true,
    writable: true,
    value: function(target) {
      if (target === undefined || target === null) {
        throw new TypeError('Cannot convert first argument to object');
      }

      var to = Object(target);
      for (var i = 1; i < arguments.length; i++) {
        var nextSource = arguments[i];
        if (nextSource === undefined || nextSource === null) {
          continue;
        }
        nextSource = Object(nextSource);

        var keysArray = Object.keys(nextSource);
        for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) {
          var nextKey = keysArray[nextIndex];
          var desc = Object.getOwnPropertyDescriptor(nextSource, nextKey);
          if (desc !== undefined && desc.enumerable) {
            to[nextKey] = nextSource[nextKey];
          }
        }
      }
      return to;
    }
  });
}
<|endoftext|>


<commit_before>/**
 * Bridge proxy
 *
 */

function WSBridgeProxy(config){

	// Simple websocket server

	var port = config.port;
	var master=null;

	(new (require('ws').Server)({
		port: port
	})).on('headers',function(h){
		console.log(h);
	}).on('connection', function(wsclient){

		//console.log(wsclient);

		if(master===null){
			master=wsclient;
			console.log('connected a master');
		}else{

			var a=master;
			master=null;
			var b=wsclient;
			console.log('connected a client');

			a.on('message', function message(data, flags) {
				console.log('master sent '+data);
				b.send(data);
			}).on('error',function(error){
				console.log('a error: '+error)
			}).on('close',function(code, message){
				console.log('a close: '+code+' '+message);
				a=null;
				if(b){
					b.close();
				}
			});

			b.on('message', function message(data, flags) {
				console.log('client sent '+data);
				a.send(data);

			}).on('error',function(error){
				console.log('b error: '+error)
			}).on('close',function(code, message){
				console.log('b close: '+code+' '+message);
				b=null;
				if(a){
					a.close();
				}

			});

		}

	}).on('error', function(error){
		console.log('error: '+error);
	})

	console.log('websocket listening on: '+port);

};

module.exports=WSBridgeProxy;

//console.log(argv);

if(process.argv){

	console.log(process.argv);

	var fs=require('fs');
	fs.realpath(process.argv[1],function(err, p1){

		fs.realpath(__filename,function(err, p2){

			console.log(p1+' '+p2);

			if(p1===p2){

				if(process.argc==3){
					new WSBridgeProxy({port:parseInt(process.argv[2])});
				}else{
					new WSBridgeProxy(require('./bridgeproxy.json'));
				}

			}

		});
	});
}

<commit_msg>upgradeReq<commit_after>/**
 * Bridge proxy
 *
 */

function WSBridgeProxy(config){

	// Simple websocket server

	var port = config.port;
	var master=null;

	(new (require('ws').Server)({
		port: port
	})).on('headers',function(h){
		//console.log(h);
	}).on('connection', function(wsclient){

		console.log(wsclient.upgradeReq);

		if(master===null){
			master=wsclient;
			console.log('connected a master');
		}else{

			var a=master;
			master=null;
			var b=wsclient;
			console.log('connected a client');

			a.on('message', function message(data, flags) {
				console.log('master sent '+data);
				b.send(data);
			}).on('error',function(error){
				console.log('a error: '+error)
			}).on('close',function(code, message){
				console.log('a close: '+code+' '+message);
				a=null;
				if(b){
					b.close();
				}
			});

			b.on('message', function message(data, flags) {
				console.log('client sent '+data);
				a.send(data);

			}).on('error',function(error){
				console.log('b error: '+error)
			}).on('close',function(code, message){
				console.log('b close: '+code+' '+message);
				b=null;
				if(a){
					a.close();
				}

			});

		}

	}).on('error', function(error){
		console.log('error: '+error);
	})

	console.log('websocket listening on: '+port);

};

module.exports=WSBridgeProxy;

//console.log(argv);

if(process.argv){

	console.log(process.argv);

	var fs=require('fs');
	fs.realpath(process.argv[1],function(err, p1){

		fs.realpath(__filename,function(err, p2){

			console.log(p1+' '+p2);

			if(p1===p2){

				if(process.argc==3){
					new WSBridgeProxy({port:parseInt(process.argv[2])});
				}else{
					new WSBridgeProxy(require('./bridgeproxy.json'));
				}

			}

		});
	});
}

<|endoftext|>