diff --git a/.codeclimate.yml b/.codeclimate.yml new file mode 100644 index 0000000..3c32358 --- /dev/null +++ b/.codeclimate.yml @@ -0,0 +1,15 @@ +version: "2" +plugins: + eslint: + enabled: true + duplication: + enabled: true + config: + languages: + - javascript + fixme: + enabled: true +exclude_patterns: +- "**/**.*" +- "**/**" +- "!index.js" diff --git a/.eslintrc.yml b/.eslintrc.yml new file mode 100644 index 0000000..30f229b --- /dev/null +++ b/.eslintrc.yml @@ -0,0 +1,210 @@ +env: + es6: true + node: true + +parserOptions: + sourceType: "module" + ecmaVersion: 6 + ecmaFeatures: + jsx: true + +# http://eslint.org/docs/rules/ +rules: + # Possible Errors + comma-dangle: [2, never] + no-cond-assign: 2 + no-console: 0 + no-constant-condition: 2 + no-control-regex: 2 + no-debugger: 2 + no-dupe-args: 2 + no-dupe-keys: 2 + no-duplicate-case: 2 + no-empty: 2 + no-empty-character-class: 2 + no-ex-assign: 2 + no-extra-boolean-cast: 2 + no-extra-parens: 0 + no-extra-semi: 2 + no-func-assign: 2 + no-inner-declarations: [2, functions] + no-invalid-regexp: 2 + no-irregular-whitespace: 2 + no-negated-in-lhs: 2 + no-obj-calls: 2 + no-regex-spaces: 2 + no-sparse-arrays: 2 + no-unexpected-multiline: 2 + no-unreachable: 2 + use-isnan: 2 + valid-jsdoc: 0 + valid-typeof: 2 + + # Best Practices + accessor-pairs: 2 + block-scoped-var: 0 + complexity: ["error", 20] + consistent-return: 0 + curly: 0 + default-case: 0 + dot-location: 0 + dot-notation: 0 + eqeqeq: 2 + guard-for-in: 2 + no-alert: 2 + no-caller: 2 + no-case-declarations: 2 + no-div-regex: 2 + no-else-return: 0 + no-labels: [ "error", { "allowLoop": true } ] + no-empty-pattern: 2 + no-eq-null: 2 + no-eval: 2 + no-extend-native: 2 + no-extra-bind: 2 + no-fallthrough: 2 + no-floating-decimal: 0 + no-implicit-coercion: 0 + no-implied-eval: 2 + no-invalid-this: 0 + no-iterator: 2 + no-lone-blocks: 2 + no-loop-func: 2 + no-magic-number: 0 + no-multi-spaces: 0 + no-multi-str: 0 + no-native-reassign: 2 + no-new-func: 2 + no-new-wrappers: 2 + no-new: 2 + no-octal-escape: 2 + no-octal: 2 + no-proto: 2 + no-redeclare: 2 + no-return-assign: 2 + no-script-url: 2 + no-self-compare: 2 + no-sequences: 0 + no-throw-literal: 0 + no-unused-expressions: 2 + no-useless-call: 2 + no-useless-concat: 2 + no-void: 2 + no-warning-comments: 0 + no-with: 2 + radix: 2 + vars-on-top: 0 + wrap-iife: 2 + yoda: 0 + + # Strict + strict: 0 + + # Variables + init-declarations: 0 + no-catch-shadow: 2 + no-delete-var: 2 + no-label-var: 2 + no-shadow-restricted-names: 2 + no-shadow: 0 + no-undef-init: 2 + no-undef: 0 + no-undefined: 0 + no-unused-vars: 0 + no-use-before-define: 0 + + # Node.js and CommonJS + callback-return: 2 + global-require: 2 + handle-callback-err: 2 + no-mixed-requires: 0 + no-new-require: 0 + no-path-concat: 2 + no-process-exit: 2 + no-restricted-modules: 0 + no-sync: 0 + + # Stylistic Issues + array-bracket-spacing: 0 + block-spacing: 0 + brace-style: 0 + camelcase: 0 + comma-spacing: 0 + comma-style: 0 + computed-property-spacing: 0 + consistent-this: 0 + eol-last: 0 + func-names: 0 + func-style: 0 + id-length: 0 + id-match: 0 + indent: 0 + jsx-quotes: 0 + key-spacing: 0 + linebreak-style: 0 + lines-around-comment: 0 + max-depth: 0 + max-len: 0 + max-nested-callbacks: 0 + max-params: 0 + max-statements: [2, 45] + new-cap: 0 + new-parens: 0 + newline-after-var: 0 + no-array-constructor: 0 + no-bitwise: 0 + no-continue: 0 + no-inline-comments: 0 + no-lonely-if: 0 + no-mixed-spaces-and-tabs: 0 + no-multiple-empty-lines: 0 + no-negated-condition: 0 + no-nested-ternary: 0 + no-new-object: 0 + no-plusplus: 0 + no-restricted-syntax: 0 + no-spaced-func: 0 + no-ternary: 0 + no-trailing-spaces: 0 + no-underscore-dangle: 0 + no-unneeded-ternary: 0 + object-curly-spacing: 0 + one-var: 0 + operator-assignment: 0 + operator-linebreak: 0 + padded-blocks: 0 + quote-props: 0 + quotes: 0 + require-jsdoc: 0 + semi-spacing: 0 + semi: 0 + sort-vars: 0 + keyword-spacing: [ "off", { "after": false, "before": false} ] + space-before-blocks: 0 + space-before-function-paren: 0 + space-in-parens: 0 + space-infix-ops: 0 + space-unary-ops: 0 + spaced-comment: 0 + wrap-regex: 0 + + # ECMAScript 6 + arrow-body-style: 0 + arrow-parens: 0 + arrow-spacing: 0 + constructor-super: 0 + generator-star-spacing: 0 + no-confusing-arrow: "off" + no-constant-condition": [ "off", { "checkLoops": false } ] + no-class-assign: 0 + no-const-assign: 0 + no-dupe-class-members: 0 + no-this-before-super: 0 + no-var: 0 + object-shorthand: 0 + prefer-arrow-callback: 0 + prefer-const: 0 + prefer-reflect: 0 + prefer-spread: 0 + prefer-template: 0 + require-yield: 0 diff --git a/.gitignore b/.gitignore index 46ad1e5..dde605a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,8 @@ .DS_Store node_modules/ .idea + +.vscode/ +coverage/ +/jsconfig.json +*.log diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..b2d5ad2 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,22 @@ +language: node_js +node_js: + - 4 + - 5 + - 6 + - 7 + - 8 + - 9 +services: + - mongodb +branches: + only: + - master +# before_install: +# - "npm install -g istanbul" +script: + - "npm run test-ci" +after_script: + - "npm install -g coveralls" + - "cat ./coverage/lcov.info | coveralls" +after_success: + - codeclimate-test-reporter < ./coverage/lcov.info \ No newline at end of file diff --git a/README.md b/README.md index 330426b..a85fcbf 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,11 @@ mongoose-i18n-localize is a mongoose plugin to support i18n and localization in It seems like [mongoose-i18n](https://github.com/elrolito/mongoose-i18n) is not longer supported and I didn't get it to work on my machine, so I decided to write my own version. +## Requirements + + - Node >= 4.0.0 + - Mongoose >= 4.12.2 + ## Usage ``` @@ -24,7 +29,8 @@ var schema = new mongoose.Schema({ }); schema.plugin(mongooseI18n, { - locales: ['en', 'de'] + locales: ['en', 'de'], + defaultLocale: 'de' // if not specified or invalid - will assume locales[0] }); var Model = mongoose.model('Name', schema); @@ -43,7 +49,9 @@ This will create a structure like: All validators of `name` get also assigned to `name.en` and `name.de`. -mongoose-i18n-localize adds the methods `toObjectLocalized(resource, locale)` and `toJSONLocalized(resource, locale)` to the i18n schema methods. To set the locale of a resource to `en`, just do: +Currently these field types (or an Array of these) support i18n: `String`, `Number`, `Boolean`, `Date`. + +mongoose-i18n-localize adds the methods `toObjectLocalized()` and `toJSONLocalized()` to the i18n schema methods. To set the locale of a resource to `en`, just do: ```js @@ -74,9 +82,46 @@ Model.find(function(err, resources) { Use `toObjectLocalized` or `toJSONLocalized` according to `toObject` or `toJSON`. -If you only want to show only one locale message use the methods -`toObjectLocalizedOnly(resource, locale, localeDefault)` or -`toJSONLocalizedOnly(resource, locale, localeDefault)`. +If you want the fields to assume only the localized values use the methods +`toObjectLocalizedOnly()` or +`toJSONLocalizedOnly()`. + + +```js +Model.find(function(err, resources) { + var localizedResources = resources.toJSONLocalizedOnly('de'); +}); + +``` + +`localizedResources` has now the following structure: + +```js +[ + { + name: 'hallo' + } +] +``` + +All methods accept 3 optional arguments: + 1. ``resource`` (Object) - document(s) to localize + 2. ``localeName`` (String) - target locale to populate ``.localized`` subfield(in case of ``.toObjectLocalized(), .toJSONLocalized()``) or the field itself (``.toObjectLocalizedOnly(), .toJSONLocalizedOnly()``). Will use ``options.defaultLocale`` if omitted. + 3. ``defaultLocaleName`` (String) - locale to fallback, if the value for ``localeName`` is ``undefined``. Will also use ``options.defaultLocale`` if omitted. + 4. ``serialization options`` (object) - params that are passed down to the native ``toObject/toJSON`` schema methods. + + ```js +Model.find(function(err, resources) { + var localizedResources; + localizedResources = resources.toJSONLocalized(); + localizedResources = resources.toJSONLocalizedOnly('de'); + localizedResources = resources.toObjectLocalized(resources, 'de', 'en'); + localizedResources = resources.toObjectLocalizedOnly('de', 'en'); + localizedResources = resources.toObjectLocalized(resources, 'de', 'en', {getters: true}); + localizedResources = resources.toObjectLocalizedOnly('de', 'en', {getters: true}); + localizedResources = resources.toObjectLocalizedOnly({getters: true}); +}); +``` # Tests diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 0000000..90a542b --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,20 @@ +environment: + matrix: + - nodejs_version: "4" + - nodejs_version: "5" + - nodejs_version: "6" + - nodejs_version: "7" + - nodejs_version: "8" + - nodejs_version: "9" +services: + - mongodb +branches: + only: + - master +install: + - "npm install -g istanbul" + - "npm install" +build: off +test_script: + - "npm run test-ci" +version: "{build}" \ No newline at end of file diff --git a/index.js b/index.js index 8d16af4..3830b75 100644 --- a/index.js +++ b/index.js @@ -1,114 +1,168 @@ /* jshint node: true */ 'use strict'; + +function forIn(obj, callb) { + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + var e = obj[k]; + callb(e, k); + } + } +} + function ArrNoDupe(a) { - var temp = {}, r = [], i = 0, k; - for (i ; i < a.length; i++) {temp[a[i]] = true;} - for (k in temp){ temp.hasOwnProperty(k) && r.push(k); } - return r; + var temp = {}, + r = [], + i = 0, + k; + for (i; i < a.length; i++) { + temp[a[i]] = true; + } + forIn(temp, function (v, k) { + r.push(k); + }); + return r; } -module.exports = function(schema, options) { - var options_locales = ArrNoDupe(options.locales||[]) + +function addLocales(prePath, pathname, schema, options_locales) { + var instance = schema.paths[pathname].instance, + config = {} ; - var addLocales = function(pathname, schema) { - var instance = schema.paths[pathname].instance; - var config = schema.paths[pathname].options; + forIn(schema.paths[pathname].options, function (el, key) { + config[key] = el; + }) + if (config.i18n && typeof instance === 'string' && instance.match(/^(String|Number|Boolean|Date)$/i)) { + delete(config.i18n); + config._i18n = true; + schema.remove(pathname); - if (config.i18n && (instance === 'String' || instance === 'Date')) { - delete(config.i18n); - schema.remove(pathname); + options_locales.forEach(function (locale) { + schema.path(pathname + '.' + locale, config); + }); + } +} - options_locales.forEach(function(locale) { - schema.path(pathname + '.' + locale, config); - }); +function recursiveIteration(prePath, schema, options_locales) { + forIn(schema.paths, function (schemaField, schemaPath) { + if (schemaField.schema) { + recursiveIteration(prePath + (prePath && '.') + schemaPath, schemaField.schema, options_locales); + } else { + addLocales(prePath, schemaField.path, schema, options_locales); + } + }); +} + +function getI18nCapsulePaths(prePath, schema) { + var i18nPathCapsules = [], + i18nCapsulePathMask = /^(.*)\.[^\.]*$/ + ; + forIn(schema.paths, function (schemaField, schemaPath) { + if (schema.childSchemas.find(function (modSch) { + return modSch.schema === schemaField.schema; + })) { + i18nPathCapsules = i18nPathCapsules.concat(getI18nCapsulePaths(prePath + (prePath && '.') + schemaPath, schemaField.schema)); + } else if (schemaField.options._i18n) { + var i18nCapsulePath = (prePath + (prePath && '.') + schemaPath).replace(i18nCapsulePathMask, '$1'); + if (!~i18nPathCapsules.indexOf(i18nCapsulePath)) { + i18nPathCapsules.push(i18nCapsulePath); + } } - }; + }); + return i18nPathCapsules; +} - var recursiveIteration = function(schema) { - for (var key in schema.paths) { - if (schema.paths[key].schema) recursiveIteration(schema.paths[key].schema); - else addLocales(schema.paths[key].path, schema); +function localyzeRecursive(obj, i18nCapsulePathArr, o) { + var thisSubObjPath = i18nCapsulePathArr[0], + thisSubObj = obj && obj[thisSubObjPath], + val, defVal + ; + if (obj && i18nCapsulePathArr.length === 1) { + if (obj[thisSubObjPath]) { + if (o.locale) { val = obj[thisSubObjPath][o.locale]; } + defVal = obj[thisSubObjPath][o.defaultLocale]; + val = (typeof val !== 'undefined') ? val : defVal; + if (o.only) { + obj[thisSubObjPath] = val; + } else { + obj[thisSubObjPath].localized = val; + } } - }; + } else if (thisSubObj && i18nCapsulePathArr.length > 1) { + if (thisSubObj instanceof Array) { + thisSubObj.map(function (i) { + localyzeRecursive(i, i18nCapsulePathArr.slice(1), o); + }); + } else { + localyzeRecursive(thisSubObj, i18nCapsulePathArr.slice(1), o); + } + } +} - if (options && options_locales instanceof Array && options_locales.length > 0) recursiveIteration(schema); +function addLocalized(o) { + var _obj = o.toJSON ? o.obj.toJSON(o.params) : o.obj.toObject(o.params), + val, defVal, _i18n_paths = []; + _i18n_paths = getI18nCapsulePaths('', o.obj.schema); + _i18n_paths.forEach(function (i18nCapsulePath) { + var i18nCapsulePathArr = i18nCapsulePath.split('.'); + localyzeRecursive(_obj, i18nCapsulePathArr, o); + }); + return _obj; +} - var localize = function(obj, locale, toJSON) { - var addLocalized = function(obj) { - for (var key in obj) { - if (key === '_id') continue; - else if (typeof obj[key] === 'object') addLocalized(obj[key]); - else if (key === locale) obj.localized = obj[key]; - } - return obj; - }; +function guessMorphAndApply(_this, args, extra) { + var o = {}, target, options_defaultLocale = extra[3]; + if (typeof args[0] === 'string') { + o.locale = args[0]; + } else if (args[0] && args[0].hasOwnProperty('isNew')) { + target = args[0]; + } + if (!o.locale && typeof args[1] === 'string') { + o.locale = args[1]; + } else if (o.locale && typeof args[1] === 'string') { + o.defaultLocale = args[1]; + } + if (args.length && typeof args[args.length-1] === 'object' && !args[args.length-1].hasOwnProperty('isNew')) { + o.params = args[args.length-1]; + } + if (target && typeof args[2] === 'string') { o.defaultLocale = args[2]; } + if (!target && _this.hasOwnProperty('isNew')) { target = _this; } + if (!o.defaultLocale) { o.defaultLocale = options_defaultLocale; } + if (!o.locale) { o.locale = options_defaultLocale; } + o.toJSON = extra[0]; + o.only = extra[1]; + o.obj = target; + return addLocalized(o); +} - if (obj instanceof Array) return obj.map(function(object) { - return addLocalized(toJSON ? object.toJSON() : object.toObject(), locale); - }); - else return addLocalized(toJSON ? obj.toJSON() : obj.toObject(), locale); - }; +function mongooseI18nLocalyse(schema, options) { + options = options || {}; + var options_locales = ArrNoDupe(options.locales || []), + options_defaultLocale = options.defaultLocale + ; - schema.methods.toJSONLocalized = function(obj, locale) { - var ret; - if (typeof obj === 'object') { - ret = localize(obj, locale, true); - } else if (typeof obj === 'string' && this.hasOwnProperty('isNew')) { - ret = localize(this, obj, true); + if (options_locales.length > 0) { + recursiveIteration('', schema, options_locales); + if (!~options_locales.indexOf(options_defaultLocale)) { + options_defaultLocale = options_locales[0]; } - return ret; - }; + } - schema.methods.toObjectLocalized = function(obj, locale) { - var ret; - if (typeof obj === 'object') { - ret = localize(obj, locale, false); - } else if (typeof obj === 'string' && this.hasOwnProperty('isNew')) { - ret = localize(this, obj, false); - } - return ret; + schema.methods.toJSONLocalized = function () { + return guessMorphAndApply(this, arguments, [true, false, 'toJSONLocalized', options_defaultLocale]); }; - - var localizeOnly = function(obj, locale, localeDefault, toJSON) { - var addLocalized = function(obj) { - for (var key in obj) { - if (key === '_id') continue; - else if (typeof obj[key] === 'object' && !(obj[key] instanceof Date)) { - addLocalized(obj[key]); - if(obj[key] && obj[key].localized !== undefined) { - obj[key] = obj[key].localized; - } else if(localeDefault && obj[key] && obj[key].default !== undefined) { - obj[key] = obj[key].default; - } - } - else if (key === locale) obj.localized = obj[key]; - else if (localeDefault && key === localeDefault) obj.default = obj[key]; - } - return obj; - }; - if (obj instanceof Array) return obj.map(function(object) { - return addLocalized(toJSON ? object.toJSON() : object.toObject(), locale); - }); - else return addLocalized(toJSON ? obj.toJSON() : obj.toObject(), locale); + schema.methods.toObjectLocalized = function () { + return guessMorphAndApply(this, arguments, [false, false, 'toObjectLocalized', options_defaultLocale]); }; - schema.methods.toJSONLocalizedOnly = function(obj, locale, localeDefault) { - var ret; - if (typeof obj === 'object') { - ret = localizeOnly(obj, locale, localeDefault, true); - } else if (typeof obj === 'string' && this.hasOwnProperty('isNew')) { - ret = localizeOnly(this, obj, locale, true); - } - return ret; + schema.methods.toJSONLocalizedOnly = function () { + return guessMorphAndApply(this, arguments, [true, true, 'toJSONLocalizedOnly', options_defaultLocale]); }; - schema.methods.toObjectLocalizedOnly = function(obj, locale, localeDefault) { - var ret; - if (typeof obj === 'object') { - ret = localizeOnly(obj, locale, localeDefault, false); - } else if (typeof obj === 'string' && this.hasOwnProperty('isNew')) { - ret = localizeOnly(this, obj, locale, false); - } - return ret; + schema.methods.toObjectLocalizedOnly = function () { + return guessMorphAndApply(this, arguments, [false, true, 'toObjectLocalizedOnly', options_defaultLocale]); }; -}; + +} + +module.exports = mongooseI18nLocalyse; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..b28abb8 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,1514 @@ +{ + "name": "mongoose-i18n-localize", + "version": "0.3.2", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "abbrev": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz", + "integrity": "sha1-kbR5JYinc4wl813W9jdSovh3YTU=", + "dev": true + }, + "align-text": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz", + "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=", + "dev": true, + "requires": { + "kind-of": "3.2.2", + "longest": "1.0.1", + "repeat-string": "1.6.1" + } + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "argparse": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz", + "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=", + "dev": true, + "requires": { + "sprintf-js": "1.0.3" + } + }, + "asn1": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz", + "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y=", + "dev": true + }, + "assert-plus": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "dev": true + }, + "async": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz", + "integrity": "sha1-LSFgx3iAMuTdbL4lAvH5osj2zeQ=", + "dev": true, + "requires": { + "lodash": "4.17.4" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "aws-sign2": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz", + "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz", + "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=", + "dev": true, + "optional": true, + "requires": { + "tweetnacl": "0.14.5" + } + }, + "bluebird": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz", + "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA==", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "brace-expansion": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz", + "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=", + "dev": true, + "requires": { + "balanced-match": "1.0.0", + "concat-map": "0.0.1" + } + }, + "browser-stdout": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.0.tgz", + "integrity": "sha1-81HTKWnTL6XXpVZxVCY9korjvR8=", + "dev": true + }, + "bson": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz", + "integrity": "sha1-k8ENOeqltYQVy8QFLz5T5WKwtyw=", + "dev": true + }, + "buffer-shims": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz", + "integrity": "sha1-mXjOMXOIxkmth5MCjDR37wRKi1E=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true, + "optional": true + }, + "caseless": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz", + "integrity": "sha1-cVuW6phBWTzDMGeSP17GDr2k99c=", + "dev": true + }, + "center-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz", + "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=", + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4", + "lazy-cache": "1.0.4" + } + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "2.2.1", + "escape-string-regexp": "1.0.5", + "has-ansi": "2.0.0", + "strip-ansi": "3.0.1", + "supports-color": "2.0.0" + }, + "dependencies": { + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "cliui": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz", + "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=", + "dev": true, + "optional": true, + "requires": { + "center-align": "0.1.3", + "right-align": "0.1.3", + "wordwrap": "0.0.2" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz", + "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=", + "dev": true, + "optional": true + } + } + }, + "codeclimate-test-reporter": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/codeclimate-test-reporter/-/codeclimate-test-reporter-0.5.0.tgz", + "integrity": "sha1-k/oGscGOQRc0kSjcTjiq0IBDgo4=", + "dev": true, + "requires": { + "async": "1.5.2", + "commander": "2.9.0", + "lcov-parse": "0.0.10", + "request": "2.79.0" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + } + } + }, + "combined-stream": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz", + "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=", + "dev": true, + "requires": { + "delayed-stream": "1.0.0" + } + }, + "commander": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz", + "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=", + "dev": true, + "requires": { + "graceful-readlink": "1.0.1" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.10.1" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true, + "optional": true + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "diff": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz", + "integrity": "sha1-yc45Okt8vQsFinJck98pkCeGj/k=", + "dev": true + }, + "ecc-jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz", + "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=", + "dev": true, + "optional": true, + "requires": { + "jsbn": "0.1.1" + } + }, + "es6-promise": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz", + "integrity": "sha1-7FYjOGgDKQkgcXDDlEjiREndH8Q=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.8.1.tgz", + "integrity": "sha1-WltTr0aTEQvrsIZ6o0MN07cKEBg=", + "dev": true, + "requires": { + "esprima": "2.7.3", + "estraverse": "1.9.3", + "esutils": "2.0.2", + "optionator": "0.8.2", + "source-map": "0.2.0" + } + }, + "esprima": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz", + "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=", + "dev": true + }, + "estraverse": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz", + "integrity": "sha1-r2fy3JIlgkFZUJJgkaQAXSnJu0Q=", + "dev": true + }, + "esutils": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", + "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", + "dev": true + }, + "extend": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz", + "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ=", + "dev": true + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "0.4.0", + "combined-stream": "1.0.5", + "mime-types": "2.1.17" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "generate-function": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz", + "integrity": "sha1-aFj+fAlpt9TpCTM3ZHrHn2DfvnQ=", + "dev": true + }, + "generate-object-property": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz", + "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=", + "dev": true, + "requires": { + "is-property": "1.0.2" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "1.0.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "glob": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz", + "integrity": "sha1-gFIR3wT6rxxjo2ADBs31reULLsg=", + "dev": true, + "requires": { + "fs.realpath": "1.0.0", + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "graceful-readlink": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz", + "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=", + "dev": true + }, + "growl": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz", + "integrity": "sha1-Dqd0NxXbjY3ixe3hd14bRayFwC8=", + "dev": true + }, + "handlebars": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.10.tgz", + "integrity": "sha1-PTDHGLCaPZbyPqTMH0A8TTup/08=", + "dev": true, + "requires": { + "async": "1.5.2", + "optimist": "0.6.1", + "source-map": "0.4.4", + "uglify-js": "2.8.29" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": "1.0.1" + } + } + } + }, + "har-validator": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz", + "integrity": "sha1-zcvAgYgmWtEZtqWnyKtw7s+10n0=", + "dev": true, + "requires": { + "chalk": "1.1.3", + "commander": "2.9.0", + "is-my-json-valid": "2.16.1", + "pinkie-promise": "2.0.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=", + "dev": true + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.10.1", + "cryptiles": "2.0.5", + "hoek": "2.16.3", + "sntp": "1.0.9" + } + }, + "he": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz", + "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=", + "dev": true + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "hooks-fixed": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-2.0.0.tgz", + "integrity": "sha1-oB2JTVKsf2WZu7H2PfycQR33DLo=", + "dev": true + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "0.2.0", + "jsprim": "1.4.1", + "sshpk": "1.13.1" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "1.4.0", + "wrappy": "1.0.2" + } + }, + "inherits": { + "version": "http://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "is-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz", + "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=", + "dev": true + }, + "is-my-json-valid": { + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.16.1.tgz", + "integrity": "sha512-ochPsqWS1WXj8ZnMIV0vnNXooaMhp7cyL4FMSIPKTtnV0Ha/T19G2b9kkhcNsabV9bxYkze7/aLZJb/bYuFduQ==", + "dev": true, + "requires": { + "generate-function": "2.0.0", + "generate-object-property": "1.2.0", + "jsonpointer": "4.0.1", + "xtend": "4.0.1" + } + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.4.5.tgz", + "integrity": "sha1-ZcfXPUxNqE1POsMQuRj7C4Azczs=", + "dev": true, + "requires": { + "abbrev": "1.0.9", + "async": "1.5.2", + "escodegen": "1.8.1", + "esprima": "2.7.3", + "glob": "5.0.15", + "handlebars": "4.0.10", + "js-yaml": "3.10.0", + "mkdirp": "0.5.1", + "nopt": "3.0.6", + "once": "1.4.0", + "resolve": "1.1.7", + "supports-color": "3.1.2", + "which": "1.3.0", + "wordwrap": "1.0.0" + }, + "dependencies": { + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "dev": true, + "requires": { + "inflight": "1.0.6", + "inherits": "2.0.3", + "minimatch": "3.0.4", + "once": "1.4.0", + "path-is-absolute": "1.0.1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "js-yaml": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz", + "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==", + "dev": true, + "requires": { + "argparse": "1.0.9", + "esprima": "4.0.0" + }, + "dependencies": { + "esprima": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz", + "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw==", + "dev": true + } + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true, + "optional": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json3": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.2.tgz", + "integrity": "sha1-PAQ0dD35Pi9cQq7nsZvLSDV19OE=", + "dev": true + }, + "jsonpointer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz", + "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=", + "dev": true + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "kareem": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/kareem/-/kareem-1.5.0.tgz", + "integrity": "sha1-4+QQHZ3P3imXadr0tNtk2JXRdEg=", + "dev": true + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "1.1.5" + } + }, + "lazy-cache": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz", + "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=", + "dev": true, + "optional": true + }, + "lcov-parse": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/lcov-parse/-/lcov-parse-0.0.10.tgz", + "integrity": "sha1-GwuP+ayceIklBYK3C3ExXZ2m2aM=", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2", + "type-check": "0.3.2" + } + }, + "lodash": { + "version": "4.17.4", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz", + "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4=", + "dev": true + }, + "lodash._baseassign": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/lodash._baseassign/-/lodash._baseassign-3.2.0.tgz", + "integrity": "sha1-jDigmVAPIVrQnlnxci/QxSv+Ck4=", + "dev": true, + "requires": { + "lodash._basecopy": "3.0.1", + "lodash.keys": "3.1.2" + } + }, + "lodash._basecopy": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz", + "integrity": "sha1-jaDmqHbPNEwK2KVIghEd08XHyjY=", + "dev": true + }, + "lodash._basecreate": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash._basecreate/-/lodash._basecreate-3.0.3.tgz", + "integrity": "sha1-G8ZhYU2qf8MRt9A78WgGoCE8+CE=", + "dev": true + }, + "lodash._getnative": { + "version": "3.9.1", + "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz", + "integrity": "sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U=", + "dev": true + }, + "lodash._isiterateecall": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz", + "integrity": "sha1-UgOte6Ql+uhCRg5pbbnPPmqsBXw=", + "dev": true + }, + "lodash.create": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/lodash.create/-/lodash.create-3.1.1.tgz", + "integrity": "sha1-1/KEnw29p+BGgruM1yqwIkYd6+c=", + "dev": true, + "requires": { + "lodash._baseassign": "3.2.0", + "lodash._basecreate": "3.0.3", + "lodash._isiterateecall": "3.0.9" + } + }, + "lodash.isarguments": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz", + "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo=", + "dev": true + }, + "lodash.isarray": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz", + "integrity": "sha1-eeTriMNqgSKvhvhEqpvNhRtfu1U=", + "dev": true + }, + "lodash.keys": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz", + "integrity": "sha1-TbwEcrFWvlCgsoaFXRvQsMZWCYo=", + "dev": true, + "requires": { + "lodash._getnative": "3.9.1", + "lodash.isarguments": "3.1.0", + "lodash.isarray": "3.0.4" + } + }, + "longest": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", + "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=", + "dev": true + }, + "mime-db": { + "version": "1.30.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz", + "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE=", + "dev": true + }, + "mime-types": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz", + "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=", + "dev": true, + "requires": { + "mime-db": "1.30.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "1.1.8" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "mocha": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-3.5.3.tgz", + "integrity": "sha512-/6na001MJWEtYxHOV1WLfsmR4YIynkUEhBwzsb+fk2qmQ3iqsi258l/Q2MWHJMImAcNpZ8DEdYAK72NHoIQ9Eg==", + "dev": true, + "requires": { + "browser-stdout": "1.3.0", + "commander": "2.9.0", + "debug": "2.6.8", + "diff": "3.2.0", + "escape-string-regexp": "1.0.5", + "glob": "7.1.1", + "growl": "1.9.2", + "he": "1.1.1", + "json3": "3.3.2", + "lodash.create": "3.1.1", + "mkdirp": "0.5.1", + "supports-color": "3.1.2" + } + }, + "mongodb": { + "version": "2.2.33", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.33.tgz", + "integrity": "sha1-tTfEcdNKZlG0jzb9vyl1A0Dgi1A=", + "dev": true, + "requires": { + "es6-promise": "3.2.1", + "mongodb-core": "2.1.17", + "readable-stream": "2.2.7" + } + }, + "mongodb-core": { + "version": "2.1.17", + "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.17.tgz", + "integrity": "sha1-pBizN6FKFJkPtRC5I97mqBMXPfg=", + "dev": true, + "requires": { + "bson": "1.0.4", + "require_optional": "1.0.1" + } + }, + "mongoose": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.12.2.tgz", + "integrity": "sha512-MyVqN3BSFoXAQw43mMFymcJoq0fqrKLfwsAmK5SnM+KucwdpWXXxTyGWJXfn5HDtsWSrQ5gyOsoHu/E8fAG6dw==", + "dev": true, + "requires": { + "async": "2.1.4", + "bson": "1.0.4", + "hooks-fixed": "2.0.0", + "kareem": "1.5.0", + "mongodb": "2.2.33", + "mpath": "0.3.0", + "mpromise": "0.5.5", + "mquery": "2.3.2", + "ms": "2.0.0", + "muri": "1.3.0", + "regexp-clone": "0.0.1", + "sliced": "1.0.1" + } + }, + "mpath": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.3.0.tgz", + "integrity": "sha1-elj3iem1/TyUUgY0FXlg8mvV70Q=", + "dev": true + }, + "mpromise": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mpromise/-/mpromise-0.5.5.tgz", + "integrity": "sha1-9bJCWddjrMIlewoMjG2Gb9UXMuY=", + "dev": true + }, + "mquery": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/mquery/-/mquery-2.3.2.tgz", + "integrity": "sha512-KXWMypZSvhCuqRtza+HMQZdYw7PfFBjBTFvP31NNAq0OX0/NTIgpcDpkWQ2uTxk6vGQtwQ2elhwhs+ZvCA8OaA==", + "dev": true, + "requires": { + "bluebird": "3.5.1", + "debug": "2.6.9", + "regexp-clone": "0.0.1", + "sliced": "0.0.5" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "sliced": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz", + "integrity": "sha1-XtwETKTrb3gW1Qui/GPiXY/kcH8=", + "dev": true + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "muri": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/muri/-/muri-1.3.0.tgz", + "integrity": "sha512-FiaFwKl864onHFFUV/a2szAl7X0fxVlSKNdhTf+BM8i8goEgYut8u5P9MqQqIYwvaMxjzVESsoEm/2kfkFH1rg==", + "dev": true + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1.0.9" + } + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "dev": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1.0.2" + } + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "0.0.8", + "wordwrap": "0.0.3" + }, + "dependencies": { + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + } + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "0.1.3", + "fast-levenshtein": "2.0.6", + "levn": "0.3.0", + "prelude-ls": "1.1.2", + "type-check": "0.3.2", + "wordwrap": "1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "2.0.4" + } + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.3.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.2.tgz", + "integrity": "sha1-51vV9uJoEioqDgvaYwslUMFmUCw=", + "dev": true + }, + "readable-stream": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.7.tgz", + "integrity": "sha1-BwV6y+JGeyIELTb5jFrVBwVOlbE=", + "dev": true, + "requires": { + "buffer-shims": "1.0.0", + "core-util-is": "1.0.2", + "inherits": "http://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "isarray": "1.0.0", + "process-nextick-args": "1.0.7", + "string_decoder": "1.0.3", + "util-deprecate": "1.0.2" + } + }, + "regexp-clone": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz", + "integrity": "sha1-p8LgmJH9vzj7sQ03b7cwA+aKxYk=", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.79.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz", + "integrity": "sha1-Tf5b9r6LjNw3/Pk+BLZVd3InEN4=", + "dev": true, + "requires": { + "aws-sign2": "0.6.0", + "aws4": "1.6.0", + "caseless": "0.11.0", + "combined-stream": "1.0.5", + "extend": "3.0.1", + "forever-agent": "0.6.1", + "form-data": "2.1.4", + "har-validator": "2.0.6", + "hawk": "3.1.3", + "http-signature": "1.1.1", + "is-typedarray": "1.0.0", + "isstream": "0.1.2", + "json-stringify-safe": "5.0.1", + "mime-types": "2.1.17", + "oauth-sign": "0.8.2", + "qs": "6.3.2", + "stringstream": "0.0.5", + "tough-cookie": "2.3.3", + "tunnel-agent": "0.4.3", + "uuid": "3.1.0" + } + }, + "require_optional": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.1.tgz", + "integrity": "sha512-qhM/y57enGWHAe3v/NcwML6a3/vfESLe/sGM2dII+gEO0BpKRUkWZow/tyloNqJyN6kXSl3RyyM8Ll5D/sJP8g==", + "dev": true, + "requires": { + "resolve-from": "2.0.0", + "semver": "5.4.1" + } + }, + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + }, + "resolve-from": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz", + "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=", + "dev": true + }, + "right-align": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz", + "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=", + "dev": true, + "optional": true, + "requires": { + "align-text": "0.1.4" + } + }, + "safe-buffer": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz", + "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==", + "dev": true + }, + "semver": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz", + "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg==", + "dev": true + }, + "should": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/should/-/should-13.1.2.tgz", + "integrity": "sha512-oiGqKOuE4t98vdCs4ICifvzL2u9nWMaziSXVwHOYPyqqY1gBzGZS6LvzIc5uEFN0PiS69Sbvcqyw9hbYXkF4og==", + "dev": true, + "requires": { + "should-equal": "2.0.0", + "should-format": "3.0.3", + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1", + "should-util": "1.0.0" + } + }, + "should-equal": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", + "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", + "dev": true, + "requires": { + "should-type": "1.4.0" + } + }, + "should-format": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", + "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-type-adaptors": "1.0.1" + } + }, + "should-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", + "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=", + "dev": true + }, + "should-type-adaptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.0.1.tgz", + "integrity": "sha1-7+VVPN9oz/ZuXF9RtxLcNRx3vqo=", + "dev": true, + "requires": { + "should-type": "1.4.0", + "should-util": "1.0.0" + } + }, + "should-util": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.0.tgz", + "integrity": "sha1-yYzaN0qmsZDfi6h8mInCtNtiAGM=", + "dev": true + }, + "sliced": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz", + "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=", + "dev": true + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.16.3" + } + }, + "source-map": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz", + "integrity": "sha1-2rc/vPwrqBm03gO9b26qSBZLP50=", + "dev": true, + "optional": true, + "requires": { + "amdefine": "1.0.1" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", + "dev": true + }, + "sshpk": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz", + "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=", + "dev": true, + "requires": { + "asn1": "0.2.3", + "assert-plus": "1.0.0", + "bcrypt-pbkdf": "1.0.1", + "dashdash": "1.14.1", + "ecc-jsbn": "0.1.1", + "getpass": "0.1.7", + "jsbn": "0.1.1", + "tweetnacl": "0.14.5" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "string_decoder": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz", + "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==", + "dev": true, + "requires": { + "safe-buffer": "5.1.1" + } + }, + "stringstream": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz", + "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg=", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "2.1.1" + } + }, + "supports-color": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.1.2.tgz", + "integrity": "sha1-cqJiiU2dQIuVbKBf83su2KbiotU=", + "dev": true, + "requires": { + "has-flag": "1.0.0" + } + }, + "tough-cookie": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz", + "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=", + "dev": true, + "requires": { + "punycode": "1.4.1" + } + }, + "tunnel-agent": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz", + "integrity": "sha1-Y3PbdpCf5XDgjXNYM2Xtgop07us=", + "dev": true + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true, + "optional": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "1.1.2" + } + }, + "uglify-js": { + "version": "2.8.29", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz", + "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=", + "dev": true, + "optional": true, + "requires": { + "source-map": "0.5.7", + "uglify-to-browserify": "1.0.2", + "yargs": "3.10.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true, + "optional": true + } + } + }, + "uglify-to-browserify": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz", + "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=", + "dev": true, + "optional": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", + "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "1.3.0" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "which": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz", + "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==", + "dev": true, + "requires": { + "isexe": "2.0.0" + } + }, + "window-size": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz", + "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=", + "dev": true, + "optional": true + }, + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "yargs": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz", + "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=", + "dev": true, + "optional": true, + "requires": { + "camelcase": "1.2.1", + "cliui": "2.1.0", + "decamelize": "1.2.0", + "window-size": "0.1.0" + } + } + } +} diff --git a/package.json b/package.json index 55564f7..4351bfb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mongoose-i18n-localize", - "version": "0.3.0", + "version": "0.3.3", "description": "Mongoose plugin to support i18n and localization", "author": { "name": "Matthias Fey", @@ -23,12 +23,21 @@ "url": "https://github.com/rusty1s/mongoose-i18n-localize/issues" }, "main": "index.js", + "engines": { + "node": ">=4.0.0" + }, + "directories": { + "test": "test" + }, "scripts": { - "test": "mocha test" + "test": "mocha test", + "test-ci": "istanbul cover ./node_modules/mocha/bin/_mocha" }, "devDependencies": { - "mocha": "^2.4.5", - "mongoose": "^4.2.8", - "should": "^7.1.1" + "mongoose": "^4.12.2", + "mocha": "^3.5.3", + "should": "^13.1.2", + "istanbul": "^0.4.5", + "codeclimate-test-reporter": "^0.5.0" } } diff --git a/test/helper.js b/test/helper.js index b1b3abc..20666f6 100644 --- a/test/helper.js +++ b/test/helper.js @@ -22,6 +22,18 @@ module.exports = { name: { type: String, i18n: true + }, + date: { + type: Date, + i18n: true + }, + number: { + type: Number, + i18n: true + }, + bool: { + type: Boolean, + i18n: true } }); }, @@ -37,6 +49,21 @@ module.exports = { }); }, + createI18nNestedObjectSchemaWithMultipleFields: function() { + return new mongoose.Schema({ + nested: { + name: { + type: String, + i18n: true + } + }, + name: { + type: String, + i18n: true + } + }); + }, + createI18nNestedArraySchema: function() { return new mongoose.Schema({ nested: [{ diff --git a/test/index.js b/test/index.js index 5f59348..4e4a95e 100644 --- a/test/index.js +++ b/test/index.js @@ -3,9 +3,16 @@ var mongoose = require('mongoose'); -mongoose.connect('mongodb://localhost/mongoose-i18n-localize'); -mongoose.connection.on('error', function() { - throw new Error('Unable to connect to database.'); +before(function name(done) { + mongoose.connect('mongodb://localhost/mongoose-i18n-localize', {useMongoClient: true}); + mongoose.connection.on('error', function() { + done(new Error('Unable to connect to database.')); + }); + mongoose.connection.on('connected', function() { + this.dropDatabase().then(function () { + done(); + }); + }); }); describe('Mongoose I18n Localize', function() { diff --git a/test/tests/i18n.js b/test/tests/i18n.js index 00c0c0c..d2469a5 100644 --- a/test/tests/i18n.js +++ b/test/tests/i18n.js @@ -1,54 +1,288 @@ /* jshint node: true, mocha: true */ 'use strict'; -var mongoose = require('mongoose'); -var should = require('should'); - -var helper = require('../helper'); -var mongooseI18n = require('../../index'); +var mongoose = require('mongoose'), + should = require('should'), + helper = require('../helper'), + mongooseI18n = require('../../index') +; +if (global.Promise) {mongoose.Promise = global.Promise;} module.exports = function() { - describe('I18n', function() { + describe('Configuration', function() { afterEach(helper.afterEach); - it('should store i18n fields', function(done) { + + it('should define defaultLocale from locales', function(done) { var Model = mongoose.model('I18nSchema', helper.createI18nSchema().plugin(mongooseI18n, { - locales: ['en', 'de'] - })); + locales: ['en', 'de'], + defaultLocale: 'fr' + })), + data = { + name: { + en: 'hello', + de: 'hallo', + fr: 'bonjour' + } + }, + doc = new Model(data), + methods = { + toJSONLocalized: { only: false }, + toJSONLocalizedOnly: { only: true }, + toObjectLocalized: { only: false }, + toObjectLocalizedOnly: { only: true }, + } + ; + for (var method in methods) { + if (methods.hasOwnProperty(method)) { + var methodOpts = methods[method], + formattedDocs = [doc[method](), doc[method]('en'), doc[method]('fr', 'en'), doc[method]('fr'), doc[method](doc), doc[method](doc, 'en'), doc[method](doc, 'fr', 'en')] + ; + formattedDocs.forEach(function(formattedDoc) { + if (methodOpts.only) { + formattedDoc.name.should.equal(data.name.en); + } else { + formattedDoc.name.localized.should.equal(data.name.en); + } + }, this); + } + } + done(); + }); + + it('should store i18n fields in nested schema', function(done) { + var Model = mongoose.model('I18nNestedSchema', helper.createI18nNestedSchema().plugin(mongooseI18n)); var model = new Model({ - name: { - en: 'hello', - de: 'hallo', - fr: 'bonjour' + nested: { + name: { + en: 'hello', + de: 'hallo' + } } }); - model.name.en.should.equal('hello'); - model.name.de.should.equal('hallo'); - should.not.exist(model.name.fr); + model.nested.name.en.should.equal('hello'); + model.nested.name.de.should.equal('hallo'); var json = Model.schema.methods.toJSONLocalized(model, 'de'); - json.name.en.should.equal('hello'); - json.name.de.should.equal('hallo'); - json.name.localized.should.equal('hallo'); + json.nested.name.en.should.equal('hello'); + json.nested.name.de.should.equal('hallo'); + should.equal(json.nested.name.localized, 'hallo'); - json = Model.schema.methods.toJSONLocalized(model, 'fr'); - json.name.en.should.equal('hello'); - json.name.de.should.equal('hallo'); - should.not.exist(json.name.localized); + var obj = Model.schema.methods.toObjectLocalized(model, 'en'); + obj.nested.name.en.should.equal('hello'); + obj.nested.name.de.should.equal('hallo'); + obj.nested.name.localized.should.equal('hello'); + + done(); + }); + + it('should store i18n fields in nested schema array', function(done) { + var Model = mongoose.model('I18nNestedSchemaArray', helper.createI18nNestedSchemaArray().plugin(mongooseI18n)); + + var model = new Model({ + nested: [{ + name: { + en: 'hello', + de: 'hallo' + } + }] + }); + + model.nested[0].name.en.should.equal('hello'); + model.nested[0].name.de.should.equal('hallo'); + + var json = Model.schema.methods.toJSONLocalized(model, 'de'); + json.nested[0].name.en.should.equal('hello'); + json.nested[0].name.de.should.equal('hallo'); + json.nested[0].name.localized.should.equal('hallo'); var obj = Model.schema.methods.toObjectLocalized(model, 'en'); - obj.name.en.should.equal('hello'); - obj.name.de.should.equal('hallo'); - obj.name.localized.should.equal('hello'); + obj.nested[0].name.en.should.equal('hello'); + obj.nested[0].name.de.should.equal('hallo'); + obj.nested[0].name.localized.should.equal('hello'); - obj = Model.schema.methods.toObjectLocalized(model, 'fr'); - obj.name.en.should.equal('hello'); - obj.name.de.should.equal('hallo'); - should.not.exist(obj.name.localized); + done(); + }); + it('should adopt validation for every i18n field', function(done) { + var Model = mongoose.model('I18nValidationSchema', helper.createI18nValidationSchema().plugin(mongooseI18n, { + locales: ['en', 'de'] + })); + Model.on('index', function name(merr) { + + new Model().save(function(err) { + should.exist(err); + err.errors['name.en'].kind.should.equal('required'); + err.errors['name.de'].kind.should.equal('required'); + + new Model({ + name: { + en: 'a', + de: '123' + } + }).save(function(err) { + should.exist(err); + err.errors['name.en'].kind.should.equal('minlength'); + err.errors['name.de'].kind.should.equal('user defined'); + + new Model({ + name: { + en: 'abc', + de: 'abc' + } + }).save(function(err) { + should.not.exist(err); + + new Model({ + name: { + en: 'abc', + de: 'def' + } + }).save(function(err, doc) { + should.exist(err); + err.message.should.match(/dup key/); + err.message.should.match(/name.en/); + + done(); + }); + }); + }); + }); + }); + }); + + }); + + describe('Consumption', function() { + afterEach(helper.afterEach); + + it('should store i18n fields', function(done) { + var Model = mongoose.model('I18nSchema', helper.createI18nSchema().plugin(mongooseI18n, { + locales: ['en', 'de'] + })), + locales = { + en: true, + de: true, + fr: false + }, + data = { + name: { + en: 'hello', + de: 'hallo', + fr: 'bonjour' + }, + date: { + en: new Date(2000, 1), + de: new Date(2000, 2), + fr: new Date(2000, 3) + }, + number: { + en: 1, + de: 2, + fr: 3 + }, + bool: { + en: true, + de: false, + fr: true + } + }, + doc = new Model(data), + formattedDocs = { + toJSONLocalized: { locale: 'de', data: doc.toJSONLocalized(doc, 'de') }, + toJSONLocalizedOnly: { locale: 'de', only: true, data: doc.toJSONLocalizedOnly(doc, 'de') }, + toObjectLocalized: { locale: 'en', data: doc.toObjectLocalized(doc, 'en') }, + toObjectLocalizedOnly: { locale: 'en', only: true, data: doc.toObjectLocalizedOnly(doc, 'en') }, + } + ; + + for (var field in data) { + if (data.hasOwnProperty(field)) { + var el = data[field], + localeName, method, methodData, methodLocaleName + ; + for (localeName in locales) { + if (locales.hasOwnProperty(localeName)) { + var exists = locales[localeName]; + if (exists) { + doc[field][localeName].toString().should.equal(el[localeName].toString(), 'document.'+field+'.'+localeName+' should be equal '+el[localeName].toString()); + for (method in formattedDocs) { + if (formattedDocs.hasOwnProperty(method)) { + if (!formattedDocs[method].only) { + formattedDocs[method].data[field][localeName].toString().should.equal(el[localeName].toString(), 'document.'+method+'().'+field+'.'+localeName+' should be equal '+el[localeName].toString()); + } + } + } + } else { + should.not.exist(doc[field][localeName], 'document.'+field+'.'+localeName+' shouldn\'t exist, got '+el.fr); + } + + } + } + for (method in formattedDocs) { + if (formattedDocs.hasOwnProperty(method)) { + methodLocaleName = formattedDocs[method].locale; + methodData = formattedDocs[method].only ? formattedDocs[method].data[field] : formattedDocs[method].data[field].localized; + methodData.toString().should.equal(el[methodLocaleName].toString(), 'document.'+method+'().'+field+'.'+methodLocaleName+(formattedDocs[method].only?'':'.localized')+' should be equal '+el[methodLocaleName].toString()); + } + } + } + } + + done(); + }); + + it('should understand different method morphology', function(done) { + var Model = mongoose.model('I18nSchema', helper.createI18nSchema().plugin(mongooseI18n, { + locales: ['en', 'de'] + })), + data = { + name: { + en: 'hello', + de: 'hallo', + fr: 'bonjour' + } + }, + doc = new Model(data), + methods = { + toJSONLocalized: { only: false }, + toJSONLocalizedOnly: { only: true }, + toObjectLocalized: { only: false }, + toObjectLocalizedOnly: { only: true }, + } + ; + for (var method in methods) { + if (methods.hasOwnProperty(method)) { + var methodOpts = methods[method], + formattedDocs = [ + doc[method](), + doc[method]('en'), + doc[method]('fr', 'en'), + doc[method]('fr'), + doc[method](doc), + doc[method](doc, 'en'), + doc[method](doc, 'fr', 'en'), + doc[method]({getters: true}), + doc[method]('en', {getters: true}), + doc[method]('fr', 'en', {getters: true}), + doc[method]('fr', {getters: true}), + doc[method](doc, {getters: true}), + doc[method](doc, 'en', {getters: true}), + doc[method](doc, 'fr', 'en', {getters: true}) + ] + ; + formattedDocs.forEach(function(formattedDoc) { + if (methodOpts.only) { + formattedDoc.name.should.equal(data.name.en); + } else { + formattedDoc.name.localized.should.equal(data.name.en); + } + }, this); + } + } done(); }); @@ -82,6 +316,34 @@ module.exports = function() { done(); }); + it('should store i18n fields with empty nested objects', function(done) { + var Model = mongoose.model('I18nNestedObjectSchema', helper.createI18nNestedObjectSchemaWithMultipleFields().plugin(mongooseI18n, { + locales: ['en', 'de'] + })); + + var model = new Model({ + name: { + en: 'hello', + de: 'hallo' + } + }); + + model.name.en.should.equal('hello'); + model.name.de.should.equal('hallo'); + + var json = Model.schema.methods.toJSONLocalized(model, 'de'); + json.name.en.should.equal('hello'); + json.name.de.should.equal('hallo'); + json.name.localized.should.equal('hallo'); + + var obj = Model.schema.methods.toObjectLocalized(model, 'en'); + obj.name.en.should.equal('hello'); + obj.name.de.should.equal('hallo'); + obj.name.localized.should.equal('hello'); + + done(); + }); + it('should store i18n fields in nested array', function(done) { var Model = mongoose.model('I18nNestedArraySchema', helper.createI18nNestedArraySchema().plugin(mongooseI18n, { locales: ['en', 'de'] @@ -169,106 +431,7 @@ module.exports = function() { done(); }); - }); - - it('should store i18n fields in nested schema', function(done) { - var Model = mongoose.model('I18nNestedSchema', helper.createI18nNestedSchema().plugin(mongooseI18n)); - - var model = new Model({ - nested: { - name: { - en: 'hello', - de: 'hallo' - } - } - }); - - model.nested.name.en.should.equal('hello'); - model.nested.name.de.should.equal('hallo'); - - var json = Model.schema.methods.toJSONLocalized(model, 'de'); - json.nested.name.en.should.equal('hello'); - json.nested.name.de.should.equal('hallo'); - json.nested.name.localized.should.equal('hallo'); - - var obj = Model.schema.methods.toObjectLocalized(model, 'en'); - obj.nested.name.en.should.equal('hello'); - obj.nested.name.de.should.equal('hallo'); - obj.nested.name.localized.should.equal('hello'); - - done(); - }); - - it('should store i18n fields in nested schema array', function(done) { - var Model = mongoose.model('I18nNestedSchemaArray', helper.createI18nNestedSchemaArray().plugin(mongooseI18n)); - - var model = new Model({ - nested: [{ - name: { - en: 'hello', - de: 'hallo' - } - }] - }); - model.nested[0].name.en.should.equal('hello'); - model.nested[0].name.de.should.equal('hallo'); - - var json = Model.schema.methods.toJSONLocalized(model, 'de'); - json.nested[0].name.en.should.equal('hello'); - json.nested[0].name.de.should.equal('hallo'); - json.nested[0].name.localized.should.equal('hallo'); - - var obj = Model.schema.methods.toObjectLocalized(model, 'en'); - obj.nested[0].name.en.should.equal('hello'); - obj.nested[0].name.de.should.equal('hallo'); - obj.nested[0].name.localized.should.equal('hello'); - - done(); }); - it('should adopt validation for every i18n field', function(done) { - var Model = mongoose.model('I18nValidationSchema', helper.createI18nValidationSchema().plugin(mongooseI18n, { - locales: ['en', 'de'] - })); - - new Model().save(function(err) { - should.exist(err); - err.errors['name.en'].kind.should.equal('required'); - err.errors['name.de'].kind.should.equal('required'); - - new Model({ - name: { - en: 'a', - de: '123' - } - }).save(function(err) { - should.exist(err); - err.errors['name.en'].kind.should.equal('minlength'); - err.errors['name.de'].kind.should.equal('user defined'); - - new Model({ - name: { - en: 'abc', - de: 'abc' - } - }).save(function(err) { - should.not.exist(err); - - new Model({ - name: { - en: 'abc', - de: 'def' - } - }).save(function(err) { - should.exist(err); - err.message.should.match(/dup key/); - err.message.should.match(/name.en/); - - done(); - }); - }); - }); - }); - }); };